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