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}