diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCScope.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCScope.java index a3771db4f9..57e6b58d73 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCScope.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/OIDCScope.java @@ -19,10 +19,10 @@ package org.apache.syncope.common.lib.types; public enum OIDCScope { - OPENID, - PROFILE, - EMAIL, - ADDRESS, - PHONE + openid, + profile, + email, + address, + phone } diff --git a/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java b/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java index 7c80d5ae03..ac06485269 100644 --- a/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java +++ b/ext/oidcc4ui/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderWizardBuilder.java @@ -270,7 +270,7 @@ protected void onUpdate(final AjaxRequestTarget target) { }); AjaxTextFieldPanel value = new AjaxTextFieldPanel("panel", "scopes", new Model<>()); - value.setChoices(Stream.of(OIDCScope.values()).map(s -> s.name().toLowerCase()).toList()); + value.setChoices(Stream.of(OIDCScope.values()).map(OIDCScope::name).toList()); content.add(new MultiFieldPanel.Builder( new PropertyModel<>(opTO, "scopes")).build("scopes", "scopes", value)); } diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java index 8ed895954c..fe056c1720 100644 --- a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java +++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.fit.sra; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.oneOf; @@ -44,6 +45,7 @@ import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.http.Consts; @@ -123,9 +125,9 @@ protected static void oidcClientAppSetup( clientApp.setLogoutUri(SRA_ADDRESS + "/logout"); clientApp.setAuthPolicy(getAuthPolicy().getKey()); clientApp.setAttrReleasePolicy(getAttrReleasePolicy().getKey()); - clientApp.getScopes().add(OIDCScope.OPENID); - clientApp.getScopes().add(OIDCScope.PROFILE); - clientApp.getScopes().add(OIDCScope.EMAIL); + clientApp.getScopes().add(OIDCScope.openid); + clientApp.getScopes().add(OIDCScope.profile); + clientApp.getScopes().add(OIDCScope.email); clientApp.getSupportedGrantTypes().add(OIDCGrantType.password); CLIENT_APP_SERVICE.update(ClientAppType.OIDCRP, clientApp); @@ -250,6 +252,23 @@ protected boolean checkIdToken() { @Test public void rest() throws IOException, ParseException { + await().atMost(60, TimeUnit.SECONDS).pollInterval(20, TimeUnit.SECONDS).until(() -> { + boolean refreshed = false; + try { + String metadata = WebClient.create( + WA_ADDRESS + "/oidc/.well-known/openid-configuration").get().readEntity(String.class); + if (!metadata.contains("groups")) { + WA_CONFIG_SERVICE.pushToWA(WAConfigService.PushSubject.conf, List.of()); + throw new IllegalStateException(); + } + + refreshed = true; + } catch (Exception e) { + // ignore + } + return refreshed; + }); + // 0. access public route WebClient client = WebClient.create(SRA_ADDRESS + "/public/post"). accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON); diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/OIDC4UIITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/OIDC4UIITCase.java index 1f10ec6d4c..2445e00e72 100644 --- a/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/OIDC4UIITCase.java +++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/OIDC4UIITCase.java @@ -94,9 +94,9 @@ private static void clientAppSetup(final String appName, final String baseAddres Set.of(OIDCResponseType.CODE, OIDCResponseType.ID_TOKEN_TOKEN, OIDCResponseType.TOKEN)); clientApp.setAuthPolicy(getAuthPolicy().getKey()); clientApp.setAttrReleasePolicy(getAttrReleasePolicy().getKey()); - clientApp.getScopes().add(OIDCScope.OPENID); - clientApp.getScopes().add(OIDCScope.PROFILE); - clientApp.getScopes().add(OIDCScope.EMAIL); + clientApp.getScopes().add(OIDCScope.openid); + clientApp.getScopes().add(OIDCScope.profile); + clientApp.getScopes().add(OIDCScope.email); CLIENT_APP_SERVICE.update(ClientAppType.OIDCRP, clientApp); WA_CONFIG_SERVICE.pushToWA(WAConfigService.PushSubject.clientApps, List.of()); @@ -139,7 +139,7 @@ private static void oidcSetup( cas.setUserinfoEndpoint(cas.getIssuer() + "/profile"); cas.setEndSessionEndpoint(cas.getIssuer() + "/logout"); - cas.getScopes().addAll(Stream.of(OIDCScope.values()).map(s -> s.name().toLowerCase()).toList()); + cas.getScopes().addAll(Stream.of(OIDCScope.values()).map(OIDCScope::name).toList()); cas.getScopes().add("syncope"); cas.setCreateUnmatching(createUnmatching); diff --git a/wa/bootstrap/pom.xml b/wa/bootstrap/pom.xml index fc1376806e..9d952cb8d9 100644 --- a/wa/bootstrap/pom.xml +++ b/wa/bootstrap/pom.xml @@ -57,6 +57,14 @@ under the License. org.apereo.cas cas-server-core-util-api + + org.apereo.cas + cas-server-core-authentication-attributes + + + org.apereo.cas + cas-server-support-oidc-core + org.slf4j diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WABootstrapConfiguration.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WABootstrapConfiguration.java index f470e9a778..dcd0fb7a21 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WABootstrapConfiguration.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WABootstrapConfiguration.java @@ -18,6 +18,10 @@ */ package org.apache.syncope.wa.bootstrap; +import org.apache.syncope.wa.bootstrap.mapping.AttrReleaseMapper; +import org.apache.syncope.wa.bootstrap.mapping.AttrRepoPropertySourceMapper; +import org.apache.syncope.wa.bootstrap.mapping.AuthModulePropertySourceMapper; +import org.apache.syncope.wa.bootstrap.mapping.DefaultAttrReleaseMapper; import org.apereo.cas.configuration.support.CasConfigurationJasyptCipherExecutor; import org.apereo.cas.util.crypto.CipherExecutor; import org.springframework.beans.factory.annotation.Qualifier; @@ -58,8 +62,8 @@ public WARestClient waRestClient() { @Configuration(proxyBeanMethods = false) public static class PropertySourceConfiguration { - @Bean @ConditionalOnMissingBean(name = "waConfigurationCipher") + @Bean public CipherExecutor waConfigurationCipher(final Environment environment) { return new CasConfigurationJasyptCipherExecutor(environment); } @@ -76,17 +80,27 @@ public AttrRepoPropertySourceMapper attrRepoPropertySourceMapper(final WARestCli return new AttrRepoPropertySourceMapper(waRestClient); } + @ConditionalOnMissingBean + @Bean + public AttrReleaseMapper attrReleaseMapper() { + return new DefaultAttrReleaseMapper(); + } + @Bean public PropertySourceLocator configPropertySourceLocator( @Qualifier("waConfigurationCipher") final CipherExecutor waConfigurationCipher, final WARestClient waRestClient, final AuthModulePropertySourceMapper authModulePropertySourceMapper, - final AttrRepoPropertySourceMapper attrRepoPropertySourceMapper) { + final AttrRepoPropertySourceMapper attrRepoPropertySourceMapper, + final AttrReleaseMapper attrReleaseMapper) { return new WAPropertySourceLocator( - waRestClient, authModulePropertySourceMapper, - attrRepoPropertySourceMapper, waConfigurationCipher); + waRestClient, + authModulePropertySourceMapper, + attrRepoPropertySourceMapper, + attrReleaseMapper, + waConfigurationCipher); } } } diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WAPropertySourceLocator.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WAPropertySourceLocator.java index 21b8ff3c2f..c74d0a71c0 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WAPropertySourceLocator.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WAPropertySourceLocator.java @@ -19,16 +19,35 @@ package org.apache.syncope.wa.bootstrap; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.client.lib.SyncopeClient; +import org.apache.syncope.common.lib.to.OIDCRPClientAppTO; +import org.apache.syncope.common.lib.types.OIDCScope; import org.apache.syncope.common.rest.api.service.AttrRepoService; import org.apache.syncope.common.rest.api.service.AuthModuleService; +import org.apache.syncope.common.rest.api.service.wa.WAClientAppService; import org.apache.syncope.common.rest.api.service.wa.WAConfigService; +import org.apache.syncope.wa.bootstrap.mapping.AttrReleaseMapper; +import org.apache.syncope.wa.bootstrap.mapping.AttrRepoPropertySourceMapper; +import org.apache.syncope.wa.bootstrap.mapping.AuthModulePropertySourceMapper; +import org.apereo.cas.configuration.model.support.oidc.OidcDiscoveryProperties; +import org.apereo.cas.oidc.claims.OidcAddressScopeAttributeReleasePolicy; +import org.apereo.cas.oidc.claims.OidcEmailScopeAttributeReleasePolicy; +import org.apereo.cas.oidc.claims.OidcPhoneScopeAttributeReleasePolicy; +import org.apereo.cas.oidc.claims.OidcProfileScopeAttributeReleasePolicy; +import org.apereo.cas.services.BaseMappedAttributeReleasePolicy; +import org.apereo.cas.services.ChainingAttributeReleasePolicy; +import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy; +import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy; import org.apereo.cas.util.crypto.CipherExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,17 +68,21 @@ public class WAPropertySourceLocator implements PropertySourceLocator { protected final AttrRepoPropertySourceMapper attrRepoPropertySourceMapper; + protected final AttrReleaseMapper attrReleaseMapper; + protected final CipherExecutor configurationCipher; public WAPropertySourceLocator( final WARestClient waRestClient, final AuthModulePropertySourceMapper authModulePropertySourceMapper, final AttrRepoPropertySourceMapper attrRepoPropertySourceMapper, + final AttrReleaseMapper attrReleaseMapper, final CipherExecutor configurationCipher) { this.waRestClient = waRestClient; this.authModulePropertySourceMapper = authModulePropertySourceMapper; this.attrRepoPropertySourceMapper = attrRepoPropertySourceMapper; + this.attrReleaseMapper = attrReleaseMapper; this.configurationCipher = configurationCipher; } @@ -109,6 +132,56 @@ public PropertySource locate(final Environment environment) { properties.putAll(index(map, prefixes)); }); + Set customClaims = syncopeClient.getService(WAClientAppService.class).list().stream(). + filter(clientApp -> clientApp.getAttrReleasePolicy() != null + && clientApp.getClientAppTO() instanceof OIDCRPClientAppTO). + flatMap(clientApp -> { + OIDCRPClientAppTO rp = OIDCRPClientAppTO.class.cast(clientApp.getClientAppTO()); + + RegisteredServiceAttributeReleasePolicy attributeReleasePolicy = + attrReleaseMapper.build(clientApp.getAttrReleasePolicy()); + + Set claims = new HashSet<>(); + if (attributeReleasePolicy instanceof BaseMappedAttributeReleasePolicy baseMapped) { + claims.addAll(baseMapped. + getAllowedAttributes().values().stream(). + map(Objects::toString).collect(Collectors.toSet())); + } else if (attributeReleasePolicy instanceof ReturnAllowedAttributeReleasePolicy returnAllowed) { + claims.addAll(returnAllowed. + getAllowedAttributes().stream().collect(Collectors.toSet())); + } else if (attributeReleasePolicy instanceof ChainingAttributeReleasePolicy chaining) { + chaining.getPolicies().stream(). + filter(ReturnAllowedAttributeReleasePolicy.class::isInstance). + findFirst().map(ReturnAllowedAttributeReleasePolicy.class::cast). + map(p -> p.getAllowedAttributes().stream().collect(Collectors.toSet())). + ifPresent(claims::addAll); + } + if (rp.getScopes().contains(OIDCScope.profile)) { + claims.removeAll(OidcProfileScopeAttributeReleasePolicy.ALLOWED_CLAIMS); + } + if (rp.getScopes().contains(OIDCScope.address)) { + claims.removeAll(OidcAddressScopeAttributeReleasePolicy.ALLOWED_CLAIMS); + } + if (rp.getScopes().contains(OIDCScope.email)) { + claims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS); + } + if (rp.getScopes().contains(OIDCScope.phone)) { + claims.removeAll(OidcPhoneScopeAttributeReleasePolicy.ALLOWED_CLAIMS); + } + + return claims.stream(); + }).collect(Collectors.toSet()); + if (!customClaims.isEmpty()) { + Stream.concat(new OidcDiscoveryProperties().getClaims().stream(), customClaims.stream()). + collect(Collectors.joining(",")); + + properties.put("cas.authn.oidc.discovery.claims", + Stream.concat(new OidcDiscoveryProperties().getClaims().stream(), customClaims.stream()). + collect(Collectors.joining(","))); + properties.put("cas.authn.oidc.core.user-defined-scopes.syncope", + customClaims.stream().collect(Collectors.joining(","))); + } + syncopeClient.getService(WAConfigService.class).list().forEach(attr -> properties.put( attr.getSchema(), attr.getValues().stream().collect(Collectors.joining(",")))); diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WARestClient.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WARestClient.java index 8d48df5a02..cd7c227782 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WARestClient.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/WARestClient.java @@ -89,7 +89,7 @@ protected Optional getCore() { return Optional.empty(); } - protected SyncopeClient getSyncopeClient() { + public SyncopeClient getSyncopeClient() { synchronized (this) { if (client == null) { getCore().ifPresent(core -> { diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrReleaseMapper.java similarity index 96% rename from wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrReleaseMapper.java index 7b54d36734..021968582a 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AttrReleaseMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrReleaseMapper.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.starter.mapping; +package org.apache.syncope.wa.bootstrap.mapping; import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf; import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO; diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AttrRepoPropertySourceMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrRepoPropertySourceMapper.java similarity index 98% rename from wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AttrRepoPropertySourceMapper.java rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrRepoPropertySourceMapper.java index 28e0e239ea..cbdf8bd665 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AttrRepoPropertySourceMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AttrRepoPropertySourceMapper.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.bootstrap; +package org.apache.syncope.wa.bootstrap.mapping; import java.util.Map; import java.util.stream.Collectors; @@ -29,6 +29,7 @@ import org.apache.syncope.common.lib.attr.SyncopeAttrRepoConf; import org.apache.syncope.common.lib.to.AttrRepoTO; import org.apache.syncope.common.lib.to.Item; +import org.apache.syncope.wa.bootstrap.WARestClient; import org.apereo.cas.configuration.CasCoreConfigurationUtils; import org.apereo.cas.configuration.model.core.authentication.AttributeRepositoryStates; import org.apereo.cas.configuration.model.core.authentication.StubPrincipalAttributesProperties; diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java similarity index 99% rename from wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java index 0efbff13b5..28667f974f 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.bootstrap; +package org.apache.syncope.wa.bootstrap.mapping; import java.util.List; import java.util.Map; @@ -46,6 +46,7 @@ import org.apache.syncope.common.lib.to.AuthModuleTO; import org.apache.syncope.common.lib.to.Item; import org.apache.syncope.common.lib.types.AuthModuleState; +import org.apache.syncope.wa.bootstrap.WARestClient; import org.apereo.cas.configuration.CasCoreConfigurationUtils; import org.apereo.cas.configuration.model.core.authentication.AuthenticationHandlerStates; import org.apereo.cas.configuration.model.support.generic.AcceptAuthenticationProperties; diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/DefaultAttrReleaseMapper.java similarity index 99% rename from wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/DefaultAttrReleaseMapper.java index 5279c15232..aa03074c32 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAttrReleaseMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/DefaultAttrReleaseMapper.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.starter.mapping; +package org.apache.syncope.wa.bootstrap.mapping; import java.util.HashSet; import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf; diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/PropertySourceMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/PropertySourceMapper.java similarity index 99% rename from wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/PropertySourceMapper.java rename to wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/PropertySourceMapper.java index 9730f4df06..b4c3d74ed9 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/PropertySourceMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/PropertySourceMapper.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.bootstrap; +package org.apache.syncope.wa.bootstrap.mapping; import java.util.Map; import java.util.Optional; diff --git a/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java b/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java index a6934e0c6a..cab01d335f 100644 --- a/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java +++ b/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java @@ -24,6 +24,7 @@ import org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf; import org.apache.syncope.common.lib.auth.SimpleMfaAuthModuleConf; import org.apache.syncope.common.lib.to.AuthModuleTO; +import org.apache.syncope.wa.bootstrap.mapping.AuthModulePropertySourceMapper; import org.junit.jupiter.api.Test; public class AuthModulePropertySourceMapperTest { diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml index e5fb2e940d..c86776e873 100644 --- a/wa/starter/pom.xml +++ b/wa/starter/pom.xml @@ -221,10 +221,6 @@ under the License. org.apereo.cas cas-server-support-oidc-core-api - - org.apereo.cas - cas-server-support-oidc-core - org.apereo.cas cas-server-support-oauth-services @@ -341,10 +337,6 @@ under the License. org.apereo.cas cas-server-support-swagger - - org.apereo.cas - cas-server-core-authentication-attributes - org.apereo.cas cas-server-core-services-authentication diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java index 98f5e9a365..122597d506 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java @@ -36,6 +36,7 @@ import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop; import org.apache.syncope.wa.bootstrap.WAProperties; import org.apache.syncope.wa.bootstrap.WARestClient; +import org.apache.syncope.wa.bootstrap.mapping.AttrReleaseMapper; import org.apache.syncope.wa.starter.actuate.SyncopeCoreHealthIndicator; import org.apache.syncope.wa.starter.actuate.SyncopeWAInfoContributor; import org.apache.syncope.wa.starter.audit.WAAuditTrailManager; @@ -43,12 +44,10 @@ import org.apache.syncope.wa.starter.gauth.WAGoogleMfaAuthCredentialRepository; import org.apache.syncope.wa.starter.gauth.WAGoogleMfaAuthTokenRepository; import org.apache.syncope.wa.starter.mapping.AccessMapper; -import org.apache.syncope.wa.starter.mapping.AttrReleaseMapper; import org.apache.syncope.wa.starter.mapping.AuthMapper; import org.apache.syncope.wa.starter.mapping.CASSPClientAppTOMapper; import org.apache.syncope.wa.starter.mapping.ClientAppMapper; import org.apache.syncope.wa.starter.mapping.DefaultAccessMapper; -import org.apache.syncope.wa.starter.mapping.DefaultAttrReleaseMapper; import org.apache.syncope.wa.starter.mapping.DefaultAuthMapper; import org.apache.syncope.wa.starter.mapping.DefaultTicketExpirationMapper; import org.apache.syncope.wa.starter.mapping.HttpRequestAccessMapper; @@ -159,19 +158,13 @@ public TimeBasedAccessMapper timeBasedAccessMapper() { @ConditionalOnMissingBean @Bean - public AttrReleaseMapper defaultAttrReleaseMapper() { - return new DefaultAttrReleaseMapper(); - } - - @ConditionalOnMissingBean - @Bean - public AuthMapper defaultAuthMapper() { + public AuthMapper authMapper() { return new DefaultAuthMapper(); } @ConditionalOnMissingBean @Bean - public TicketExpirationMapper defaultTicketExpirationMapper() { + public TicketExpirationMapper ticketExpirationMapper() { return new DefaultTicketExpirationMapper(); } 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 d1d66bf9dd..f9d6da44c0 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 @@ -20,6 +20,7 @@ import java.util.HashSet; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.syncope.common.lib.to.ClientAppTO; @@ -83,17 +84,15 @@ public RegisteredService map( service.setJwtAccessToken(rp.isJwtAccessToken()); service.setBypassApprovalPrompt(rp.isBypassApprovalPrompt()); service.setSupportedGrantTypes(rp.getSupportedGrantTypes().stream(). - map(OIDCGrantType::name).collect(Collectors.toCollection(HashSet::new))); + map(OIDCGrantType::name).collect(Collectors.toSet())); service.setSupportedResponseTypes(rp.getSupportedResponseTypes().stream(). - map(OIDCResponseType::getExternalForm).collect(Collectors.toCollection(HashSet::new))); - if (rp.getSubjectType() != null) { - service.setSubjectType(rp.getSubjectType().name()); - } + map(OIDCResponseType::getExternalForm).collect(Collectors.toSet())); + Optional.ofNullable(rp.getSubjectType()).ifPresent(st -> service.setSubjectType(st.name())); service.setLogoutUrl(rp.getLogoutUri()); service.setScopes(rp.getScopes().stream(). - map(s -> s.name().toLowerCase()). - collect(Collectors.toCollection(HashSet::new))); + map(OIDCScope::name). + collect(Collectors.toSet())); Set customClaims = new HashSet<>(); if (attributeReleasePolicy instanceof BaseMappedAttributeReleasePolicy baseMapped) { @@ -110,16 +109,16 @@ public RegisteredService map( map(p -> p.getAllowedAttributes().stream().collect(Collectors.toSet())). ifPresent(customClaims::addAll); } - if (rp.getScopes().contains(OIDCScope.PROFILE)) { + if (rp.getScopes().contains(OIDCScope.profile)) { customClaims.removeAll(OidcProfileScopeAttributeReleasePolicy.ALLOWED_CLAIMS); } - if (rp.getScopes().contains(OIDCScope.ADDRESS)) { + if (rp.getScopes().contains(OIDCScope.address)) { customClaims.removeAll(OidcAddressScopeAttributeReleasePolicy.ALLOWED_CLAIMS); } - if (rp.getScopes().contains(OIDCScope.EMAIL)) { + if (rp.getScopes().contains(OIDCScope.email)) { customClaims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS); } - if (rp.getScopes().contains(OIDCScope.PHONE)) { + if (rp.getScopes().contains(OIDCScope.phone)) { customClaims.removeAll(OidcPhoneScopeAttributeReleasePolicy.ALLOWED_CLAIMS); } diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java index f5ff9024b5..8c1dd47fc3 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java @@ -23,6 +23,7 @@ import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO; import org.apache.syncope.common.lib.policy.DefaultAttrReleasePolicyConf; import org.apache.syncope.common.lib.wa.WAClientApp; +import org.apache.syncope.wa.bootstrap.mapping.AttrReleaseMapper; import org.apereo.cas.authentication.AuthenticationEventExecutionPlan; import org.apereo.cas.authentication.MultifactorAuthenticationProvider; import org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy; @@ -81,15 +82,17 @@ public RegisteredServiceMapper( } public RegisteredService toRegisteredService(final WAClientApp clientApp) { - ClientAppMapper clientAppMapper = clientAppMappers.stream(). + return clientAppMappers.stream(). filter(m -> m.supports(clientApp.getClientAppTO())). findFirst(). - orElse(null); - if (clientAppMapper == null) { - LOG.warn("Unable to locate ClientAppMapper for {}", clientApp.getClientAppTO().getClass().getName()); - return null; - } + map(clientAppMapper -> toRegisteredService(clientApp, clientAppMapper)). + orElseGet(() -> { + LOG.warn("Unable to locate mapper for {}", clientApp.getClientAppTO().getClass().getName()); + return null; + }); + } + public RegisteredService toRegisteredService(final WAClientApp clientApp, final ClientAppMapper clientAppMapper) { RegisteredServiceAuthenticationPolicy authPolicy = null; RegisteredServiceMultifactorPolicy mfaPolicy = null; RegisteredServiceDelegatedAuthenticationPolicy delegatedAuthPolicy = null; diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/WAServiceRegistryTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/WAServiceRegistryTest.java index 01f7d2b34f..1ae5282b0a 100644 --- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/WAServiceRegistryTest.java +++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/WAServiceRegistryTest.java @@ -54,6 +54,7 @@ import org.apereo.cas.services.RegisteredService; import org.apereo.cas.services.RegisteredServiceAccessStrategy; import org.apereo.cas.services.RegisteredServiceDelegatedAuthenticationPolicy; +import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.support.saml.services.SamlRegisteredService; import org.apereo.cas.util.RandomUtils; @@ -184,7 +185,7 @@ public void addClientApp() { assertTrue(oidc.getAuthenticationPolicy().getRequiredAuthenticationHandlers().contains("TestAuthModule")); assertTrue(((AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria) oidc. getAuthenticationPolicy().getCriteria()).isTryAll()); - assertTrue(oidc.getAttributeReleasePolicy() instanceof ChainingAttributeReleasePolicy); + assertTrue(oidc.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy); // 5. more client with different attributes waClientApp = new WAClientApp();