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.HashMap;
022import java.util.Map;
023
024import javax.mail.internet.ContentType;
025
026import net.jcip.annotations.Immutable;
027
028import com.nimbusds.oauth2.sdk.ParseException;
029import com.nimbusds.oauth2.sdk.SerializeException;
030import com.nimbusds.oauth2.sdk.id.ClientID;
031import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
032import com.nimbusds.oauth2.sdk.http.HTTPRequest;
033import com.nimbusds.oauth2.sdk.util.URLUtils;
034
035
036/**
037 * Client secret post authentication at the Token endpoint. Implements
038 * {@link ClientAuthenticationMethod#CLIENT_SECRET_POST}.
039 *
040 * <p>Related specifications:
041 *
042 * <ul>
043 *     <li>OAuth 2.0 (RFC 6749), sections 2.3.1 and 3.2.1.
044 *     <li>OpenID Connect Core 1.0, section 9.
045 * </ul>
046 */
047@Immutable
048public final class ClientSecretPost extends PlainClientSecret {
049
050
051        /**
052         * Creates a new client secret post authentication.
053         *
054         * @param clientID The client identifier. Must not be {@code null}.
055         * @param secret   The client secret. Must not be {@code null}.
056         */
057        public ClientSecretPost(final ClientID clientID, final Secret secret) {
058        
059                super(ClientAuthenticationMethod.CLIENT_SECRET_POST, clientID, secret);
060        }
061        
062        
063        /**
064         * Returns the parameter representation of this client secret post
065         * authentication. Note that the parameters are not 
066         * {@code application/x-www-form-urlencoded} encoded.
067         *
068         * <p>Parameters map:
069         *
070         * <pre>
071         * "client_id" -> [client-identifier]
072         * "client_secret" -> [client-secret]
073         * </pre>
074         *
075         * @return The parameters map, with keys "client_id" and 
076         *         "client_secret".
077         */
078        public Map<String,String> toParameters() {
079        
080                Map<String,String> params = new HashMap<>();
081                params.put("client_id", getClientID().getValue());
082                params.put("client_secret", getClientSecret().getValue());
083                return params;
084        }
085        
086        
087        @Override
088        public void applyTo(final HTTPRequest httpRequest) {
089        
090                if (httpRequest.getMethod() != HTTPRequest.Method.POST)
091                        throw new SerializeException("The HTTP request method must be POST");
092                
093                ContentType ct = httpRequest.getContentType();
094                
095                if (ct == null)
096                        throw new SerializeException("Missing HTTP Content-Type header");
097                
098                if (! ct.match(CommonContentTypes.APPLICATION_URLENCODED))
099                        throw new SerializeException("The HTTP Content-Type header must be " + CommonContentTypes.APPLICATION_URLENCODED);
100                
101                Map <String,String> params = httpRequest.getQueryParameters();
102                
103                params.putAll(toParameters());
104                
105                String queryString = URLUtils.serializeParameters(params);
106                
107                httpRequest.setQuery(queryString);
108        }
109        
110        
111        /**
112         * Parses a client secret post authentication from the specified 
113         * parameters map. Note that the parameters must not be
114         * {@code application/x-www-form-urlencoded} encoded.
115         *
116         * @param params The parameters map to parse. The client secret post
117         *               parameters must be keyed under "client_id" and 
118         *               "client_secret". The map must not be {@code null}.
119         *
120         * @return The client secret post authentication.
121         *
122         * @throws ParseException If the parameters map couldn't be parsed to a 
123         *                        client secret post authentication.
124         */
125        public static ClientSecretPost parse(final Map<String,String> params)
126                throws ParseException {
127        
128                String clientIDString = params.get("client_id");
129                
130                if (clientIDString == null)
131                        throw new ParseException("Malformed client secret post authentication: Missing \"client_id\" parameter");
132                
133                String secretValue = params.get("client_secret");
134                
135                if (secretValue == null)
136                        throw new ParseException("Malformed client secret post authentication: Missing \"client_secret\" parameter");
137                
138                return new ClientSecretPost(new ClientID(clientIDString), new Secret(secretValue));
139        }
140        
141        
142        /**
143         * Parses a client secret post authentication from the specified 
144         * {@code application/x-www-form-urlencoded} encoded parameters string.
145         *
146         * @param paramsString The parameters string to parse. The client secret
147         *                     post parameters must be keyed under "client_id" 
148         *                     and "client_secret". The string must not be 
149         *                     {@code null}.
150         *
151         * @return The client secret post authentication.
152         *
153         * @throws ParseException If the parameters string couldn't be parsed to
154         *                        a client secret post authentication.
155         */
156        public static ClientSecretPost parse(final String paramsString)
157                throws ParseException {
158                
159                Map<String,String> params = URLUtils.parseParameters(paramsString);
160                
161                return parse(params);
162        }
163        
164        
165        /**
166         * Parses a client secret post authentication from the specified HTTP
167         * POST request.
168         *
169         * @param httpRequest The HTTP POST request to parse. Must not be 
170         *                    {@code null} and must contain a valid 
171         *                    {@code application/x-www-form-urlencoded} encoded 
172         *                    parameters string in the entity body. The client 
173         *                    secret post parameters must be keyed under 
174         *                    "client_id" and "client_secret".
175         *
176         * @return The client secret post authentication.
177         *
178         * @throws ParseException If the HTTP request header couldn't be parsed
179         *                        to a valid client secret post authentication.
180         */
181        public static ClientSecretPost parse(final HTTPRequest httpRequest)
182                throws ParseException {
183                
184                httpRequest.ensureMethod(HTTPRequest.Method.POST);
185                httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
186                
187                return parse(httpRequest.getQueryParameters());
188        }
189}