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