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