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