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