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