Add X.509 authenticator option for canonical DN
Because the current distinguished name determination is security provider dependent, a new authenticator option is added to use the canonical format of the distinguished name, as descriped in javax.security.auth.x500.X500Principal.getName(String format).
This commit is contained in:
parent
7a671052a3
commit
43393220bf
7 changed files with 233 additions and 14 deletions
|
@ -23,6 +23,7 @@ import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
@ -52,6 +53,7 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
|
||||||
public static final String ENABLE_CRL = "x509-cert-auth.crl-checking-enabled";
|
public static final String ENABLE_CRL = "x509-cert-auth.crl-checking-enabled";
|
||||||
public static final String ENABLE_OCSP = "x509-cert-auth.ocsp-checking-enabled";
|
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 ENABLE_CRLDP = "x509-cert-auth.crldp-checking-enabled";
|
||||||
|
public static final String CANONICAL_DN = "x509-cert-auth.canonical-dn-enabled";
|
||||||
public static final String CRL_RELATIVE_PATH = "x509-cert-auth.crl-relative-path";
|
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_URI = "x509-cert-auth.ocsp-responder-uri";
|
||||||
public static final String OCSPRESPONDER_CERTIFICATE = "x509-cert-auth.ocsp-responder-certificate";
|
public static final String OCSPRESPONDER_CERTIFICATE = "x509-cert-auth.ocsp-responder-certificate";
|
||||||
|
@ -131,13 +133,20 @@ public abstract class AbstractX509ClientCertificateAuthenticator implements Auth
|
||||||
String pattern = config.getRegularExpression();
|
String pattern = config.getRegularExpression();
|
||||||
|
|
||||||
UserIdentityExtractor extractor = null;
|
UserIdentityExtractor extractor = null;
|
||||||
|
Function<X509Certificate[], String> func = null;
|
||||||
switch(userIdentitySource) {
|
switch(userIdentitySource) {
|
||||||
|
|
||||||
case SUBJECTDN:
|
case SUBJECTDN:
|
||||||
extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, certs -> certs[0].getSubjectDN().getName());
|
func = config.isCanonicalDnEnabled() ?
|
||||||
|
certs -> certs[0].getSubjectX500Principal().getName(X500Principal.CANONICAL) :
|
||||||
|
certs -> certs[0].getSubjectDN().getName();
|
||||||
|
extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, func);
|
||||||
break;
|
break;
|
||||||
case ISSUERDN:
|
case ISSUERDN:
|
||||||
extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, certs -> certs[0].getIssuerDN().getName());
|
func = config.isCanonicalDnEnabled() ?
|
||||||
|
certs -> certs[0].getIssuerX500Principal().getName(X500Principal.CANONICAL) :
|
||||||
|
certs -> certs[0].getIssuerDN().getName();
|
||||||
|
extractor = UserIdentityExtractor.getPatternIdentityExtractor(pattern, func);
|
||||||
break;
|
break;
|
||||||
case SERIALNUMBER:
|
case SERIALNUMBER:
|
||||||
extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, certs -> certs[0].getSerialNumber().toString());
|
extractor = UserIdentityExtractor.getPatternIdentityExtractor(DEFAULT_MATCH_ALL_EXPRESSION, certs -> certs[0].getSerialNumber().toString());
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
|
|
||||||
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CERTIFICATE_EXTENDED_KEY_USAGE;
|
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.*;
|
||||||
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CERTIFICATE_KEY_USAGE;
|
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CERTIFICATE_KEY_USAGE;
|
||||||
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CONFIRMATION_PAGE_DISALLOWED;
|
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CONFIRMATION_PAGE_DISALLOWED;
|
||||||
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CRL_RELATIVE_PATH;
|
import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CRL_RELATIVE_PATH;
|
||||||
|
@ -101,6 +101,13 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
|
||||||
mappingMethodList.setDefaultValue(mappingSources[0]);
|
mappingMethodList.setDefaultValue(mappingSources[0]);
|
||||||
mappingMethodList.setOptions(mappingSourceTypes);
|
mappingMethodList.setOptions(mappingSourceTypes);
|
||||||
|
|
||||||
|
ProviderConfigProperty canonicalDn = new ProviderConfigProperty();
|
||||||
|
canonicalDn.setType(BOOLEAN_TYPE);
|
||||||
|
canonicalDn.setName(CANONICAL_DN);
|
||||||
|
canonicalDn.setLabel("Canonical DN representation enabled");
|
||||||
|
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 regExp = new ProviderConfigProperty();
|
ProviderConfigProperty regExp = new ProviderConfigProperty();
|
||||||
regExp.setType(STRING_TYPE);
|
regExp.setType(STRING_TYPE);
|
||||||
regExp.setName(REGULAR_EXPRESSION);
|
regExp.setName(REGULAR_EXPRESSION);
|
||||||
|
@ -189,6 +196,7 @@ public abstract class AbstractX509ClientCertificateAuthenticatorFactory implemen
|
||||||
identityConfirmationPageDisallowed.setHelpText("By default, the users are prompted to confirm their identity extracted from X509 client certificate. The identity confirmation prompt is skipped if the option is switched on.");
|
identityConfirmationPageDisallowed.setHelpText("By default, the users are prompted to confirm their identity extracted from X509 client certificate. The identity confirmation prompt is skipped if the option is switched on.");
|
||||||
|
|
||||||
configProperties = asList(mappingMethodList,
|
configProperties = asList(mappingMethodList,
|
||||||
|
canonicalDn,
|
||||||
regExp,
|
regExp,
|
||||||
userMapperList,
|
userMapperList,
|
||||||
attributeOrPropertyValue,
|
attributeOrPropertyValue,
|
||||||
|
|
|
@ -244,4 +244,12 @@ public class X509AuthenticatorConfigModel extends AuthenticatorConfigModel {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCanonicalDnEnabled() {
|
||||||
|
return Boolean.parseBoolean(getConfig().get(CANONICAL_DN));
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509AuthenticatorConfigModel setCanonicalDnEnabled(boolean value) {
|
||||||
|
getConfig().put(CANONICAL_DN, Boolean.toString(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.testsuite.x509;
|
||||||
|
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -50,6 +51,7 @@ import org.keycloak.testsuite.pages.AbstractPage;
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
|
import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
|
||||||
|
import org.keycloak.testsuite.updaters.SetSystemProperty;
|
||||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||||
import org.keycloak.testsuite.util.AssertAdminEvents;
|
import org.keycloak.testsuite.util.AssertAdminEvents;
|
||||||
import org.keycloak.testsuite.util.ClientBuilder;
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
@ -74,6 +76,7 @@ import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorC
|
||||||
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.ISSUERDN_CN;
|
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_EMAIL;
|
||||||
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_OTHERNAME;
|
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTALTNAME_OTHERNAME;
|
||||||
|
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN;
|
||||||
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_CN;
|
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_CN;
|
||||||
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
|
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
|
||||||
|
|
||||||
|
@ -106,6 +109,8 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
|
||||||
|
|
||||||
protected AuthenticationExecutionInfoRepresentation directGrantExecution;
|
protected AuthenticationExecutionInfoRepresentation directGrantExecution;
|
||||||
|
|
||||||
|
private static SetSystemProperty phantomjsCliArgs;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public AssertEvents events = new AssertEvents(this);
|
public AssertEvents events = new AssertEvents(this);
|
||||||
|
|
||||||
|
@ -141,6 +146,10 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
|
||||||
configurePhantomJS("/ca.crt", "/client.crt", "/client.key", "password");
|
configurePhantomJS("/ca.crt", "/client.crt", "/client.key", "password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void onAfterTestClass() {
|
||||||
|
phantomjsCliArgs.revert();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup phantom JS to be used for mutual TLS testing. All file paths are relative to "authServerHome"
|
* Setup phantom JS to be used for mutual TLS testing. All file paths are relative to "authServerHome"
|
||||||
|
@ -163,7 +172,7 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
|
||||||
cliArgs.append("--ssl-client-key-file=").append(authServerHome).append(clientKeyFile).append(" ");
|
cliArgs.append("--ssl-client-key-file=").append(authServerHome).append(clientKeyFile).append(" ");
|
||||||
cliArgs.append("--ssl-client-key-passphrase=" + clientKeyPassword).append(" ");
|
cliArgs.append("--ssl-client-key-passphrase=" + clientKeyPassword).append(" ");
|
||||||
|
|
||||||
System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
|
phantomjsCliArgs = new SetSystemProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +451,26 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
|
||||||
.setCustomAttributeName("x509_certificate_identity");
|
.setCustomAttributeName("x509_certificate_identity");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static X509AuthenticatorConfigModel createLoginSubjectDNToCustomAttributeConfig(boolean canonicalDnEnabled) {
|
||||||
|
return new X509AuthenticatorConfigModel()
|
||||||
|
.setConfirmationPageAllowed(true)
|
||||||
|
.setCanonicalDnEnabled(canonicalDnEnabled)
|
||||||
|
.setMappingSourceType(SUBJECTDN)
|
||||||
|
.setRegularExpression("(.*?)(?:$)")
|
||||||
|
.setUserIdentityMapperType(USER_ATTRIBUTE)
|
||||||
|
.setCustomAttributeName("x509_certificate_identity");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static X509AuthenticatorConfigModel createLoginIssuerDNToCustomAttributeConfig(boolean canonicalDnEnabled) {
|
||||||
|
return new X509AuthenticatorConfigModel()
|
||||||
|
.setConfirmationPageAllowed(true)
|
||||||
|
.setCanonicalDnEnabled(canonicalDnEnabled)
|
||||||
|
.setMappingSourceType(ISSUERDN)
|
||||||
|
.setRegularExpression("(.*?)(?:$)")
|
||||||
|
.setUserIdentityMapperType(USER_ATTRIBUTE)
|
||||||
|
.setCustomAttributeName("x509_certificate_identity");
|
||||||
|
}
|
||||||
|
|
||||||
protected void setUserEnabled(String userName, boolean enabled) {
|
protected void setUserEnabled(String userName, boolean enabled) {
|
||||||
UserRepresentation user = findUser(userName);
|
UserRepresentation user = findUser(userName);
|
||||||
Assert.assertNotNull(user);
|
Assert.assertNotNull(user);
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed 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.keycloak.testsuite.x509;
|
||||||
|
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.junit.Assume;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.PhantomJSBrowser;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sebastian Loesch
|
||||||
|
* @date 02/14/2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class X509BrowserLoginIssuerDnTest extends AbstractX509AuthenticationTest {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
@PhantomJSBrowser
|
||||||
|
private WebDriver phantomJS;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void replaceTheDefaultDriver() {
|
||||||
|
replaceDefaultWebDriver(phantomJS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void checkAssumption() {
|
||||||
|
try {
|
||||||
|
CertificateFactory.getInstance("X.509", "SUN");
|
||||||
|
}
|
||||||
|
catch (CertificateException | NoSuchProviderException e) {
|
||||||
|
Assume.assumeNoException("Test assumes the SUN security provider", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void onBeforeTestClass() {
|
||||||
|
configurePhantomJS("/ca.crt", "/certs/clients/test-user-san@localhost.cert.pem",
|
||||||
|
"/certs/clients/test-user@localhost.key.pem", "password");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String setup(boolean canonicalDnEnabled) throws Exception {
|
||||||
|
String issuerDn = canonicalDnEnabled ?
|
||||||
|
"1.2.840.113549.1.9.1=#1614636f6e74616374406b6579636c6f616b2e6f7267,cn=keycloak intermediate ca,ou=keycloak,o=red hat,st=ma,c=us" :
|
||||||
|
"EMAILADDRESS=contact@keycloak.org, CN=Keycloak Intermediate CA, OU=Keycloak, O=Red Hat, ST=MA, C=US";
|
||||||
|
|
||||||
|
UserRepresentation user = findUser("test-user@localhost");
|
||||||
|
user.singleAttribute("x509_certificate_identity", issuerDn);
|
||||||
|
updateUser(user);
|
||||||
|
return issuerDn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginAsUserFromCertIssuerDnCanonical() throws Exception {
|
||||||
|
String issuerDn = setup(true);
|
||||||
|
x509BrowserLogin(createLoginIssuerDNToCustomAttributeConfig(true), userId, "test-user@localhost", issuerDn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginAsUserFromCertIssuerDnNonCanonical() throws Exception {
|
||||||
|
String issuerDn = setup(false);
|
||||||
|
x509BrowserLogin(createLoginIssuerDNToCustomAttributeConfig(false), userId, "test-user@localhost", issuerDn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,18 +18,9 @@
|
||||||
package org.keycloak.testsuite.x509;
|
package org.keycloak.testsuite.x509;
|
||||||
|
|
||||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
|
||||||
import org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel;
|
|
||||||
import org.keycloak.events.Details;
|
|
||||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
|
||||||
import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
|
|
||||||
import org.keycloak.testsuite.util.PhantomJSBrowser;
|
import org.keycloak.testsuite.util.PhantomJSBrowser;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
@ -56,7 +47,6 @@ public class X509BrowserLoginSubjectAltNameTest extends AbstractX509Authenticati
|
||||||
"/certs/clients/test-user@localhost.key.pem", "password");
|
"/certs/clients/test-user@localhost.key.pem", "password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loginAsUserFromCertSANEmail() {
|
public void loginAsUserFromCertSANEmail() {
|
||||||
x509BrowserLogin(createLoginSubjectAltNameEmail2UserAttributeConfig(), userId, "test-user@localhost", "test-user-altmail@localhost");
|
x509BrowserLogin(createLoginSubjectAltNameEmail2UserAttributeConfig(), userId, "test-user@localhost", "test-user-altmail@localhost");
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed 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.keycloak.testsuite.x509;
|
||||||
|
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||||
|
import org.junit.Assume;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.PhantomJSBrowser;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sebastian Loesch
|
||||||
|
* @date 02/14/2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class X509BrowserLoginSubjectDnTest extends AbstractX509AuthenticationTest {
|
||||||
|
|
||||||
|
@Drone
|
||||||
|
@PhantomJSBrowser
|
||||||
|
private WebDriver phantomJS;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void replaceTheDefaultDriver() {
|
||||||
|
replaceDefaultWebDriver(phantomJS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void checkAssumption() {
|
||||||
|
try {
|
||||||
|
CertificateFactory.getInstance("X.509", "SUN");
|
||||||
|
}
|
||||||
|
catch (CertificateException | NoSuchProviderException e) {
|
||||||
|
Assume.assumeNoException("Test assumes the SUN security provider", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void onBeforeTestClass() {
|
||||||
|
configurePhantomJS("/ca.crt", "/certs/clients/test-user-san@localhost.cert.pem",
|
||||||
|
"/certs/clients/test-user@localhost.key.pem", "password");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String setup(boolean canonicalDnEnabled) throws Exception {
|
||||||
|
String subjectDn = canonicalDnEnabled ?
|
||||||
|
"1.2.840.113549.1.9.1=#1613746573742d75736572406c6f63616c686f7374,cn=test-user,ou=keycloak,o=red hat,l=boston,st=ma,c=us" :
|
||||||
|
"EMAILADDRESS=test-user@localhost, CN=test-user, OU=Keycloak, O=Red Hat, L=Boston, ST=MA, C=US";
|
||||||
|
|
||||||
|
UserRepresentation user = findUser("test-user@localhost");
|
||||||
|
user.singleAttribute("x509_certificate_identity",subjectDn);
|
||||||
|
updateUser(user);
|
||||||
|
return subjectDn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginAsUserFromCertSubjectDnCanonical() throws Exception {
|
||||||
|
String subjectDn = setup(true);
|
||||||
|
x509BrowserLogin(createLoginSubjectDNToCustomAttributeConfig(true), userId, "test-user@localhost", subjectDn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginAsUserFromCertSubjectDnNonCanonical() throws Exception {
|
||||||
|
String subjectDn = setup(false);
|
||||||
|
x509BrowserLogin(createLoginSubjectDNToCustomAttributeConfig(false), userId, "test-user@localhost", subjectDn);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue