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