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