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;
027import net.minidev.json.JSONObject;
028
029import com.nimbusds.common.contenttype.ContentType;
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.HTTPRequest;
035import com.nimbusds.oauth2.sdk.id.ClientID;
036import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
037import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
038
039
040/**
041 * Client registration request.
042 * 
043 * <p>Example HTTP request:
044 *
045 * <pre>
046 * PUT /register/s6BhdRkqt3 HTTP/1.1
047 * Accept: application/json
048 * Host: server.example.com
049 * Authorization: Bearer reg-23410913-abewfq.123483
050 *
051 * {
052 *  "client_id"                  :"s6BhdRkqt3",
053 *  "client_secret"              : "cf136dc3c1fc93f31185e5885805d",
054 *  "redirect_uris"              : [ "https://client.example.org/callback",
055 *                                   "https://client.example.org/alt" ],
056 *  "scope"                      : "read write dolphin",
057 *  "grant_types"                : [ "authorization_code", "refresh_token" ]
058 *  "token_endpoint_auth_method" : "client_secret_basic",
059 *  "jwks_uri"                   : "https://client.example.org/my_public_keys.jwks"
060 *  "client_name"                : "My New Example",
061 *  "client_name#fr"             : "Mon Nouvel Exemple",
062 *  "logo_uri"                   : "https://client.example.org/newlogo.png"
063 *  "logo_uri#fr"                : "https://client.example.org/fr/newlogo.png"
064 * }
065 *
066 * </pre>
067 *
068 * <p>Related specifications:
069 *
070 * <ul>
071 *     <li>OAuth 2.0 Dynamic Client Registration Management Protocol (RFC
072 *         7592), section 2.2.
073 *     <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), section
074 *         2.
075 * </ul>
076 */
077@Immutable
078public class ClientUpdateRequest extends ProtectedResourceRequest {
079        
080        
081        /**
082         * The registered client ID.
083         */
084        private final ClientID id;
085        
086        
087        /**
088         * The client metadata.
089         */
090        private final ClientMetadata metadata;
091        
092        
093        /**
094         * The optional client secret.
095         */
096        private final Secret secret;
097        
098        
099        /**
100         * Creates a new client update request.
101         *
102         * @param uri         The URI of the client update endpoint. May be
103         *                    {@code null} if the {@link #toHTTPRequest()}
104         *                    method will not be used.
105         * @param id          The client ID. Must not be {@code null}.
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.setEntityContentType(ContentType.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}