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