This is an automated email from the ASF dual-hosted git repository.
buhhunyx pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/master by this push:
new 169be66 CXF-8229 OAuth 2.0 Dynamic Client Registration: Client Update
Request (#646)
169be66 is described below
commit 169be66c11851d723e4a8d93f752e0b3dff1fa60
Author: Alexey Markevich <[email protected]>
AuthorDate: Fri Mar 6 23:43:31 2020 +0300
CXF-8229 OAuth 2.0 Dynamic Client Registration: Client Update Request (#646)
* CXF-8229 OAuth 2.0 Dynamic Client Registration: Client Update Request
* add negative test cases
---
.../services/DynamicRegistrationService.java | 50 +++++---
.../cxf/rs/security/oauth2/utils/OAuthUtils.java | 2 +-
.../security/oidc/OIDCDynamicRegistrationTest.java | 141 +++++++++++++--------
3 files changed, 120 insertions(+), 73 deletions(-)
diff --git
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java
index 86fb4b2..0f518d4 100644
---
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java
+++
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java
@@ -127,8 +127,13 @@ public class DynamicRegistrationService {
@PUT
@Path("{clientId}")
@Consumes("application/json")
- public Response updateClientRegistration(@PathParam("clientId") String
clientId) {
- return Response.ok().build();
+ @Produces("application/json")
+ public ClientRegistration updateClientRegistration(@PathParam("clientId")
String clientId,
+ ClientRegistration request) {
+ Client client = readClient(clientId);
+ fromClientRegistrationToClient(request, client);
+ clientProvider.setClient(client);
+ return fromClientToClientRegistration(client);
}
@DELETE
@@ -278,16 +283,35 @@ public class DynamicRegistrationService {
// Client Registration Time
newClient.setRegisteredAt(System.currentTimeMillis() / 1000L);
+ fromClientRegistrationToClient(request, newClient);
+
+ SecurityContext sc = mc.getSecurityContext();
+ if (sc != null && sc.getUserPrincipal() != null &&
sc.getUserPrincipal().getName() != null) {
+ UserSubject subject = new
UserSubject(sc.getUserPrincipal().getName());
+ newClient.setResourceOwnerSubject(subject);
+ }
+
+ newClient.setRegisteredDynamically(true);
+ return newClient;
+ }
+
+ protected void fromClientRegistrationToClient(ClientRegistration request,
Client client) {
+ final List<String> grantTypes = client.getAllowedGrantTypes();
+
// Client Redirect URIs
List<String> redirectUris = request.getRedirectUris();
if (redirectUris != null) {
+ String appType = request.getApplicationType();
+ if (appType == null) {
+ appType = DEFAULT_APPLICATION_TYPE;
+ }
for (String uri : redirectUris) {
validateRequestUri(uri, appType, grantTypes);
}
- newClient.setRedirectUris(redirectUris);
+ client.setRedirectUris(redirectUris);
}
- if (newClient.getRedirectUris().isEmpty()
+ if (client.getRedirectUris().isEmpty()
&& (grantTypes.contains(OAuthConstants.AUTHORIZATION_CODE_GRANT)
|| grantTypes.contains(OAuthConstants.IMPLICIT_GRANT))) {
// Throw an error as we need a redirect URI for these grants.
@@ -299,39 +323,31 @@ public class DynamicRegistrationService {
// Client Resource Audience URIs
List<String> resourceUris = request.getResourceUris();
if (resourceUris != null) {
- newClient.setRegisteredAudiences(resourceUris);
+ client.setRegisteredAudiences(resourceUris);
}
// Client Scopes
String scope = request.getScope();
if (!StringUtils.isEmpty(scope)) {
- newClient.setRegisteredScopes(OAuthUtils.parseScope(scope));
+ client.setRegisteredScopes(OAuthUtils.parseScope(scope));
}
// Client Application URI
String clientUri = request.getClientUri();
if (clientUri != null) {
- newClient.setApplicationWebUri(clientUri);
+ client.setApplicationWebUri(clientUri);
}
// Client Logo URI
String clientLogoUri = request.getLogoUri();
if (clientLogoUri != null) {
- newClient.setApplicationLogoUri(clientLogoUri);
+ client.setApplicationLogoUri(clientLogoUri);
}
//TODO: check other properties
// Add more typed properties like tosUri, policyUri, etc to Client
// or set them as Client extra properties
-
- SecurityContext sc = mc.getSecurityContext();
- if (sc != null && sc.getUserPrincipal() != null &&
sc.getUserPrincipal().getName() != null) {
- UserSubject subject = new
UserSubject(sc.getUserPrincipal().getName());
- newClient.setResourceOwnerSubject(subject);
- }
-
- newClient.setRegisteredDynamically(true);
- return newClient;
}
+
protected boolean isPasswordRequired(List<String> grantTypes, String
tokenEndpointAuthMethod) {
if (grantTypes.contains(OAuthConstants.IMPLICIT_GRANT)) {
return false;
diff --git
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
index 3896f7c..6064d00 100644
---
a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
+++
b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
@@ -429,6 +429,6 @@ public final class OAuthUtils {
}
public static String convertListOfScopesToString(List<String>
registeredScopes) {
- return String.join(", ", registeredScopes);
+ return String.join(" ", registeredScopes);
}
}
diff --git
a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCDynamicRegistrationTest.java
b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCDynamicRegistrationTest.java
index 74ff6bd..ea5393f 100644
---
a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCDynamicRegistrationTest.java
+++
b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oidc/OIDCDynamicRegistrationTest.java
@@ -23,6 +23,7 @@ import java.net.URL;
import java.util.Collections;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.jaxrs.provider.json.JsonMapObjectProvider;
@@ -76,16 +77,13 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
public void testRegisterClientInitialAccessTokenCodeGrant() throws
Exception {
URL busFile =
OIDCDynamicRegistrationTest.class.getResource("client.xml");
String address = "https://localhost:" + DYNREG_SERVER.getPort() +
"/services/dynamicWithAt/register";
- WebClient wc = WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()),
- busFile.toString());
+ WebClient wc =
+ WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()), busFile.toString())
+ .accept("application/json").type("application/json")
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
- wc.accept("application/json").type("application/json");
ClientRegistration reg = newClientRegistrationCodeGrant();
- ClientRegistrationResponse resp = null;
- assertEquals(401, wc.post(reg).getStatus());
-
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
- resp = wc.post(reg, ClientRegistrationResponse.class);
+ ClientRegistrationResponse resp = wc.post(reg,
ClientRegistrationResponse.class);
assertNotNull(resp.getClientId());
assertNotNull(resp.getClientSecret());
@@ -94,12 +92,12 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
String regAccessToken = resp.getRegistrationAccessToken();
assertNotNull(regAccessToken);
- wc.reset();
wc.path(resp.getClientId());
assertEquals(401, wc.get().getStatus());
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken));
- ClientRegistration clientRegResp = wc.get(ClientRegistration.class);
+ ClientRegistration clientRegResp = wc
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken))
+ .get(ClientRegistration.class);
testCommonRegCodeGrantProperties(clientRegResp);
assertNull(clientRegResp.getTokenEndpointAuthMethod());
@@ -111,16 +109,15 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
public void testRegisterClientPasswordGrant() throws Exception {
URL busFile =
OIDCDynamicRegistrationTest.class.getResource("client.xml");
String address = "https://localhost:" + DYNREG_SERVER.getPort() +
"/services/dynamicWithAt/register";
- WebClient wc = WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()),
- busFile.toString());
-
- wc.accept("application/json").type("application/json");
+ WebClient wc =
+ WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()), busFile.toString())
+ .accept("application/json").type("application/json")
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
ClientRegistration reg = new ClientRegistration();
reg.setClientName("dynamic_client");
reg.setGrantTypes(Collections.singletonList(OAuthConstants.RESOURCE_OWNER_GRANT));
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
ClientRegistrationResponse resp = wc.post(reg,
ClientRegistrationResponse.class);
assertNotNull(resp.getClientId());
@@ -130,11 +127,10 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
String regAccessToken = resp.getRegistrationAccessToken();
assertNotNull(regAccessToken);
- wc.reset();
- wc.path(resp.getClientId());
+ ClientRegistration clientRegResp = wc.path(resp.getClientId())
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken))
+ .get(ClientRegistration.class);
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken));
- ClientRegistration clientRegResp = wc.get(ClientRegistration.class);
assertEquals("web", clientRegResp.getApplicationType());
assertEquals("dynamic_client", clientRegResp.getClientName());
assertEquals(Collections.singletonList(OAuthConstants.RESOURCE_OWNER_GRANT),
@@ -150,16 +146,15 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
public void testRegisterClientPasswordGrantPublic() throws Exception {
URL busFile =
OIDCDynamicRegistrationTest.class.getResource("client.xml");
String address = "https://localhost:" + DYNREG_SERVER.getPort() +
"/services/dynamicWithAt/register";
- WebClient wc = WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()),
- busFile.toString());
-
- wc.accept("application/json").type("application/json");
+ WebClient wc =
+ WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()), busFile.toString())
+ .accept("application/json").type("application/json")
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
ClientRegistration reg = new ClientRegistration();
reg.setClientName("dynamic_client");
reg.setGrantTypes(Collections.singletonList(OAuthConstants.RESOURCE_OWNER_GRANT));
reg.setTokenEndpointAuthMethod(OAuthConstants.TOKEN_ENDPOINT_AUTH_NONE);
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
ClientRegistrationResponse resp = wc.post(reg,
ClientRegistrationResponse.class);
assertNotNull(resp.getClientId());
@@ -168,11 +163,10 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
String regAccessToken = resp.getRegistrationAccessToken();
assertNotNull(regAccessToken);
- wc.reset();
- wc.path(resp.getClientId());
+ ClientRegistration clientRegResp = wc.path(resp.getClientId())
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken))
+ .get(ClientRegistration.class);
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken));
- ClientRegistration clientRegResp = wc.get(ClientRegistration.class);
assertEquals("native", clientRegResp.getApplicationType());
assertEquals("dynamic_client", clientRegResp.getClientName());
assertEquals(Collections.singletonList(OAuthConstants.RESOURCE_OWNER_GRANT),
@@ -184,37 +178,21 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
assertEquals(200, wc.delete().getStatus());
}
- private void testCommonRegCodeGrantProperties(ClientRegistration
clientRegResp) {
- assertNotNull(clientRegResp);
- assertEquals("web", clientRegResp.getApplicationType());
- assertEquals("dynamic_client", clientRegResp.getClientName());
- assertEquals("openid", clientRegResp.getScope());
-
assertEquals(Collections.singletonList(OAuthConstants.AUTHORIZATION_CODE_GRANT),
- clientRegResp.getGrantTypes());
- assertEquals(Collections.singletonList("https://a/b/c"),
- clientRegResp.getRedirectUris());
- assertEquals(Collections.singletonList("https://rp/logout"),
-
clientRegResp.getListStringProperty("post_logout_redirect_uris"));
- }
-
@org.junit.Test
public void testRegisterClientInitialAccessTokenCodeGrantTls() throws
Exception {
URL busFile =
OIDCDynamicRegistrationTest.class.getResource("client.xml");
String address = "https://localhost:" + DYNREG_SERVER.getPort() +
"/services/dynamicWithAt/register";
- WebClient wc = WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()),
- busFile.toString());
+ WebClient wc =
+ WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()), busFile.toString())
+ .accept("application/json").type("application/json")
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
- wc.accept("application/json").type("application/json");
ClientRegistration reg = newClientRegistrationCodeGrant();
reg.setTokenEndpointAuthMethod(OAuthConstants.TOKEN_ENDPOINT_AUTH_TLS);
reg.setProperty(OAuthConstants.TLS_CLIENT_AUTH_SUBJECT_DN,
"CN=whateverhost.com,OU=Morpit,O=ApacheTest,L=Syracuse,C=US");
- ClientRegistrationResponse resp = null;
- assertEquals(401, wc.post(reg).getStatus());
-
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
- resp = wc.post(reg, ClientRegistrationResponse.class);
+ ClientRegistrationResponse resp = wc.post(reg,
ClientRegistrationResponse.class);
assertNotNull(resp.getClientId());
assertNull(resp.getClientSecret());
@@ -223,12 +201,10 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
String regAccessToken = resp.getRegistrationAccessToken();
assertNotNull(regAccessToken);
- wc.reset();
- wc.path(resp.getClientId());
- assertEquals(401, wc.get().getStatus());
+ ClientRegistration clientRegResp = wc.path(resp.getClientId())
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken))
+ .get(ClientRegistration.class);
- wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken));
- ClientRegistration clientRegResp = wc.get(ClientRegistration.class);
testCommonRegCodeGrantProperties(clientRegResp);
assertEquals(OAuthConstants.TOKEN_ENDPOINT_AUTH_TLS,
clientRegResp.getTokenEndpointAuthMethod());
assertEquals("CN=whateverhost.com,OU=Morpit,O=ApacheTest,L=Syracuse,C=US",
@@ -237,12 +213,52 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
assertEquals(200, wc.delete().getStatus());
}
+ @org.junit.Test
+ public void testUpdateClient() throws Exception {
+ URL busFile =
OIDCDynamicRegistrationTest.class.getResource("client.xml");
+ String address = "https://localhost:" + DYNREG_SERVER.getPort() +
"/services/dynamicWithAt/register";
+ WebClient wc =
+ WebClient.create(address, Collections.singletonList(new
JsonMapObjectProvider()), busFile.toString())
+ .accept("application/json").type("application/json")
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, ACCESS_TOKEN));
+
+ final ClientRegistration reg = newClientRegistrationCodeGrant();
+ final ClientRegistrationResponse clientRegistrationResponse = wc
+ .post(reg, ClientRegistrationResponse.class);
+
+ final String regAccessToken =
clientRegistrationResponse.getRegistrationAccessToken();
+ assertNotNull(regAccessToken);
+
+ reg.setScope(OidcUtils.getEmailScope());
+ final ClientRegistration updatedClientRegistration =
wc.path(clientRegistrationResponse.getClientId())
+ .authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken))
+ .put(reg, ClientRegistration.class);
+
+ assertEquals(OidcUtils.getEmailScope(),
updatedClientRegistration.getScope());
+ // https://tools.ietf.org/html/rfc7592#section-2.2
+
assertNull(updatedClientRegistration.getProperty("registration_access_token"));
+
assertNull(updatedClientRegistration.getProperty("registration_client_uri"));
+
assertNull(updatedClientRegistration.getProperty("client_secret_expires_at"));
+
assertNull(updatedClientRegistration.getProperty("client_id_issued_at"));
+
+ wc.authorization(null);
+
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(),
+ wc.put(reg).getStatus());
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(),
+ wc.delete().getStatus());
+
+ wc.authorization(new
ClientAccessToken(OAuthConstants.BEARER_AUTHORIZATION_SCHEME, regAccessToken));
+ assertEquals(200, wc.delete().getStatus());
+ }
+
private static ClientRegistration newClientRegistrationCodeGrant() {
final ClientRegistration reg = new ClientRegistration();
reg.setApplicationType("web");
reg.setScope(OidcUtils.getOpenIdScope());
reg.setClientName("dynamic_client");
reg.setGrantTypes(Collections.singletonList(OAuthConstants.AUTHORIZATION_CODE_GRANT));
+//
reg.setResponseTypes(Collections.singletonList(OAuthConstants.CODE_RESPONSE_TYPE));
reg.setRedirectUris(Collections.singletonList("https://a/b/c"));
reg.setProperty("post_logout_redirect_uris",
@@ -250,4 +266,19 @@ public class OIDCDynamicRegistrationTest extends
AbstractBusClientServerTestBase
return reg;
}
+ private static void testCommonRegCodeGrantProperties(ClientRegistration
clientRegResp) {
+ assertNotNull(clientRegResp);
+ assertEquals("web", clientRegResp.getApplicationType());
+ assertEquals("openid", clientRegResp.getScope());
+ assertEquals("dynamic_client", clientRegResp.getClientName());
+
assertEquals(Collections.singletonList(OAuthConstants.AUTHORIZATION_CODE_GRANT),
+ clientRegResp.getGrantTypes());
+//
assertEquals(Collections.singletonList(OAuthConstants.CODE_RESPONSE_TYPE),
+// clientRegResp.getResponseTypes());
+ assertEquals(Collections.singletonList("https://a/b/c"),
+ clientRegResp.getRedirectUris());
+ assertEquals(Collections.singletonList("https://rp/logout"),
+
clientRegResp.getListStringProperty("post_logout_redirect_uris"));
+ }
+
}