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