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.Map;
022
023import com.nimbusds.oauth2.sdk.ParseException;
024import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
025import com.nimbusds.oauth2.sdk.http.HTTPRequest;
026import com.nimbusds.oauth2.sdk.id.ClientID;
027import org.apache.commons.lang3.StringUtils;
028
029
030/**
031 * Base abstract class for client authentication at the Token endpoint.
032 *
033 * <p>Related specifications:
034 *
035 * <ul>
036 *     <li>OAuth 2.0 (RFC 6749), section 2.3.
037 *     <li>Mutual TLS Profile for OAuth 2.0 (draft-ietf-oauth-mtls-03), section
038 *         2.1.
039 * </ul>
040 */
041public abstract class ClientAuthentication {
042        
043        
044        /**
045         * The client authentication method.
046         */
047        private final ClientAuthenticationMethod method;
048
049
050        /**
051         * The client ID.
052         */
053        private final ClientID clientID;
054        
055        
056        /**
057         * Creates a new abstract client authentication.
058         *
059         * @param method   The client authentication method. Must not be
060         *                 {@code null}.
061         * @param clientID The client identifier. Must not be {@code null}.
062         */
063        protected ClientAuthentication(final ClientAuthenticationMethod method, final ClientID clientID) {
064        
065                if (method == null)
066                        throw new IllegalArgumentException("The client authentication method must not be null");
067                
068                this.method = method;
069
070
071                if (clientID == null)
072                        throw new IllegalArgumentException("The client identifier must not be null");
073
074                this.clientID = clientID;
075        }
076        
077        
078        /**
079         * Gets the client authentication method.
080         *
081         * @return The client authentication method.
082         */
083        public ClientAuthenticationMethod getMethod() {
084        
085                return method;
086        }
087
088
089        /**
090         * Gets the client identifier.
091         *
092         * @return The client identifier.
093         */
094        public ClientID getClientID() {
095
096                return clientID;
097        }
098        
099        
100        /**
101         * Parses the specified HTTP request for a supported client 
102         * authentication (see {@link ClientAuthenticationMethod}). This method
103         * is intended to aid parsing of authenticated 
104         * {@link com.nimbusds.oauth2.sdk.TokenRequest}s.
105         *
106         * @param httpRequest The HTTP request to parse. Must not be 
107         *                    {@code null}.
108         *
109         * @return The client authentication method, {@code null} if none or 
110         *         the method is not supported.
111         *
112         * @throws ParseException If the inferred client authentication 
113         *                        couldn't be parsed.
114         */
115        public static ClientAuthentication parse(final HTTPRequest httpRequest)
116                throws ParseException {
117        
118                // Check for client secret basic
119                if (httpRequest.getAuthorization() != null && 
120                    httpRequest.getAuthorization().startsWith("Basic")) {
121                        
122                        return ClientSecretBasic.parse(httpRequest);
123                }
124                
125                // The other methods require HTTP POST with URL-encoded params
126                if (httpRequest.getMethod() != HTTPRequest.Method.POST &&
127                    ! httpRequest.getContentType().match(CommonContentTypes.APPLICATION_URLENCODED)) {
128                        return null; // no auth
129                }
130                
131                Map<String,String> params = httpRequest.getQueryParameters();
132                
133                // We have client secret post
134                if (StringUtils.isNotBlank(params.get("client_id")) && StringUtils.isNotBlank(params.get("client_secret"))) {
135                        return ClientSecretPost.parse(httpRequest);
136                }
137                
138                // Do we have a signed JWT assertion?
139                if (StringUtils.isNotBlank(params.get("client_assertion")) && StringUtils.isNotBlank(params.get("client_assertion_type"))) {
140                        return JWTAuthentication.parse(httpRequest);
141                }
142                
143                // Public key bound client TLS?
144                if (StringUtils.isNotBlank(params.get("client_id")) && httpRequest.getClientX509Certificate() != null) {
145                        // Don't do self-signed check, too expensive in terms of CPU time
146                        return PublicKeyTLSClientAuthentication.parse(httpRequest);
147                }
148                
149                // PKI bound client TLS?
150                if (StringUtils.isNotBlank(httpRequest.getClientX509CertificateSubjectDN())) {
151                        return TLSClientAuthentication.parse(httpRequest);
152                }
153                
154                return null; // no auth
155        }
156        
157        
158        /**
159         * Applies the authentication to the specified HTTP request by setting 
160         * its Authorization header and/or POST entity-body parameters 
161         * (according to the implemented client authentication method).
162         *
163         * @param httpRequest The HTTP request. Must not be {@code null}.
164         */
165        public abstract void applyTo(final HTTPRequest httpRequest);
166}