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/07/21 12:26:09 UTC
[syncope] branch master updated: [SYNCOPE-1771] Adding support for delegated auth via Google, Keycloak and Apple ID
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 4268571d17 [SYNCOPE-1771] Adding support for delegated auth via Google, Keycloak and Apple ID
4268571d17 is described below
commit 4268571d172d3bb936cdfa79f93a70cd5d3df111
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Fri Jul 21 14:17:46 2023 +0200
[SYNCOPE-1771] Adding support for delegated auth via Google, Keycloak and Apple ID
---
.../common/lib/auth/AppleOIDCAuthModuleConf.java | 88 ++++++++++++++
.../syncope/common/lib/auth/AuthModuleConf.java | 14 ++-
...oduleConf.java => AzureOIDCAuthModuleConf.java} | 3 +-
...duleConf.java => GoogleOIDCAuthModuleConf.java} | 21 +---
...leConf.java => KeycloakOIDCAuthModuleConf.java} | 33 +++--
.../bootstrap/AuthModulePropertySourceMapper.java | 134 ++++++++++++++-------
6 files changed, 209 insertions(+), 84 deletions(-)
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AppleOIDCAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AppleOIDCAuthModuleConf.java
new file mode 100644
index 0000000000..cc1ce7a80d
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AppleOIDCAuthModuleConf.java
@@ -0,0 +1,88 @@
+/*
+ * 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.Map;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+
+public class AppleOIDCAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
+
+ private static final long serialVersionUID = -471527731042579522L;
+
+ /**
+ * Client secret expiration timeout.
+ * This settings supports the java.time.Duration syntax.
+ */
+ protected String timeout = "PT30S";
+
+ /**
+ * Apple team identifier.
+ * Usually, 10 character string given to you by Apple.
+ */
+ protected String teamId;
+
+ /**
+ * Private key obtained from Apple.
+ * Must point to a resource that resolved to an elliptic curve (EC) private key.
+ */
+ protected String privateKey;
+
+ /**
+ * The identifier for the private key.
+ * Usually the 10 character Key ID of the private key you create in Apple.
+ */
+ protected String privateKeyId;
+
+ public String getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(final String timeout) {
+ this.timeout = timeout;
+ }
+
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(final String privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ public String getPrivateKeyId() {
+ return privateKeyId;
+ }
+
+ public void setPrivateKeyId(final String privateKeyId) {
+ this.privateKeyId = privateKeyId;
+ }
+
+ public String getTeamId() {
+ return teamId;
+ }
+
+ public void setTeamId(final String teamId) {
+ this.teamId = teamId;
+ }
+
+ @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/AuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
index 2cca813cdf..8bc5a4fa6d 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
@@ -36,8 +36,18 @@ public interface AuthModuleConf extends BaseBean {
Map<String, Object> map(AuthModuleTO authModule, JaasAuthModuleConf conf);
+ Map<String, Object> map(AuthModuleTO authModule, OAuth20AuthModuleConf conf);
+
Map<String, Object> map(AuthModuleTO authModule, OIDCAuthModuleConf conf);
+ Map<String, Object> map(AuthModuleTO authModule, AzureOIDCAuthModuleConf conf);
+
+ Map<String, Object> map(AuthModuleTO authModule, GoogleOIDCAuthModuleConf conf);
+
+ Map<String, Object> map(AuthModuleTO authModule, KeycloakOIDCAuthModuleConf conf);
+
+ Map<String, Object> map(AuthModuleTO authModule, AppleOIDCAuthModuleConf conf);
+
Map<String, Object> map(AuthModuleTO authModule, SAML2IdPAuthModuleConf conf);
Map<String, Object> map(AuthModuleTO authModule, SyncopeAuthModuleConf conf);
@@ -49,10 +59,6 @@ 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, AzureAuthModuleConf conf);
}
Map<String, Object> map(AuthModuleTO authModule, Mapper mapper);
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureOIDCAuthModuleConf.java
similarity index 94%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
copy to common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureOIDCAuthModuleConf.java
index c5cb26a85d..f1cd5b73f1 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureOIDCAuthModuleConf.java
@@ -21,7 +21,7 @@ package org.apache.syncope.common.lib.auth;
import java.util.Map;
import org.apache.syncope.common.lib.to.AuthModuleTO;
-public class AzureAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
+public class AzureOIDCAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
private static final long serialVersionUID = -471527731042579522L;
@@ -47,5 +47,4 @@ public class AzureAuthModuleConf extends AbstractOIDCAuthModuleConf implements A
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/AzureAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleOIDCAuthModuleConf.java
similarity index 61%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
copy to common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleOIDCAuthModuleConf.java
index c5cb26a85d..f848f450a7 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleOIDCAuthModuleConf.java
@@ -21,31 +21,12 @@ package org.apache.syncope.common.lib.auth;
import java.util.Map;
import org.apache.syncope.common.lib.to.AuthModuleTO;
-public class AzureAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
+public class GoogleOIDCAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
private static final long serialVersionUID = -471527731042579522L;
- /**
- * Azure AD tenant name. After tenant is configured, #getDiscoveryUri() property will be overridden.
- *
- * Azure AD tenant name can take 4 different values:
- * - organizations: Only users with work or school accounts from Azure AD can sign in.
- * - consumers: Only users with a personal Microsoft account can sign in.
- * - Specific tenant domain name or ID: Only user with account under that the specified tenant can login
- */
- protected String tenant;
-
- public String getTenant() {
- return tenant;
- }
-
- public void setTenant(final String tenant) {
- this.tenant = tenant;
- }
-
@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/AzureAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/KeycloakOIDCAuthModuleConf.java
similarity index 62%
rename from common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
rename to common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/KeycloakOIDCAuthModuleConf.java
index c5cb26a85d..a4f464c157 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AzureAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/KeycloakOIDCAuthModuleConf.java
@@ -21,31 +21,38 @@ package org.apache.syncope.common.lib.auth;
import java.util.Map;
import org.apache.syncope.common.lib.to.AuthModuleTO;
-public class AzureAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
+public class KeycloakOIDCAuthModuleConf extends AbstractOIDCAuthModuleConf implements AuthModuleConf {
private static final long serialVersionUID = -471527731042579522L;
/**
- * Azure AD tenant name. After tenant is configured, #getDiscoveryUri() property will be overridden.
- *
- * Azure AD tenant name can take 4 different values:
- * - organizations: Only users with work or school accounts from Azure AD can sign in.
- * - consumers: Only users with a personal Microsoft account can sign in.
- * - Specific tenant domain name or ID: Only user with account under that the specified tenant can login
+ * Keycloak realm used to construct metadata discovery URI.
*/
- protected String tenant;
+ protected String realm;
- public String getTenant() {
- return tenant;
+ /**
+ * Keycloak base URL used to construct metadata discovery URI.
+ */
+ protected String baseUri;
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public void setRealm(final String realm) {
+ this.realm = realm;
+ }
+
+ public String getBaseUri() {
+ return baseUri;
}
- public void setTenant(final String tenant) {
- this.tenant = tenant;
+ public void setBaseUri(final String baseUri) {
+ this.baseUri = baseUri;
}
@Override
public Map<String, Object> map(final AuthModuleTO authModule, final Mapper mapper) {
return mapper.map(authModule, this);
}
-
}
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 a40b63086e..0efbff13b5 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
@@ -25,12 +25,16 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.auth.AbstractOIDCAuthModuleConf;
+import org.apache.syncope.common.lib.auth.AppleOIDCAuthModuleConf;
import org.apache.syncope.common.lib.auth.AuthModuleConf;
-import org.apache.syncope.common.lib.auth.AzureAuthModuleConf;
+import org.apache.syncope.common.lib.auth.AzureOIDCAuthModuleConf;
import org.apache.syncope.common.lib.auth.DuoMfaAuthModuleConf;
import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf;
+import org.apache.syncope.common.lib.auth.GoogleOIDCAuthModuleConf;
import org.apache.syncope.common.lib.auth.JDBCAuthModuleConf;
import org.apache.syncope.common.lib.auth.JaasAuthModuleConf;
+import org.apache.syncope.common.lib.auth.KeycloakOIDCAuthModuleConf;
import org.apache.syncope.common.lib.auth.LDAPAuthModuleConf;
import org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf;
import org.apache.syncope.common.lib.auth.OIDCAuthModuleConf;
@@ -56,8 +60,12 @@ import org.apereo.cas.configuration.model.support.mfa.gauth.LdapGoogleAuthentica
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.BasePac4jOidcClientProperties;
+import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jAppleOidcClientProperties;
import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jAzureOidcClientProperties;
import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jGenericOidcClientProperties;
+import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jGoogleOidcClientProperties;
+import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jKeyCloakOidcClientProperties;
import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jOidcClientProperties;
import org.apereo.cas.configuration.model.support.pac4j.saml.Pac4jSamlClientProperties;
import org.apereo.cas.configuration.model.support.syncope.SyncopeAuthenticationProperties;
@@ -149,8 +157,32 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
}
@Override
- public Map<String, Object> map(final AuthModuleTO authModuleTO, final OIDCAuthModuleConf conf) {
- Pac4jGenericOidcClientProperties props = new Pac4jGenericOidcClientProperties();
+ 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.setProfileVerb(conf.getProfileVerb());
+ props.setProfileUrl(conf.getProfileUrl());
+ props.setTokenUrl(conf.getTokenUrl());
+ props.setResponseType(conf.getResponseType());
+ props.setScope(conf.getScope());
+ props.setPrincipalIdAttribute(conf.getUserIdAttribute());
+ props.setWithState(conf.isWithState());
+ props.setProfileAttrs(authModuleTO.getItems().stream().
+ collect(Collectors.toMap(Item::getIntAttrName, Item::getExtAttrName)));
+
+ return prefix("cas.authn.pac4j.oauth2[].", CasCoreConfigurationUtils.asMap(props));
+ }
+
+ protected void map(
+ final AuthModuleTO authModuleTO,
+ final BasePac4jOidcClientProperties props,
+ final AbstractOIDCAuthModuleConf conf) {
+
props.setId(conf.getClientId());
props.setSecret(conf.getClientSecret());
props.setClientName(Optional.ofNullable(conf.getClientName()).orElse(authModuleTO.getKey()));
@@ -165,6 +197,13 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
props.setPrincipalIdAttribute(conf.getUserIdAttribute());
props.setExpireSessionWithToken(conf.isExpireSessionWithToken());
props.setTokenExpirationAdvance(conf.getTokenExpirationAdvance());
+ }
+
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final OIDCAuthModuleConf conf) {
+ Pac4jGenericOidcClientProperties props = new Pac4jGenericOidcClientProperties();
+ map(authModuleTO, props, conf);
+
Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
client.setGeneric(props);
@@ -172,25 +211,54 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
}
@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.setProfileVerb(conf.getProfileVerb());
- props.setProfileUrl(conf.getProfileUrl());
- props.setTokenUrl(conf.getTokenUrl());
- props.setResponseType(conf.getResponseType());
- props.setScope(conf.getScope());
- props.setPrincipalIdAttribute(conf.getUserIdAttribute());
- props.setWithState(conf.isWithState());
- props.setProfileAttrs(authModuleTO.getItems().stream().
- collect(Collectors.toMap(Item::getIntAttrName, Item::getExtAttrName)));
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final AzureOIDCAuthModuleConf conf) {
+ Pac4jAzureOidcClientProperties props = new Pac4jAzureOidcClientProperties();
+ map(authModuleTO, props, conf);
+ props.setTenant(conf.getTenant());
- return prefix("cas.authn.pac4j.oauth2[].", CasCoreConfigurationUtils.asMap(props));
+ Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
+ client.setAzure(props);
+
+ return prefix("cas.authn.pac4j.oidc[].azure.", CasCoreConfigurationUtils.asMap(props));
+ }
+
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final GoogleOIDCAuthModuleConf conf) {
+ Pac4jGoogleOidcClientProperties props = new Pac4jGoogleOidcClientProperties();
+ map(authModuleTO, props, conf);
+
+ Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
+ client.setGoogle(props);
+
+ return prefix("cas.authn.pac4j.oidc[].google.", CasCoreConfigurationUtils.asMap(props));
+ }
+
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final KeycloakOIDCAuthModuleConf conf) {
+ Pac4jKeyCloakOidcClientProperties props = new Pac4jKeyCloakOidcClientProperties();
+ map(authModuleTO, props, conf);
+ props.setRealm(conf.getRealm());
+ props.setBaseUri(conf.getBaseUri());
+
+ Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
+ client.setKeycloak(props);
+
+ return prefix("cas.authn.pac4j.oidc[].keycloak.", CasCoreConfigurationUtils.asMap(props));
+ }
+
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final AppleOIDCAuthModuleConf conf) {
+ Pac4jAppleOidcClientProperties props = new Pac4jAppleOidcClientProperties();
+ map(authModuleTO, props, conf);
+ props.setTimeout(conf.getTimeout());
+ props.setPrivateKey(conf.getPrivateKey());
+ props.setPrivateKeyId(conf.getPrivateKeyId());
+ props.setTeamId(conf.getTeamId());
+
+ Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
+ client.setApple(props);
+
+ return prefix("cas.authn.pac4j.oidc[].apple.", CasCoreConfigurationUtils.asMap(props));
}
@Override
@@ -315,28 +383,4 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
return prefix("cas.authn.mfa.simple.", CasCoreConfigurationUtils.asMap(props));
}
-
- @Override
- public Map<String, Object> map(final AuthModuleTO authModuleTO, final AzureAuthModuleConf conf) {
- Pac4jAzureOidcClientProperties props = new Pac4jAzureOidcClientProperties();
- 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.setDiscoveryUri(conf.getDiscoveryUri());
- props.setMaxClockSkew(conf.getMaxClockSkew());
- props.setPreferredJwsAlgorithm(conf.getPreferredJwsAlgorithm());
- props.setResponseMode(conf.getResponseMode());
- props.setResponseType(conf.getResponseType());
- props.setScope(conf.getScope());
- props.setPrincipalIdAttribute(conf.getUserIdAttribute());
- props.setExpireSessionWithToken(conf.isExpireSessionWithToken());
- props.setTokenExpirationAdvance(conf.getTokenExpirationAdvance());
- props.setTenant(conf.getTenant());
- Pac4jOidcClientProperties client = new Pac4jOidcClientProperties();
- client.setAzure(props);
-
- return prefix("cas.authn.pac4j.oidc[].azure.", CasCoreConfigurationUtils.asMap(props));
- }
}