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