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.util.Collections;
022import java.util.List;
023import java.util.Map;
024import javax.mail.internet.ContentType;
025import javax.net.ssl.SSLSocketFactory;
026
027import com.nimbusds.oauth2.sdk.SerializeException;
028import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
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 SSL socket factory for an outgoing HTTPS request, {@code null}
043         * to use the default one.
044         */
045        private final SSLSocketFactory sslSocketFactory;
046        
047        
048        /**
049         * Creates a new abstract mutual TLS client authentication. This
050         * constructor is intended for an outgoing token request.
051         *
052         * @param method           The client authentication method. Must not
053         *                         be {@code null}.
054         * @param clientID         The client identifier. Must not be
055         *                         {@code null}.
056         * @param sslSocketFactory The SSL socket factory to use for the
057         *                         outgoing HTTPS request and to present the
058         *                         client certificate(s), {@code null} to use
059         *                         the default one.
060         */
061        protected TLSClientAuthentication(final ClientAuthenticationMethod method,
062                                          final ClientID clientID,
063                                          final SSLSocketFactory sslSocketFactory) {
064                
065                super(method, clientID);
066                this.sslSocketFactory = sslSocketFactory;
067        }
068        
069        
070        /**
071         * Creates a new abstract mutual TLS client authentication. This
072         * constructor is intended for a received token request.
073         *
074         * @param method   The client authentication method. Must not be
075         *                 {@code null}.
076         * @param clientID The client identifier. Must not be {@code null}.
077         */
078        protected TLSClientAuthentication(final ClientAuthenticationMethod method,
079                                          final ClientID clientID) {
080                super(method, clientID);
081                sslSocketFactory = null;
082        }
083        
084        
085        /**
086         * Returns the SSL socket factory to use for an outgoing HTTPS request
087         * and to present the client certificate(s).
088         *
089         * @return The SSL socket factory, {@code null} to use the default one.
090         */
091        public SSLSocketFactory getSSLSocketFactory() {
092                
093                return sslSocketFactory;
094        }
095        
096        
097        @Override
098        public void applyTo(final HTTPRequest httpRequest) {
099                
100                if (httpRequest.getMethod() != HTTPRequest.Method.POST)
101                        throw new SerializeException("The HTTP request method must be POST");
102                
103                ContentType ct = httpRequest.getContentType();
104                
105                if (ct == null)
106                        throw new SerializeException("Missing HTTP Content-Type header");
107                
108                if (ct.match(CommonContentTypes.APPLICATION_JSON)) {
109                        
110                        // Possibly request object POST request, nothing to set
111                        
112                } else if (ct.match(CommonContentTypes.APPLICATION_URLENCODED)) {
113                        
114                        // Token or similar request
115                        Map<String,List<String>> params = httpRequest.getQueryParameters();
116                        params.put("client_id", Collections.singletonList(getClientID().getValue()));
117                        String queryString = URLUtils.serializeParameters(params);
118                        httpRequest.setQuery(queryString);
119                        
120                } else {
121                        throw new SerializeException("The HTTP Content-Type header must be " + CommonContentTypes.APPLICATION_URLENCODED);
122                }
123                
124                // If set for an outgoing request
125                httpRequest.setSSLSocketFactory(sslSocketFactory);
126        }
127}