You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2023/03/10 13:26:43 UTC

[syncope] branch 3_0_X updated: WA: better scope management for OIDC RP client application (#423)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 3_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/3_0_X by this push:
     new 32df251f21 WA: better scope management for OIDC RP client application (#423)
32df251f21 is described below

commit 32df251f211bbfa1f06cd5ed51cd6b8411851504
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Fri Mar 10 14:26:37 2023 +0100

    WA: better scope management for OIDC RP client application (#423)
---
 .../clientapps/ClientAppModalPanelBuilder.java     |  4 +-
 .../syncope/common/lib/to/OIDCRPClientAppTO.java   | 19 +++++
 .../syncope/common/lib/types/OIDCGrantType.java    |  3 +-
 .../syncope/common/lib/types/OIDCResponseType.java |  4 +-
 pom.xml                                            |  2 +-
 .../starter/mapping/OIDCRPClientAppTOMapper.java   | 82 ++++++++++++++--------
 6 files changed, 77 insertions(+), 37 deletions(-)

diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
index 3ce93ab3b9..d4515ae480 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java
@@ -180,7 +180,7 @@ public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractM
             fields.add(new AjaxTextFieldPanel(
                     "field", Constants.DESCRIPTION_FIELD_NAME,
                     new PropertyModel<>(clientAppTO, Constants.DESCRIPTION_FIELD_NAME), false));
-            
+
             fields.add(new AjaxTextFieldPanel(
                     "field", "logo",
                     new PropertyModel<>(clientAppTO, "logo"), false));
@@ -252,7 +252,6 @@ public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractM
                     fields.add(subjectType);
 
                     AjaxTextFieldPanel redirectUri = new AjaxTextFieldPanel("panel", "redirectUris", new Model<>());
-                    redirectUri.addValidator(new UrlValidator());
                     fields.add(new MultiFieldPanel.Builder<String>(
                             new PropertyModel<>(clientAppTO, "redirectUris")).build(
                             "field",
@@ -278,7 +277,6 @@ public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractM
                 case SAML2SP:
                     AjaxTextFieldPanel entityId = new AjaxTextFieldPanel(
                             "field", "entityId", new PropertyModel<>(clientAppTO, "entityId"), false);
-                    entityId.addValidator(new UrlValidator());
                     fields.add(entityId.setRequired(true));
 
                     fields.add(new AjaxTextFieldPanel("field", "metadataLocation",
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCRPClientAppTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCRPClientAppTO.java
index a40eae7aac..480ff8edc4 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCRPClientAppTO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCRPClientAppTO.java
@@ -35,6 +35,15 @@ public class OIDCRPClientAppTO extends ClientAppTO {
 
     private static final long serialVersionUID = -6370888503924521351L;
 
+    public enum SCOPE {
+        OPENID,
+        PROFILE,
+        EMAIL,
+        ADDRESS,
+        PHONE
+
+    }
+
     private String clientId;
 
     private String clientSecret;
@@ -53,6 +62,8 @@ public class OIDCRPClientAppTO extends ClientAppTO {
 
     private String logoutUri;
 
+    private final List<SCOPE> scopes = new ArrayList<>();
+
     private boolean bypassApprovalPrompt = true;
 
     @JacksonXmlProperty(localName = "_class", isAttribute = true)
@@ -130,6 +141,12 @@ public class OIDCRPClientAppTO extends ClientAppTO {
         this.jwtAccessToken = jwtAccessToken;
     }
 
+    @JacksonXmlElementWrapper(localName = "scopes")
+    @JacksonXmlProperty(localName = "scope")
+    public List<SCOPE> getScopes() {
+        return scopes;
+    }
+
     public boolean isBypassApprovalPrompt() {
         return bypassApprovalPrompt;
     }
@@ -161,6 +178,7 @@ public class OIDCRPClientAppTO extends ClientAppTO {
                 .append(this.supportedResponseTypes, rhs.supportedResponseTypes)
                 .append(this.logoutUri, rhs.logoutUri)
                 .append(this.jwtAccessToken, rhs.jwtAccessToken)
+                .append(this.scopes, rhs.scopes)
                 .append(this.bypassApprovalPrompt, rhs.bypassApprovalPrompt)
                 .isEquals();
     }
@@ -178,6 +196,7 @@ public class OIDCRPClientAppTO extends ClientAppTO {
                 .append(supportedResponseTypes)
                 .append(logoutUri)
                 .append(jwtAccessToken)
+                .append(scopes)
                 .append(bypassApprovalPrompt)
                 .toHashCode();
     }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCGrantType.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCGrantType.java
index c1471b1010..837f80ec3d 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCGrantType.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCGrantType.java
@@ -22,6 +22,7 @@ public enum OIDCGrantType {
     authorization_code,
     password,
     client_credentials,
-    refresh_token;
+    refresh_token,
+    device_code;
 
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCResponseType.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCResponseType.java
index 2ccffa9c21..7e2b8cb90f 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCResponseType.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCResponseType.java
@@ -21,7 +21,9 @@ package org.apache.syncope.common.lib.types;
 public enum OIDCResponseType {
     CODE("code"),
     TOKEN("token"),
-    ID_TOKEN_TOKEN("id_token token");
+    ID_TOKEN("id_token"),
+    ID_TOKEN_TOKEN("id_token token"),
+    DEVICE_CODE("device_code");
 
     private final String externalForm;
 
diff --git a/pom.xml b/pom.xml
index b896c9cd44..4d9ba1432e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1737,7 +1737,7 @@ under the License.
             <dependency>
               <groupId>com.puppycrawl.tools</groupId>
               <artifactId>checkstyle</artifactId>
-              <version>10.8.0</version>
+              <version>10.8.1</version>
             </dependency>
           </dependencies>
           <configuration>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
index 290e9762c5..884cd5243c 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPClientAppTOMapper.java
@@ -32,6 +32,7 @@ import org.apereo.cas.configuration.CasConfigurationProperties;
 import org.apereo.cas.oidc.claims.OidcAddressScopeAttributeReleasePolicy;
 import org.apereo.cas.oidc.claims.OidcCustomScopeAttributeReleasePolicy;
 import org.apereo.cas.oidc.claims.OidcEmailScopeAttributeReleasePolicy;
+import org.apereo.cas.oidc.claims.OidcOpenIdScopeAttributeReleasePolicy;
 import org.apereo.cas.oidc.claims.OidcPhoneScopeAttributeReleasePolicy;
 import org.apereo.cas.oidc.claims.OidcProfileScopeAttributeReleasePolicy;
 import org.apereo.cas.services.BaseMappedAttributeReleasePolicy;
@@ -91,43 +92,62 @@ public class OIDCRPClientAppTOMapper extends AbstractClientAppMapper {
             if (attributeReleasePolicy != null) {
                 chain.addPolicies(attributeReleasePolicy);
             }
+        }
 
-            chain.addPolicies(new OidcProfileScopeAttributeReleasePolicy(),
-                    new OidcEmailScopeAttributeReleasePolicy(),
-                    new OidcAddressScopeAttributeReleasePolicy(),
-                    new OidcPhoneScopeAttributeReleasePolicy());
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.OPENID)) {
+            chain.addPolicies(new OidcOpenIdScopeAttributeReleasePolicy());
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.PROFILE)) {
+            chain.addPolicies(new OidcProfileScopeAttributeReleasePolicy());
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.ADDRESS)) {
+            chain.addPolicies(new OidcAddressScopeAttributeReleasePolicy());
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.EMAIL)) {
+            chain.addPolicies(new OidcEmailScopeAttributeReleasePolicy());
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.PHONE)) {
+            chain.addPolicies(new OidcPhoneScopeAttributeReleasePolicy());
+        }
 
-            Set<String> customClaims = new HashSet<>();
-            if (attributeReleasePolicy instanceof BaseMappedAttributeReleasePolicy) {
-                customClaims.addAll(((BaseMappedAttributeReleasePolicy) attributeReleasePolicy).
-                        getAllowedAttributes().values().stream().
-                        map(Objects::toString).collect(Collectors.toSet()));
-            } else if (attributeReleasePolicy instanceof ReturnAllowedAttributeReleasePolicy) {
-                customClaims.addAll(((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).
-                        getAllowedAttributes().stream().collect(Collectors.toSet()));
-            } else if (attributeReleasePolicy instanceof ChainingAttributeReleasePolicy) {
-                ((ChainingAttributeReleasePolicy) attributeReleasePolicy).getPolicies().stream().
-                        filter(ReturnAllowedAttributeReleasePolicy.class::isInstance).
-                        findFirst().map(ReturnAllowedAttributeReleasePolicy.class::cast).
-                        map(p -> p.getAllowedAttributes().stream().collect(Collectors.toSet())).
-                        ifPresent(customClaims::addAll);
-            }
+        Set<String> customClaims = new HashSet<>();
+        if (attributeReleasePolicy instanceof BaseMappedAttributeReleasePolicy) {
+            customClaims.addAll(((BaseMappedAttributeReleasePolicy) attributeReleasePolicy).
+                    getAllowedAttributes().values().stream().
+                    map(Objects::toString).collect(Collectors.toSet()));
+        } else if (attributeReleasePolicy instanceof ReturnAllowedAttributeReleasePolicy) {
+            customClaims.addAll(((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).
+                    getAllowedAttributes().stream().collect(Collectors.toSet()));
+        } else if (attributeReleasePolicy instanceof ChainingAttributeReleasePolicy) {
+            ((ChainingAttributeReleasePolicy) attributeReleasePolicy).getPolicies().stream().
+                    filter(ReturnAllowedAttributeReleasePolicy.class::isInstance).
+                    findFirst().map(ReturnAllowedAttributeReleasePolicy.class::cast).
+                    map(p -> p.getAllowedAttributes().stream().collect(Collectors.toSet())).
+                    ifPresent(customClaims::addAll);
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.PROFILE)) {
             customClaims.removeAll(OidcProfileScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
-            customClaims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.ADDRESS)) {
             customClaims.removeAll(OidcAddressScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.EMAIL)) {
+            customClaims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+        }
+        if (rp.getScopes().contains(OIDCRPClientAppTO.SCOPE.PHONE)) {
             customClaims.removeAll(OidcPhoneScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
-            if (!customClaims.isEmpty()) {
-                CasConfigurationProperties properties = ctx.getBean(CasConfigurationProperties.class);
-                List<String> supportedClaims = properties.getAuthn().getOidc().getDiscovery().getClaims();
-                if (!supportedClaims.containsAll(customClaims)) {
-                    properties.getAuthn().getOidc().getDiscovery().setClaims(
-                            Stream.concat(supportedClaims.stream(), customClaims.stream()).
-                                    distinct().collect(Collectors.toList()));
-                }
-
-                chain.addPolicies(new OidcCustomScopeAttributeReleasePolicy(
-                        CUSTOM_SCOPE, customClaims.stream().collect(Collectors.toList())));
+        }
+        if (!customClaims.isEmpty()) {
+            CasConfigurationProperties properties = ctx.getBean(CasConfigurationProperties.class);
+            List<String> supportedClaims = properties.getAuthn().getOidc().getDiscovery().getClaims();
+            if (!supportedClaims.containsAll(customClaims)) {
+                properties.getAuthn().getOidc().getDiscovery().setClaims(
+                        Stream.concat(supportedClaims.stream(), customClaims.stream()).
+                                distinct().collect(Collectors.toList()));
             }
+
+            chain.addPolicies(new OidcCustomScopeAttributeReleasePolicy(
+                    CUSTOM_SCOPE, customClaims.stream().collect(Collectors.toList())));
         }
 
         setPolicies(service, authPolicy, mfaPolicy, accessStrategy, chain);