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 2020/04/10 08:28:04 UTC
[syncope] 02/08: [SYNCOPE-160] AuthModule service
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
commit 426b2f2a332f2246b2888aabd3537bfeb903704d
Author: Matteo Alessandroni <sk...@apache.org>
AuthorDate: Thu Apr 9 12:58:10 2020 +0200
[SYNCOPE-160] AuthModule service
---
.../common/lib/auth/AbstractAuthModuleConf.java | 48 ++
.../syncope/common/lib/auth/AuthModuleConf.java | 35 ++
.../common/lib/auth/GoogleMfaAuthModuleConf.java | 99 ++++
.../common/lib/auth/JDBCAuthModuleConf.java | 99 ++++
.../common/lib/auth/JaasAuthModuleConf.java | 88 +++
.../common/lib/auth/LDAPAuthModuleConf.java | 126 +++++
.../common/lib/auth/OIDCAuthModuleConf.java | 182 +++++++
.../common/lib/auth/RadiusAuthModuleConf.java | 172 ++++++
.../common/lib/auth/SAML2IdPAuthModuleConf.java | 430 +++++++++++++++
.../common/lib/auth/StaticAuthModuleConf.java | 47 ++
.../common/lib/auth/SyncopeAuthModuleConf.java | 56 ++
.../syncope/common/lib/auth/U2FAuthModuleConf.java | 69 +++
.../syncope/common/lib/auth/package-info.java | 30 ++
.../apache/syncope/common/lib/to/AuthModuleTO.java | 132 +++++
.../common/rest/api/service/AuthModuleService.java | 126 +++++
.../apache/syncope/core/logic/AuthModuleLogic.java | 131 +++++
.../rest/cxf/service/AuthModuleServiceImpl.java | 65 +++
.../persistence/api/dao/auth/AuthModuleDAO.java | 37 ++
.../persistence/api/entity/auth/AuthModule.java | 48 ++
.../api/entity/auth/AuthModuleItem.java | 25 +
.../persistence/jpa/dao/auth/JPAAuthModuleDAO.java | 68 +++
.../persistence/jpa/entity/auth/JPAAuthModule.java | 104 ++++
.../jpa/entity/auth/JPAAuthModuleItem.java | 69 +++
.../core/persistence/jpa/inner/AuthModuleTest.java | 502 ++++++++++++++++++
.../api/data/AuthModuleDataBinder.java | 32 ++
.../java/data/AuthModuleDataBinderImpl.java | 79 +++
.../apache/syncope/fit/core/AuthModuleITCase.java | 589 +++++++++++++++++++++
27 files changed, 3488 insertions(+)
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java
new file mode 100644
index 0000000..a4399d6
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java
@@ -0,0 +1,48 @@
+/*
+ * 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.io.Serializable;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType
+@XmlSeeAlso({ JaasAuthModuleConf.class, StaticAuthModuleConf.class, LDAPAuthModuleConf.class,
+ OIDCAuthModuleConf.class, GoogleMfaAuthModuleConf.class, SAML2IdPAuthModuleConf.class, U2FAuthModuleConf.class,
+ JDBCAuthModuleConf.class, SyncopeAuthModuleConf.class, RadiusAuthModuleConf.class })
+public abstract class AbstractAuthModuleConf implements Serializable, AuthModuleConf {
+
+ private static final long serialVersionUID = 4153200197344709778L;
+
+ private String name;
+
+ public AbstractAuthModuleConf() {
+ setName(getClass().getName());
+ }
+
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ public final void setName(final String name) {
+ this.name = name;
+ }
+
+}
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
new file mode 100644
index 0000000..28c1357
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonTypeInfo;
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlTransient;
+
+@XmlTransient
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+public interface AuthModuleConf extends Serializable {
+
+ /**
+ * Given name of related authentication module instance.
+ *
+ * @return name of this authentication module instance
+ */
+ String getName();
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleMfaAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleMfaAuthModuleConf.java
new file mode 100644
index 0000000..a2e4168
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/GoogleMfaAuthModuleConf.java
@@ -0,0 +1,99 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "googleMfaAuthModuleConf")
+@XmlType
+public class GoogleMfaAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -7883257599139312426L;
+
+ /**
+ * Issuer used in the barcode when dealing with device registration events.
+ * Used in the registration URL to identify CAS.
+ */
+ private String issuer = "Syncope";
+
+ /**
+ * Label used in the barcode when dealing with device registration events.
+ * Used in the registration URL to identify CAS.
+ */
+ private String label = "Syncope";
+
+ /**
+ * Length of the generated code.
+ */
+ private int codeDigits = 6;
+
+ /**
+ * The expiration time of the generated code in seconds.
+ */
+ private long timeStepSize = 30;
+
+ /**
+ * Since TOTP passwords are time-based, it is essential that
+ * the clock of both the server and
+ * the client are synchronised within
+ * the tolerance defined here as the window size.
+ */
+ private int windowSize = 3;
+
+ public String getIssuer() {
+ return issuer;
+ }
+
+ public void setIssuer(final String issuer) {
+ this.issuer = issuer;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(final String label) {
+ this.label = label;
+ }
+
+ public int getCodeDigits() {
+ return codeDigits;
+ }
+
+ public void setCodeDigits(final int codeDigits) {
+ this.codeDigits = codeDigits;
+ }
+
+ public long getTimeStepSize() {
+ return timeStepSize;
+ }
+
+ public void setTimeStepSize(final long timeStepSize) {
+ this.timeStepSize = timeStepSize;
+ }
+
+ public int getWindowSize() {
+ return windowSize;
+ }
+
+ public void setWindowSize(final int windowSize) {
+ this.windowSize = windowSize;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JDBCAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JDBCAuthModuleConf.java
new file mode 100644
index 0000000..0141078
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JDBCAuthModuleConf.java
@@ -0,0 +1,99 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonProperty;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "jdbcAuthModuleConf")
+@XmlType
+public class JDBCAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = 8383233437907219385L;
+
+ /**
+ * SQL query to execute. Example: {@code SELECT * FROM table WHERE name=?}.
+ */
+ private String sql;
+
+ /**
+ * Password field/column name to retrieve.
+ */
+ private String fieldPassword;
+
+ /**
+ * Boolean field that should indicate whether the account is expired.
+ */
+ private String fieldExpired;
+
+ /**
+ * Boolean field that should indicate whether the account is disabled.
+ */
+ private String fieldDisabled;
+
+ /**
+ * List of column names to fetch as user attributes.
+ */
+ private final List<String> principalAttributeList = new ArrayList<>();
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(final String sql) {
+ this.sql = sql;
+ }
+
+ public String getFieldPassword() {
+ return fieldPassword;
+ }
+
+ public void setFieldPassword(final String fieldPassword) {
+ this.fieldPassword = fieldPassword;
+ }
+
+ public String getFieldExpired() {
+ return fieldExpired;
+ }
+
+ public void setFieldExpired(final String fieldExpired) {
+ this.fieldExpired = fieldExpired;
+ }
+
+ public String getFieldDisabled() {
+ return fieldDisabled;
+ }
+
+ public void setFieldDisabled(final String fieldDisabled) {
+ this.fieldDisabled = fieldDisabled;
+ }
+
+ @XmlElementWrapper(name = "principalAttributeList")
+ @XmlElement(name = "principalAttributeList")
+ @JsonProperty("principalAttributeList")
+ public List<String> getPrincipalAttributeList() {
+ return principalAttributeList;
+ }
+
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JaasAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JaasAuthModuleConf.java
new file mode 100644
index 0000000..b8627ab
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/JaasAuthModuleConf.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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "jaasAuthModuleConf")
+@XmlType
+public class JaasAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -7775771400318503131L;
+
+ /**
+ * The realm that contains the login module information.
+ */
+ private String realm;
+
+ /**
+ * System property value to overwrite the realm in krb5 config.
+ */
+ private String kerberosRealmSystemProperty;
+
+ /**
+ * System property value to overwrite the kdc in krb5 config.
+ */
+ private String kerberosKdcSystemProperty;
+
+ private String loginConfigType;
+
+ private String loginConfigurationFile;
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public void setRealm(final String realm) {
+ this.realm = realm;
+ }
+
+ public String getKerberosRealmSystemProperty() {
+ return kerberosRealmSystemProperty;
+ }
+
+ public void setKerberosRealmSystemProperty(final String kerberosRealmSystemProperty) {
+ this.kerberosRealmSystemProperty = kerberosRealmSystemProperty;
+ }
+
+ public String getKerberosKdcSystemProperty() {
+ return kerberosKdcSystemProperty;
+ }
+
+ public void setKerberosKdcSystemProperty(final String kerberosKdcSystemProperty) {
+ this.kerberosKdcSystemProperty = kerberosKdcSystemProperty;
+ }
+
+ public String getLoginConfigType() {
+ return loginConfigType;
+ }
+
+ public void setLoginConfigType(final String loginConfigType) {
+ this.loginConfigType = loginConfigType;
+ }
+
+ public String getLoginConfigurationFile() {
+ return loginConfigurationFile;
+ }
+
+ public void setLoginConfigurationFile(final String loginConfigurationFile) {
+ this.loginConfigurationFile = loginConfigurationFile;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/LDAPAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/LDAPAuthModuleConf.java
new file mode 100644
index 0000000..afd7f90
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/LDAPAuthModuleConf.java
@@ -0,0 +1,126 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "ldapAuthModuleConf")
+@XmlType
+public class LDAPAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -471527731042579422L;
+
+ protected String searchFilter;
+
+ /**
+ * The attribute value that should be used
+ * for the authenticated username, upon a successful authentication
+ * attempt.
+ */
+ private String userIdAttribute;
+
+ /**
+ * Whether subtree searching is allowed.
+ */
+ private boolean subtreeSearch = true;
+
+ private String ldapUrl;
+
+ /**
+ * The bind DN to use when connecting to LDAP.
+ * LDAP connection configuration injected into the LDAP connection pool
+ * can be initialized with the following parameters:
+ * <ul>
+ * <li>{@code bindDn/bindCredential} provided - Use the provided credentials
+ * to bind when initializing connections.</li>
+ * <li>{@code bindDn/bindCredential} set to {@code *} - Use a fast-bind
+ * strategy to initialize the pool.</li>
+ * <li>{@code bindDn/bindCredential} set to blank - Skip connection
+ * initializing; perform operations anonymously.</li>
+ * <li>SASL mechanism provided - Use the given SASL mechanism
+ * to bind when initializing connections. </li>
+ * </ul>
+ */
+ private String bindDn;
+
+ /**
+ * The bind credential to use when connecting to LDAP.
+ */
+ private String bindCredential;
+
+ private String baseDn;
+
+ public String getSearchFilter() {
+ return searchFilter;
+ }
+
+ public void setSearchFilter(final String searchFilter) {
+ this.searchFilter = searchFilter;
+ }
+
+ public String getUserIdAttribute() {
+ return userIdAttribute;
+ }
+
+ public void setUserIdAttribute(final String userIdAttribute) {
+ this.userIdAttribute = userIdAttribute;
+ }
+
+ public boolean isSubtreeSearch() {
+ return subtreeSearch;
+ }
+
+ public void setSubtreeSearch(final boolean subtreeSearch) {
+ this.subtreeSearch = subtreeSearch;
+ }
+
+ public String getLdapUrl() {
+ return ldapUrl;
+ }
+
+ public void setLdapUrl(final String ldapUrl) {
+ this.ldapUrl = ldapUrl;
+ }
+
+ public String getBindDn() {
+ return bindDn;
+ }
+
+ public void setBindDn(final String bindDn) {
+ this.bindDn = bindDn;
+ }
+
+ public String getBindCredential() {
+ return bindCredential;
+ }
+
+ public void setBindCredential(final String bindCredential) {
+ this.bindCredential = bindCredential;
+ }
+
+ public String getBaseDn() {
+ return baseDn;
+ }
+
+ public void setBaseDn(final String baseDn) {
+ this.baseDn = baseDn;
+ }
+
+}
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
new file mode 100644
index 0000000..d59b34d
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OIDCAuthModuleConf.java
@@ -0,0 +1,182 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonProperty;
+import javax.xml.bind.annotation.XmlType;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.apache.syncope.common.lib.jaxb.XmlGenericMapAdapter;
+
+@XmlRootElement(name = "oidcAuthModuleConf")
+@XmlType
+public class OIDCAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -471527731042579422L;
+
+ /**
+ * The client id.
+ */
+ private String id;
+
+ /**
+ * The client secret.
+ */
+ private String secret;
+
+ /**
+ * The attribute value that should be used
+ * for the authenticated username, upon a successful authentication
+ * attempt.
+ */
+ private String userIdAttribute;
+
+ private String discoveryUri;
+
+ /**
+ * Whether an initial nonce should be to used
+ * initially for replay attack mitigation.
+ */
+ private boolean useNonce;
+
+ /**
+ * Requested scope(s).
+ */
+ private String scope;
+
+ /**
+ * The JWS algorithm to use forcefully when validating ID tokens.
+ * If none is defined, the first algorithm from metadata will be used.
+ */
+ private String preferredJwsAlgorithm;
+
+ /**
+ * Clock skew in order to account for drift, when validating id tokens.
+ */
+ private int maxClockSkew;
+
+ /**
+ * Custom parameters to send along in authZ requests, etc.
+ */
+ @XmlJavaTypeAdapter(XmlGenericMapAdapter.class)
+ private 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"
+ */
+ private String responseMode;
+
+ /**
+ * The response type tells the authorization server which grant to execute.
+ * Possibles values includes "code", "token" or "id_token".
+ */
+ private String responseType;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public void setSecret(final String secret) {
+ this.secret = secret;
+ }
+
+ public String getUserIdAttribute() {
+ return userIdAttribute;
+ }
+
+ public void setUserIdAttribute(final String userIdAttribute) {
+ this.userIdAttribute = userIdAttribute;
+ }
+
+ public String getDiscoveryUri() {
+ return discoveryUri;
+ }
+
+ public void setDiscoveryUri(final String discoveryUri) {
+ this.discoveryUri = discoveryUri;
+ }
+
+ public boolean isUseNonce() {
+ return useNonce;
+ }
+
+ public void setUseNonce(final boolean useNonce) {
+ this.useNonce = useNonce;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(final String scope) {
+ this.scope = scope;
+ }
+
+ public String getPreferredJwsAlgorithm() {
+ return preferredJwsAlgorithm;
+ }
+
+ public void setPreferredJwsAlgorithm(final String preferredJwsAlgorithm) {
+ this.preferredJwsAlgorithm = preferredJwsAlgorithm;
+ }
+
+ public int getMaxClockSkew() {
+ return maxClockSkew;
+ }
+
+ public void setMaxClockSkew(final int maxClockSkew) {
+ this.maxClockSkew = maxClockSkew;
+ }
+
+ @XmlElementWrapper(name = "customParams")
+ @XmlElement(name = "customParam")
+ @JsonProperty("customParams")
+ public Map<String, String> getCustomParams() {
+ return customParams;
+ }
+
+ public String getResponseMode() {
+ return responseMode;
+ }
+
+ public void setResponseMode(final String responseMode) {
+ this.responseMode = responseMode;
+ }
+
+ public String getResponseType() {
+ return responseType;
+ }
+
+ public void setResponseType(final String responseType) {
+ this.responseType = responseType;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/RadiusAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/RadiusAuthModuleConf.java
new file mode 100644
index 0000000..7cd543c
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/RadiusAuthModuleConf.java
@@ -0,0 +1,172 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "radiusAuthModuleConf")
+@XmlType
+public class RadiusAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -2235771400318503131L;
+
+ /**
+ * Radius protocol to use when communicating with the server.
+ */
+ private String protocol = "EAP_MSCHAPv2";
+
+ private String inetAddress;
+
+ private String sharedSecret;
+
+ private int socketTimeout;
+
+ private int authenticationPort = 1812;
+
+ private int accountingPort = 1813;
+
+ private int retries = 3;
+
+ private String nasIdentifier;
+
+ private long nasPort = -1;
+
+ private long nasPortId = -1;
+
+ private long nasRealPort = -1;
+
+ private int nasPortType = -1;
+
+ private String nasIpAddress;
+
+ private String nasIpv6Address;
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public void setProtocol(final String protocol) {
+ this.protocol = protocol;
+ }
+
+ public int getRetries() {
+ return retries;
+ }
+
+ public void setRetries(final int retries) {
+ this.retries = retries;
+ }
+
+ public String getNasIdentifier() {
+ return nasIdentifier;
+ }
+
+ public void setNasIdentifier(final String nasIdentifier) {
+ this.nasIdentifier = nasIdentifier;
+ }
+
+ public long getNasPort() {
+ return nasPort;
+ }
+
+ public void setNasPort(final long nasPort) {
+ this.nasPort = nasPort;
+ }
+
+ public long getNasPortId() {
+ return nasPortId;
+ }
+
+ public void setNasPortId(final long nasPortId) {
+ this.nasPortId = nasPortId;
+ }
+
+ public long getNasRealPort() {
+ return nasRealPort;
+ }
+
+ public void setNasRealPort(final long nasRealPort) {
+ this.nasRealPort = nasRealPort;
+ }
+
+ public int getNasPortType() {
+ return nasPortType;
+ }
+
+ public void setNasPortType(final int nasPortType) {
+ this.nasPortType = nasPortType;
+ }
+
+ public String getNasIpAddress() {
+ return nasIpAddress;
+ }
+
+ public void setNasIpAddress(final String nasIpAddress) {
+ this.nasIpAddress = nasIpAddress;
+ }
+
+ public String getNasIpv6Address() {
+ return nasIpv6Address;
+ }
+
+ public void setNasIpv6Address(final String nasIpv6Address) {
+ this.nasIpv6Address = nasIpv6Address;
+ }
+
+ public String getInetAddress() {
+ return inetAddress;
+ }
+
+ public void setInetAddress(final String inetAddress) {
+ this.inetAddress = inetAddress;
+ }
+
+ public String getSharedSecret() {
+ return sharedSecret;
+ }
+
+ public void setSharedSecret(final String sharedSecret) {
+ this.sharedSecret = sharedSecret;
+ }
+
+ public int getSocketTimeout() {
+ return socketTimeout;
+ }
+
+ public void setSocketTimeout(final int socketTimeout) {
+ this.socketTimeout = socketTimeout;
+ }
+
+ public int getAuthenticationPort() {
+ return authenticationPort;
+ }
+
+ public void setAuthenticationPort(final int authenticationPort) {
+ this.authenticationPort = authenticationPort;
+ }
+
+ public int getAccountingPort() {
+ return accountingPort;
+ }
+
+ public void setAccountingPort(final int accountingPort) {
+ this.accountingPort = accountingPort;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java
new file mode 100644
index 0000000..03b6aed
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java
@@ -0,0 +1,430 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "saml2IdPAuthModuleConf")
+@XmlType
+public class SAML2IdPAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -471527731042579422L;
+
+ /**
+ * The attribute value that should be used
+ * for the authenticated username, upon a successful authentication
+ * attempt.
+ */
+ private String userIdAttribute;
+
+ /**
+ * The destination binding to use
+ * when creating authentication requests.
+ */
+ private String destinationBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";
+
+ /**
+ * The password to use when generating the SP keystore.
+ */
+ private String keystorePassword;
+
+ /**
+ * The password to use when generating the private key for the SP keystore.
+ */
+ private String privateKeyPassword;
+
+ /**
+ * Location of the keystore to use and generate the SP keystore.
+ */
+ private String keystorePath;
+
+ /**
+ * The metadata location of the identity provider that is to handle authentications.
+ */
+ private String identityProviderMetadataPath;
+
+ /**
+ * Flag to indicate whether the allow-create flags
+ * for nameid policies should be set to true, false or ignored/defined.
+ * Accepted values are true, false or undefined.
+ */
+ private String nameIdPolicyAllowCreate = "undefined";
+
+ /**
+ * Once you have an authenticated session on the identity provider, usually it won't prompt you again to enter your
+ * credentials and it will automatically generate a new assertion for you. By default, the SAML client
+ * will accept assertions based on a previous authentication for one hour.
+ * You can adjust this behavior by modifying this setting. The unit of time here is seconds.
+ */
+ private int maximumAuthenticationLifetime = 3600;
+
+ /**
+ * Maximum skew in seconds between SP and IDP clocks.
+ * This skew is added onto the {@code NotOnOrAfter} field in seconds
+ * for the SAML response validation.
+ */
+ private int acceptedSkew = 300;
+
+ /**
+ * The entity id of the SP that is used in the SP metadata generation process.
+ */
+ private String serviceProviderEntityId;
+
+ /**
+ * Location of the SP metadata to use and generate.
+ */
+ private String serviceProviderMetadataPath;
+
+ /**
+ * Whether authentication requests should be tagged as forced auth.
+ */
+ private boolean forceAuth;
+
+ /**
+ * Whether authentication requests should be tagged as passive.
+ */
+ private boolean passive;
+
+ /**
+ * Requested authentication context class in authn requests.
+ */
+ private final List<String> authnContextClassRefs = new ArrayList<>(0);
+
+ /**
+ * Specifies the comparison rule that should be used to evaluate the specified authentication methods.
+ * For example, if exact is specified, the authentication method used must match one of the authentication
+ * methods specified by the AuthnContextClassRef elements.
+ * AuthContextClassRef element require comparison rule to be used to evaluate the specified
+ * authentication methods. If not explicitly specified "exact" rule will be used by default.
+ * Other acceptable values are minimum, maximum, better.
+ */
+ private String authnContextComparisonType = "exact";
+
+ /**
+ * The key alias used in the keystore.
+ */
+ private String keystoreAlias;
+
+ /**
+ * NameID policy to request in the authentication requests.
+ */
+ private String nameIdPolicyFormat;
+
+ /**
+ * Whether metadata should be marked to request sign assertions.
+ */
+ private boolean wantsAssertionsSigned;
+
+ /**
+ * AttributeConsumingServiceIndex attribute of AuthnRequest element.
+ * The given index points out a specific AttributeConsumingService structure, declared into the
+ * Service Provider (SP)'s metadata, to be used to specify all the attributes that the Service Provider
+ * is asking to be released within the authentication assertion returned by the Identity Provider (IdP).
+ * This attribute won't be sent with the request unless a positive value (including 0) is defined.
+ */
+ private int attributeConsumingServiceIndex;
+
+ /**
+ * Allows the SAML client to select a specific ACS url from the metadata, if defined.
+ * A negative value de-activates the selection process and is the default.
+ */
+ private int assertionConsumerServiceIndex = -1;
+
+ /**
+ * Whether name qualifiers should be produced
+ * in the final saml response.
+ */
+ private boolean useNameQualifier = true;
+
+ /**
+ * Whether or not SAML SP metadata should be signed when generated.
+ */
+ private boolean signServiceProviderMetadata;
+
+ /**
+ * Whether or not the authnRequest should be signed.
+ */
+ private boolean signAuthnRequest;
+
+ /**
+ * Whether or not the Logout Request sent from the SP should be signed.
+ */
+ private boolean signServiceProviderLogoutRequest;
+
+ /**
+ * Collection of signing signature blacklisted algorithms, if any, to override the global defaults.
+ */
+ private final List<String> blackListedSignatureSigningAlgorithms = new ArrayList<>(0);
+
+ /**
+ * Collection of signing signature algorithms, if any, to override the global defaults.
+ */
+ private final List<String> signatureAlgorithms = new ArrayList<>(0);
+
+ /**
+ * Collection of signing signature reference digest methods, if any, to override the global defaults.
+ */
+ private final List<String> signatureReferenceDigestMethods = new ArrayList<>(0);
+
+ /**
+ * The signing signature canonicalization algorithm, if any, to override the global defaults.
+ */
+ private String signatureCanonicalizationAlgorithm;
+
+ /**
+ * Provider name set for the saml authentication request.
+ * Sets the human-readable name of the requester for use by
+ * the presenter's user agent or the identity provider.
+ */
+ private String providerName;
+
+ public String getUserIdAttribute() {
+ return userIdAttribute;
+ }
+
+ public void setUserIdAttribute(final String userIdAttribute) {
+ this.userIdAttribute = userIdAttribute;
+ }
+
+ public String getDestinationBinding() {
+ return destinationBinding;
+ }
+
+ public void setDestinationBinding(final String destinationBinding) {
+ this.destinationBinding = destinationBinding;
+ }
+
+ public String getKeystorePassword() {
+ return keystorePassword;
+ }
+
+ public void setKeystorePassword(final String keystorePassword) {
+ this.keystorePassword = keystorePassword;
+ }
+
+ public String getPrivateKeyPassword() {
+ return privateKeyPassword;
+ }
+
+ public void setPrivateKeyPassword(final String privateKeyPassword) {
+ this.privateKeyPassword = privateKeyPassword;
+ }
+
+ public String getKeystorePath() {
+ return keystorePath;
+ }
+
+ public void setKeystorePath(final String keystorePath) {
+ this.keystorePath = keystorePath;
+ }
+
+ public String getIdentityProviderMetadataPath() {
+ return identityProviderMetadataPath;
+ }
+
+ public void setIdentityProviderMetadataPath(final String identityProviderMetadataPath) {
+ this.identityProviderMetadataPath = identityProviderMetadataPath;
+ }
+
+ public int getMaximumAuthenticationLifetime() {
+ return maximumAuthenticationLifetime;
+ }
+
+ public void setMaximumAuthenticationLifetime(final int maximumAuthenticationLifetime) {
+ this.maximumAuthenticationLifetime = maximumAuthenticationLifetime;
+ }
+
+ public int getAcceptedSkew() {
+ return acceptedSkew;
+ }
+
+ public void setAcceptedSkew(final int acceptedSkew) {
+ this.acceptedSkew = acceptedSkew;
+ }
+
+ public String getServiceProviderEntityId() {
+ return serviceProviderEntityId;
+ }
+
+ public void setServiceProviderEntityId(final String serviceProviderEntityId) {
+ this.serviceProviderEntityId = serviceProviderEntityId;
+ }
+
+ public String getServiceProviderMetadataPath() {
+ return serviceProviderMetadataPath;
+ }
+
+ public void setServiceProviderMetadataPath(final String serviceProviderMetadataPath) {
+ this.serviceProviderMetadataPath = serviceProviderMetadataPath;
+ }
+
+ public boolean isForceAuth() {
+ return forceAuth;
+ }
+
+ public void setForceAuth(final boolean forceAuth) {
+ this.forceAuth = forceAuth;
+ }
+
+ public boolean isPassive() {
+ return passive;
+ }
+
+ public void setPassive(final boolean passive) {
+ this.passive = passive;
+ }
+
+ public String getNameIdPolicyAllowCreate() {
+ return nameIdPolicyAllowCreate;
+ }
+
+ public void setNameIdPolicyAllowCreate(final String nameIdPolicyAllowCreate) {
+ this.nameIdPolicyAllowCreate = nameIdPolicyAllowCreate;
+ }
+
+ @XmlElementWrapper(name = "authnContextClassRefs")
+ @XmlElement(name = "authnContextClassRef")
+ @JsonProperty("authnContextClassRefs")
+ public List<String> getAuthnContextClassRefs() {
+ return authnContextClassRefs;
+ }
+
+ public String getAuthnContextComparisonType() {
+ return authnContextComparisonType;
+ }
+
+ public void setAuthnContextComparisonType(final String authnContextComparisonType) {
+ this.authnContextComparisonType = authnContextComparisonType;
+ }
+
+ public String getKeystoreAlias() {
+ return keystoreAlias;
+ }
+
+ public void setKeystoreAlias(final String keystoreAlias) {
+ this.keystoreAlias = keystoreAlias;
+ }
+
+ public String getNameIdPolicyFormat() {
+ return nameIdPolicyFormat;
+ }
+
+ public void setNameIdPolicyFormat(final String nameIdPolicyFormat) {
+ this.nameIdPolicyFormat = nameIdPolicyFormat;
+ }
+
+ public boolean isWantsAssertionsSigned() {
+ return wantsAssertionsSigned;
+ }
+
+ public void setWantsAssertionsSigned(final boolean wantsAssertionsSigned) {
+ this.wantsAssertionsSigned = wantsAssertionsSigned;
+ }
+
+ public int getAttributeConsumingServiceIndex() {
+ return attributeConsumingServiceIndex;
+ }
+
+ public void setAttributeConsumingServiceIndex(final int attributeConsumingServiceIndex) {
+ this.attributeConsumingServiceIndex = attributeConsumingServiceIndex;
+ }
+
+ public int getAssertionConsumerServiceIndex() {
+ return assertionConsumerServiceIndex;
+ }
+
+ public void setAssertionConsumerServiceIndex(final int assertionConsumerServiceIndex) {
+ this.assertionConsumerServiceIndex = assertionConsumerServiceIndex;
+ }
+
+ public boolean isUseNameQualifier() {
+ return useNameQualifier;
+ }
+
+ public void setUseNameQualifier(final boolean useNameQualifier) {
+ this.useNameQualifier = useNameQualifier;
+ }
+
+ public boolean isSignServiceProviderMetadata() {
+ return signServiceProviderMetadata;
+ }
+
+ public void setSignServiceProviderMetadata(final boolean signServiceProviderMetadata) {
+ this.signServiceProviderMetadata = signServiceProviderMetadata;
+ }
+
+ public boolean isSignAuthnRequest() {
+ return signAuthnRequest;
+ }
+
+ public void setSignAuthnRequest(final boolean signAuthnRequest) {
+ this.signAuthnRequest = signAuthnRequest;
+ }
+
+ public boolean isSignServiceProviderLogoutRequest() {
+ return signServiceProviderLogoutRequest;
+ }
+
+ public void setSignServiceProviderLogoutRequest(final boolean signServiceProviderLogoutRequest) {
+ this.signServiceProviderLogoutRequest = signServiceProviderLogoutRequest;
+ }
+
+ @XmlElementWrapper(name = "blackListedSignatureSigningAlgorithms")
+ @XmlElement(name = "blackListedSignatureSigningAlgorithm")
+ @JsonProperty("blackListedSignatureSigningAlgorithms")
+ public List<String> getBlackListedSignatureSigningAlgorithms() {
+ return blackListedSignatureSigningAlgorithms;
+ }
+
+ @XmlElementWrapper(name = "signatureAlgorithms")
+ @XmlElement(name = "signatureAlgorithm")
+ @JsonProperty("signatureAlgorithms")
+ public List<String> getSignatureAlgorithms() {
+ return signatureAlgorithms;
+ }
+
+ @XmlElementWrapper(name = "signatureReferenceDigestMethods")
+ @XmlElement(name = "signatureReferenceDigestMethod")
+ @JsonProperty("signatureReferenceDigestMethods")
+ public List<String> getSignatureReferenceDigestMethods() {
+ return signatureReferenceDigestMethods;
+ }
+
+ public String getSignatureCanonicalizationAlgorithm() {
+ return signatureCanonicalizationAlgorithm;
+ }
+
+ public void setSignatureCanonicalizationAlgorithm(final String signatureCanonicalizationAlgorithm) {
+ this.signatureCanonicalizationAlgorithm = signatureCanonicalizationAlgorithm;
+ }
+
+ public String getProviderName() {
+ return providerName;
+ }
+
+ public void setProviderName(final String providerName) {
+ this.providerName = providerName;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/StaticAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/StaticAuthModuleConf.java
new file mode 100644
index 0000000..60d2751
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/StaticAuthModuleConf.java
@@ -0,0 +1,47 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonProperty;
+import javax.xml.bind.annotation.XmlType;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.apache.syncope.common.lib.jaxb.XmlGenericMapAdapter;
+
+@XmlRootElement(name = "staticAuthModuleConf")
+@XmlType
+public class StaticAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -7775771400318503131L;
+
+ @XmlJavaTypeAdapter(XmlGenericMapAdapter.class)
+ private final Map<String, String> users = new HashMap<>();
+
+ @XmlElementWrapper(name = "users")
+ @XmlElement(name = "user")
+ @JsonProperty("users")
+ public Map<String, String> getUsers() {
+ return users;
+ }
+
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java
new file mode 100644
index 0000000..2ac2192
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java
@@ -0,0 +1,56 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "syncopeAuthModuleConf")
+@XmlType
+public class SyncopeAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -3334329948161152222L;
+
+ /**
+ * Syncope domain used for authentication, etc.
+ */
+ private String domain = "Master";
+
+ /**
+ * Syncope instance URL primary used for REST.
+ */
+ private String url;
+
+ public String getDomain() {
+ return domain;
+ }
+
+ public void setDomain(final String domain) {
+ this.domain = domain;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(final String url) {
+ this.url = url;
+ }
+
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/U2FAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/U2FAuthModuleConf.java
new file mode 100644
index 0000000..cc127da
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/U2FAuthModuleConf.java
@@ -0,0 +1,69 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "u2fAuthModuleConf")
+@XmlType
+public class U2FAuthModuleConf extends AbstractAuthModuleConf {
+
+ private static final long serialVersionUID = -1235771400318503131L;
+
+ private long expireRegistrations = 30;
+
+ private String expireRegistrationsTimeUnit = "SECONDS";
+
+ private long expireDevices = 30;
+
+ private String expireDevicesTimeUnit = "DAYS";
+
+ public long getExpireRegistrations() {
+ return expireRegistrations;
+ }
+
+ public void setExpireRegistrations(final long expireRegistrations) {
+ this.expireRegistrations = expireRegistrations;
+ }
+
+ public String getExpireRegistrationsTimeUnit() {
+ return expireRegistrationsTimeUnit;
+ }
+
+ public void setExpireRegistrationsTimeUnit(final String expireRegistrationsTimeUnit) {
+ this.expireRegistrationsTimeUnit = expireRegistrationsTimeUnit;
+ }
+
+ public long getExpireDevices() {
+ return expireDevices;
+ }
+
+ public void setExpireDevices(final long expireDevices) {
+ this.expireDevices = expireDevices;
+ }
+
+ public String getExpireDevicesTimeUnit() {
+ return expireDevicesTimeUnit;
+ }
+
+ public void setExpireDevicesTimeUnit(final String expireDevicesTimeUnit) {
+ this.expireDevicesTimeUnit = expireDevicesTimeUnit;
+ }
+}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/package-info.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/package-info.java
new file mode 100644
index 0000000..e3765a0
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+@XmlSchema(namespace = SyncopeConstants.NS)
+@XmlJavaTypeAdapters({ @XmlJavaTypeAdapter(type = Date.class, value = DateAdapter.class), })
+package org.apache.syncope.common.lib.auth;
+
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.jaxb.DateAdapter;
+
+import javax.xml.bind.annotation.XmlSchema;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
+
+import java.util.Date;
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java
new file mode 100644
index 0000000..492227f
--- /dev/null
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java
@@ -0,0 +1,132 @@
+/*
+ * 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.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.common.lib.BaseBean;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.auth.AuthModuleConf;
+
+@XmlRootElement(name = "authModule")
+@XmlType
+public class AuthModuleTO extends BaseBean implements EntityTO {
+
+ private static final long serialVersionUID = -7490425997956703057L;
+
+ private String key;
+
+ private String name;
+
+ private String description;
+
+ private final List<ItemTO> profileItems = new ArrayList<>();
+
+ private AuthModuleConf conf;
+
+ @Override
+ public String getKey() {
+ return key;
+ }
+
+ @Override
+ public void setKey(final String key) {
+ this.key = key;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public AuthModuleConf getConf() {
+ return conf;
+ }
+
+ public void setConf(final AuthModuleConf conf) {
+ this.conf = conf;
+ }
+
+ @XmlElementWrapper(name = "profileItems")
+ @XmlElement(name = "profileItem")
+ @JsonProperty("profileItems")
+ public List<ItemTO> getProfileItems() {
+ return profileItems;
+ }
+
+ public boolean add(final ItemTO item) {
+ return Optional.ofNullable(item)
+ .filter(itemTO -> this.profileItems.contains(itemTO) || this.profileItems.add(itemTO)).isPresent();
+ }
+
+ public boolean remove(final ItemTO item) {
+ return this.profileItems.remove(item);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AuthModuleTO other = (AuthModuleTO) obj;
+ return new EqualsBuilder().
+ append(key, other.key).
+ append(name, other.name).
+ append(description, other.description).
+ append(profileItems, other.profileItems).
+ append(conf, other.conf).
+ build();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().
+ append(key).
+ append(name).
+ append(description).
+ append(profileItems).
+ append(conf).
+ build();
+ }
+
+}
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthModuleService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthModuleService.java
new file mode 100644
index 0000000..83e6015
--- /dev/null
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthModuleService.java
@@ -0,0 +1,126 @@
+/*
+ * 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.rest.api.service;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.security.SecurityRequirements;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+
+/**
+ * REST operations for authentication modules.
+ */
+@Tag(name = "AuthModules")
+@SecurityRequirements({
+ @SecurityRequirement(name = "BasicAuthentication"),
+ @SecurityRequirement(name = "Bearer") })
+@Path("authModules")
+public interface AuthModuleService extends JAXRSService {
+
+ /**
+ * Returns the authentication module matching the given key.
+ *
+ * @param key key of requested authentication module
+ * @return authentication module with matching id
+ */
+ @GET
+ @Path("{key}")
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ AuthModuleTO read(
+ @NotNull @PathParam("key") String key);
+
+ /**
+ * Returns a list of authentication modules of the matching type.
+ *
+ * @return list of authentication modules with matching type
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ List<AuthModuleTO> list();
+
+ /**
+ * Create a new authentication module.
+ *
+ * @param authModuleTO AuthModule to be created (needs to match type)
+ * @return Response object featuring Location header of created authentication module
+ */
+ @ApiResponses(
+ @ApiResponse(responseCode = "201",
+ description = "AuthModule successfully created", headers = {
+ @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+ @Schema(type = "string"),
+ description = "UUID generated for the entity created"),
+ @Header(name = HttpHeaders.LOCATION, schema =
+ @Schema(type = "string"),
+ description = "URL of the entity created") }))
+ @POST
+ @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ Response create(
+ @NotNull AuthModuleTO authModuleTO);
+
+ /**
+ * Updates authentication module matching the given key.
+ *
+ * @param authModuleTO AuthModule to replace existing authentication module
+ */
+ @Parameter(name = "key", description = "AuthModule's key", in = ParameterIn.PATH, schema =
+ @Schema(type = "string"))
+ @ApiResponses(
+ @ApiResponse(responseCode = "204", description = "Operation was successful"))
+ @PUT
+ @Path("{key}")
+ @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ void update(
+ @NotNull AuthModuleTO authModuleTO);
+
+ /**
+ * Delete authentication module matching the given key.
+ *
+ * @param key key of authentication module to be deleted
+ */
+ @ApiResponses(
+ @ApiResponse(responseCode = "204", description = "Operation was successful"))
+ @DELETE
+ @Path("{key}")
+ @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ void delete(
+ @NotNull @PathParam("key") String key);
+}
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java
new file mode 100644
index 0000000..538dc82
--- /dev/null
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java
@@ -0,0 +1,131 @@
+/*
+ * 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.core.logic;
+
+import static org.apache.syncope.core.logic.AbstractLogic.LOG;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.common.lib.types.AMEntitlement;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.auth.AuthModuleDAO;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+import org.apache.syncope.core.provisioning.api.data.AuthModuleDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class AuthModuleLogic extends AbstractTransactionalLogic<AuthModuleTO> {
+
+ @Autowired
+ private AuthModuleDataBinder binder;
+
+ @Autowired
+ private AuthModuleDAO authModuleDAO;
+
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_CREATE + "')")
+ public AuthModuleTO create(final AuthModuleTO authModuleTO) {
+ return binder.getAuthModuleTO(authModuleDAO.save(binder.create(authModuleTO)));
+ }
+
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_UPDATE + "')")
+ public AuthModuleTO update(final AuthModuleTO authModuleTO) {
+ AuthModule authModule = authModuleDAO.find(authModuleTO.getKey());
+ if (authModule == null) {
+ throw new NotFoundException("AuthModule " + authModuleTO.getKey() + " not found");
+ }
+
+ return binder.getAuthModuleTO(authModuleDAO.save(binder.update(authModule, authModuleTO)));
+ }
+
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_LIST + "')")
+ @Transactional(readOnly = true)
+ public List<AuthModuleTO> list() {
+ return authModuleDAO.findAll().stream().
+ filter(Objects::nonNull).
+ map(authModule -> {
+ AuthModuleTO result = null;
+ try {
+ result = binder.getAuthModuleTO(authModule);
+ } catch (NotFoundException e) {
+ LOG.error("Authentication module '{}' not found", authModule.getName());
+ }
+
+ return result;
+ }).collect(Collectors.toList());
+ }
+
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_READ + "')")
+ @Transactional(readOnly = true)
+ public AuthModuleTO read(final String key) {
+ AuthModule authModule = authModuleDAO.find(key);
+ if (authModule == null) {
+ throw new NotFoundException("AuthModule " + key + " not found");
+ }
+
+ return binder.getAuthModuleTO(authModule);
+ }
+
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_DELETE + "')")
+ public AuthModuleTO delete(final String key) {
+ AuthModule authModule = authModuleDAO.find(key);
+ if (authModule == null) {
+ throw new NotFoundException("AuthModule " + key + " not found");
+ }
+
+ AuthModuleTO deleted = binder.getAuthModuleTO(authModule);
+ authModuleDAO.delete(authModule);
+
+ return deleted;
+ }
+
+ @Override
+ protected AuthModuleTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ String key = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; key == null && i < args.length; i++) {
+ if (args[i] instanceof String) {
+ key = (String) args[i];
+ } else if (args[i] instanceof AuthModuleTO) {
+ key = ((AuthModuleTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if (key != null) {
+ try {
+ return binder.getAuthModuleTO(authModuleDAO.find(key));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthModuleServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthModuleServiceImpl.java
new file mode 100644
index 0000000..68bdd90
--- /dev/null
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthModuleServiceImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.core.rest.cxf.service;
+
+import java.net.URI;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AuthModuleService;
+import org.apache.syncope.core.logic.AuthModuleLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AuthModuleServiceImpl extends AbstractServiceImpl implements AuthModuleService {
+
+ @Autowired
+ private AuthModuleLogic logic;
+
+ @Override
+ public Response create(final AuthModuleTO authModuleTO) {
+ AuthModuleTO authModule = logic.create(authModuleTO);
+ URI location = uriInfo.getAbsolutePathBuilder().path(authModule.getKey()).build();
+ return Response.created(location).
+ header(RESTHeaders.RESOURCE_KEY, authModule.getKey()).
+ build();
+ }
+
+ @Override
+ public void delete(final String key) {
+ logic.delete(key);
+ }
+
+ @Override
+ public List<AuthModuleTO> list() {
+ return logic.list();
+ }
+
+ @Override
+ public AuthModuleTO read(final String key) {
+ return logic.read(key);
+ }
+
+ @Override
+ public void update(final AuthModuleTO authModuleTO) {
+ logic.update(authModuleTO);
+ }
+}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthModuleDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthModuleDAO.java
new file mode 100644
index 0000000..fc5e18c
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/auth/AuthModuleDAO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.core.persistence.api.dao.auth;
+
+import org.apache.syncope.core.persistence.api.dao.DAO;
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+
+public interface AuthModuleDAO extends DAO<AuthModule> {
+
+ AuthModule find(String key);
+
+ List<AuthModule> findAll();
+
+ AuthModule save(AuthModule authModule);
+
+ void delete(String key);
+
+ void delete(AuthModule authModule);
+
+}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java
new file mode 100644
index 0000000..5d2393e
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java
@@ -0,0 +1,48 @@
+/*
+ * 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.core.persistence.api.entity.auth;
+
+import java.util.List;
+import org.apache.syncope.common.lib.auth.AuthModuleConf;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
+
+public interface AuthModule extends Entity {
+
+ String getName();
+
+ void setName(String name);
+
+ String getDescription();
+
+ void setDescription(String description);
+
+ /**
+ * Specify the mapping items for the attributes fetched from the source.
+ *
+ * @return list of mapping items
+ */
+ List<? extends Item> getProfileItems();
+
+ boolean add(Item profileItem);
+
+ AuthModuleConf getConf();
+
+ void setConf(AuthModuleConf description);
+}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModuleItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModuleItem.java
new file mode 100644
index 0000000..9f249e4
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModuleItem.java
@@ -0,0 +1,25 @@
+/*
+ * 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.core.persistence.api.entity.auth;
+
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
+
+public interface AuthModuleItem extends Item {
+
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthModuleDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthModuleDAO.java
new file mode 100644
index 0000000..dd765ad
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/auth/JPAAuthModuleDAO.java
@@ -0,0 +1,68 @@
+/*
+ * 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.core.persistence.jpa.dao.auth;
+
+import org.apache.syncope.core.persistence.jpa.dao.AbstractDAO;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.TypedQuery;
+import java.util.List;
+import org.apache.syncope.core.persistence.api.dao.auth.AuthModuleDAO;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+import org.apache.syncope.core.persistence.jpa.entity.auth.JPAAuthModule;
+
+@Repository
+public class JPAAuthModuleDAO extends AbstractDAO<AuthModule> implements AuthModuleDAO {
+
+ @Override
+ public AuthModule find(final String key) {
+ return entityManager().find(JPAAuthModule.class, key);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<AuthModule> findAll() {
+ TypedQuery<AuthModule> query = entityManager().createQuery("SELECT e FROM " + JPAAuthModule.class.
+ getSimpleName() + " e", AuthModule.class);
+
+ return query.getResultList();
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public AuthModule save(final AuthModule authModule) {
+ return entityManager().merge(authModule);
+ }
+
+ @Override
+ public void delete(final String key) {
+ AuthModule authModule = find(key);
+ if (authModule == null) {
+ return;
+ }
+
+ delete(authModule);
+ }
+
+ @Override
+ public void delete(final AuthModule authModule) {
+ entityManager().remove(authModule);
+ }
+
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java
new file mode 100644
index 0000000..e2b6586
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java
@@ -0,0 +1,104 @@
+/*
+ * 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.core.persistence.jpa.entity.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Lob;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.auth.AuthModuleConf;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+@Entity
+@Table(name = JPAAuthModule.TABLE)
+public class JPAAuthModule extends AbstractGeneratedKeyEntity implements AuthModule {
+
+ public static final String TABLE = "AuthModule";
+
+ private static final long serialVersionUID = 5681033638234853077L;
+
+ @Column(unique = true, nullable = false)
+ private String name;
+
+ @Column(nullable = false)
+ private String description;
+
+ @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "mapping")
+ private final List<JPAAuthModuleItem> profileItems = new ArrayList<>();
+
+ @Lob
+ private String jsonConf;
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public List<? extends Item> getProfileItems() {
+ return profileItems;
+ }
+
+ @Override
+ public boolean add(final Item profileItem) {
+ checkType(profileItem, JPAAuthModuleItem.class);
+ return profileItems.contains((JPAAuthModuleItem) profileItem)
+ || profileItems.add((JPAAuthModuleItem) profileItem);
+ }
+
+ @Override
+ public AuthModuleConf getConf() {
+ AuthModuleConf conf = null;
+ if (!StringUtils.isBlank(jsonConf)) {
+ conf = POJOHelper.deserialize(jsonConf, AuthModuleConf.class);
+ }
+
+ return conf;
+ }
+
+ @Override
+ public void setConf(final AuthModuleConf conf) {
+ jsonConf = POJOHelper.serialize(conf);
+ }
+
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModuleItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModuleItem.java
new file mode 100644
index 0000000..bc92d49
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModuleItem.java
@@ -0,0 +1,69 @@
+/*
+ * 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.core.persistence.jpa.entity.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import org.apache.syncope.common.lib.types.IdMImplementationType;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModuleItem;
+import org.apache.syncope.core.persistence.jpa.entity.JPAImplementation;
+import org.apache.syncope.core.persistence.jpa.entity.resource.AbstractItem;
+
+@Entity
+@Table(name = JPAAuthModuleItem.TABLE)
+@Cacheable
+public class JPAAuthModuleItem extends AbstractItem implements AuthModuleItem {
+
+ public static final String TABLE = "AuthModuleItem";
+
+ private static final long serialVersionUID = 3165440920144995781L;
+
+ @ManyToMany(fetch = FetchType.EAGER)
+ @JoinTable(name = TABLE + "Transformer",
+ joinColumns =
+ @JoinColumn(name = "item_id"),
+ inverseJoinColumns =
+ @JoinColumn(name = "implementation_id"),
+ uniqueConstraints =
+ @UniqueConstraint(columnNames = { "item_id", "implementation_id" }))
+ private final List<JPAImplementation> transformers = new ArrayList<>();
+
+ @Override
+ public boolean add(final Implementation transformer) {
+ checkType(transformer, JPAImplementation.class);
+ checkImplementationType(transformer, IdMImplementationType.ITEM_TRANSFORMER);
+ return transformers.contains((JPAImplementation) transformer)
+ || this.transformers.add((JPAImplementation) transformer);
+ }
+
+ @Override
+ public List<? extends Implementation> getTransformers() {
+ return transformers;
+ }
+
+}
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java
new file mode 100644
index 0000000..27c0d22
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java
@@ -0,0 +1,502 @@
+/*
+ * 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.core.persistence.jpa.inner;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.UUID;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.syncope.common.lib.auth.AuthModuleConf;
+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.OIDCAuthModuleConf;
+import org.apache.syncope.common.lib.auth.RadiusAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf;
+import org.apache.syncope.common.lib.auth.StaticAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf;
+import org.apache.syncope.common.lib.auth.U2FAuthModuleConf;
+import org.apache.syncope.core.persistence.api.dao.auth.AuthModuleDAO;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModuleItem;
+
+@Transactional("Master")
+public class AuthModuleTest extends AbstractTest {
+
+ @Autowired
+ private AuthModuleDAO authModuleDAO;
+
+ @Test
+ public void find() {
+ AuthModule authModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
+ assertNotNull(authModule);
+
+ authModule = authModuleDAO.find(UUID.randomUUID().toString());
+ assertNull(authModule);
+ }
+
+ @Test
+ public void findAll() {
+ List<AuthModule> modules = authModuleDAO.findAll();
+ assertNotNull(modules);
+ assertFalse(modules.isEmpty());
+ assertTrue(modules.size() >= 10);
+ }
+
+ @Test
+ public void findByAuthModuleImpl() {
+ AuthModule ldapAuthModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+ assertNotNull(ldapAuthModule);
+ AuthModule jdbcAuthModule = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+ assertNotNull(jdbcAuthModule);
+ AuthModule googleMfaAuthModule = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(googleMfaAuthModule);
+ AuthModule oidcAuthModule = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(oidcAuthModule);
+ AuthModule saml2IdPAuthModule = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+ assertNotNull(saml2IdPAuthModule);
+ AuthModule jaasAuthModule = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
+ assertNotNull(jaasAuthModule);
+ AuthModule staticAuthModule = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
+ assertNotNull(staticAuthModule);
+ AuthModule syncopeAuthModule = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
+ assertNotNull(syncopeAuthModule);
+ AuthModule radiusAuthModule = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+ assertNotNull(radiusAuthModule);
+ AuthModule u2fAuthModule = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
+ assertNotNull(u2fAuthModule);
+
+ assertTrue(isSpecificConf(ldapAuthModule.getConf(), LDAPAuthModuleConf.class));
+ assertFalse(isSpecificConf(ldapAuthModule.getConf(), JDBCAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(jdbcAuthModule.getConf(), JDBCAuthModuleConf.class));
+ assertFalse(isSpecificConf(jdbcAuthModule.getConf(), GoogleMfaAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(googleMfaAuthModule.getConf(), GoogleMfaAuthModuleConf.class));
+ assertFalse(isSpecificConf(googleMfaAuthModule.getConf(), OIDCAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(oidcAuthModule.getConf(), OIDCAuthModuleConf.class));
+ assertFalse(isSpecificConf(oidcAuthModule.getConf(), SAML2IdPAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(saml2IdPAuthModule.getConf(), SAML2IdPAuthModuleConf.class));
+ assertFalse(isSpecificConf(saml2IdPAuthModule.getConf(), JaasAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(jaasAuthModule.getConf(), JaasAuthModuleConf.class));
+ assertFalse(isSpecificConf(jaasAuthModule.getConf(), StaticAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(staticAuthModule.getConf(), StaticAuthModuleConf.class));
+ assertFalse(isSpecificConf(staticAuthModule.getConf(), SyncopeAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(syncopeAuthModule.getConf(), SyncopeAuthModuleConf.class));
+ assertFalse(isSpecificConf(syncopeAuthModule.getConf(), RadiusAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(radiusAuthModule.getConf(), RadiusAuthModuleConf.class));
+ assertFalse(isSpecificConf(radiusAuthModule.getConf(), U2FAuthModuleConf.class));
+
+ assertTrue(isSpecificConf(u2fAuthModule.getConf(), U2FAuthModuleConf.class));
+ assertFalse(isSpecificConf(u2fAuthModule.getConf(), LDAPAuthModuleConf.class));
+ }
+
+ @Test
+ public void findByType() {
+ List<AuthModule> authModules = authModuleDAO.findAll();
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), LDAPAuthModuleConf.class)
+ && authModule.getName().equals("DefaultLDAPAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), JDBCAuthModuleConf.class)
+ && authModule.getName().equals("DefaultJDBCAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), GoogleMfaAuthModuleConf.class)
+ && authModule.getName().equals("DefaultGoogleMfaAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), OIDCAuthModuleConf.class)
+ && authModule.getName().equals("DefaultOIDCAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), SAML2IdPAuthModuleConf.class)
+ && authModule.getName().equals("DefaultSAML2IdPAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), JaasAuthModuleConf.class)
+ && authModule.getName().equals("DefaultJaasAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), StaticAuthModuleConf.class)
+ && authModule.getName().equals("DefaultStaticAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), SyncopeAuthModuleConf.class)
+ && authModule.getName().equals("DefaultSyncopeAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), RadiusAuthModuleConf.class)
+ && authModule.getName().equals("DefaultRadiusAuthModule")));
+ assertTrue(authModules.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), U2FAuthModuleConf.class)
+ && authModule.getName().equals("DefaultU2FAuthModule")));
+ }
+
+ @Test
+ public void saveWithStaticModule() {
+ StaticAuthModuleConf conf = new StaticAuthModuleConf();
+ conf.getUsers().put("user1", UUID.randomUUID().toString());
+ conf.getUsers().put("user2", "user2Password123");
+
+ saveAuthModule("StaticAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithJaasModule() {
+ JaasAuthModuleConf conf = new JaasAuthModuleConf();
+ conf.setKerberosKdcSystemProperty("sample-value");
+ conf.setKerberosRealmSystemProperty("sample-value");
+ conf.setLoginConfigType("JavaLoginConfig");
+ conf.setRealm("SYNCOPE");
+ conf.setLoginConfigurationFile("/opt/jaas/login.conf");
+
+ saveAuthModule("JaasAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithLdapModule() {
+ LDAPAuthModuleConf conf = new LDAPAuthModuleConf();
+ conf.setBaseDn("dc=example,dc=org");
+ conf.setSearchFilter("cn={user}");
+ conf.setSubtreeSearch(true);
+ conf.setLdapUrl("ldap://localhost:1389");
+ conf.setUserIdAttribute("uid");
+ conf.setBindCredential("Password");
+
+ saveAuthModule("LDAPAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithGoogleAuthenticatorModule() {
+ GoogleMfaAuthModuleConf conf = new GoogleMfaAuthModuleConf();
+ conf.setCodeDigits(6);
+ conf.setIssuer("SyncopeTest");
+ conf.setLabel("Syncope");
+ conf.setTimeStepSize(30);
+ conf.setWindowSize(3);
+
+ saveAuthModule("GoogleMfaAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithOIDCAuthModule() {
+ OIDCAuthModuleConf conf = new OIDCAuthModuleConf();
+ conf.setId("OIDCTestId");
+ conf.setDiscoveryUri("www.testurl.com");
+ conf.setUserIdAttribute("username");
+ conf.setResponseType("code");
+ conf.setScope("openid email profile");
+
+ saveAuthModule("OIDCAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithJDBCModule() {
+ JDBCAuthModuleConf conf = new JDBCAuthModuleConf();
+ conf.setSql("SELECT * FROM table WHERE name=?");
+ conf.setFieldPassword("password");
+ conf.getPrincipalAttributeList().addAll(List.of("sn", "cn:commonName", "givenName"));
+
+ saveAuthModule("JDBCAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithSyncopeModule() {
+ SyncopeAuthModuleConf conf = new SyncopeAuthModuleConf();
+ conf.setDomain("Master");
+ conf.setUrl("http://mydomain.com/syncope/rest");
+
+ saveAuthModule("SyncopeAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithSAML2IdPModule() {
+ SAML2IdPAuthModuleConf conf = new SAML2IdPAuthModuleConf();
+ conf.setServiceProviderEntityId("testEntityId");
+ conf.setProviderName("testProviderName");
+ conf.setServiceProviderMetadataPath("file:/etc/metadata");
+
+ saveAuthModule("SAML2IdPAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithRadiusModule() {
+ RadiusAuthModuleConf conf = new RadiusAuthModuleConf();
+ conf.setProtocol("MSCHAPv2");
+ conf.setInetAddress("1.2.3.4");
+ conf.setSharedSecret("xyz");
+ conf.setSocketTimeout(40);
+
+ saveAuthModule("RadiusAuthModuleTest", conf);
+ }
+
+ @Test
+ public void saveWithU2FModule() {
+ U2FAuthModuleConf conf = new U2FAuthModuleConf();
+ conf.setExpireDevices(50);
+
+ saveAuthModule("U2FAuthModuleTest", conf);
+ }
+
+ @Test
+ public void updateWithLDAPModule() {
+ AuthModule module = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ LDAPAuthModuleConf.class.cast(conf).setBaseDn("dc=example2,dc=org");
+ LDAPAuthModuleConf.class.cast(conf).setSearchFilter("cn={user2}");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("dc=example2,dc=org", LDAPAuthModuleConf.class.cast(found.getConf()).getBaseDn());
+ assertEquals("cn={user2}", LDAPAuthModuleConf.class.cast(found.getConf()).getSearchFilter());
+ }
+
+ @Test
+ public void updateWithJDBCModule() {
+ AuthModule module = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ JDBCAuthModuleConf.class.cast(conf).setSql("SELECT * FROM otherTable WHERE name=?");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("SELECT * FROM otherTable WHERE name=?",
+ JDBCAuthModuleConf.class.cast(found.getConf()).getSql());
+ }
+
+ @Test
+ public void updateWithGoogleMfaModule() {
+ AuthModule module = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ GoogleMfaAuthModuleConf.class.cast(conf).setLabel("newLabel");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("newLabel", GoogleMfaAuthModuleConf.class.cast(found.getConf()).getLabel());
+ }
+
+ @Test
+ public void updateWithSAML2IdPModule() {
+ AuthModule module = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("newEntityId");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("newEntityId", SAML2IdPAuthModuleConf.class.cast(found.getConf()).getServiceProviderEntityId());
+ }
+
+ @Test
+ public void updateWithOIDCModule() {
+ AuthModule module = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ OIDCAuthModuleConf.class.cast(conf).setResponseType("newCode");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("newCode", OIDCAuthModuleConf.class.cast(found.getConf()).getResponseType());
+ }
+
+ @Test
+ public void updateWithJaasModule() {
+ AuthModule module = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ JaasAuthModuleConf.class.cast(conf).setRealm("SYNCOPE_NEW");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("SYNCOPE_NEW", JaasAuthModuleConf.class.cast(found.getConf()).getRealm());
+ }
+
+ @Test
+ public void updateWithStaticModule() {
+ AuthModule module = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ assertEquals(1, StaticAuthModuleConf.class.cast(module.getConf()).getUsers().size());
+ AuthModuleConf conf = module.getConf();
+ StaticAuthModuleConf.class.cast(conf).getUsers().put("user3", "user3Password123");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals(2, StaticAuthModuleConf.class.cast(found.getConf()).getUsers().size());
+ }
+
+ @Test
+ public void updateWithRadiusModule() {
+ AuthModule module = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ RadiusAuthModuleConf.class.cast(conf).setSocketTimeout(45);
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals(45, RadiusAuthModuleConf.class.cast(found.getConf()).getSocketTimeout());
+ }
+
+ @Test
+ public void updateWithU2fModule() {
+ AuthModule module = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ U2FAuthModuleConf.class.cast(conf).setExpireDevices(24);
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals(24, U2FAuthModuleConf.class.cast(found.getConf()).getExpireDevices());
+ }
+
+ @Test
+ public void updateWithSyncopeModule() {
+ AuthModule module = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
+ assertNotNull(module);
+ AuthModuleConf conf = module.getConf();
+ SyncopeAuthModuleConf.class.cast(conf).setDomain("Two");
+ module.setConf(conf);
+
+ module = authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ AuthModule found = authModuleDAO.find(module.getKey());
+ assertNotNull(found);
+ assertEquals("Two", SyncopeAuthModuleConf.class.cast(found.getConf()).getDomain());
+ }
+
+ @Test
+ public void delete() {
+ testDelete("be456831-593d-4003-b273-4c3fb61700df");
+ testDelete("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3edbbc-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3edc98-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+ testDelete("4c3edd60-7008-11ea-bc55-0242ac130003");
+ testDelete("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+ testDelete("f6e1288d-50d9-45fe-82ee-597c42242205");
+ }
+
+ private void saveAuthModule(final String name, final AuthModuleConf conf) {
+ AuthModule module = entityFactory.newEntity(AuthModule.class);
+ module.setName(name);
+ module.setDescription("An authentication module");
+ module.setConf(conf);
+ AuthModuleItem keyMapping = entityFactory.newEntity(AuthModuleItem.class);
+ keyMapping.setIntAttrName("uid");
+ keyMapping.setExtAttrName("username");
+ AuthModuleItem fullnameMapping = entityFactory.newEntity(AuthModuleItem.class);
+ fullnameMapping.setIntAttrName("cn");
+ fullnameMapping.setExtAttrName("fullname");
+ module.add(keyMapping);
+ module.add(fullnameMapping);
+ authModuleDAO.save(module);
+ assertNotNull(module);
+ assertNotNull(module.getKey());
+ assertNotNull(authModuleDAO.find(module.getKey()));
+ }
+
+ private void testDelete(final String key) {
+ AuthModule authModule = authModuleDAO.find(key);
+ assertNotNull(authModule);
+ authModuleDAO.delete(key);
+ authModule = authModuleDAO.find(key);
+ assertNull(authModule);
+ }
+
+ private boolean isSpecificConf(final AuthModuleConf conf, final Class<? extends AuthModuleConf> clazz) {
+ return ClassUtils.isAssignable(clazz, conf.getClass());
+ }
+}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuthModuleDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuthModuleDataBinder.java
new file mode 100644
index 0000000..1eab9f4
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuthModuleDataBinder.java
@@ -0,0 +1,32 @@
+/*
+ * 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.core.provisioning.api.data;
+
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+
+public interface AuthModuleDataBinder {
+
+ AuthModule create(AuthModuleTO authModuleTO);
+
+ AuthModule update(AuthModule authModule, AuthModuleTO authModuleTO);
+
+ AuthModuleTO getAuthModuleTO(AuthModule authModule);
+
+}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java
new file mode 100644
index 0000000..0b0e38b
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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.core.provisioning.java.data;
+
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
+import org.apache.syncope.core.provisioning.api.data.AuthModuleDataBinder;
+
+@Component
+public class AuthModuleDataBinderImpl implements AuthModuleDataBinder {
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ private AuthModule getAuthModule(final AuthModule authModule, final AuthModuleTO authModuleTO) {
+ AuthModule result = authModule;
+
+ if (result == null) {
+ result = entityFactory.newEntity(AuthModule.class);
+ }
+
+ AuthModule authenticationModule = AuthModule.class.cast(result);
+ AuthModuleTO authenticationModuleTO = AuthModuleTO.class.cast(authModuleTO);
+
+ authenticationModule.setName(authenticationModuleTO.getName());
+ authenticationModule.setConf(authenticationModuleTO.getConf());
+ authenticationModule.setDescription(authenticationModuleTO.getDescription());
+ // remove all profile items not contained in the TO
+ authenticationModule.getProfileItems().
+ removeIf(item -> !authenticationModuleTO.getProfileItems().stream().
+ anyMatch(otherItem -> item.getKey().equals(otherItem.getKey())));
+
+ return result;
+ }
+
+ @Override
+ public AuthModule create(final AuthModuleTO authModuleTO) {
+ return getAuthModule(null, authModuleTO);
+ }
+
+ @Override
+ public AuthModule update(final AuthModule authModule, final AuthModuleTO authModuleTO) {
+ return getAuthModule(authModule, authModuleTO);
+ }
+
+ @Override
+ public AuthModuleTO getAuthModuleTO(final AuthModule authModule) {
+ AuthModuleTO authModuleTO = new AuthModuleTO();
+
+ authModuleTO.setName(authModule.getName());
+ authModuleTO.setKey(authModule.getKey());
+ authModuleTO.setDescription(authModule.getDescription());
+ authModuleTO.setConf(authModule.getConf());
+ authModuleTO.getProfileItems().forEach(item -> {
+ authModuleTO.add(item);
+ });
+
+ return authModuleTO;
+ }
+}
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
new file mode 100644
index 0000000..a13c4fa
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java
@@ -0,0 +1,589 @@
+/*
+ * 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.fit.core;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.fit.AbstractITCase;
+import org.junit.jupiter.api.Test;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.UUID;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.auth.AuthModuleConf;
+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.OIDCAuthModuleConf;
+import org.apache.syncope.common.lib.auth.RadiusAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf;
+import org.apache.syncope.common.lib.auth.StaticAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf;
+import org.apache.syncope.common.lib.auth.U2FAuthModuleConf;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+
+public class AuthModuleITCase extends AbstractITCase {
+
+ private enum AuthModuleSupportedType {
+ GOOGLE_MFA,
+ SAML2_IDP,
+ STATIC,
+ SYNCOPE,
+ LDAP,
+ JAAS,
+ JDBC,
+ U2F,
+ RADIUS,
+ OIDC;
+
+ };
+
+ private static AuthModuleTO buildAuthModuleTO(final AuthModuleSupportedType type) {
+ AuthModuleTO authModuleTO = new AuthModuleTO();
+ authModuleTO.setName("Test" + type + "AuthenticationModule" + getUUIDString());
+ authModuleTO.setDescription("A test " + type + " Authentication Module");
+ AuthModuleConf conf;
+
+ switch (type) {
+ case LDAP:
+ conf = new LDAPAuthModuleConf();
+ LDAPAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ LDAPAuthModuleConf.class.cast(conf).setBaseDn("dc=example,dc=org");
+ LDAPAuthModuleConf.class.cast(conf).setSearchFilter("cn={user}");
+ LDAPAuthModuleConf.class.cast(conf).setSubtreeSearch(true);
+ LDAPAuthModuleConf.class.cast(conf).setLdapUrl("ldap://localhost:1389");
+ LDAPAuthModuleConf.class.cast(conf).setUserIdAttribute("uid");
+ LDAPAuthModuleConf.class.cast(conf).setBaseDn("cn=Directory Manager,dc=example,dc=org");
+ LDAPAuthModuleConf.class.cast(conf).setBindCredential("Password");
+ break;
+
+ case GOOGLE_MFA:
+ conf = new GoogleMfaAuthModuleConf();
+ GoogleMfaAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ GoogleMfaAuthModuleConf.class.cast(conf).setCodeDigits(6);
+ GoogleMfaAuthModuleConf.class.cast(conf).setIssuer("SyncopeTest");
+ GoogleMfaAuthModuleConf.class.cast(conf).setLabel("Syncope");
+ GoogleMfaAuthModuleConf.class.cast(conf).setTimeStepSize(30);
+ GoogleMfaAuthModuleConf.class.cast(conf).setWindowSize(3);
+ break;
+
+ case JAAS:
+ conf = new JaasAuthModuleConf();
+ JaasAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ JaasAuthModuleConf.class.cast(conf).setKerberosKdcSystemProperty("sample-value");
+ JaasAuthModuleConf.class.cast(conf).setKerberosRealmSystemProperty("sample-value");
+ JaasAuthModuleConf.class.cast(conf).setLoginConfigType("JavaLoginConfig");
+ JaasAuthModuleConf.class.cast(conf).setRealm("SYNCOPE");
+ JaasAuthModuleConf.class.cast(conf).setLoginConfigurationFile("/opt/jaas/login.conf");
+ break;
+
+ case JDBC:
+ conf = new JDBCAuthModuleConf();
+ JDBCAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ JDBCAuthModuleConf.class.cast(conf).setSql("SELECT * FROM table WHERE name=?");
+ JDBCAuthModuleConf.class.cast(conf).setFieldPassword("password");
+ JDBCAuthModuleConf.class.cast(conf).getPrincipalAttributeList().addAll(
+ List.of("sn", "cn:commonName", "givenName"));
+ break;
+
+ case OIDC:
+ conf = new OIDCAuthModuleConf();
+ OIDCAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ OIDCAuthModuleConf.class.cast(conf).setId("OIDCTestId");
+ OIDCAuthModuleConf.class.cast(conf).setDiscoveryUri("www.testurl.com");
+ OIDCAuthModuleConf.class.cast(conf).setUserIdAttribute("username");
+ OIDCAuthModuleConf.class.cast(conf).setResponseType("code");
+ OIDCAuthModuleConf.class.cast(conf).setScope("openid email profile");
+ break;
+
+ case SAML2_IDP:
+ conf = new SAML2IdPAuthModuleConf();
+ SAML2IdPAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("testEntityId");
+ SAML2IdPAuthModuleConf.class.cast(conf).setProviderName("testProviderName");
+ SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderMetadataPath(
+ "file:/etc/metadata");
+ break;
+
+ case SYNCOPE:
+ conf = new SyncopeAuthModuleConf();
+ SyncopeAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ SyncopeAuthModuleConf.class.cast(conf).setDomain("Master");
+ SyncopeAuthModuleConf.class.cast(conf).setUrl("http://mydomain.com/syncope/rest");
+ break;
+
+ case U2F:
+ conf = new U2FAuthModuleConf();
+ U2FAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ U2FAuthModuleConf.class.cast(conf).setExpireDevices(50);
+ break;
+
+ case RADIUS:
+ conf = new RadiusAuthModuleConf();
+ RadiusAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ RadiusAuthModuleConf.class.cast(conf).setProtocol("MSCHAPv2");
+ RadiusAuthModuleConf.class.cast(conf).setInetAddress("1.2.3.4");
+ RadiusAuthModuleConf.class.cast(conf).setSharedSecret("xyz");
+ RadiusAuthModuleConf.class.cast(conf).setSocketTimeout(40);
+ break;
+
+ case STATIC:
+ default:
+ conf = new StaticAuthModuleConf();
+ StaticAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
+ StaticAuthModuleConf.class.cast(conf).getUsers().put("user1", UUID.randomUUID().toString());
+ StaticAuthModuleConf.class.cast(conf).getUsers().put("user2", "user2Password123");
+ break;
+ }
+ authModuleTO.setConf(conf);
+
+ return authModuleTO;
+ }
+
+ @Test
+ public void findAll() {
+ List<AuthModuleTO> authModuleTOs = authModuleService.list();
+ assertNotNull(authModuleTOs);
+ assertFalse(authModuleTOs.isEmpty());
+ assertTrue(authModuleTOs.size() >= 10);
+ }
+
+ @Test
+ public void listByType() {
+ List<AuthModuleTO> authModuleTOs = authModuleService.list();
+ assertNotNull(authModuleTOs);
+ assertFalse(authModuleTOs.isEmpty());
+
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), LDAPAuthModuleConf.class)
+ && authModule.getName().equals("DefaultLDAPAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), JDBCAuthModuleConf.class)
+ && authModule.getName().equals("DefaultJDBCAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), GoogleMfaAuthModuleConf.class)
+ && authModule.getName().equals("DefaultGoogleMfaAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), OIDCAuthModuleConf.class)
+ && authModule.getName().equals("DefaultOIDCAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), SAML2IdPAuthModuleConf.class)
+ && authModule.getName().equals("DefaultSAML2IdPAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), JaasAuthModuleConf.class)
+ && authModule.getName().equals("DefaultJaasAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), StaticAuthModuleConf.class)
+ && authModule.getName().equals("DefaultStaticAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), SyncopeAuthModuleConf.class)
+ && authModule.getName().equals("DefaultSyncopeAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), U2FAuthModuleConf.class)
+ && authModule.getName().equals("DefaultU2FAuthModule")));
+ assertTrue(authModuleTOs.stream().anyMatch(
+ authModule -> isSpecificConf(authModule.getConf(), RadiusAuthModuleConf.class)
+ && authModule.getName().equals("DefaultRadiusAuthModule")));
+ }
+
+ @Test
+ public void getLDAPAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), LDAPAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), JDBCAuthModuleConf.class));
+ }
+
+ @Test
+ public void getJDBCAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), JDBCAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), GoogleMfaAuthModuleConf.class));
+ }
+
+ @Test
+ public void getGoogleMfaAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), GoogleMfaAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), OIDCAuthModuleConf.class));
+ }
+
+ @Test
+ public void getOIDCAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), OIDCAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class));
+ }
+
+ @Test
+ public void getSAML2IdPAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), JaasAuthModuleConf.class));
+ }
+
+ @Test
+ public void getJaasAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3edbbc-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), JaasAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), StaticAuthModuleConf.class));
+ }
+
+ @Test
+ public void getStaticAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3edc98-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), StaticAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), SyncopeAuthModuleConf.class));
+ }
+
+ @Test
+ public void getSyncopeAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("4c3edd60-7008-11ea-bc55-0242ac130003");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), SyncopeAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), RadiusAuthModuleConf.class));
+ }
+
+ @Test
+ public void getRadiusAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), RadiusAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), U2FAuthModuleConf.class));
+ }
+
+ @Test
+ public void getU2FAuthModule() {
+ AuthModuleTO authModuleTO = authModuleService.read("f6e1288d-50d9-45fe-82ee-597c42242205");
+
+ assertNotNull(authModuleTO);
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
+ assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
+ assertTrue(isSpecificConf(authModuleTO.getConf(), U2FAuthModuleConf.class));
+ assertFalse(isSpecificConf(authModuleTO.getConf(), LDAPAuthModuleConf.class));
+ }
+
+ @Test
+ public void create() throws IOException {
+ EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> testCreate(type));
+ }
+
+ @Test
+ public void updateGoogleMfaAuthModule() {
+ AuthModuleTO googleMfaAuthModuleTO = authModuleService.read("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(googleMfaAuthModuleTO);
+
+ AuthModuleTO newGoogleMfaAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.GOOGLE_MFA);
+ newGoogleMfaAuthModuleTO = createAuthModule(newGoogleMfaAuthModuleTO);
+ assertNotNull(newGoogleMfaAuthModuleTO);
+
+ AuthModuleConf conf = googleMfaAuthModuleTO.getConf();
+ assertNotNull(conf);
+ GoogleMfaAuthModuleConf.class.cast(conf).setLabel("newLabel");
+ newGoogleMfaAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newGoogleMfaAuthModuleTO);
+ newGoogleMfaAuthModuleTO = authModuleService.read(newGoogleMfaAuthModuleTO.getKey());
+ assertNotNull(newGoogleMfaAuthModuleTO);
+
+ conf = newGoogleMfaAuthModuleTO.getConf();
+ assertEquals("newLabel", GoogleMfaAuthModuleConf.class.cast(conf).getLabel());
+ }
+
+ @Test
+ public void updateLDAPAuthModule() {
+ AuthModuleTO ldapAuthModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+ assertNotNull(ldapAuthModuleTO);
+
+ AuthModuleTO newLdapAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.LDAP);
+ newLdapAuthModuleTO = createAuthModule(newLdapAuthModuleTO);
+ assertNotNull(newLdapAuthModuleTO);
+
+ AuthModuleConf conf = ldapAuthModuleTO.getConf();
+ assertNotNull(conf);
+ LDAPAuthModuleConf.class.cast(conf).setSubtreeSearch(false);
+ newLdapAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newLdapAuthModuleTO);
+ newLdapAuthModuleTO = authModuleService.read(newLdapAuthModuleTO.getKey());
+ assertNotNull(newLdapAuthModuleTO);
+
+ conf = newLdapAuthModuleTO.getConf();
+ assertFalse(LDAPAuthModuleConf.class.cast(conf).isSubtreeSearch());
+ }
+
+ @Test
+ public void updateSAML2IdPAuthModule() {
+ AuthModuleTO saml2IdpAuthModuleTO = authModuleService.read("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+ assertNotNull(saml2IdpAuthModuleTO);
+
+ AuthModuleTO newsaml2IdpAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.SAML2_IDP);
+ newsaml2IdpAuthModuleTO = createAuthModule(newsaml2IdpAuthModuleTO);
+ assertNotNull(newsaml2IdpAuthModuleTO);
+
+ AuthModuleConf conf = saml2IdpAuthModuleTO.getConf();
+ assertNotNull(conf);
+ SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("newEntityId");
+ newsaml2IdpAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newsaml2IdpAuthModuleTO);
+ newsaml2IdpAuthModuleTO = authModuleService.read(newsaml2IdpAuthModuleTO.getKey());
+ assertNotNull(newsaml2IdpAuthModuleTO);
+
+ conf = newsaml2IdpAuthModuleTO.getConf();
+ assertEquals("newEntityId", SAML2IdPAuthModuleConf.class.cast(conf).getServiceProviderEntityId());
+ }
+
+ @Test
+ public void updateOIDCAuthModule() {
+ AuthModuleTO oidcAuthModuleTO = authModuleService.read("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+ assertNotNull(oidcAuthModuleTO);
+
+ AuthModuleTO newOIDCAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.OIDC);
+ newOIDCAuthModuleTO = createAuthModule(newOIDCAuthModuleTO);
+ assertNotNull(newOIDCAuthModuleTO);
+
+ AuthModuleConf conf = oidcAuthModuleTO.getConf();
+ assertNotNull(conf);
+ OIDCAuthModuleConf.class.cast(conf).setResponseType("newCode");
+ newOIDCAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newOIDCAuthModuleTO);
+ newOIDCAuthModuleTO = authModuleService.read(newOIDCAuthModuleTO.getKey());
+ assertNotNull(newOIDCAuthModuleTO);
+
+ conf = newOIDCAuthModuleTO.getConf();
+ assertEquals("newCode", OIDCAuthModuleConf.class.cast(conf).getResponseType());
+ }
+
+ @Test
+ public void updateJDBCAuthModule() {
+ AuthModuleTO jdbcAuthModuleTO = authModuleService.read("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+ assertNotNull(jdbcAuthModuleTO);
+
+ AuthModuleTO newJDBCAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.JDBC);
+ newJDBCAuthModuleTO = createAuthModule(newJDBCAuthModuleTO);
+ assertNotNull(newJDBCAuthModuleTO);
+
+ AuthModuleConf conf = jdbcAuthModuleTO.getConf();
+ assertNotNull(conf);
+ JDBCAuthModuleConf.class.cast(conf).setFieldPassword("uPassword");
+ newJDBCAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newJDBCAuthModuleTO);
+ newJDBCAuthModuleTO = authModuleService.read(newJDBCAuthModuleTO.getKey());
+ assertNotNull(newJDBCAuthModuleTO);
+
+ conf = newJDBCAuthModuleTO.getConf();
+ assertEquals("uPassword", JDBCAuthModuleConf.class.cast(conf).getFieldPassword());
+ }
+
+ @Test
+ public void updateJaasAuthModule() {
+ AuthModuleTO jaasAuthModuleTO = authModuleService.read("4c3edbbc-7008-11ea-bc55-0242ac130003");
+ assertNotNull(jaasAuthModuleTO);
+
+ AuthModuleTO newJaasAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.JAAS);
+ newJaasAuthModuleTO = createAuthModule(newJaasAuthModuleTO);
+ assertNotNull(newJaasAuthModuleTO);
+
+ AuthModuleConf conf = jaasAuthModuleTO.getConf();
+ assertNotNull(conf);
+ JaasAuthModuleConf.class.cast(conf).setRealm("SYNCOPE_NEW");
+ newJaasAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newJaasAuthModuleTO);
+ newJaasAuthModuleTO = authModuleService.read(newJaasAuthModuleTO.getKey());
+ assertNotNull(newJaasAuthModuleTO);
+
+ conf = newJaasAuthModuleTO.getConf();
+ assertEquals("SYNCOPE_NEW", JaasAuthModuleConf.class.cast(conf).getRealm());
+ }
+
+ @Test
+ public void updateStaticAuthModule() {
+ AuthModuleTO staticAuthModuleTO = authModuleService.read("4c3edc98-7008-11ea-bc55-0242ac130003");
+ assertNotNull(staticAuthModuleTO);
+
+ AuthModuleTO newStaticAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.STATIC);
+ newStaticAuthModuleTO = createAuthModule(newStaticAuthModuleTO);
+ assertNotNull(newStaticAuthModuleTO);
+
+ AuthModuleConf conf = staticAuthModuleTO.getConf();
+ assertNotNull(conf);
+ assertEquals(1, StaticAuthModuleConf.class.cast(conf).getUsers().size());
+ StaticAuthModuleConf.class.cast(conf).getUsers().put("user3", "user3Password123");
+ newStaticAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newStaticAuthModuleTO);
+ newStaticAuthModuleTO = authModuleService.read(newStaticAuthModuleTO.getKey());
+ assertNotNull(newStaticAuthModuleTO);
+
+ conf = newStaticAuthModuleTO.getConf();
+ assertEquals(2, StaticAuthModuleConf.class.cast(conf).getUsers().size());
+ }
+
+ @Test
+ public void updateRadiusAuthModule() {
+ AuthModuleTO radiusAuthModuleTO = authModuleService.read("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+ assertNotNull(radiusAuthModuleTO);
+
+ AuthModuleTO newRadiusAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.RADIUS);
+ newRadiusAuthModuleTO = createAuthModule(newRadiusAuthModuleTO);
+ assertNotNull(newRadiusAuthModuleTO);
+
+ AuthModuleConf conf = radiusAuthModuleTO.getConf();
+ assertNotNull(conf);
+ RadiusAuthModuleConf.class.cast(conf).setSocketTimeout(45);
+ newRadiusAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newRadiusAuthModuleTO);
+ newRadiusAuthModuleTO = authModuleService.read(newRadiusAuthModuleTO.getKey());
+ assertNotNull(newRadiusAuthModuleTO);
+
+ conf = newRadiusAuthModuleTO.getConf();
+ assertEquals(45, RadiusAuthModuleConf.class.cast(conf).getSocketTimeout());
+ }
+
+ @Test
+ public void updateU2fAuthModule() {
+ AuthModuleTO u2fAuthModuleTO = authModuleService.read("f6e1288d-50d9-45fe-82ee-597c42242205");
+ assertNotNull(u2fAuthModuleTO);
+
+ AuthModuleTO newU2fAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.U2F);
+ newU2fAuthModuleTO = createAuthModule(newU2fAuthModuleTO);
+ assertNotNull(newU2fAuthModuleTO);
+
+ AuthModuleConf conf = u2fAuthModuleTO.getConf();
+ assertNotNull(conf);
+ U2FAuthModuleConf.class.cast(conf).setExpireDevices(24);
+ newU2fAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newU2fAuthModuleTO);
+ newU2fAuthModuleTO = authModuleService.read(newU2fAuthModuleTO.getKey());
+ assertNotNull(newU2fAuthModuleTO);
+
+ conf = newU2fAuthModuleTO.getConf();
+ assertEquals(24, U2FAuthModuleConf.class.cast(conf).getExpireDevices());
+ }
+
+ @Test
+ public void updateSyncopeAuthModule() {
+ AuthModuleTO syncopeAuthModuleTO = authModuleService.read("4c3edd60-7008-11ea-bc55-0242ac130003");
+ assertNotNull(syncopeAuthModuleTO);
+
+ AuthModuleTO newSyncopeAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.SYNCOPE);
+ newSyncopeAuthModuleTO = createAuthModule(newSyncopeAuthModuleTO);
+ assertNotNull(newSyncopeAuthModuleTO);
+
+ AuthModuleConf conf = syncopeAuthModuleTO.getConf();
+ assertNotNull(conf);
+ SyncopeAuthModuleConf.class.cast(conf).setDomain("Two");
+ newSyncopeAuthModuleTO.setConf(conf);
+
+ // update new auth module
+ authModuleService.update(newSyncopeAuthModuleTO);
+ newSyncopeAuthModuleTO = authModuleService.read(newSyncopeAuthModuleTO.getKey());
+ assertNotNull(newSyncopeAuthModuleTO);
+
+ conf = newSyncopeAuthModuleTO.getConf();
+ assertEquals("Two", SyncopeAuthModuleConf.class.cast(conf).getDomain());
+ }
+
+ @Test
+ public void delete() throws IOException {
+ EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> testDelete(type));
+ }
+
+ private void testCreate(final AuthModuleSupportedType type) {
+ AuthModuleTO authModuleTO = createAuthModule(buildAuthModuleTO(type));
+ assertNotNull(authModuleTO);
+ assertTrue(authModuleTO.getName().contains(
+ "Test" + type + "AuthenticationModule"));
+ assertTrue(authModuleTO.getDescription().contains(
+ "A test " + type + " Authentication Module"));
+ }
+
+ private void testDelete(final AuthModuleSupportedType type) {
+ AuthModuleTO authModuleTO = buildAuthModuleTO(type);
+ AuthModuleTO read = createAuthModule(authModuleTO);
+ assertNotNull(read);
+ authModuleService.delete(read.getKey());
+ try {
+ authModuleService.read(read.getKey());
+ fail("This should not happen");
+ } catch (SyncopeClientException e) {
+ assertNotNull(e);
+ }
+ }
+
+ private boolean isSpecificConf(final AuthModuleConf conf, final Class<? extends AuthModuleConf> clazz) {
+ return ClassUtils.isAssignable(clazz, conf.getClass());
+ }
+}