001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk.auth;
019
020
021import java.security.cert.X509Certificate;
022import java.util.Map;
023import javax.net.ssl.SSLSocketFactory;
024
025import com.nimbusds.oauth2.sdk.ParseException;
026import com.nimbusds.oauth2.sdk.http.HTTPRequest;
027import com.nimbusds.oauth2.sdk.id.ClientID;
028import com.nimbusds.oauth2.sdk.util.URLUtils;
029import net.jcip.annotations.Immutable;
030import org.apache.commons.lang3.StringUtils;
031
032
033/**
034 * Public key TLS / X.509 certificate client authentication at the Token
035 * endpoint. The client certificate is public key bound and typically
036 * self-signed, as opposed to {@link TLSClientAuthentication tls_client_auth}
037 * which relies on PKI binding. Implements
038 * {@link ClientAuthenticationMethod#PUB_KEY_TLS_CLIENT_AUTH}.
039 *
040 * <p>Related specifications:
041 *
042 * <ul>
043 *     <li>Mutual TLS Profile for OAuth 2.0 (draft-ietf-oauth-mtls-03), section
044 *         2.1.
045 * </ul>
046 */
047@Immutable
048public class PublicKeyTLSClientAuthentication extends AbstractTLSClientAuthentication {
049        
050        
051        /**
052         * The validated client X.509 certificate from the received HTTPS
053         * request, {@code null} for an outgoing HTTPS request.
054         */
055        private final X509Certificate x509Certificate;
056        
057        
058        /**
059         * Creates a new public key TLS / X.509 certificate client
060         * authentication. This constructor is intended for an outgoing token
061         * request.
062         *
063         * @param clientID         The client identifier. Must not be
064         *                         {@code null}.
065         * @param sslSocketFactory The SSL socket factory to use for the
066         *                         outgoing HTTPS request and to present the
067         *                         client certificate(s), {@code null} to use
068         *                         the default one.
069         */
070        public PublicKeyTLSClientAuthentication(final ClientID clientID,
071                                                final SSLSocketFactory sslSocketFactory) {
072                
073                super(ClientAuthenticationMethod.PUB_KEY_TLS_CLIENT_AUTH, clientID, sslSocketFactory);
074                x509Certificate = null;
075        }
076        
077        
078        /**
079         * Creates a new public key TLS / X.509 certificate client
080         * authentication. This constructor is intended for a received token
081         * request.
082         *
083         * @param clientID        The client identifier. Must not be
084         *                        {@code null}.
085         * @param x509Certificate The validated client X.509 certificate from
086         *                        the received HTTPS request. Must not be
087         *                        {@code null}.
088         */
089        public PublicKeyTLSClientAuthentication(final ClientID clientID,
090                                                final X509Certificate x509Certificate) {
091                
092                super(ClientAuthenticationMethod.PUB_KEY_TLS_CLIENT_AUTH, clientID);
093                
094                if (x509Certificate == null) {
095                        throw new IllegalArgumentException("The client X.509 certificate must not be null");
096                }
097                
098                this.x509Certificate = x509Certificate;
099        }
100        
101        
102        /**
103         * Returns the validated client X.509 certificate from the received
104         * HTTPS request.
105         *
106         * @return The client X.509 certificate, {@code null} for an outgoing
107         *         HTTPS request.
108         */
109        public X509Certificate getClientX509Certificate() {
110                
111                return x509Certificate;
112        }
113        
114        
115        /**
116         * Parses a public key TLS / X.509 certificate client authentication
117         * from the specified HTTP request.
118         *
119         * @param httpRequest The HTTP request to parse. Must not be
120         *                    {@code null} and must include a validated client
121         *                    X.509 certificate.
122         *
123         * @return The public key TLS / X.509 certificate client
124         *         authentication.
125         *
126         * @throws ParseException If the {@code client_id} or client X.509
127         *                        certificate is missing.
128         */
129        public static PublicKeyTLSClientAuthentication parse(final HTTPRequest httpRequest)
130                throws ParseException {
131                
132                String query = httpRequest.getQuery();
133                
134                if (query == null) {
135                        throw new ParseException("Missing HTTP POST request entity body");
136                }
137                
138                Map<String,String> params = URLUtils.parseParameters(query);
139                
140                String clientIDString = params.get("client_id");
141                
142                if (StringUtils.isBlank(clientIDString)) {
143                        throw new ParseException("Missing client_id parameter");
144                }
145                
146                X509Certificate cert = httpRequest.getClientX509Certificate();
147                
148                if (cert == null) {
149                        throw new ParseException("Missing client X.509 certificate");
150                }
151                
152                return new PublicKeyTLSClientAuthentication(new ClientID(clientIDString), cert);
153        }
154}