diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
index e8571d34e4..bbaa98b5b7 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticator.java
@@ -29,16 +29,22 @@ import javax.ws.rs.core.Response;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.bouncycastle.util.encoders.Hex;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.events.Details;
import org.keycloak.forms.login.LoginFormsProvider;
+import org.keycloak.jose.jws.crypto.HashUtils;
+import org.keycloak.crypto.HashException;
+import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.x509.X509ClientCertificateLookup;
+
/**
* @author Peter Nalyvayko
* @version $Revision: 1 $
@@ -55,6 +61,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
public static final String ENABLE_OCSP = "x509-cert-auth.ocsp-checking-enabled";
public static final String ENABLE_CRLDP = "x509-cert-auth.crldp-checking-enabled";
public static final String CANONICAL_DN = "x509-cert-auth.canonical-dn-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 OCSPRESPONDER_URI = "x509-cert-auth.ocsp-responder-uri";
public static final String OCSPRESPONDER_CERTIFICATE = "x509-cert-auth.ocsp-responder-certificate";
@@ -65,9 +72,9 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
public static final String MAPPING_SOURCE_CERT_SUBJECTALTNAME_OTHERNAME = "Subject's Alternative Name otherName (UPN)";
public static final String MAPPING_SOURCE_CERT_SUBJECTDN_CN = "Subject's Common Name";
public static final String MAPPING_SOURCE_CERT_ISSUERDN = "Match IssuerDN using regular expression";
- public static final String MAPPING_SOURCE_CERT_ISSUERDN_EMAIL = "Issuer's e-mail";
- public static final String MAPPING_SOURCE_CERT_ISSUERDN_CN = "Issuer's Common Name";
public static final String MAPPING_SOURCE_CERT_SERIALNUMBER = "Certificate Serial Number";
+ public static final String MAPPING_SOURCE_CERT_SHA256_THUMBPRINT = "SHA-256 Thumbprint";
+ public static final String MAPPING_SOURCE_CERT_SERIALNUMBER_ISSUERDN = "Certificate Serial Number and IssuerDN";
public static final String MAPPING_SOURCE_CERT_CERTIFICATE_PEM = "Full Certificate in PEM format";
public static final String USER_MAPPER_SELECTION = "x509-cert-auth.mapper-selection";
public static final String USER_ATTRIBUTE_MAPPER = "Custom Attribute Mapper";
@@ -129,6 +136,18 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
}
return null;
};
+
+ private static final Function getSerialnumberFunc(X509AuthenticatorConfigModel config) {
+ return config.isSerialnumberHex() ?
+ certs -> Hex.toHexString(certs[0].getSerialNumber().toByteArray()) :
+ certs -> certs[0].getSerialNumber().toString();
+ }
+
+ private static final Function getIssuerDNFunc(X509AuthenticatorConfigModel config) {
+ return config.isCanonicalDnEnabled() ?
+ certs -> certs[0].getIssuerX500Principal().getName(X500Principal.CANONICAL) :
+ certs -> certs[0].getIssuerDN().getName();
+ }
static UserIdentityExtractor fromConfig(X509AuthenticatorConfigModel config) {
@@ -146,13 +165,24 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, func);
break;
case ISSUERDN:
- func = config.isCanonicalDnEnabled() ?
- certs -> certs[0].getIssuerX500Principal().getName(X500Principal.CANONICAL) :
- certs -> certs[0].getIssuerDN().getName();
- extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, func);
+ extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, getIssuerDNFunc(config));
break;
case SERIALNUMBER:
- extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, certs -> certs[0].getSerialNumber().toString());
+ extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, getSerialnumberFunc(config));
+ break;
+ case SHA256_THUMBPRINT:
+ extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, certs -> {
+ try {
+ return Hex.toHexString(HashUtils.hash(JavaAlgorithm.SHA256, certs[0].getEncoded()));
+ } catch (CertificateEncodingException | HashException e) {
+ logger.warn("Unable to get certificate's thumbprint", e);
+ }
+ return null;
+ });
+ break;
+ case SERIALNUMBER_ISSUERDN:
+ func = certs -> getSerialnumberFunc(config).apply(certs) + Constants.CFG_DELIMITER + getIssuerDNFunc(config).apply(certs);
+ extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, func);
break;
case SUBJECTDN_CN:
extractor = UserIdentityExtractor.getX500NameExtractor(BCStyle.CN, subject);
@@ -168,14 +198,6 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
case SUBJECTALTNAME_OTHERNAME:
extractor = UserIdentityExtractor.getSubjectAltNameExtractor(0);
break;
- case ISSUERDN_CN:
- extractor = UserIdentityExtractor.getX500NameExtractor(BCStyle.CN, issuer);
- break;
- case ISSUERDN_EMAIL:
- extractor = UserIdentityExtractor
- .either(UserIdentityExtractor.getX500NameExtractor(BCStyle.EmailAddress, issuer))
- .or(UserIdentityExtractor.getX500NameExtractor(BCStyle.E, issuer));
- break;
case CERTIFICATE_PEM:
extractor = UserIdentityExtractor.getCertificatePemIdentityExtractor(config);
break;
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
index e729472765..e62d04b85a 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/AbstractX509ClientCertificateAuthenticatorFactory.java
@@ -40,8 +40,6 @@ import static org.keycloak.authentication.authenticators.x509.AbstractX509Client
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.ENABLE_CRLDP;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.ENABLE_OCSP;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN;
-import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_CN;
-import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_ISSUERDN_EMAIL;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SERIALNUMBER;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.MAPPING_SOURCE_CERT_SUBJECTALTNAME_OTHERNAME;
@@ -77,9 +75,9 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
MAPPING_SOURCE_CERT_SUBJECTALTNAME_OTHERNAME,
MAPPING_SOURCE_CERT_SUBJECTDN_CN,
MAPPING_SOURCE_CERT_ISSUERDN,
- MAPPING_SOURCE_CERT_ISSUERDN_EMAIL,
- MAPPING_SOURCE_CERT_ISSUERDN_CN,
MAPPING_SOURCE_CERT_SERIALNUMBER,
+ MAPPING_SOURCE_CERT_SERIALNUMBER_ISSUERDN,
+ MAPPING_SOURCE_CERT_SHA256_THUMBPRINT,
MAPPING_SOURCE_CERT_CERTIFICATE_PEM
};
@@ -109,6 +107,14 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
canonicalDn.setDefaultValue(false);
canonicalDn.setHelpText("Use the canonical format to determine the distinguished name. This option is relevant for authenticators using a distinguished name.");
+ ProviderConfigProperty serialnumberHex = new ProviderConfigProperty();
+ serialnumberHex.setType(BOOLEAN_TYPE);
+ serialnumberHex.setName(SERIALNUMBER_HEX);
+ serialnumberHex.setLabel("Enable Serial Number hexadecimal representation");
+ serialnumberHex.setDefaultValue(false);
+ serialnumberHex.setHelpText("Use the hex representation of the serial number. This option is relevant for authenticators using serial number.");
+
+
ProviderConfigProperty regExp = new ProviderConfigProperty();
regExp.setType(STRING_TYPE);
regExp.setName(REGULAR_EXPRESSION);
@@ -130,11 +136,12 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
userMapperList.setOptions(mapperTypes);
ProviderConfigProperty attributeOrPropertyValue = new ProviderConfigProperty();
- attributeOrPropertyValue.setType(STRING_TYPE);
+ attributeOrPropertyValue.setType(MULTIVALUED_STRING_TYPE);
attributeOrPropertyValue.setName(CUSTOM_ATTRIBUTE_NAME);
attributeOrPropertyValue.setDefaultValue(DEFAULT_ATTRIBUTE_NAME);
attributeOrPropertyValue.setLabel("A name of user attribute");
- attributeOrPropertyValue.setHelpText("A name of user attribute to map the extracted user identity to existing user. The name must be a valid, existing user attribute if User Mapping Method is set to Custom Attribute Mapper.");
+ attributeOrPropertyValue.setHelpText("A name of user attribute to map the extracted user identity to existing user. The name must be a valid, existing user attribute if User Mapping Method is set to Custom Attribute Mapper. " +
+ "Multiple values are relevant when attribute mapping is related to multiple values, e.g. 'Certificate Serial Number and IssuerDN'");
ProviderConfigProperty crlCheckingEnabled = new ProviderConfigProperty();
crlCheckingEnabled.setType(BOOLEAN_TYPE);
@@ -198,6 +205,7 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
configProperties = asList(mappingMethodList,
canonicalDn,
+ serialnumberHex,
regExp,
userMapperList,
attributeOrPropertyValue,
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
index 0fb92e1a01..1362b6b5a4 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityExtractor.java
@@ -37,6 +37,7 @@ import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -222,7 +223,7 @@ public abstract class UserIdentityExtractor {
@Override
public Object extractUserIdentity(X509Certificate[] certs) {
- String value = _f.apply(certs);
+ String value = Optional.ofNullable(_f.apply(certs)).orElseThrow(IllegalArgumentException::new);
Pattern r = Pattern.compile(_pattern, Pattern.CASE_INSENSITIVE);
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityToModelMapper.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityToModelMapper.java
index e86e1c25da..6457090697 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityToModelMapper.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/UserIdentityToModelMapper.java
@@ -18,9 +18,12 @@
package org.keycloak.authentication.authenticators.x509;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
import org.keycloak.authentication.AuthenticationFlowContext;
+import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.UserModel;
@@ -45,16 +48,27 @@ public abstract class UserIdentityToModelMapper {
}
static class UserIdentityToCustomAttributeMapper extends UserIdentityToModelMapper {
-
- private String _customAttribute;
- UserIdentityToCustomAttributeMapper(String customAttribute) {
- _customAttribute = customAttribute;
+ private List _customAttributes;
+ UserIdentityToCustomAttributeMapper(String customAttributes) {
+ _customAttributes = Arrays.asList(Constants.CFG_DELIMITER_PATTERN.split(customAttributes));
}
@Override
public UserModel find(AuthenticationFlowContext context, Object userIdentity) throws Exception {
KeycloakSession session = context.getSession();
- List users = session.users().searchForUserByUserAttribute(_customAttribute, userIdentity.toString(), context.getRealm());
+ List userIdentityValues = Arrays.asList(Constants.CFG_DELIMITER_PATTERN.split(userIdentity.toString()));
+
+ if (_customAttributes.isEmpty() || userIdentityValues.isEmpty() || (_customAttributes.size() != userIdentityValues.size())) {
+ return null;
+ }
+ List users = session.users().searchForUserByUserAttribute(_customAttributes.get(0), userIdentityValues.get(0), context.getRealm());
+
+ for (int i = 1; i <_customAttributes.size(); ++i) {
+ String customAttribute = _customAttributes.get(i);
+ String userIdentityValue = userIdentityValues.get(i);
+
+ users = users.stream().filter(user -> user.getFirstAttribute(customAttribute).equals(userIdentityValue)).collect(Collectors.toList());
+ }
if (users != null && users.size() > 1) {
throw new ModelDuplicateException();
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
index 80e7dd6ddf..5826d634fc 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509AuthenticatorConfigModel.java
@@ -55,16 +55,16 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
public enum MappingSourceType {
SERIALNUMBER(MAPPING_SOURCE_CERT_SERIALNUMBER),
- ISSUERDN_CN(MAPPING_SOURCE_CERT_ISSUERDN_CN),
- ISSUERDN_EMAIL(MAPPING_SOURCE_CERT_ISSUERDN_EMAIL),
ISSUERDN(MAPPING_SOURCE_CERT_ISSUERDN),
SUBJECTDN_CN(MAPPING_SOURCE_CERT_SUBJECTDN_CN),
SUBJECTDN_EMAIL(MAPPING_SOURCE_CERT_SUBJECTDN_EMAIL),
SUBJECTALTNAME_EMAIL(MAPPING_SOURCE_CERT_SUBJECTALTNAME_EMAIL),
SUBJECTALTNAME_OTHERNAME(MAPPING_SOURCE_CERT_SUBJECTALTNAME_OTHERNAME),
SUBJECTDN(MAPPING_SOURCE_CERT_SUBJECTDN),
+ SHA256_THUMBPRINT(MAPPING_SOURCE_CERT_SHA256_THUMBPRINT),
+ SERIALNUMBER_ISSUERDN(MAPPING_SOURCE_CERT_SERIALNUMBER_ISSUERDN),
CERTIFICATE_PEM(MAPPING_SOURCE_CERT_CERTIFICATE_PEM);
-
+
private String name;
MappingSourceType(String name) {
this.name = name;
@@ -253,4 +253,13 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
getConfig().put(CANONICAL_DN, Boolean.toString(value));
return this;
}
+
+ public boolean isSerialnumberHex() {
+ return Boolean.parseBoolean(getConfig().get(SERIALNUMBER_HEX));
+ }
+
+ public X509AuthenticatorConfigModel setSerialnumberHex(boolean value) {
+ getConfig().put(SERIALNUMBER_HEX, Boolean.toString(value));
+ return this;
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
index 5ff3ff454f..d0e98a67ce 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
@@ -76,7 +76,6 @@ import java.util.Map;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USERNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USER_ATTRIBUTE;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN;
-import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_CN;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_OTHERNAME;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
index cee4569384..111ef7e5e3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
@@ -40,8 +40,8 @@ import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USERNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USER_ATTRIBUTE;
-import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_CN;
-import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_EMAIL;
+import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SERIALNUMBER_ISSUERDN;
+import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SHA256_THUMBPRINT;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SERIALNUMBER;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
@@ -146,9 +146,34 @@ public class X509BrowserLoginTest extends AbstractX509AuthenticationTest {
}
@Test
- public void loginAsUserFromCertIssuerCNMappedToUserAttribute() {
- x509BrowserLogin(createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(ISSUERDN_CN, "x509_issuer_identity"),
- userId2, "keycloak", "Keycloak Intermediate CA");
+ public void loginAsUserFromCertSerialnumberAndIssuerDNMappedToUserAttribute() {
+ UserRepresentation user = testRealm().users().get(userId2).toRepresentation();
+ Assert.assertNotNull(user);
+
+ user.singleAttribute("x509_certificate_serialnumber", "4105");
+ user.singleAttribute("x509_issuer_dn", "EMAILADDRESS=contact@keycloak.org, CN=Keycloak Intermediate CA, OU=Keycloak, O=Red Hat, ST=MA, C=US");
+ this.updateUser(user);
+
+ events.clear();
+
+ x509BrowserLogin(createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(SERIALNUMBER_ISSUERDN, "x509_certificate_serialnumber##x509_issuer_dn"),
+ userId2, "keycloak", "4105##EMAILADDRESS=contact@keycloak.org, CN=Keycloak Intermediate CA, OU=Keycloak, O=Red Hat, ST=MA, C=US");
+ }
+
+ @Test
+ public void loginAsUserFromHexCertSerialnumberAndIssuerDNMappedToUserAttribute() {
+ UserRepresentation user = testRealm().users().get(userId2).toRepresentation();
+ Assert.assertNotNull(user);
+
+ user.singleAttribute("x509_certificate_serialnumber", "1009");
+ user.singleAttribute("x509_issuer_dn", "EMAILADDRESS=contact@keycloak.org, CN=Keycloak Intermediate CA, OU=Keycloak, O=Red Hat, ST=MA, C=US");
+ this.updateUser(user);
+
+ events.clear();
+
+ X509AuthenticatorConfigModel config = createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(SERIALNUMBER_ISSUERDN, "x509_certificate_serialnumber##x509_issuer_dn");
+ config.setSerialnumberHex(true);
+ x509BrowserLogin(config, userId2, "keycloak", "1009##EMAILADDRESS=contact@keycloak.org, CN=Keycloak Intermediate CA, OU=Keycloak, O=Red Hat, ST=MA, C=US");
}
@Test
@@ -167,18 +192,18 @@ public class X509BrowserLoginTest extends AbstractX509AuthenticationTest {
@Test
- public void loginAsUserFromCertIssuerEmailMappedToUserAttribute() {
+ public void loginAsUserFromCertSHA256MappedToUserAttribute() {
UserRepresentation user = testRealm().users().get(userId2).toRepresentation();
Assert.assertNotNull(user);
- user.singleAttribute("x509_issuer_identity", "contact@keycloak.org");
+ user.singleAttribute("x509_cert_sha256thumbprint", "71237a14c118a90cc8406f14d039ed3431c9065f68e535293ee919d4c33b5e15");
this.updateUser(user);
events.clear();
- x509BrowserLogin(createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(ISSUERDN_EMAIL, "x509_issuer_identity"),
- userId2, "keycloak", "contact@keycloak.org");
+ x509BrowserLogin(createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(SHA256_THUMBPRINT, "x509_cert_sha256thumbprint"),
+ userId2, "keycloak", "71237a14c118a90cc8406f14d039ed3431c9065f68e535293ee919d4c33b5e15");
}
@@ -196,6 +221,22 @@ public class X509BrowserLoginTest extends AbstractX509AuthenticationTest {
x509BrowserLogin(createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(SERIALNUMBER, "x509_serial_number"),
userId2, "keycloak", "4105");
}
+
+ @Test
+ public void loginAsUserFromHexCertSerialNumberMappedToUserAttribute() {
+
+ UserRepresentation user = testRealm().users().get(userId2).toRepresentation();
+ Assert.assertNotNull(user);
+
+ user.singleAttribute("x509_serial_number", "1009");
+ this.updateUser(user);
+
+ events.clear();
+
+ X509AuthenticatorConfigModel config = createLoginWithSpecifiedSourceTypeToCustomAttributeConfig(SERIALNUMBER, "x509_serial_number");
+ config.setSerialnumberHex(true);
+ x509BrowserLogin(config, userId2, "keycloak", "1009");
+ }
@Test