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