mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Check next update time for CRL in certificate validation
Closes #35983 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
d73794cdc1
commit
f89be1813d
@ -16,6 +16,9 @@ include::topics/templates/release-header.adoc[]
|
||||
== {project_name_full} 26.2.0
|
||||
include::topics/26_2_0.adoc[leveloffset=2]
|
||||
|
||||
== {project_name_full} 26.1.1
|
||||
include::topics/26_1_1.adoc[leveloffset=2]
|
||||
|
||||
== {project_name_full} 26.1.0
|
||||
include::topics/26_1_0.adoc[leveloffset=2]
|
||||
|
||||
|
||||
5
docs/documentation/release_notes/topics/26_1_1.adoc
Normal file
5
docs/documentation/release_notes/topics/26_1_1.adoc
Normal file
@ -0,0 +1,5 @@
|
||||
= New option in X.509 authenticator to abort authentication if CRL is outdated
|
||||
|
||||
The X.509 authenticator has a new option `x509-cert-auth-crl-abort-if-non-updated` (*CRL abort if non updated* in the Admin Console) to abort the login if a CRL is configured to validate the certificate and the CRL is not updated in the time specified in the next update field. The new option defaults to `true` in the Admin Console. For more details about the CRL next update field, see link:https://datatracker.ietf.org/doc/html/rfc5280#section-5.1.2.5[RFC5280, Section-5.1.2.5].
|
||||
|
||||
The value `false` is maintained for compatibility with the previous behavior. Note that existing configurations will not have the new option and will act as if this option was set to `false`, but the Admin Console will add the default value `true` on edit.
|
||||
@ -134,6 +134,9 @@ Use CDP to check the certificate revocation status. Most PKI authorities include
|
||||
*CRL file path*::
|
||||
The path to a file containing a CRL list. The value must be a path to a valid file if the *CRL Checking Enabled* option is enabled.
|
||||
|
||||
*CRL abort if non updated*::
|
||||
A CRL conforming to link:https://datatracker.ietf.org/doc/html/rfc5280#section-5.1.2.5[RFC5280] contains a next update field that indicates the date by which the next CRL will be issued. When that time is passed, the CRL is considered outdated and it should be refreshed. If this option is `true`, the authentication will fail if the CRL is outdated (recommended). If the option is set to `false`, the outdated CRL is still used to validate the user certificates.
|
||||
|
||||
*OCSP Checking Enabled*::
|
||||
Checks the certificate revocation status by using Online Certificate Status Protocol.
|
||||
|
||||
|
||||
@ -66,6 +66,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
|
||||
public static final String TIMESTAMP_VALIDATION = "x509-cert-auth.timestamp-validation-enabled";
|
||||
public static final String SERIALNUMBER_HEX = "x509-cert-auth.serialnumber-hex-enabled";
|
||||
public static final String CRL_RELATIVE_PATH = "x509-cert-auth.crl-relative-path";
|
||||
public static final String CRL_ABORT_IF_NON_UPDATED = "x509-cert-auth-crl-abort-if-non-updated";
|
||||
public static final String OCSPRESPONDER_URI = "x509-cert-auth.ocsp-responder-uri";
|
||||
public static final String OCSPRESPONDER_CERTIFICATE = "x509-cert-auth.ocsp-responder-certificate";
|
||||
public static final String MAPPING_SOURCE_SELECTION = "x509-cert-auth.mapping-source-selection";
|
||||
@ -115,6 +116,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
|
||||
.mode(config.getCertificatePolicyMode().getMode())
|
||||
.parse(config.getCertificatePolicy())
|
||||
.revocation()
|
||||
.crlAbortIfNonUpdated(config.getCrlAbortIfNonUpdated())
|
||||
.cRLEnabled(config.getCRLEnabled())
|
||||
.cRLDPEnabled(config.getCRLDistributionPointEnabled())
|
||||
.cRLrelativePath(config.getCRLRelativePath())
|
||||
|
||||
@ -173,6 +173,16 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
|
||||
"Multiple CRLs can be included, however it can affect performance as the certificate will be checked against all listed CRLs."
|
||||
);
|
||||
|
||||
ProviderConfigProperty cRLAbortIfNonUpdated = new ProviderConfigProperty();
|
||||
cRLAbortIfNonUpdated.setType(BOOLEAN_TYPE);
|
||||
cRLAbortIfNonUpdated.setName(CRL_ABORT_IF_NON_UPDATED);
|
||||
cRLAbortIfNonUpdated.setDefaultValue(Boolean.TRUE.toString());
|
||||
cRLAbortIfNonUpdated.setLabel("CRL abort if non updated");
|
||||
cRLAbortIfNonUpdated.setHelpText("A CRL conforming RFC 5280 must include a next update time that marks when the CRL will be updated. " +
|
||||
"If this option is true, the authentication fails when the CRL is outdated and cannot be updated. " +
|
||||
"If false, the authentication continues when the CRL cannot be updated after the next update time."
|
||||
);
|
||||
|
||||
ProviderConfigProperty oCspCheckingEnabled = new ProviderConfigProperty();
|
||||
oCspCheckingEnabled.setType(BOOLEAN_TYPE);
|
||||
oCspCheckingEnabled.setName(ENABLE_OCSP);
|
||||
@ -248,6 +258,7 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
|
||||
crlCheckingEnabled,
|
||||
crlDPEnabled,
|
||||
cRLRelativePath,
|
||||
cRLAbortIfNonUpdated,
|
||||
oCspCheckingEnabled,
|
||||
ocspFailOpen,
|
||||
ocspResponderUri,
|
||||
|
||||
@ -48,6 +48,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedList;
|
||||
@ -238,10 +239,10 @@ public class CertificateValidator {
|
||||
|
||||
private final List<CRLLoaderImpl> delegates;
|
||||
|
||||
public CRLListLoader(KeycloakSession session, String cRLConfigValue) {
|
||||
public CRLListLoader(KeycloakSession session, String cRLConfigValue, boolean abortIfNonUpdated) {
|
||||
String[] delegatePaths = Constants.CFG_DELIMITER_PATTERN.split(cRLConfigValue);
|
||||
this.delegates = Arrays.stream(delegatePaths)
|
||||
.map(cRLPath -> new CRLFileLoader(session, cRLPath))
|
||||
.map(cRLPath -> new CRLFileLoader(session, cRLPath, abortIfNonUpdated))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@ -261,16 +262,16 @@ public class CertificateValidator {
|
||||
private final KeycloakSession session;
|
||||
private final String cRLPath;
|
||||
private final LdapContext ldapContext;
|
||||
private final boolean abortIfNonUpdated;
|
||||
|
||||
public CRLFileLoader(KeycloakSession session, String cRLPath) {
|
||||
this.session = session;
|
||||
this.cRLPath = cRLPath;
|
||||
ldapContext = new LdapContext();
|
||||
public CRLFileLoader(KeycloakSession session, String cRLPath, boolean abortIfNonUpdated) {
|
||||
this(session, cRLPath, abortIfNonUpdated, new LdapContext());
|
||||
}
|
||||
|
||||
public CRLFileLoader(KeycloakSession session, String cRLPath, LdapContext ldapContext) {
|
||||
public CRLFileLoader(KeycloakSession session, String cRLPath, boolean abortIfNonUpdated, LdapContext ldapContext) {
|
||||
this.session = session;
|
||||
this.cRLPath = cRLPath;
|
||||
this.abortIfNonUpdated = abortIfNonUpdated;
|
||||
this.ldapContext = ldapContext;
|
||||
|
||||
if (ldapContext == null)
|
||||
@ -278,37 +279,49 @@ public class CertificateValidator {
|
||||
}
|
||||
|
||||
public Collection<X509CRL> getX509CRLs() throws GeneralSecurityException {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Collection<X509CRL> crlColl = null;
|
||||
X509CRL crl = loadCRL();
|
||||
if (crl == null) {
|
||||
throw new GeneralSecurityException(String.format("Unable to load CRL from \"%s\"", cRLPath));
|
||||
}
|
||||
|
||||
if (crl.getNextUpdate() != null && crl.getNextUpdate().compareTo(new Date(Time.currentTimeMillis())) < 0) {
|
||||
final String message = String.format("CRL from '%s' is not refreshed. Next update is %s.", cRLPath, crl.getNextUpdate());
|
||||
logger.warn(message);
|
||||
if (abortIfNonUpdated) {
|
||||
throw new GeneralSecurityException(message);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.singletonList(crl);
|
||||
}
|
||||
|
||||
private X509CRL loadCRL() throws GeneralSecurityException {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
X509CRL crl = null;
|
||||
if (cRLPath != null) {
|
||||
if (cRLPath.startsWith("http") || cRLPath.startsWith("https")) {
|
||||
// load CRL using remote URI
|
||||
try {
|
||||
crlColl = loadFromURI(cf, new URI(cRLPath));
|
||||
crl = loadFromURI(cf, new URI(cRLPath));
|
||||
} catch (URISyntaxException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
} else if (cRLPath.startsWith("ldap")) {
|
||||
// load CRL from LDAP
|
||||
try {
|
||||
crlColl = loadCRLFromLDAP(cf, new URI(cRLPath));
|
||||
crl = loadCRLFromLDAP(cf, new URI(cRLPath));
|
||||
} catch(URISyntaxException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// load CRL from file
|
||||
crlColl = loadCRLFromFile(cf, cRLPath);
|
||||
crl = loadCRLFromFile(cf, cRLPath);
|
||||
}
|
||||
}
|
||||
if (crlColl == null || crlColl.size() == 0) {
|
||||
String message = String.format("Unable to load CRL from \"%s\"", cRLPath);
|
||||
throw new GeneralSecurityException(message);
|
||||
}
|
||||
return crlColl;
|
||||
return crl;
|
||||
}
|
||||
|
||||
private Collection<X509CRL> loadFromURI(CertificateFactory cf, URI remoteURI) throws GeneralSecurityException {
|
||||
private X509CRL loadFromURI(CertificateFactory cf, URI remoteURI) throws GeneralSecurityException {
|
||||
try {
|
||||
logger.debugf("Loading CRL from %s", remoteURI.toString());
|
||||
|
||||
@ -320,7 +333,7 @@ public class CertificateValidator {
|
||||
try {
|
||||
InputStream content = response.getEntity().getContent();
|
||||
X509CRL crl = loadFromStream(cf, content);
|
||||
return Collections.singleton(crl);
|
||||
return crl;
|
||||
} finally {
|
||||
EntityUtils.consumeQuietly(response.getEntity());
|
||||
}
|
||||
@ -329,11 +342,11 @@ public class CertificateValidator {
|
||||
catch(IOException ex) {
|
||||
logger.errorf(ex.getMessage());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private Collection<X509CRL> loadCRLFromLDAP(CertificateFactory cf, URI remoteURI) throws GeneralSecurityException {
|
||||
private X509CRL loadCRLFromLDAP(CertificateFactory cf, URI remoteURI) throws GeneralSecurityException {
|
||||
Hashtable<String, String> env = new Hashtable<>(2);
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, ldapContext.getLdapFactoryClassName());
|
||||
env.put(Context.PROVIDER_URL, remoteURI.toString());
|
||||
@ -348,7 +361,7 @@ public class CertificateValidator {
|
||||
throw new CertificateException(String.format("Failed to download CRL from \"%s\"", remoteURI.toString()));
|
||||
}
|
||||
X509CRL crl = loadFromStream(cf, new ByteArrayInputStream(data));
|
||||
return Collections.singleton(crl);
|
||||
return crl;
|
||||
} finally {
|
||||
ctx.close();
|
||||
}
|
||||
@ -358,10 +371,10 @@ public class CertificateValidator {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<X509CRL> loadCRLFromFile(CertificateFactory cf, String relativePath) throws GeneralSecurityException {
|
||||
private X509CRL loadCRLFromFile(CertificateFactory cf, String relativePath) throws GeneralSecurityException {
|
||||
try {
|
||||
String configDir = System.getProperty("jboss.server.config.dir");
|
||||
if (configDir != null) {
|
||||
@ -374,7 +387,7 @@ public class CertificateValidator {
|
||||
}
|
||||
try (FileInputStream is = new FileInputStream(f.getAbsolutePath())) {
|
||||
X509CRL crl = loadFromStream(cf, is);
|
||||
return Collections.singleton(crl);
|
||||
return crl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -382,7 +395,7 @@ public class CertificateValidator {
|
||||
catch(IOException ex) {
|
||||
logger.errorf(ex.getMessage());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
}
|
||||
private X509CRL loadFromStream(CertificateFactory cf, InputStream is) throws IOException, CRLException {
|
||||
DataInputStream dis = new DataInputStream(is);
|
||||
@ -399,6 +412,7 @@ public class CertificateValidator {
|
||||
List<String> _certificatePolicy;
|
||||
String _certificatePolicyMode;
|
||||
boolean _crlCheckingEnabled;
|
||||
boolean _crlAbortIfNonUpdated;
|
||||
boolean _crldpEnabled;
|
||||
CRLLoaderImpl _crlLoader;
|
||||
boolean _ocspEnabled;
|
||||
@ -414,6 +428,7 @@ public class CertificateValidator {
|
||||
int keyUsageBits, List<String> extendedKeyUsage,
|
||||
List<String> certificatePolicy, String certificatePolicyMode,
|
||||
boolean cRLCheckingEnabled,
|
||||
boolean cRLAbortIfNonUpdated,
|
||||
boolean cRLDPCheckingEnabled,
|
||||
CRLLoaderImpl crlLoader,
|
||||
boolean oCSPCheckingEnabled,
|
||||
@ -428,6 +443,7 @@ public class CertificateValidator {
|
||||
_certificatePolicy = certificatePolicy;
|
||||
_certificatePolicyMode = certificatePolicyMode;
|
||||
_crlCheckingEnabled = cRLCheckingEnabled;
|
||||
_crlAbortIfNonUpdated = cRLAbortIfNonUpdated;
|
||||
_crldpEnabled = cRLDPCheckingEnabled;
|
||||
_crlLoader = crlLoader;
|
||||
_ocspEnabled = oCSPCheckingEnabled;
|
||||
@ -510,7 +526,7 @@ public class CertificateValidator {
|
||||
|
||||
|
||||
private static void validatePolicy(X509Certificate[] certs, List<String> expectedPolicies, String policyCheckMode) throws GeneralSecurityException {
|
||||
if (expectedPolicies == null || expectedPolicies.size() == 0) {
|
||||
if (expectedPolicies == null || expectedPolicies.isEmpty()) {
|
||||
logger.debug("Certificate Policy validation is not enabled.");
|
||||
return;
|
||||
}
|
||||
@ -748,7 +764,7 @@ public class CertificateValidator {
|
||||
|
||||
private static void checkRevocationStatusUsingCRL(X509Certificate[] certs, CRLLoaderImpl crLoader, KeycloakSession session) throws GeneralSecurityException {
|
||||
Collection<X509CRL> crlColl = crLoader.getX509CRLs();
|
||||
if (crlColl != null && crlColl.size() > 0) {
|
||||
if (crlColl != null && !crlColl.isEmpty()) {
|
||||
for (X509CRL it : crlColl) {
|
||||
CRLUtils.check(certs, it, session);
|
||||
}
|
||||
@ -765,15 +781,15 @@ public class CertificateValidator {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private static void checkRevocationStatusUsingCRLDistributionPoints(X509Certificate[] certs, KeycloakSession session) throws GeneralSecurityException {
|
||||
private static void checkRevocationStatusUsingCRLDistributionPoints(X509Certificate[] certs, KeycloakSession session, boolean abortIfNonUpdated) throws GeneralSecurityException {
|
||||
|
||||
List<String> distributionPoints = getCRLDistributionPoints(certs[0]);
|
||||
if (distributionPoints == null || distributionPoints.size() == 0) {
|
||||
if (distributionPoints == null || distributionPoints.isEmpty()) {
|
||||
throw new GeneralSecurityException("Could not find any CRL distribution points in the certificate, unable to check the certificate revocation status using CRL/DP.");
|
||||
}
|
||||
for (String dp : distributionPoints) {
|
||||
logger.tracef("CRL Distribution point: \"%s\"", dp);
|
||||
checkRevocationStatusUsingCRL(certs, new CRLFileLoader(session, dp), session);
|
||||
checkRevocationStatusUsingCRL(certs, new CRLFileLoader(session, dp, abortIfNonUpdated), session);
|
||||
}
|
||||
}
|
||||
|
||||
@ -785,7 +801,7 @@ public class CertificateValidator {
|
||||
if (!_crldpEnabled) {
|
||||
checkRevocationStatusUsingCRL(_certChain, _crlLoader, session);
|
||||
} else {
|
||||
checkRevocationStatusUsingCRLDistributionPoints(_certChain, session);
|
||||
checkRevocationStatusUsingCRLDistributionPoints(_certChain, session, _crlAbortIfNonUpdated);
|
||||
}
|
||||
}
|
||||
if (_ocspEnabled) {
|
||||
@ -808,6 +824,7 @@ public class CertificateValidator {
|
||||
List<String> _certificatePolicy;
|
||||
String _certificatePolicyMode;
|
||||
boolean _crlCheckingEnabled;
|
||||
boolean _crlAbortIfNonUpdated;
|
||||
boolean _crldpEnabled;
|
||||
CRLLoaderImpl _crlLoader;
|
||||
boolean _ocspEnabled;
|
||||
@ -954,6 +971,11 @@ public class CertificateValidator {
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public RevocationStatusCheckBuilder crlAbortIfNonUpdated(boolean abortIfNonUpdated) {
|
||||
_crlAbortIfNonUpdated = abortIfNonUpdated;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GotCRL cRLEnabled(boolean value) {
|
||||
_crlCheckingEnabled = value;
|
||||
return new GotCRL();
|
||||
@ -975,7 +997,7 @@ public class CertificateValidator {
|
||||
public class GotCRLDP {
|
||||
public GotCRLRelativePath cRLrelativePath(String value) {
|
||||
if (value != null)
|
||||
_crlLoader = new CRLListLoader(session, value);
|
||||
_crlLoader = new CRLListLoader(session, value, _crlAbortIfNonUpdated);
|
||||
return new GotCRLRelativePath();
|
||||
}
|
||||
|
||||
@ -1071,11 +1093,11 @@ public class CertificateValidator {
|
||||
|
||||
public CertificateValidator build(X509Certificate[] certs) {
|
||||
if (_crlLoader == null) {
|
||||
_crlLoader = new CRLFileLoader(session, "");
|
||||
_crlLoader = new CRLFileLoader(session, "", _crlAbortIfNonUpdated);
|
||||
}
|
||||
return new CertificateValidator(certs, _keyUsageBits, _extendedKeyUsage,
|
||||
_certificatePolicy, _certificatePolicyMode,
|
||||
_crlCheckingEnabled, _crldpEnabled, _crlLoader, _ocspEnabled, _ocspFailOpen,
|
||||
_crlCheckingEnabled, _crlAbortIfNonUpdated, _crldpEnabled, _crlLoader, _ocspEnabled, _ocspFailOpen,
|
||||
new BouncyCastleOCSPChecker(session, _responderUri, _responderCert), session, _timestampValidationEnabled, _trustValidationEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,6 +161,15 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getCrlAbortIfNonUpdated() {
|
||||
return Boolean.parseBoolean(getConfig().get(CRL_ABORT_IF_NON_UPDATED));
|
||||
}
|
||||
|
||||
public X509AuthenticatorConfigModel setCrlAbortIfNonUpdated(boolean crlAbortIfNonUpdated) {
|
||||
getConfig().put(CRL_ABORT_IF_NON_UPDATED, Boolean.toString(crlAbortIfNonUpdated));
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getOCSPResponder() {
|
||||
return getConfig().getOrDefault(OCSPRESPONDER_URI, null);
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@ import java.util.stream.Collectors;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.util.BouncyIntegration;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.truststore.TruststoreProvider;
|
||||
|
||||
@ -74,13 +73,12 @@ public final class CRLUtils {
|
||||
// Try to find the CRL issuer certificate in the truststore
|
||||
if (crlSignatureCertificate == null) {
|
||||
log.tracef("Not found CRL issuer '%s' in the CA chain of the certificate. Fallback to lookup CRL issuer in the truststore", crlIssuerPrincipal);
|
||||
crlSignatureCertificate = findCRLSignatureCertificateInTruststore(session, certs, crl);
|
||||
findCRLSignatureCertificateInTruststore(session, certs, crl);
|
||||
} else {
|
||||
// Verify signature on CRL with the previous found certificate
|
||||
crl.verify(crlSignatureCertificate.getPublicKey());
|
||||
}
|
||||
|
||||
// Verify signature on CRL
|
||||
// TODO: It will be nice to cache CRLs and also verify their signatures just once at the time when CRL is loaded, rather than in every request
|
||||
crl.verify(crlSignatureCertificate.getPublicKey());
|
||||
|
||||
// Finally check if
|
||||
if (crl.isRevoked(certs[0])) {
|
||||
String message = String.format("Certificate has been revoked, certificate's subject: %s", certs[0].getSubjectDN().getName());
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIDAzCB7AIBATANBgkqhkiG9w0BAQsFADCBhzELMAkGA1UEBhMCVVMxCzAJBgNV
|
||||
BAgMAk1BMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazEhMB8G
|
||||
A1UEAwwYS2V5Y2xvYWsgSW50ZXJtZWRpYXRlIENBMSMwIQYJKoZIhvcNAQkBFhRj
|
||||
b250YWN0QGtleWNsb2FrLm9yZxcNMTkwMzE0MTEwNTI1WhcNMTkwNDEzMTEwNTI1
|
||||
WqAwMC4wHwYDVR0jBBgwFoAURxJ8iQtHVxlUCvUDBM2fhqKWdpQwCwYDVR0UBAQC
|
||||
AhAAMA0GCSqGSIb3DQEBCwUAA4ICAQAnH3w3I/EYB51RrB0ZEmiVtxbuEoy4bbhj
|
||||
N1jvXsnM6OZb0me3Q6NzkozgVfDbDrWSGvdOaGqWcWrxsFuCqi5T8yHhTU3eRphh
|
||||
+z01jOvk3UjfOdEOWMJGJWgBLAQj0RUsxRXqGT6n7gyndB+5RTuN/WNjCd96Vf0q
|
||||
yRDfoGGlanGh8sg7BFFnTfDH0dYw8ApYbt/rFT1suFmEaiH44Nd8dldSJxqjK2Ph
|
||||
B0+4etNpZZEjuUGq0U+oYUeppI4oE3vqAPrP9f/Wd0Kc+Ci56RC8X2lf9TSN4qb9
|
||||
xv2a85pUgxBhioZT2fXTDjiUbYKXZhj5tMPixP0M+NcI2yutHpm0Y44BO76bmcVf
|
||||
8AAfH8RcyJlPwfEGwENzY+CZTqCYbCbSg12CLs9UL6ITx8Z1lt/LnLOGCq672rWb
|
||||
Pw3wO3Wmam8Zdyyr2Pff+/+ZcL587/Xif+ho48JSWrJynGwOe9WEBjWqYkfcxCP7
|
||||
plZxWj8MF7A389eBmpLF95BVLFHJECJYUfN7CPU2g+4cKSuzXenlSWtqDs/GdbeJ
|
||||
tFMoA9SzFut9tZg7BMA/gXF/2dTMsjU/1Cy1AVzvWl654wB6OYZv8pktwrjQ77qj
|
||||
S0X4hovoKfpoxYIzw1OTdOuyu7oc6Wh3XWtJWHssrdZuGczDTXtu1qRstFeag/iO
|
||||
cpvmIaTdvQ==
|
||||
-----END X509 CRL-----
|
||||
@ -1,19 +1,19 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIDAzCB7AIBATANBgkqhkiG9w0BAQsFADCBhzELMAkGA1UEBhMCVVMxCzAJBgNV
|
||||
MIIDBTCB7gIBATANBgkqhkiG9w0BAQsFADCBhzELMAkGA1UEBhMCVVMxCzAJBgNV
|
||||
BAgMAk1BMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazEhMB8G
|
||||
A1UEAwwYS2V5Y2xvYWsgSW50ZXJtZWRpYXRlIENBMSMwIQYJKoZIhvcNAQkBFhRj
|
||||
b250YWN0QGtleWNsb2FrLm9yZxcNMTkwMzE0MTEwNTI1WhcNMTkwNDEzMTEwNTI1
|
||||
WqAwMC4wHwYDVR0jBBgwFoAURxJ8iQtHVxlUCvUDBM2fhqKWdpQwCwYDVR0UBAQC
|
||||
AhAAMA0GCSqGSIb3DQEBCwUAA4ICAQAnH3w3I/EYB51RrB0ZEmiVtxbuEoy4bbhj
|
||||
N1jvXsnM6OZb0me3Q6NzkozgVfDbDrWSGvdOaGqWcWrxsFuCqi5T8yHhTU3eRphh
|
||||
+z01jOvk3UjfOdEOWMJGJWgBLAQj0RUsxRXqGT6n7gyndB+5RTuN/WNjCd96Vf0q
|
||||
yRDfoGGlanGh8sg7BFFnTfDH0dYw8ApYbt/rFT1suFmEaiH44Nd8dldSJxqjK2Ph
|
||||
B0+4etNpZZEjuUGq0U+oYUeppI4oE3vqAPrP9f/Wd0Kc+Ci56RC8X2lf9TSN4qb9
|
||||
xv2a85pUgxBhioZT2fXTDjiUbYKXZhj5tMPixP0M+NcI2yutHpm0Y44BO76bmcVf
|
||||
8AAfH8RcyJlPwfEGwENzY+CZTqCYbCbSg12CLs9UL6ITx8Z1lt/LnLOGCq672rWb
|
||||
Pw3wO3Wmam8Zdyyr2Pff+/+ZcL587/Xif+ho48JSWrJynGwOe9WEBjWqYkfcxCP7
|
||||
plZxWj8MF7A389eBmpLF95BVLFHJECJYUfN7CPU2g+4cKSuzXenlSWtqDs/GdbeJ
|
||||
tFMoA9SzFut9tZg7BMA/gXF/2dTMsjU/1Cy1AVzvWl654wB6OYZv8pktwrjQ77qj
|
||||
S0X4hovoKfpoxYIzw1OTdOuyu7oc6Wh3XWtJWHssrdZuGczDTXtu1qRstFeag/iO
|
||||
cpvmIaTdvQ==
|
||||
b250YWN0QGtleWNsb2FrLm9yZxcNMjQxMjIzMTMzNDA4WhgPMjA3NDEyMTExMzM0
|
||||
MDhaoDAwLjAfBgNVHSMEGDAWgBRHEnyJC0dXGVQK9QMEzZ+GopZ2lDALBgNVHRQE
|
||||
BAICEAIwDQYJKoZIhvcNAQELBQADggIBALX2BSzYnZOEHkawBEMJkpa2mz5CTNKK
|
||||
XLGauiEnWwYkd/lDYG/UqX1q5K2qXqmqdlM3VmwcVYUmIxxUz9eL4vj/PmCvWbmQ
|
||||
PNwuGoNR44EAUM+0M5hrdbO1BzigTtTD1I5r8BOhMsRDeq/cWDIEqulGqAgjaN2P
|
||||
dDBqZzIN5ljQeEJ6j3tgSNKbeB+XY9itS5RdYxGY9aPIO7N+zlgvAV+jOgImGApo
|
||||
uUteq8xgOZVsqquMzuzDwN+OUWsYebxacXmuXFmbLrPLM6qgCUyv4jH73KuyDVib
|
||||
loubYrx84XexAogZP/IGHSt+NEJv8LeLyGPzhBYBdXCKY5e0qdZMpf7IbrXqm335
|
||||
dPqNdLEMWjCaoh2mMmEBZJgifjiW2vekzzHUbWrKcrEv+xvDnaciRYyzPya2xoJz
|
||||
+GpUkETqLxbgUAlDMAkFpVYBpWfcgi3Tnuxbm183pxmnQw+IoAjHIrLCkQCKQbJX
|
||||
eqms3bJgVSLxQcflJr3EcdraElrTzaYq9DdbXpcnjrEHmF+Fp74VSe8+fDz6bTTe
|
||||
+OVXq22vsMsdOmzPg2EGc9u9e6NRWdAarN8sIUee3Nl04K8vuSQVn7ioJJam7llQ
|
||||
F5JM6nRNtJx5owbq8PiDZYvAQZneEXrXFOWtdMTZ3KKlUPP3yTwlS1Gpa1l+eQT+
|
||||
eItihr7GRPDI
|
||||
-----END X509 CRL-----
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
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
|
||||
-----END X509 CRL-----
|
||||
|
||||
@ -1 +1 @@
|
||||
1002
|
||||
1003
|
||||
|
||||
@ -1 +1 @@
|
||||
1001
|
||||
1002
|
||||
|
||||
@ -105,6 +105,7 @@ import static org.keycloak.utils.StringUtil.isBlank;
|
||||
public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
public static final String EMPTY_CRL_PATH = "empty.crl";
|
||||
public static final String EMPTY_EXPIRED_CRL_PATH = "empty-expired.crl";
|
||||
public static final String INTERMEDIATE_CA_CRL_PATH = "intermediate-ca.crl";
|
||||
public static final String INTERMEDIATE_CA_INVALID_SIGNATURE_CRL_PATH = "intermediate-ca-invalid-signature.crl";
|
||||
public static final String INTERMEDIATE_CA_3_CRL_PATH = "intermediate-ca-3.crl";
|
||||
|
||||
@ -64,6 +64,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(EMPTY_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -71,6 +72,25 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
x509BrowserLogin(config, userId, "test-user@localhost", "test-user@localhost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginFailureWithEmptyRevocationListFromFileButExpired() {
|
||||
// Not possible to test file CRL on undertow at this moment - jboss config dir doesn't exist
|
||||
ContainerAssume.assumeNotAuthServerUndertow();
|
||||
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(EMPTY_EXPIRED_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
.setUserIdentityMapperType(USERNAME_EMAIL);
|
||||
AuthenticatorConfigRepresentation cfg = newConfig("x509-browser-config", config.getConfig());
|
||||
String cfgId = createConfig(browserExecution.getId(), cfg);
|
||||
Assert.assertNotNull(cfgId);
|
||||
|
||||
assertLoginFailedDueRevokedCertificate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginFailedWithIntermediateRevocationListFromFile() {
|
||||
@ -80,6 +100,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(INTERMEDIATE_CA_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -97,6 +118,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + EMPTY_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -104,12 +126,29 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
x509BrowserLogin(config, userId, "test-user@localhost", "test-user@localhost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginFailureWithEmptyRevocationListFromHttpButExpired() {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + EMPTY_EXPIRED_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
.setUserIdentityMapperType(USERNAME_EMAIL);
|
||||
AuthenticatorConfigRepresentation cfg = newConfig("x509-browser-config", config.getConfig());
|
||||
String cfgId = createConfig(browserExecution.getId(), cfg);
|
||||
Assert.assertNotNull(cfgId);
|
||||
|
||||
assertLoginFailedDueRevokedCertificate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginFailedWithIntermediateRevocationListFromHttp() {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + INTERMEDIATE_CA_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -127,6 +166,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + INTERMEDIATE_CA_INVALID_SIGNATURE_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -145,6 +185,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(false)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + INTERMEDIATE_CA_3_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -163,6 +204,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + EMPTY_CRL_PATH + Constants.CFG_DELIMITER + CRLRule.CRL_RESPONDER_ORIGIN + "/" + INTERMEDIATE_CA_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -182,6 +224,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(false)
|
||||
.setCRLRelativePath(CRLRule.CRL_RESPONDER_ORIGIN + "/" + INVALID_CRL_PATH)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
@ -198,6 +241,7 @@ public class X509BrowserCRLTest extends AbstractX509AuthenticationTest {
|
||||
X509AuthenticatorConfigModel config =
|
||||
new X509AuthenticatorConfigModel()
|
||||
.setCRLEnabled(true)
|
||||
.setCrlAbortIfNonUpdated(true)
|
||||
.setCRLDistributionPointEnabled(true)
|
||||
.setConfirmationPageAllowed(true)
|
||||
.setMappingSourceType(SUBJECTDN_EMAIL)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user