This is an automated email from the ASF dual-hosted git repository. mdisabatino 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 54f0304156 [SYNCOPE-1733] Added OAuth20 AuthModule (#414) 54f0304156 is described below commit 54f030415641f46ee4c92e3e4c61d62a644ea03f Author: mdisabatino <mdisabat...@apache.org> AuthorDate: Fri Feb 24 13:32:43 2023 +0100 [SYNCOPE-1733] Added OAuth20 AuthModule (#414) * [SYNCOPE-1733] Added OAuth20 AuthModule * [SYNCOPE-1733] Fix code scanning * [SYNCOPE-1733] Fix code scanning --- .../lib/auth/AbstractOIDCAuthModuleConf.java | 121 +++++++++++++++++++++ .../syncope/common/lib/auth/AuthModuleConf.java | 2 + .../common/lib/auth/OAuth20AuthModuleConf.java | 93 ++++++++++++++++ .../common/lib/auth/OIDCAuthModuleConf.java | 78 +------------ .../src/test/resources/domains/MasterContent.xml | 3 + .../src/test/resources/domains/MasterContent.xml | 2 + .../apache/syncope/fit/core/AuthModuleITCase.java | 59 +++++++++- .../bootstrap/AuthModulePropertySourceMapper.java | 23 ++++ .../AuthModulePropertySourceMapperTest.java | 28 +++++ 9 files changed, 331 insertions(+), 78 deletions(-) diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractOIDCAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractOIDCAuthModuleConf.java new file mode 100644 index 0000000000..9d4b577437 --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractOIDCAuthModuleConf.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.auth; + +import java.util.LinkedHashMap; +import java.util.Map; + +public abstract class AbstractOIDCAuthModuleConf extends Pac4jAuthModuleConf { + + protected String clientId; + + protected String clientSecret; + + protected String clientName; + + protected boolean enabled; + + protected Map<String, String> customParams = new LinkedHashMap<>(); + + protected String tokenUrl; + + protected String responseType = "code"; + + protected String scope; + + protected String userIdAttribute; + + public String getClientId() { + return clientId; + } + + public void setId(final String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(final String clientSecret) { + this.clientSecret = clientSecret; + } + + @Override + public String getClientName() { + return clientName; + } + + @Override + public void setClientName(final String clientName) { + this.clientName = clientName; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + public Map<String, String> getCustomParams() { + return customParams; + } + + public void setCustomParams(final Map<String, String> customParams) { + this.customParams = customParams; + } + + public String getTokenUrl() { + return tokenUrl; + } + + public void setTokenUrl(final String tokenUrl) { + this.tokenUrl = tokenUrl; + } + + public String getResponseType() { + return responseType; + } + + public void setResponseType(final String responseType) { + this.responseType = responseType; + } + + public String getScope() { + return scope; + } + + public void setScope(final String scope) { + this.scope = scope; + } + + public void setClientId(final String clientId) { + this.clientId = clientId; + } + + public String getUserIdAttribute() { + return userIdAttribute; + } + + public void setUserIdAttribute(final String userIdAttribute) { + this.userIdAttribute = userIdAttribute; + } +} diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java index bb08dc9c14..c41588b85d 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java @@ -49,6 +49,8 @@ public interface AuthModuleConf extends BaseBean { Map<String, Object> map(AuthModuleTO authModule, U2FAuthModuleConf conf); Map<String, Object> map(AuthModuleTO authModule, SimpleMfaAuthModuleConf conf); + + Map<String, Object> map(AuthModuleTO authModule, OAuth20AuthModuleConf conf); } Map<String, Object> map(AuthModuleTO authModule, Mapper mapper); diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java new file mode 100644 index 0000000000..097016a995 --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.auth; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.syncope.common.lib.to.AuthModuleTO; + +public class OAuth20AuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf { + + private static final long serialVersionUID = 299820485764241682L; + + protected String authUrl; + + protected String profileUrl; + + protected Map<String, String> profileAttrs = new LinkedHashMap<>(); + + protected boolean withState; + + protected String profilePath; + + protected String profileVerb = "POST"; + + public String getAuthUrl() { + return authUrl; + } + + public void setAuthUrl(final String authUrl) { + this.authUrl = authUrl; + } + + public Map<String, String> getProfileAttrs() { + return profileAttrs; + } + + public void setProfileAttrs(final Map<String, String> profileAttrs) { + this.profileAttrs = profileAttrs; + } + + public boolean isWithState() { + return withState; + } + + public void setWithState(final boolean withState) { + this.withState = withState; + } + + public String getProfilePath() { + return profilePath; + } + + public void setProfilePath(final String profilePath) { + this.profilePath = profilePath; + } + + public String getProfileUrl() { + return profileUrl; + } + + public void setProfileUrl(final String profileUrl) { + this.profileUrl = profileUrl; + } + + public String getProfileVerb() { + return profileVerb; + } + + public void setProfileVerb(final String profileVerb) { + this.profileVerb = profileVerb; + } + + @Override + public Map<String, Object> map(final AuthModuleTO authModule, final Mapper mapper) { + return mapper.map(authModule, this); + } +} diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OIDCAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OIDCAuthModuleConf.java index b4899dec51..1419e87730 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OIDCAuthModuleConf.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OIDCAuthModuleConf.java @@ -18,29 +18,13 @@ */ package org.apache.syncope.common.lib.auth; -import java.util.HashMap; import java.util.Map; import org.apache.syncope.common.lib.to.AuthModuleTO; -public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModuleConf { +public class OIDCAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf { private static final long serialVersionUID = -471527731042579422L; - /** - * The client id. - */ - protected String clientId; - - /** - * The client secret. - */ - protected String clientSecret; - - /** - * The attribute value that should be used for the authenticated username, upon a successful authentication attempt. - */ - protected String userIdAttribute; - protected String discoveryUri; /** @@ -49,11 +33,6 @@ public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModul */ protected boolean useNonce; - /** - * Requested scope(s). - */ - protected String scope; - /** * The JWS algorithm to use forcefully when validating ID tokens. * If none is defined, the first algorithm from metadata will be used. @@ -65,47 +44,12 @@ public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModul */ protected String maxClockSkew; - /** - * Custom parameters to send along in authZ requests, etc. - */ - protected final Map<String, String> customParams = new HashMap<>(0); - /** * The response mode specifies how the result of the authorization request is formatted. * Possible values includes "query", "fragment", "form_post", or "web_message" */ protected String responseMode; - /** - * The response type tells the authorization server which grant to execute. - * Possibles values includes "code", "token" or "id_token". - */ - protected String responseType; - - public String getClientId() { - return clientId; - } - - public void setClientId(final String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(final String clientSecret) { - this.clientSecret = clientSecret; - } - - public String getUserIdAttribute() { - return userIdAttribute; - } - - public void setUserIdAttribute(final String userIdAttribute) { - this.userIdAttribute = userIdAttribute; - } - public String getDiscoveryUri() { return discoveryUri; } @@ -122,14 +66,6 @@ public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModul this.useNonce = useNonce; } - public String getScope() { - return scope; - } - - public void setScope(final String scope) { - this.scope = scope; - } - public String getPreferredJwsAlgorithm() { return preferredJwsAlgorithm; } @@ -146,10 +82,6 @@ public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModul this.maxClockSkew = maxClockSkew; } - public Map<String, String> getCustomParams() { - return customParams; - } - public String getResponseMode() { return responseMode; } @@ -158,14 +90,6 @@ public class OIDCAuthModuleConf extends Pac4jAuthModuleConf implements AuthModul this.responseMode = responseMode; } - public String getResponseType() { - return responseType; - } - - public void setResponseType(final String responseType) { - this.responseType = responseType; - } - @Override public Map<String, Object> map(final AuthModuleTO authModule, final Mapper mapper) { return mapper.map(authModule, this); diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml index e2fba179a1..d778a528c7 100644 --- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml @@ -87,6 +87,9 @@ under the License. items='[{"intAttrName":"syncopeUserAttr_surname","extAttrName":"family_name","connObjectKey":false,"password":false,"mandatoryCondition":"false","purpose":"NONE","propagationJEXLTransformer":null,"pullJEXLTransformer":null,"transformers":[]},{"intAttrName":"syncopeUserAttr_fullname","extAttrName":"name","connObjectKey":false,"password":false,"mandatoryCondition":"false","purpose":"NONE","propagationJEXLTransformer":null,"pullJEXLTransformer":null,"transformers":[]},{"intAtt [...] <AuthModule id="DefaultU2FAuthModule" authModuleState="ACTIVE" description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/> + <AuthModule id="DefaultOAuth20AuthModule" description="OAuth20 auth module" authModuleOrder="0" + jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","profileAttrs":{},"withState":false,"profilePath":null,"profileVerb":"POST"}' authModuleStat [...] + <!-- Attribute repositories --> <AttrRepo id="DefaultLDAPAttrRepo" attrRepoState="ACTIVE" diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml index abfbc39271..f804bf8eda 100644 --- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml @@ -87,6 +87,8 @@ under the License. items='[{"intAttrName":"syncopeUserAttr_surname","extAttrName":"family_name","connObjectKey":false,"password":false,"mandatoryCondition":"false","purpose":"NONE","propagationJEXLTransformer":null,"pullJEXLTransformer":null,"transformers":[]},{"intAttrName":"syncopeUserAttr_fullname","extAttrName":"name","connObjectKey":false,"password":false,"mandatoryCondition":"false","purpose":"NONE","propagationJEXLTransformer":null,"pullJEXLTransformer":null,"transformers":[]},{"intAtt [...] <AuthModule id="DefaultU2FAuthModule" authModuleState="ACTIVE" description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/> + <AuthModule id="DefaultOAuth20AuthModule" description="OAuth20 auth module" authModuleOrder="0" + jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","profileAttrs":{},"withState":false,"profilePath":null,"profileVerb":"POST"}' authModuleStat [...] <!-- Attribute repositories --> <AttrRepo id="DefaultLDAPAttrRepo" attrRepoState="ACTIVE" diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java index feac556db6..0785f8d3cb 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java @@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.UUID; import javax.ws.rs.core.Response; import org.apache.commons.lang3.ClassUtils; @@ -39,6 +40,7 @@ import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf; import org.apache.syncope.common.lib.auth.JDBCAuthModuleConf; import org.apache.syncope.common.lib.auth.JaasAuthModuleConf; import org.apache.syncope.common.lib.auth.LDAPAuthModuleConf; +import org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf; import org.apache.syncope.common.lib.auth.OIDCAuthModuleConf; import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf; import org.apache.syncope.common.lib.auth.StaticAuthModuleConf; @@ -62,7 +64,8 @@ public class AuthModuleITCase extends AbstractITCase { JAAS, JDBC, U2F, - OIDC; + OIDC, + OAUTH20; }; @@ -138,6 +141,24 @@ public class AuthModuleITCase extends AbstractITCase { OIDCAuthModuleConf.class.cast(conf).setScope("openid email profile"); break; + case OAUTH20: + conf = new OAuth20AuthModuleConf(); + OAuth20AuthModuleConf.class.cast(conf).setClientId("OAUTH20TestId"); + OAuth20AuthModuleConf.class.cast(conf).setClientSecret("secret"); + OAuth20AuthModuleConf.class.cast(conf).setClientName("oauth20"); + OAuth20AuthModuleConf.class.cast(conf).setEnabled(true); + OAuth20AuthModuleConf.class.cast(conf).setCustomParams(Map.of("param1", "param1")); + OAuth20AuthModuleConf.class.cast(conf).setAuthUrl("https://localhost/oauth2/auth"); + OAuth20AuthModuleConf.class.cast(conf).setProfileAttrs(Map.of("uid", "id")); + OAuth20AuthModuleConf.class.cast(conf).setProfileUrl("https://localhost/oauth2/profile"); + OAuth20AuthModuleConf.class.cast(conf).setProfilePath("/info"); + OAuth20AuthModuleConf.class.cast(conf).setTokenUrl("https://localhost/oauth2/token"); + OAuth20AuthModuleConf.class.cast(conf).setResponseType("code"); + OAuth20AuthModuleConf.class.cast(conf).setScope("oauth test"); + OAuth20AuthModuleConf.class.cast(conf).setUserIdAttribute("username"); + OAuth20AuthModuleConf.class.cast(conf).setWithState(true); + break; + case SAML2_IDP: conf = new SAML2IdPAuthModuleConf(); SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("testEntityId"); @@ -216,6 +237,9 @@ public class AuthModuleITCase extends AbstractITCase { assertTrue(authModuleTOs.stream().anyMatch( authModule -> isSpecificConf(authModule.getConf(), U2FAuthModuleConf.class) && authModule.getKey().equals("DefaultU2FAuthModule"))); + assertTrue(authModuleTOs.stream().anyMatch( + authModule -> isSpecificConf(authModule.getConf(), OAuth20AuthModuleConf.class) + && authModule.getKey().equals("DefaultOAuth20AuthModule"))); } @Test @@ -267,6 +291,16 @@ public class AuthModuleITCase extends AbstractITCase { assertFalse(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class)); } + @Test + public void getOAuth20AuthModule() { + AuthModuleTO authModuleTO = AUTH_MODULE_SERVICE.read("DefaultOAuth20AuthModule"); + + assertNotNull(authModuleTO); + assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription())); + assertTrue(isSpecificConf(authModuleTO.getConf(), OAuth20AuthModuleConf.class)); + assertFalse(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class)); + } + @Test public void getSAML2IdPAuthModule() { AuthModuleTO authModuleTO = AUTH_MODULE_SERVICE.read("DefaultSAML2IdPAuthModule"); @@ -443,6 +477,29 @@ public class AuthModuleITCase extends AbstractITCase { assertEquals("newCode", OIDCAuthModuleConf.class.cast(conf).getResponseType()); } + @Test + public void updateOAuth20AuthModule() { + AuthModuleTO oauth20AuthModuleTO = AUTH_MODULE_SERVICE.read("DefaultOAuth20AuthModule"); + assertNotNull(oauth20AuthModuleTO); + + AuthModuleTO newoauth20AuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.OAUTH20); + newoauth20AuthModuleTO = createAuthModule(newoauth20AuthModuleTO); + assertNotNull(newoauth20AuthModuleTO); + + AuthModuleConf conf = oauth20AuthModuleTO.getConf(); + assertNotNull(conf); + OAuth20AuthModuleConf.class.cast(conf).setClientName("OAUTH APP"); + newoauth20AuthModuleTO.setConf(conf); + + // update new auth module + AUTH_MODULE_SERVICE.update(newoauth20AuthModuleTO); + newoauth20AuthModuleTO = AUTH_MODULE_SERVICE.read(newoauth20AuthModuleTO.getKey()); + assertNotNull(newoauth20AuthModuleTO); + + conf = newoauth20AuthModuleTO.getConf(); + assertEquals("OAUTH APP", OAuth20AuthModuleConf.class.cast(conf).getClientName()); + } + @Test public void updateJDBCAuthModule() { AuthModuleTO jdbcAuthModuleTO = AUTH_MODULE_SERVICE.read("DefaultJDBCAuthModule"); 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/AuthModulePropertySourceMapper.java index b14c7fe137..7f2e9886f0 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/AuthModulePropertySourceMapper.java @@ -30,6 +30,7 @@ import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf; import org.apache.syncope.common.lib.auth.JDBCAuthModuleConf; import org.apache.syncope.common.lib.auth.JaasAuthModuleConf; import org.apache.syncope.common.lib.auth.LDAPAuthModuleConf; +import org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf; import org.apache.syncope.common.lib.auth.OIDCAuthModuleConf; import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf; import org.apache.syncope.common.lib.auth.SimpleMfaAuthModuleConf; @@ -50,6 +51,7 @@ import org.apereo.cas.configuration.model.support.mfa.gauth.GoogleAuthenticatorM import org.apereo.cas.configuration.model.support.mfa.gauth.LdapGoogleAuthenticatorMultifactorProperties; import org.apereo.cas.configuration.model.support.mfa.simple.CasSimpleMultifactorAuthenticationProperties; import org.apereo.cas.configuration.model.support.mfa.u2f.U2FMultifactorAuthenticationProperties; +import org.apereo.cas.configuration.model.support.pac4j.oauth.Pac4jOAuth20ClientProperties; import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jGenericOidcClientProperties; import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jOidcClientProperties; import org.apereo.cas.configuration.model.support.pac4j.saml.Pac4jSamlClientProperties; @@ -147,6 +149,27 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme return prefix("cas.authn.pac4j.oidc[].generic.", CasCoreConfigurationUtils.asMap(props)); } + @Override + public Map<String, Object> map(final AuthModuleTO authModuleTO, final OAuth20AuthModuleConf conf) { + Pac4jOAuth20ClientProperties props = new Pac4jOAuth20ClientProperties(); + props.setId(conf.getClientId()); + props.setSecret(conf.getClientSecret()); + props.setClientName(Optional.ofNullable(conf.getClientName()).orElse(authModuleTO.getKey())); + props.setEnabled(authModuleTO.getState() == AuthModuleState.ACTIVE); + props.setCustomParams(conf.getCustomParams()); + props.setAuthUrl(conf.getAuthUrl()); + props.setProfileAttrs(conf.getProfileAttrs()); + props.setProfilePath(conf.getProfilePath()); + props.setProfileUrl(conf.getProfileUrl()); + props.setTokenUrl(conf.getTokenUrl()); + props.setResponseType(conf.getResponseType()); + props.setScope(conf.getScope()); + props.setPrincipalAttributeId(conf.getUserIdAttribute()); + props.setWithState(conf.isWithState()); + + return prefix("cas.authn.pac4j.oauth2[].", CasCoreConfigurationUtils.asMap(props)); + } + @Override public Map<String, Object> map(final AuthModuleTO authModuleTO, final SAML2IdPAuthModuleConf conf) { Pac4jSamlClientProperties props = new Pac4jSamlClientProperties(); 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 a5175ebe98..37d6165323 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 @@ -21,6 +21,7 @@ package org.apache.syncope.wa.bootstrap; import static org.junit.jupiter.api.Assertions.assertFalse; import java.util.Map; +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.junit.jupiter.api.Test; @@ -46,4 +47,31 @@ public class AuthModulePropertySourceMapperTest { Map<String, Object> map = new AuthModulePropertySourceMapper(null).map(authModuleTO, conf); assertFalse(map.keySet().stream().anyMatch(k -> k.endsWith("defined"))); } + + @Test + public void mapOAuth20AuthModuleConf() { + AuthModuleTO authModuleTO = new AuthModuleTO(); + authModuleTO.setKey("oauth20"); + authModuleTO.setOrder(0); + + OAuth20AuthModuleConf conf = new OAuth20AuthModuleConf(); + + conf.setClientId("1000"); + conf.setClientSecret("secret"); + conf.setClientName("oauth20"); + conf.setEnabled(true); + conf.setCustomParams(Map.of("param1", "param1")); + conf.setAuthUrl("https://localhost/oauth2/auth"); + conf.setProfileAttrs(Map.of("uid", "id")); + conf.setProfileUrl("https://localhost/oauth2/profile"); + conf.setProfilePath("/info"); + conf.setTokenUrl("https://localhost/oauth2/token"); + conf.setResponseType("code"); + conf.setScope("cns"); + conf.setUserIdAttribute("uid"); + conf.setWithState(true); + + Map<String, Object> map = new AuthModulePropertySourceMapper(null).map(authModuleTO, conf); + assertFalse(map.keySet().stream().anyMatch(k -> k.endsWith("defined"))); + } }