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 * PKI mutual TLS client authentication at the Token endpoint. The client
034 * certificate is PKI bound, as opposed to
035 * {@link SelfSignedTLSClientAuthentication self_signed_tls_client_auth} which
036 * relies on a self-signed certificate. Implements
037 * {@link ClientAuthenticationMethod#TLS_CLIENT_AUTH}.
038 *
039 * <p>Related specifications:
040 *
041 * <ul>
042 *     <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound
043 *         Access Tokens (draft-ietf-oauth-mtls-07), section 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         * Creates a new PKI mutual TLS client authentication. This constructor
058         * is intended for an outgoing token request.
059         *
060         * @param clientID         The client identifier. Must not be
061         *                         {@code null}.
062         * @param sslSocketFactory The SSL socket factory to use for the
063         *                         outgoing HTTPS request and to present the
064         *                         client certificate(s), {@code null} to use
065         *                         the default one.
066         */
067        public TLSClientAuthentication(final ClientID clientID,
068                                       final SSLSocketFactory sslSocketFactory) {
069                
070                super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID, sslSocketFactory);
071                certSubjectDN = null;
072        }
073        
074        
075        /**
076         * Creates a new PKI mutual TLS client authentication. This constructor
077         * is intended for a received token request.
078         *
079         * @param clientID      The client identifier. Must not be
080         *                      {@code null}.
081         * @param certSubjectDN The subject DN of the received validated client
082         *                      X.509 certificate. Must not be {@code null}.
083         */
084        public TLSClientAuthentication(final ClientID clientID,
085                                       final String certSubjectDN) {
086                
087                super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID);
088                
089                if (certSubjectDN == null) {
090                        throw new IllegalArgumentException("The X.509 client certificate subject DN must not be null");
091                }
092                this.certSubjectDN = certSubjectDN;
093        }
094        
095        
096        /**
097         * Gets the subject DN of the received validated client X.509
098         * certificate.
099         *
100         * @return The subject DN.
101         */
102        public String getClientX509CertificateSubjectDN() {
103                
104                return certSubjectDN;
105        }
106        
107        
108        /**
109         * Parses a PKI mutual TLS client authentication from the specified
110         * HTTP request.
111         *
112         * @param httpRequest The HTTP request to parse. Must not be
113         *                    {@code null} and must include a validated client
114         *                    X.509 certificate.
115         *
116         * @return The PKI mutual TLS client authentication.
117         *
118         * @throws ParseException If the {@code client_id} or client X.509
119         *                        certificate is missing.
120         */
121        public static TLSClientAuthentication parse(final HTTPRequest httpRequest)
122                throws ParseException {
123                
124                String query = httpRequest.getQuery();
125                
126                if (query == null) {
127                        throw new ParseException("Missing HTTP POST request entity body");
128                }
129                
130                Map<String,String> params = URLUtils.parseParameters(query);
131                
132                String clientIDString = params.get("client_id");
133                
134                if (StringUtils.isBlank(clientIDString)) {
135                        throw new ParseException("Missing client_id parameter");
136                }
137                
138                if (httpRequest.getClientX509CertificateSubjectDN() == null) {
139                        throw new ParseException("Missing client X.509 certificate subject DN");
140                }
141                
142                return new TLSClientAuthentication(
143                        new ClientID(clientIDString),
144                        httpRequest.getClientX509CertificateSubjectDN()
145                );
146        }
147}