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.Collections;
023import java.util.List;
024import java.util.Map;
025import javax.net.ssl.SSLSocketFactory;
026
027import com.nimbusds.common.contenttype.ContentType;
028import com.nimbusds.oauth2.sdk.SerializeException;
029import com.nimbusds.oauth2.sdk.http.HTTPRequest;
030import com.nimbusds.oauth2.sdk.id.ClientID;
031import com.nimbusds.oauth2.sdk.util.URLUtils;
032
033
034/**
035 * The base abstract class for mutual TLS client authentication at the Token
036 * endpoint.
037 */
038public abstract class TLSClientAuthentication extends ClientAuthentication {
039        
040        
041        /**
042         * The validated client X.509 certificate from the received HTTPS
043         * request, {@code null} for an outgoing HTTPS request.
044         */
045        protected final X509Certificate certificate;
046        
047        
048        /**
049         * The SSL socket factory for an outgoing HTTPS request, {@code null}
050         * to use the default one.
051         */
052        private final SSLSocketFactory sslSocketFactory;
053        
054        
055        /**
056         * Creates a new abstract mutual TLS client authentication. This
057         * constructor is intended for an outgoing token request.
058         *
059         * @param method           The client authentication method. Must not
060         *                         be {@code null}.
061         * @param clientID         The client identifier. Must not be
062         *                         {@code null}.
063         * @param sslSocketFactory The SSL socket factory to use for the
064         *                         outgoing HTTPS request and to present the
065         *                         client certificate(s), {@code null} to use
066         *                         the default one.
067         */
068        protected TLSClientAuthentication(final ClientAuthenticationMethod method,
069                                          final ClientID clientID,
070                                          final SSLSocketFactory sslSocketFactory) {
071                
072                super(method, clientID);
073                this.sslSocketFactory = sslSocketFactory;
074                certificate = null;
075        }
076        
077        
078        /**
079         * Creates a new abstract mutual TLS client authentication. This
080         * constructor is intended for a received token request.
081         *
082         * @param method      The client authentication method. Must not be
083         *                    {@code null}.
084         * @param clientID    The client identifier. Must not be {@code null}.
085         * @param certificate The validated client X.509 certificate from the
086         *                    received HTTPS request. Should not be
087         *                    {@code null}.
088         */
089        protected TLSClientAuthentication(final ClientAuthenticationMethod method,
090                                          final ClientID clientID,
091                                          final X509Certificate certificate) {
092                super(method, clientID);
093                sslSocketFactory = null;
094                this.certificate = certificate;
095        }
096        
097        
098        /**
099         * Returns the SSL socket factory to use for an outgoing HTTPS request
100         * and to present the client certificate(s).
101         *
102         * @return The SSL socket factory, {@code null} to use the default one.
103         */
104        public SSLSocketFactory getSSLSocketFactory() {
105                
106                return sslSocketFactory;
107        }
108        
109        
110        /**
111         * The validated client X.509 certificate from the received HTTPS
112         * request.
113         *
114         * @return The validated client X.509 certificate from the received
115         *         HTTPS request, {@code null} for an outgoing HTTPS request.
116         */
117        public X509Certificate getClientX509Certificate() {
118                
119                return certificate;
120        }
121        
122        
123        @Override
124        public void applyTo(final HTTPRequest httpRequest) {
125                
126                if (httpRequest.getMethod() != HTTPRequest.Method.POST)
127                        throw new SerializeException("The HTTP request method must be POST");
128                
129                ContentType ct = httpRequest.getEntityContentType();
130                
131                if (ct == null)
132                        throw new SerializeException("Missing HTTP Content-Type header");
133                
134                if (ct.matches(ContentType.APPLICATION_JSON)) {
135                        
136                        // Possibly request object POST request, nothing to set
137                        
138                } else if (ct.matches(ContentType.APPLICATION_URLENCODED)) {
139                        
140                        // Token or similar request
141                        Map<String,List<String>> params = httpRequest.getQueryParameters();
142                        params.put("client_id", Collections.singletonList(getClientID().getValue()));
143                        String queryString = URLUtils.serializeParameters(params);
144                        httpRequest.setQuery(queryString);
145                        
146                } else {
147                        throw new SerializeException("The HTTP Content-Type header must be " + ContentType.APPLICATION_URLENCODED);
148                }
149                
150                // If set for an outgoing request
151                httpRequest.setSSLSocketFactory(sslSocketFactory);
152        }
153}