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 accessToken The client registration access token. Must not be
107         *                    {@code null}.
108         * @param metadata    The client metadata. Must not be {@code null} and 
109         *                    must specify one or more redirection URIs.
110         * @param secret      The optional client secret, {@code null} if not
111         *                    specified.
112         */
113        public ClientUpdateRequest(final URI uri,
114                                   final ClientID id,
115                                   final BearerAccessToken accessToken,
116                                   final ClientMetadata metadata, 
117                                   final Secret secret) {
118
119                super(uri, accessToken);
120                
121                if (id == null)
122                        throw new IllegalArgumentException("The client identifier must not be null");
123                
124                this.id = id;
125
126                if (metadata == null)
127                        throw new IllegalArgumentException("The client metadata must not be null");
128                
129                this.metadata = metadata;
130                
131                this.secret = secret;
132        }
133        
134        
135        /**
136         * Gets the client ID. Corresponds to the {@code client_id} client
137         * registration parameter.
138         *
139         * @return The client ID, {@code null} if not specified.
140         */
141        public ClientID getClientID() {
142
143                return id;
144        }
145        
146        
147        /**
148         * Gets the associated client metadata.
149         *
150         * @return The client metadata.
151         */
152        public ClientMetadata getClientMetadata() {
153
154                return metadata;
155        }
156        
157        
158        /**
159         * Gets the client secret. Corresponds to the {@code client_secret} 
160         * registration parameters.
161         *
162         * @return The client secret, {@code null} if not specified.
163         */
164        public Secret getClientSecret() {
165
166                return secret;
167        }
168        
169        
170        @Override
171        public HTTPRequest toHTTPRequest() {
172                
173                if (getEndpointURI() == null)
174                        throw new SerializeException("The endpoint URI is not specified");
175
176                URL endpointURL;
177
178                try {
179                        endpointURL = getEndpointURI().toURL();
180
181                } catch (MalformedURLException e) {
182
183                        throw new SerializeException(e.getMessage(), e);
184                }
185
186                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.PUT, endpointURL);
187
188                httpRequest.setAuthorization(getAccessToken().toAuthorizationHeader());
189
190                httpRequest.setContentType(CommonContentTypes.APPLICATION_JSON);
191                
192                JSONObject jsonObject = metadata.toJSONObject();
193                
194                jsonObject.put("client_id", id.getValue());
195                
196                if (secret != null)
197                        jsonObject.put("client_secret", secret.getValue());
198
199                httpRequest.setQuery(jsonObject.toString());
200
201                return httpRequest;
202        }
203        
204        
205        /**
206         * Parses a client update request from the specified HTTP PUT request.
207         *
208         * @param httpRequest The HTTP request. Must not be {@code null}.
209         *
210         * @return The client update request.
211         *
212         * @throws ParseException If the HTTP request couldn't be parsed to a 
213         *                        client update request.
214         */
215        public static ClientUpdateRequest parse(final HTTPRequest httpRequest)
216                throws ParseException {
217
218                httpRequest.ensureMethod(HTTPRequest.Method.PUT);
219                
220                BearerAccessToken accessToken = BearerAccessToken.parse(httpRequest.getAuthorization());
221                
222                JSONObject jsonObject = httpRequest.getQueryAsJSONObject();
223                
224                ClientID id = new ClientID(JSONObjectUtils.getString(jsonObject, "client_id"));
225
226                ClientMetadata metadata = ClientMetadata.parse(jsonObject);
227                
228                Secret clientSecret = null;
229                
230                if (jsonObject.get("client_secret") != null)
231                        clientSecret = new Secret(JSONObjectUtils.getString(jsonObject, "client_secret"));
232                        
233                URI endpointURI;
234
235                try {
236                        endpointURI = httpRequest.getURL().toURI();
237
238                } catch (URISyntaxException e) {
239
240                        throw new ParseException(e.getMessage(), e);
241                }
242
243                return new ClientUpdateRequest(endpointURI, id, accessToken, metadata, clientSecret);
244        }
245}