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"));
+    }
+
 }

Reply via email to