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