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 com.nimbusds.oauth2.sdk.ParseException;
027import com.nimbusds.oauth2.sdk.http.HTTPRequest;
028import com.nimbusds.oauth2.sdk.id.ClientID;
029import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
030import com.nimbusds.oauth2.sdk.util.StringUtils;
031import com.nimbusds.oauth2.sdk.util.URLUtils;
032import net.jcip.annotations.Immutable;
033
034
035/**
036 * Self-signed certificate mutual TLS client authentication at the Token
037 * endpoint. The client certificate is self-signed, as opposed to
038 * {@link PKITLSClientAuthentication tls_client_auth} which relies on PKI
039 * binding. Implements
040 * {@link ClientAuthenticationMethod#SELF_SIGNED_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 (draft-ietf-oauth-mtls-14), section 2.2.
047 * </ul>
048 */
049@Immutable
050public class SelfSignedTLSClientAuthentication extends TLSClientAuthentication {
051        
052        
053        /**
054         * The validated client X.509 certificate from the received HTTPS
055         * request, {@code null} for an outgoing HTTPS request.
056         */
057        private final X509Certificate x509Certificate;
058        
059        
060        /**
061         * Creates a new self-signed certificate mutual TLS client
062         * authentication. This constructor is intended for an outgoing token
063         * request.
064         *
065         * @param clientID         The client identifier. Must not be
066         *                         {@code null}.
067         * @param sslSocketFactory The SSL socket factory to use for the
068         *                         outgoing HTTPS request and to present the
069         *                         client certificate(s), {@code null} to use
070         *                         the default one.
071         */
072        public SelfSignedTLSClientAuthentication(final ClientID clientID,
073                                                 final SSLSocketFactory sslSocketFactory) {
074                
075                super(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH, clientID, sslSocketFactory);
076                x509Certificate = null;
077        }
078        
079        
080        /**
081         * Creates a new self-signed certificate mutual TLS client
082         * authentication. This constructor is intended for a received token
083         * request.
084         *
085         * @param clientID        The client identifier. Must not be
086         *                        {@code null}.
087         * @param x509Certificate The validated client X.509 certificate from
088         *                        the received HTTPS request. Must not be
089         *                        {@code null}.
090         */
091        public SelfSignedTLSClientAuthentication(final ClientID clientID,
092                                                 final X509Certificate x509Certificate) {
093                
094                super(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH, clientID);
095                
096                if (x509Certificate == null) {
097                        throw new IllegalArgumentException("The client X.509 certificate must not be null");
098                }
099                
100                this.x509Certificate = x509Certificate;
101        }
102        
103        
104        /**
105         * Returns the validated client X.509 certificate from the received
106         * HTTPS request.
107         *
108         * @return The client X.509 certificate, {@code null} for an outgoing
109         *         HTTPS request.
110         */
111        public X509Certificate getClientX509Certificate() {
112                
113                return x509Certificate;
114        }
115        
116        
117        /**
118         * Parses a self-signed certificate mutual TLS client authentication
119         * from the specified HTTP request.
120         *
121         * @param httpRequest The HTTP request to parse. Must not be
122         *                    {@code null} and must include a validated client
123         *                    X.509 certificate.
124         *
125         * @return The self-signed TLS / X.509 certificate client
126         *         authentication.
127         *
128         * @throws ParseException If the {@code client_id} or client X.509
129         *                        certificate is missing.
130         */
131        public static SelfSignedTLSClientAuthentication parse(final HTTPRequest httpRequest)
132                throws ParseException {
133                
134                String query = httpRequest.getQuery();
135                
136                if (query == null) {
137                        throw new ParseException("Missing HTTP POST request entity body");
138                }
139                
140                Map<String,List<String>> params = URLUtils.parseParameters(query);
141                
142                String clientIDString = MultivaluedMapUtils.getFirstValue(params, "client_id");
143                
144                if (StringUtils.isBlank(clientIDString)) {
145                        throw new ParseException("Missing client_id parameter");
146                }
147                
148                X509Certificate cert = httpRequest.getClientX509Certificate();
149                
150                if (cert == null) {
151                        throw new ParseException("Missing client X.509 certificate");
152                }
153                
154                return new SelfSignedTLSClientAuthentication(new ClientID(clientIDString), cert);
155        }
156}