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