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.List;
023import java.util.Map;
024import javax.net.ssl.SSLSocketFactory;
025
026import net.jcip.annotations.Immutable;
027
028import com.nimbusds.oauth2.sdk.ParseException;
029import com.nimbusds.oauth2.sdk.http.HTTPRequest;
030import com.nimbusds.oauth2.sdk.id.ClientID;
031import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
032import com.nimbusds.oauth2.sdk.util.StringUtils;
033import com.nimbusds.oauth2.sdk.util.URLUtils;
034
035
036/**
037 * PKI mutual TLS client authentication at the Token endpoint. The client
038 * certificate is PKI bound, as opposed to
039 * {@link SelfSignedTLSClientAuthentication self_signed_tls_client_auth} which
040 * relies on a self-signed certificate. Implements
041 * {@link ClientAuthenticationMethod#TLS_CLIENT_AUTH}.
042 *
043 * <p>Related specifications:
044 *
045 * <ul>
046 *     <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound
047 *         Access Tokens (RFC 8705), section 2.1.
048 * </ul>
049 */
050@Immutable
051public class PKITLSClientAuthentication extends TLSClientAuthentication {
052        
053        
054        /**
055         * The client X.509 certificate subject DN.
056         */
057        private final String certSubjectDN;
058        
059        
060        /**
061         * Creates a new PKI mutual TLS client authentication. This constructor
062         * is intended for an outgoing token request.
063         *
064         * @param clientID         The client identifier. Must not be
065         *                         {@code null}.
066         * @param sslSocketFactory The SSL socket factory to use for the
067         *                         outgoing HTTPS request and to present the
068         *                         client certificate(s), {@code null} to use
069         *                         the default one.
070         */
071        public PKITLSClientAuthentication(final ClientID clientID,
072                                          final SSLSocketFactory sslSocketFactory) {
073                
074                super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID, sslSocketFactory);
075                certSubjectDN = null;
076        }
077        
078        
079        /**
080         * Creates a new PKI mutual TLS client authentication. This constructor
081         * is intended for a received token request.
082         *
083         * @param clientID      The client identifier. Must not be
084         *                      {@code null}.
085         * @param certSubjectDN The subject DN of the received validated client
086         *                      X.509 certificate. Must not be {@code null}.
087         * @deprecated This constructor does set the certificate
088         */
089        @Deprecated
090        public PKITLSClientAuthentication(final ClientID clientID,
091                                          final String certSubjectDN) {
092                
093                super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID, (X509Certificate) null);
094                
095                if (certSubjectDN == null) {
096                        throw new IllegalArgumentException("The X.509 client certificate subject DN must not be null");
097                }
098                this.certSubjectDN = certSubjectDN;
099        }
100        
101        
102        /**
103         * Creates a new PKI mutual TLS client authentication. This constructor
104         * is intended for a received token request.
105         *
106         * @param clientID    The client identifier. Must not be {@code null}.
107         * @param certificate The validated client X.509 certificate from the
108         *                    received HTTPS request. Must not be {@code null}.
109         */
110        public PKITLSClientAuthentication(final ClientID clientID,
111                                          final X509Certificate certificate) {
112                
113                super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID, certificate);
114                
115                if (certificate == null) {
116                        throw new IllegalArgumentException("The X.509 client certificate must not be null");
117                }
118                this.certSubjectDN = certificate.getSubjectX500Principal().getName();
119        }
120        
121        
122        /**
123         * Gets the subject DN of the received validated client X.509
124         * certificate.
125         *
126         * @return The subject DN.
127         */
128        public String getClientX509CertificateSubjectDN() {
129                
130                return certSubjectDN;
131        }
132        
133        
134        /**
135         * Parses a PKI mutual TLS client authentication from the specified
136         * HTTP request.
137         *
138         * @param httpRequest The HTTP request to parse. Must not be
139         *                    {@code null} and must include a validated client
140         *                    X.509 certificate.
141         *
142         * @return The PKI mutual TLS client authentication.
143         *
144         * @throws ParseException If the {@code client_id} or client X.509
145         *                        certificate is missing.
146         */
147        public static PKITLSClientAuthentication parse(final HTTPRequest httpRequest)
148                throws ParseException {
149                
150                String query = httpRequest.getQuery();
151                
152                if (query == null) {
153                        throw new ParseException("Missing HTTP POST request entity body");
154                }
155                
156                Map<String,List<String>> params = URLUtils.parseParameters(query);
157                
158                String clientIDString = MultivaluedMapUtils.getFirstValue(params, "client_id");
159                
160                if (StringUtils.isBlank(clientIDString)) {
161                        throw new ParseException("Missing client_id parameter");
162                }
163                
164                if (httpRequest.getClientX509Certificate() == null) {
165                        throw new ParseException("Missing client X.509 certificate");
166                }
167                
168                return new PKITLSClientAuthentication(
169                        new ClientID(clientIDString),
170                        httpRequest.getClientX509Certificate()
171                );
172        }
173}