This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 71dbf4bb50 [SYNCOPE-1789] WA: adding support for X509 auth
71dbf4bb50 is described below
commit 71dbf4bb5045bb82f4c71fea337cafba860adf61
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Thu Nov 16 13:15:35 2023 +0100
[SYNCOPE-1789] WA: adding support for X509 auth
---
.../syncope/common/lib/auth/AuthModuleConf.java | 2 +
.../common/lib/auth/OAuth20AuthModuleConf.java | 4 +-
.../common/lib/auth/X509AuthModuleConf.java | 483 +++++++++++++++++++++
.../common/lib/types/X509PolicySetting.java | 35 ++
.../common/lib/types/X509PrincipalType.java | 59 +++
.../lib/types/X509RevocationCheckerType.java | 38 ++
.../lib/types/X509RevocationFetcherType.java | 32 ++
.../common/lib/types/X509SubjectDnFormat.java | 47 ++
.../concepts/authenticationmodules.adoc | 11 +-
.../mapping/AuthModulePropertySourceMapper.java | 74 ++++
wa/starter/pom.xml | 4 +
11 files changed, 783 insertions(+), 6 deletions(-)
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
index 4e0c7f0991..6d476ea748 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
@@ -52,6 +52,8 @@ public interface AuthModuleConf extends BaseBean {
Map<String, Object> map(AuthModuleTO authModule, SyncopeAuthModuleConf
conf);
+ Map<String, Object> map(AuthModuleTO authModule, X509AuthModuleConf
conf);
+
Map<String, Object> map(AuthModuleTO authModule,
GoogleMfaAuthModuleConf conf);
Map<String, Object> map(AuthModuleTO authModule, DuoMfaAuthModuleConf
conf);
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java
index 9b04b1fe8c..8d7b97eb8d 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java
@@ -27,9 +27,9 @@ public class OAuth20AuthModuleConf extends
AbstractOAuth20AuthModuleConf impleme
private static final long serialVersionUID = 299820485764241682L;
protected String authUrl;
-
+
protected String profileUrl;
-
+
protected Map<String, String> profileAttrs = new LinkedHashMap<>();
protected boolean withState;
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/X509AuthModuleConf.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/X509AuthModuleConf.java
new file mode 100644
index 0000000000..30f5159705
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/X509AuthModuleConf.java
@@ -0,0 +1,483 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.common.lib.AbstractLDAPConf;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.common.lib.types.X509PolicySetting;
+import org.apache.syncope.common.lib.types.X509PrincipalType;
+import org.apache.syncope.common.lib.types.X509RevocationCheckerType;
+import org.apache.syncope.common.lib.types.X509RevocationFetcherType;
+import org.apache.syncope.common.lib.types.X509SubjectDnFormat;
+
+public class X509AuthModuleConf implements AuthModuleConf {
+
+ private static final long serialVersionUID = 1915254775199296906L;
+
+ public static class LDAP extends AbstractLDAPConf implements Serializable {
+
+ private static final long serialVersionUID = -7274446267090678730L;
+
+ /**
+ * The LDAP attribute that holds the certificate revocation list.
+ */
+ private String certificateAttribute = "certificateRevocationList";
+
+ public String getCertificateAttribute() {
+ return certificateAttribute;
+ }
+
+ public void setCertificateAttribute(final String certificateAttribute)
{
+ this.certificateAttribute = certificateAttribute;
+ }
+ }
+
+ /**
+ * The authentication handler name.
+ */
+ private String name;
+
+ /**
+ * The order of the authentication handler in the chain.
+ */
+ private int order = Integer.MAX_VALUE;
+
+ /**
+ * Threshold value if expired CRL revocation policy is to be handled via
threshold.
+ */
+ private int revocationPolicyThreshold = 172_800;
+
+ /**
+ * Whether revocation checking should check all resources, or stop at
first one.
+ */
+ private boolean checkAll;
+
+ /**
+ * The refresh interval of the internal scheduler in cases where CRL
revocation checking
+ * is done via resources.
+ */
+ private int refreshIntervalSeconds = 3_600;
+
+ /**
+ * When CRL revocation checking is done via distribution points,
+ * decide if fetch failures should throw errors.
+ */
+ private boolean throwOnFetchFailure;
+
+ private X509PrincipalType principalType = X509PrincipalType.SUBJECT_DN;
+
+ /**
+ * Relevant for {@code CN_EDIPI}, {@code RFC822_EMAIL}, {@code SUBJECT},
{@code SUBJECT_ALT_NAME} principal types.
+ */
+ private String principalAlternateAttribute;
+
+ /**
+ * Relevant for {@code SUBJECT_DN} principal type.
+ */
+ private X509SubjectDnFormat principalTypeSubjectDnFormat =
X509SubjectDnFormat.DEFAULT;
+
+ /**
+ * Relevant for {@code SERIAL_NO_DN} principal type.
+ * The serial number prefix used for principal resolution.
+ */
+ private String principalTypeSerialNoDnSerialNumberPrefix = "SERIALNUMBER=";
+
+ /**
+ * Relevant for {@code SERIAL_NO_DN} principal type.
+ * Value delimiter used for principal resolution.
+ */
+ private String principalTypeSerialNoDnValueDelimiter = ", ";
+
+ /**
+ * Relevant for {@code SERIAL_NO} principal type.
+ * Radix used.
+ */
+ private int principalTypeSerialNoSNRadix;
+
+ /**
+ * Relevant for {@code SERIAL_NO} principal type.
+ * If radix hex padding should be used.
+ */
+ private boolean principalTypeSerialNoHexSNZeroPadding;
+
+ /**
+ * Revocation certificate checking is carried out according to this
setting.
+ */
+ private X509RevocationCheckerType revocationChecker =
X509RevocationCheckerType.NONE;
+
+ /**
+ * Options to describe how to fetch CRL resources.
+ */
+ private X509RevocationFetcherType crlFetcher =
X509RevocationFetcherType.RESOURCE;
+
+ /**
+ * List of CRL resources to use for fetching.
+ */
+ private final List<String> crlResources = new ArrayList<>(0);
+
+ /**
+ * When CRLs are cached, indicate maximum number of elements kept in
memory.
+ */
+ private int cacheMaxElementsInMemory = 1_000;
+
+ /**
+ * Determine whether X509 authentication should allow other forms of
authentication such as username/password.
+ * If this setting is turned off, typically the ability to view the login
form as the primary form of
+ * authentication is turned off.
+ */
+ private boolean mixedMode = true;
+
+ /**
+ * When CRLs are cached, indicate the time-to-live of cache items.
+ */
+ private String cacheTimeToLiveSeconds = "PT4H";
+
+ /**
+ * If the CRL resource is unavailable, activate the this policy.
+ */
+ private X509PolicySetting crlResourceUnavailablePolicy =
X509PolicySetting.DENY;
+
+ /**
+ * If the CRL resource has expired, activate the this policy.
+ * Activated if {@link #revocationChecker} is {@code RESOURCE}.
+ */
+ private X509PolicySetting crlResourceExpiredPolicy =
X509PolicySetting.DENY;
+
+ /**
+ * If the CRL is unavailable, activate the this policy.
+ * Activated if {@link #revocationChecker} is {@code CRL}.
+ */
+ private X509PolicySetting crlUnavailablePolicy = X509PolicySetting.DENY;
+
+ /**
+ * If the CRL has expired, activate the this policy.
+ * Activated if {@link #revocationChecker} is {@code CRL}.
+ */
+ private X509PolicySetting crlExpiredPolicy = X509PolicySetting.DENY;
+
+ /**
+ * The compiled pattern supplied by the deployer.
+ */
+ private String regExTrustedIssuerDnPattern;
+
+ /**
+ * Deployer supplied setting for maximum pathLength in a SUPPLIED
+ * certificate.
+ */
+ private int maxPathLength = 1;
+
+ /**
+ * Deployer supplied setting to allow unlimited pathLength in a SUPPLIED
+ * certificate.
+ */
+ private boolean maxPathLengthAllowUnspecified = false;
+
+ /**
+ * Deployer supplied setting to check the KeyUsage extension.
+ */
+ private boolean checkKeyUsage = false;
+
+ /**
+ * Deployer supplied setting to force require the correct KeyUsage
+ * extension.
+ */
+ private boolean requireKeyUsage = false;
+
+ /**
+ * The pattern that authorizes an acceptable certificate by its subject dn.
+ */
+ private String regExSubjectDnPattern = ".+";
+
+ /**
+ * Whether to extract certificate from request.
+ * The default implementation extracts certificate from header via Tomcat
SSLValve parsing logic
+ * and using the {@link #DEFAULT_CERT_HEADER_NAME} header.
+ * Must be false by default because if someone enables it they need to
make sure they are
+ * behind proxy that won't let the header arrive directly from the browser.
+ */
+ private boolean extractCert;
+
+ /**
+ * The name of the header to consult for an X509 cert (e.g. when behind
proxy).
+ */
+ private String sslHeaderName = "ssl_client_cert";
+
+ private LDAP ldap;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(final int order) {
+ this.order = order;
+ }
+
+ public int getRevocationPolicyThreshold() {
+ return revocationPolicyThreshold;
+ }
+
+ public void setRevocationPolicyThreshold(final int
revocationPolicyThreshold) {
+ this.revocationPolicyThreshold = revocationPolicyThreshold;
+ }
+
+ public boolean isCheckAll() {
+ return checkAll;
+ }
+
+ public void setCheckAll(final boolean checkAll) {
+ this.checkAll = checkAll;
+ }
+
+ public int getRefreshIntervalSeconds() {
+ return refreshIntervalSeconds;
+ }
+
+ public void setRefreshIntervalSeconds(final int refreshIntervalSeconds) {
+ this.refreshIntervalSeconds = refreshIntervalSeconds;
+ }
+
+ public boolean isThrowOnFetchFailure() {
+ return throwOnFetchFailure;
+ }
+
+ public void setThrowOnFetchFailure(final boolean throwOnFetchFailure) {
+ this.throwOnFetchFailure = throwOnFetchFailure;
+ }
+
+ public X509PrincipalType getPrincipalType() {
+ return principalType;
+ }
+
+ public void setPrincipalType(final X509PrincipalType principalType) {
+ this.principalType = principalType;
+ }
+
+ public String getPrincipalAlternateAttribute() {
+ return principalAlternateAttribute;
+ }
+
+ public void setPrincipalAlternateAttribute(final String
principalAlternateAttribute) {
+ this.principalAlternateAttribute = principalAlternateAttribute;
+ }
+
+ public X509SubjectDnFormat getPrincipalTypeSubjectDnFormat() {
+ return principalTypeSubjectDnFormat;
+ }
+
+ public void setPrincipalTypeSubjectDnFormat(final X509SubjectDnFormat
principalTypeSubjectDnFormat) {
+ this.principalTypeSubjectDnFormat = principalTypeSubjectDnFormat;
+ }
+
+ public String getPrincipalTypeSerialNoDnSerialNumberPrefix() {
+ return principalTypeSerialNoDnSerialNumberPrefix;
+ }
+
+ public void setPrincipalTypeSerialNoDnSerialNumberPrefix(final String
principalTypeSerialNoDnSerialNumberPrefix) {
+ this.principalTypeSerialNoDnSerialNumberPrefix =
principalTypeSerialNoDnSerialNumberPrefix;
+ }
+
+ public String getPrincipalTypeSerialNoDnValueDelimiter() {
+ return principalTypeSerialNoDnValueDelimiter;
+ }
+
+ public void setPrincipalTypeSerialNoDnValueDelimiter(final String
principalTypeSerialNoDnValueDelimiter) {
+ this.principalTypeSerialNoDnValueDelimiter =
principalTypeSerialNoDnValueDelimiter;
+ }
+
+ public int getPrincipalTypeSerialNoSNRadix() {
+ return principalTypeSerialNoSNRadix;
+ }
+
+ public void setPrincipalTypeSerialNoSNRadix(final int
principalTypeSerialNoSNRadix) {
+ this.principalTypeSerialNoSNRadix = principalTypeSerialNoSNRadix;
+ }
+
+ public boolean isPrincipalTypeSerialNoHexSNZeroPadding() {
+ return principalTypeSerialNoHexSNZeroPadding;
+ }
+
+ public void setPrincipalTypeSerialNoHexSNZeroPadding(final boolean
principalTypeSerialNoHexSNZeroPadding) {
+ this.principalTypeSerialNoHexSNZeroPadding =
principalTypeSerialNoHexSNZeroPadding;
+ }
+
+ public X509RevocationCheckerType getRevocationChecker() {
+ return revocationChecker;
+ }
+
+ public void setRevocationChecker(final X509RevocationCheckerType
revocationChecker) {
+ this.revocationChecker = revocationChecker;
+ }
+
+ public X509RevocationFetcherType getCrlFetcher() {
+ return crlFetcher;
+ }
+
+ public void setCrlFetcher(final X509RevocationFetcherType crlFetcher) {
+ this.crlFetcher = crlFetcher;
+ }
+
+ public int getCacheMaxElementsInMemory() {
+ return cacheMaxElementsInMemory;
+ }
+
+ public void setCacheMaxElementsInMemory(final int
cacheMaxElementsInMemory) {
+ this.cacheMaxElementsInMemory = cacheMaxElementsInMemory;
+ }
+
+ public boolean isMixedMode() {
+ return mixedMode;
+ }
+
+ public void setMixedMode(final boolean mixedMode) {
+ this.mixedMode = mixedMode;
+ }
+
+ public String getCacheTimeToLiveSeconds() {
+ return cacheTimeToLiveSeconds;
+ }
+
+ public void setCacheTimeToLiveSeconds(final String cacheTimeToLiveSeconds)
{
+ this.cacheTimeToLiveSeconds = cacheTimeToLiveSeconds;
+ }
+
+ public X509PolicySetting getCrlResourceUnavailablePolicy() {
+ return crlResourceUnavailablePolicy;
+ }
+
+ public void setCrlResourceUnavailablePolicy(final X509PolicySetting
crlResourceUnavailablePolicy) {
+ this.crlResourceUnavailablePolicy = crlResourceUnavailablePolicy;
+ }
+
+ public X509PolicySetting getCrlResourceExpiredPolicy() {
+ return crlResourceExpiredPolicy;
+ }
+
+ public void setCrlResourceExpiredPolicy(final X509PolicySetting
crlResourceExpiredPolicy) {
+ this.crlResourceExpiredPolicy = crlResourceExpiredPolicy;
+ }
+
+ public X509PolicySetting getCrlUnavailablePolicy() {
+ return crlUnavailablePolicy;
+ }
+
+ public void setCrlUnavailablePolicy(final X509PolicySetting
crlUnavailablePolicy) {
+ this.crlUnavailablePolicy = crlUnavailablePolicy;
+ }
+
+ public X509PolicySetting getCrlExpiredPolicy() {
+ return crlExpiredPolicy;
+ }
+
+ public void setCrlExpiredPolicy(final X509PolicySetting crlExpiredPolicy) {
+ this.crlExpiredPolicy = crlExpiredPolicy;
+ }
+
+ public List<String> getCrlResources() {
+ return crlResources;
+ }
+
+ public String getRegExTrustedIssuerDnPattern() {
+ return regExTrustedIssuerDnPattern;
+ }
+
+ public void setRegExTrustedIssuerDnPattern(final String
regExTrustedIssuerDnPattern) {
+ this.regExTrustedIssuerDnPattern = regExTrustedIssuerDnPattern;
+ }
+
+ public int getMaxPathLength() {
+ return maxPathLength;
+ }
+
+ public void setMaxPathLength(final int maxPathLength) {
+ this.maxPathLength = maxPathLength;
+ }
+
+ public boolean isMaxPathLengthAllowUnspecified() {
+ return maxPathLengthAllowUnspecified;
+ }
+
+ public void setMaxPathLengthAllowUnspecified(final boolean
maxPathLengthAllowUnspecified) {
+ this.maxPathLengthAllowUnspecified = maxPathLengthAllowUnspecified;
+ }
+
+ public boolean isCheckKeyUsage() {
+ return checkKeyUsage;
+ }
+
+ public void setCheckKeyUsage(final boolean checkKeyUsage) {
+ this.checkKeyUsage = checkKeyUsage;
+ }
+
+ public boolean isRequireKeyUsage() {
+ return requireKeyUsage;
+ }
+
+ public void setRequireKeyUsage(final boolean requireKeyUsage) {
+ this.requireKeyUsage = requireKeyUsage;
+ }
+
+ public String getRegExSubjectDnPattern() {
+ return regExSubjectDnPattern;
+ }
+
+ public void setRegExSubjectDnPattern(final String regExSubjectDnPattern) {
+ this.regExSubjectDnPattern = regExSubjectDnPattern;
+ }
+
+ public boolean isExtractCert() {
+ return extractCert;
+ }
+
+ public void setExtractCert(final boolean extractCert) {
+ this.extractCert = extractCert;
+ }
+
+ public String getSslHeaderName() {
+ return sslHeaderName;
+ }
+
+ public void setSslHeaderName(final String sslHeaderName) {
+ this.sslHeaderName = sslHeaderName;
+ }
+
+ public LDAP getLdap() {
+ return ldap;
+ }
+
+ public void setLdap(final LDAP ldap) {
+ this.ldap = ldap;
+ }
+
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModule, final Mapper
mapper) {
+ return mapper.map(authModule, this);
+ }
+}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PolicySetting.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PolicySetting.java
new file mode 100644
index 0000000000..40d09bb772
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PolicySetting.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.types;
+
+public enum X509PolicySetting {
+ /**
+ * Allow to proceed.
+ */
+ ALLOW,
+ /**
+ * Deny and block.
+ */
+ DENY,
+ /**
+ * Throttle the request whereby expired data is permitted up to a
threshold period of time but not afterward.
+ */
+ THRESHOLD;
+
+}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PrincipalType.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PrincipalType.java
new file mode 100644
index 0000000000..a970e3baba
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509PrincipalType.java
@@ -0,0 +1,59 @@
+/*
+ * 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.types;
+
+public enum X509PrincipalType {
+ /**
+ * Create principal by common name and EDIPI.
+ */
+ CN_EDIPI,
+ /**
+ * Create principal from the RFC822 type name (aka email address) in the
subject alternative name field.
+ * The subject alternative name field contains a list of various types of
names, one type is RFC822 e-mail
+ * address. This will return the first e-mail address that is found (if
there are more than one).
+ */
+ RFC822_EMAIL,
+ /**
+ * Create principal by serial no.
+ * Resolve the principal by the serial number with a configurable
<strong>radix</strong>, ranging from 2 to 36.
+ * If {@code radix} is {@code 16}, then the serial number could be filled
with leading zeros to even the number of
+ * digits.
+ */
+ SERIAL_NO,
+ /**
+ * Create principal by serial no and DN.
+ */
+ SERIAL_NO_DN,
+ /**
+ * Create principal by subject.
+ * Resolve the principal by extracting one or more attribute values from
the
+ * certificate subject DN and combining them with intervening delimiters.
+ */
+ SUBJECT,
+ /**
+ * Create principal by subject alternative name.
+ * Resolve the principal by the subject alternative name extension. (type:
otherName)
+ */
+ SUBJECT_ALT_NAME,
+ /**
+ * Create principal by subject DN.
+ */
+ SUBJECT_DN;
+
+}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationCheckerType.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationCheckerType.java
new file mode 100644
index 0000000000..cdf75f9416
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationCheckerType.java
@@ -0,0 +1,38 @@
+/*
+ * 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.types;
+
+public enum X509RevocationCheckerType {
+ /**
+ * No revocation is performed.
+ */
+ NONE,
+ /**
+ * The CRL URI(s) mentioned in the certificate cRLDistributionPoints
extension field.
+ *
+ * Caches are available to prevent excessive IO against CRL endpoints. CRL
data fetched if does not exist in the
+ * cache or if it is expired
+ */
+ CRL,
+ /**
+ * A CRL hosted at a fixed location. The CRL is fetched at periodic
intervals and cached.
+ */
+ RESOURCE;
+
+}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationFetcherType.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationFetcherType.java
new file mode 100644
index 0000000000..f0713ac6e5
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509RevocationFetcherType.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.common.lib.types;
+
+public enum X509RevocationFetcherType {
+ /**
+ * All revocation checks use fixed resources to fetch the CRL resource
from the specified location.
+ */
+ RESOURCE,
+ /**
+ * A CRL resource may be fetched from a pre-configured attribute, in the
event that the CRL resource location is an
+ * LDAP URI.
+ */
+ LDAP;
+
+}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509SubjectDnFormat.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509SubjectDnFormat.java
new file mode 100644
index 0000000000..50b631f43d
--- /dev/null
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/X509SubjectDnFormat.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.types;
+
+public enum X509SubjectDnFormat {
+ /**
+ * Denigrated result of calling certificate.getSubjectDN() method.
+ * Javadocs designate this method as "denigrated" for not being portable
and/or not being well defined.
+ * It is what has been used by CAS for a long time so it remains the
default.
+ */
+ DEFAULT,
+ /**
+ * RFC 1779 String format of Distinguished Names.
+ * Calls {@code X500Principal.getName("RFC1779")} which emits a subject DN
with the attribute keywords defined
+ * in RFC 1779 (CN, L, ST, O, OU, C, STREET). Any other attribute type is
emitted as an OID.
+ */
+ RFC1779,
+ /**
+ * RFC 2253 String format of Distinguished Names.
+ * Calls {@code X500Principal.getName("RFC2253")} which emits a subject DN
with the attribute keywords defined in
+ * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID). Any other attribute
type is emitted as an OID.
+ */
+ RFC2253,
+ /**
+ * Canonical String format of Distinguished Names.
+ * Calls X500Principal.getName("CANONICAL" which emits a subject DN that
starts with RFC 2253 and applies
+ * additional canonicalizations described in the javadoc.
+ */
+ CANONICAL;
+
+}
diff --git
a/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
b/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
index becac0352f..319a2ac3ae 100644
--- a/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
@@ -27,12 +27,15 @@ Several authentication modules are provided:
**
https://apereo.github.io/cas/6.6.x/authentication/Database-Authentication.html[Database^]
**
https://apereo.github.io/cas/6.6.x/authentication/JAAS-Authentication.html[JAAS^]
**
https://apereo.github.io/cas/6.6.x/authentication/LDAP-Authentication.html[LDAP^]
- **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication.html[OpenID
Connect^]
- **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication.html[OAuth2^]
- **
https://apereo.github.io/cas/6.6.x/authentication/Syncope-Authentication.html[Static^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-Generic-OpenID-Connect.html[OpenID
Connect^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-OAuth20.html[OAuth2^]
**
https://apereo.github.io/cas/6.6.x/authentication/Syncope-Authentication.html[Syncope^]
- **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication.html[SAML^]
+ **
https://apereo.github.io/cas/6.6.x/authentication/X509-Authentication.html[X509^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-SAML.htmll[SAML^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-Apple.html[Apple
Signin^]
**
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-Azure-AD.html[Azure
Active Directory^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-Google-OpenID-Connect.html[Google
OpenID^]
+ **
https://apereo.github.io/cas/6.6.x/integration/Delegate-Authentication-Keycloak.html[Keycloak^]
* MFA:
**
https://apereo.github.io/cas/6.6.x/mfa/DuoSecurity-Authentication.html[Duo
Security^]
**
https://apereo.github.io/cas/6.6.x/mfa/GoogleAuthenticator-Authentication.html[Google
Authenticator^]
diff --git
a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
index dcd300afc6..7431fcefe9 100644
---
a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
+++
b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
@@ -41,6 +41,7 @@ import
org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf;
import org.apache.syncope.common.lib.auth.SimpleMfaAuthModuleConf;
import org.apache.syncope.common.lib.auth.StaticAuthModuleConf;
import org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf;
+import org.apache.syncope.common.lib.auth.X509AuthModuleConf;
import org.apache.syncope.common.lib.to.AuthModuleTO;
import org.apache.syncope.common.lib.to.Item;
import org.apache.syncope.common.lib.types.AuthModuleState;
@@ -66,6 +67,10 @@ import
org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jKeyCloakOidcCl
import
org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jOidcClientProperties;
import
org.apereo.cas.configuration.model.support.pac4j.saml.Pac4jSamlClientProperties;
import
org.apereo.cas.configuration.model.support.syncope.SyncopeAuthenticationProperties;
+import
org.apereo.cas.configuration.model.support.x509.SubjectDnPrincipalResolverProperties.SubjectDnFormat;
+import org.apereo.cas.configuration.model.support.x509.X509LdapProperties;
+import org.apereo.cas.configuration.model.support.x509.X509Properties;
+import
org.apereo.cas.configuration.model.support.x509.X509Properties.PrincipalTypes;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.model.TriStateBoolean;
@@ -288,6 +293,75 @@ public class AuthModulePropertySourceMapper extends
PropertySourceMapper impleme
return prefix("cas.authn.pac4j.saml[].", WAConfUtils.asMap(props));
}
+ @Override
+ public Map<String, Object> map(final AuthModuleTO authModuleTO, final
X509AuthModuleConf conf) {
+ X509Properties props = new X509Properties();
+ props.setName(conf.getName());
+ props.setOrder(conf.getOrder());
+ props.setCacheMaxElementsInMemory(conf.getCacheMaxElementsInMemory());
+ props.setCacheTimeToLiveSeconds(conf.getCacheTimeToLiveSeconds());
+ props.setCheckAll(conf.isCheckAll());
+ props.setCheckKeyUsage(conf.isCheckKeyUsage());
+ props.setCrlExpiredPolicy(conf.getCrlExpiredPolicy().name());
+ props.setCrlFetcher(conf.getCrlFetcher().name());
+
props.setCrlResourceExpiredPolicy(conf.getCrlResourceExpiredPolicy().name());
+
props.setCrlResourceUnavailablePolicy(conf.getCrlResourceUnavailablePolicy().name());
+ props.setCrlResources(conf.getCrlResources());
+ props.setCrlUnavailablePolicy(conf.getCrlUnavailablePolicy().name());
+ props.setExtractCert(conf.isExtractCert());
+ props.setMaxPathLength(conf.getMaxPathLength());
+
props.setMaxPathLengthAllowUnspecified(conf.isMaxPathLengthAllowUnspecified());
+ props.setMixedMode(conf.isMixedMode());
+ props.setRefreshIntervalSeconds(conf.getRefreshIntervalSeconds());
+ props.setRegExSubjectDnPattern(conf.getRegExSubjectDnPattern());
+
props.setRegExTrustedIssuerDnPattern(conf.getRegExTrustedIssuerDnPattern());
+ props.setRequireKeyUsage(conf.isRequireKeyUsage());
+ props.setRevocationChecker(conf.getRevocationChecker().name());
+
props.setRevocationPolicyThreshold(conf.getRevocationPolicyThreshold());
+ props.setSslHeaderName(conf.getSslHeaderName());
+ props.setThrowOnFetchFailure(conf.isThrowOnFetchFailure());
+
+
props.setPrincipalType(PrincipalTypes.valueOf(conf.getPrincipalType().name()));
+ if (StringUtils.isNotBlank(conf.getPrincipalAlternateAttribute())) {
+ switch (props.getPrincipalType()) {
+ case CN_EDIPI:
+
props.getCnEdipi().setAlternatePrincipalAttribute(conf.getPrincipalAlternateAttribute());
+ break;
+
+ case RFC822_EMAIL:
+
props.getRfc822Email().setAlternatePrincipalAttribute(conf.getPrincipalAlternateAttribute());
+ break;
+
+ case SUBJECT:
+
props.setPrincipalDescriptor(conf.getPrincipalAlternateAttribute());
+ break;
+
+ case SUBJECT_ALT_NAME:
+
props.getSubjectAltName().setAlternatePrincipalAttribute(conf.getPrincipalAlternateAttribute());
+ break;
+
+ case SUBJECT_DN:
+ case SERIAL_NO_DN:
+ case SERIAL_NO:
+ default:
+ }
+ }
+
props.getSubjectDn().setFormat(SubjectDnFormat.valueOf(conf.getPrincipalTypeSubjectDnFormat().name()));
+
props.getSerialNoDn().setSerialNumberPrefix(conf.getPrincipalTypeSerialNoDnSerialNumberPrefix());
+
props.getSerialNoDn().setValueDelimiter(conf.getPrincipalTypeSerialNoDnValueDelimiter());
+
props.getSerialNo().setPrincipalHexSNZeroPadding(conf.isPrincipalTypeSerialNoHexSNZeroPadding());
+
props.getSerialNo().setPrincipalSNRadix(conf.getPrincipalTypeSerialNoSNRadix());
+
+ if (conf.getLdap() != null) {
+ X509LdapProperties ldapProps = new X509LdapProperties();
+
ldapProps.setCertificateAttribute(conf.getLdap().getCertificateAttribute());
+ fill(ldapProps, conf.getLdap());
+ props.setLdap(ldapProps);
+ }
+
+ return prefix("cas.authn.x509.", WAConfUtils.asMap(props));
+ }
+
@Override
public Map<String, Object> map(final AuthModuleTO authModuleTO, final
SyncopeAuthModuleConf conf) {
SyncopeClient syncopeClient = waRestClient.getSyncopeClient();
diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml
index e98faae7e4..0ccb677695 100644
--- a/wa/starter/pom.xml
+++ b/wa/starter/pom.xml
@@ -353,6 +353,10 @@ under the License.
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-passwordless-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apereo.cas</groupId>
+ <artifactId>cas-server-support-x509-webflow</artifactId>
+ </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>