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