001package com.nimbusds.oauth2.sdk.client;
002
003
004import java.net.MalformedURLException;
005import java.net.URI;
006import java.net.URISyntaxException;
007import java.net.URL;
008
009import net.jcip.annotations.Immutable;
010
011import net.minidev.json.JSONObject;
012
013import com.nimbusds.oauth2.sdk.ParseException;
014import com.nimbusds.oauth2.sdk.ProtectedResourceRequest;
015import com.nimbusds.oauth2.sdk.SerializeException;
016import com.nimbusds.oauth2.sdk.auth.Secret;
017import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
018import com.nimbusds.oauth2.sdk.http.HTTPRequest;
019import com.nimbusds.oauth2.sdk.id.ClientID;
020import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
021import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
022
023
024/**
025 * Client registration request.
026 * 
027 * <p>Example HTTP request:
028 *
029 * <pre>
030 * PUT /register/s6BhdRkqt3 HTTP/1.1
031 * Accept: application/json
032 * Host: server.example.com
033 * Authorization: Bearer reg-23410913-abewfq.123483
034 *
035 * {
036 *  "client_id"                  :"s6BhdRkqt3",
037 *  "client_secret"              : "cf136dc3c1fc93f31185e5885805d",
038 *  "redirect_uris"              : ["https://client.example.org/callback", "https://client.example.org/alt"],
039 *  "scope"                      : "read write dolphin",
040 *  "grant_types"                : ["authorization_code", "refresh_token"]
041 *  "token_endpoint_auth_method" : "client_secret_basic",
042 *  "jwks_uri"                   : "https://client.example.org/my_public_keys.jwks"
043 *  "client_name"                : "My New Example",
044 *  "client_name#fr"             : "Mon Nouvel Exemple",
045 *  "logo_uri"                   : "https://client.example.org/newlogo.png"
046 *  "logo_uri#fr"                : "https://client.example.org/fr/newlogo.png"
047 * }
048 *
049 * </pre>
050 *
051 * <p>Related specifications:
052 *
053 * <ul>
054 *     <li>OAuth 2.0 Dynamic Client Registration Protocol 
055 *         (draft-ietf-oauth-dyn-reg-14), section 4.3.
056 * </ul>
057 */
058@Immutable
059public class ClientUpdateRequest extends ProtectedResourceRequest {
060        
061        
062        /**
063         * The registered client ID.
064         */
065        private final ClientID id;
066        
067        
068        /**
069         * The client metadata.
070         */
071        private final ClientMetadata metadata;
072        
073        
074        /**
075         * The optional client secret.
076         */
077        private final Secret secret;
078        
079        
080        /**
081         * Creates a new client update request.
082         *
083         * @param uri         The URI of the client update endpoint. May be
084         *                    {@code null} if the {@link #toHTTPRequest()}
085         *                    method will not be used.
086         * @param accessToken The client registration access token. Must not be
087         *                    {@code null}.
088         * @param metadata    The client metadata. Must not be {@code null} and 
089         *                    must specify one or more redirection URIs.
090         * @param secret      The optional client secret, {@code null} if not
091         *                    specified.
092         */
093        public ClientUpdateRequest(final URI uri,
094                                   final ClientID id,
095                                   final BearerAccessToken accessToken,
096                                   final ClientMetadata metadata, 
097                                   final Secret secret) {
098
099                super(uri, accessToken);
100                
101                if (id == null)
102                        throw new IllegalArgumentException("The client identifier must not be null");
103                
104                this.id = id;
105
106                if (metadata == null)
107                        throw new IllegalArgumentException("The client metadata must not be null");
108                
109                this.metadata = metadata;
110                
111                this.secret = secret;
112        }
113        
114        
115        /**
116         * Gets the client ID. Corresponds to the {@code client_id} client
117         * registration parameter.
118         *
119         * @return The client ID, {@code null} if not specified.
120         */
121        public ClientID getClientID() {
122
123                return id;
124        }
125        
126        
127        /**
128         * Gets the associated client metadata.
129         *
130         * @return The client metadata.
131         */
132        public ClientMetadata getClientMetadata() {
133
134                return metadata;
135        }
136        
137        
138        /**
139         * Gets the client secret. Corresponds to the {@code client_secret} 
140         * registration parameters.
141         *
142         * @return The client secret, {@code null} if not specified.
143         */
144        public Secret getClientSecret() {
145
146                return secret;
147        }
148        
149        
150        @Override
151        public HTTPRequest toHTTPRequest()
152                throws SerializeException{
153                
154                if (getEndpointURI() == null)
155                        throw new SerializeException("The endpoint URI is not specified");
156
157                URL endpointURL;
158
159                try {
160                        endpointURL = getEndpointURI().toURL();
161
162                } catch (MalformedURLException e) {
163
164                        throw new SerializeException(e.getMessage(), e);
165                }
166
167                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.PUT, endpointURL);
168
169                httpRequest.setAuthorization(getAccessToken().toAuthorizationHeader());
170
171                httpRequest.setContentType(CommonContentTypes.APPLICATION_JSON);
172                
173                JSONObject jsonObject = metadata.toJSONObject();
174                
175                jsonObject.put("client_id", id.getValue());
176                
177                if (secret != null)
178                        jsonObject.put("client_secret", secret.getValue());
179
180                httpRequest.setQuery(jsonObject.toString());
181
182                return httpRequest;
183        }
184        
185        
186        /**
187         * Parses a client update request from the specified HTTP PUT request.
188         *
189         * @param httpRequest The HTTP request. Must not be {@code null}.
190         *
191         * @return The client update request.
192         *
193         * @throws ParseException If the HTTP request couldn't be parsed to a 
194         *                        client update request.
195         */
196        public static ClientUpdateRequest parse(final HTTPRequest httpRequest)
197                throws ParseException {
198
199                httpRequest.ensureMethod(HTTPRequest.Method.PUT);
200                
201                BearerAccessToken accessToken = BearerAccessToken.parse(httpRequest.getAuthorization());
202                
203                JSONObject jsonObject = httpRequest.getQueryAsJSONObject();
204                
205                ClientID id = new ClientID(JSONObjectUtils.getString(jsonObject, "client_id"));
206
207                ClientMetadata metadata = ClientMetadata.parse(jsonObject);
208                
209                Secret clientSecret = null;
210                
211                if (jsonObject.get("client_secret") != null)
212                        clientSecret = new Secret(JSONObjectUtils.getString(jsonObject, "client_secret"));
213                        
214                URI endpointURI;
215
216                try {
217                        endpointURI = httpRequest.getURL().toURI();
218
219                } catch (URISyntaxException e) {
220
221                        throw new ParseException(e.getMessage(), e);
222                }
223
224                return new ClientUpdateRequest(endpointURI, id, accessToken, metadata, clientSecret);
225        }
226}