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