Merge pull request #3726 from mposolda/master
KEYCLOAK-2888 KEYCLOAK-3927 Fully migrate kerberos tests to the new t…
This commit is contained in:
commit
5cec0d4bef
31 changed files with 832 additions and 1631 deletions
|
@ -18,7 +18,9 @@
|
||||||
package org.keycloak.federation.kerberos;
|
package org.keycloak.federation.kerberos;
|
||||||
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -29,31 +31,39 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public abstract class CommonKerberosConfig {
|
public abstract class CommonKerberosConfig {
|
||||||
|
|
||||||
protected ComponentModel componentModel;
|
protected MultivaluedHashMap<String, String> userStorageConfig;
|
||||||
|
|
||||||
public CommonKerberosConfig(ComponentModel componentModel) {
|
public CommonKerberosConfig(ComponentModel componentModel) {
|
||||||
this.componentModel = componentModel;
|
this.userStorageConfig = componentModel.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommonKerberosConfig(ComponentRepresentation componentRep) {
|
||||||
|
this.userStorageConfig = componentRep.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MultivaluedHashMap<String, String> getConfig() {
|
||||||
|
return userStorageConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be always true for KerberosFederationProvider
|
// Should be always true for KerberosFederationProvider
|
||||||
public boolean isAllowKerberosAuthentication() {
|
public boolean isAllowKerberosAuthentication() {
|
||||||
return Boolean.valueOf(componentModel.getConfig().getFirst(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION));
|
return Boolean.valueOf(getConfig().getFirst(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKerberosRealm() {
|
public String getKerberosRealm() {
|
||||||
return componentModel.getConfig().getFirst(KerberosConstants.KERBEROS_REALM);
|
return getConfig().getFirst(KerberosConstants.KERBEROS_REALM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerPrincipal() {
|
public String getServerPrincipal() {
|
||||||
return componentModel.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL);
|
return getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKeyTab() {
|
public String getKeyTab() {
|
||||||
return componentModel.getConfig().getFirst(KerberosConstants.KEYTAB);
|
return getConfig().getFirst(KerberosConstants.KEYTAB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return Boolean.valueOf(componentModel.getConfig().getFirst(KerberosConstants.DEBUG));
|
return Boolean.valueOf(getConfig().getFirst(KerberosConstants.DEBUG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.federation.kerberos;
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProvider.EditMode;
|
import org.keycloak.storage.UserStorageProvider.EditMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,8 +34,12 @@ public class KerberosConfig extends CommonKerberosConfig {
|
||||||
super(component);
|
super(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KerberosConfig(ComponentRepresentation component) {
|
||||||
|
super(component);
|
||||||
|
}
|
||||||
|
|
||||||
public EditMode getEditMode() {
|
public EditMode getEditMode() {
|
||||||
String editModeString = componentModel.getConfig().getFirst(LDAPConstants.EDIT_MODE);
|
String editModeString = getConfig().getFirst(LDAPConstants.EDIT_MODE);
|
||||||
if (editModeString == null) {
|
if (editModeString == null) {
|
||||||
return EditMode.UNSYNCED;
|
return EditMode.UNSYNCED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,11 +48,11 @@ public class KerberosConfig extends CommonKerberosConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowPasswordAuthentication() {
|
public boolean isAllowPasswordAuthentication() {
|
||||||
return Boolean.valueOf(componentModel.getConfig().getFirst(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION));
|
return Boolean.valueOf(getConfig().getFirst(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUpdateProfileFirstLogin() {
|
public boolean isUpdateProfileFirstLogin() {
|
||||||
return Boolean.valueOf(componentModel.getConfig().getFirst(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN));
|
return Boolean.valueOf(getConfig().getFirst(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.storage.ldap.kerberos;
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +34,11 @@ public class LDAPProviderKerberosConfig extends CommonKerberosConfig {
|
||||||
super(componentModel);
|
super(componentModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LDAPProviderKerberosConfig(ComponentRepresentation componentRep) {
|
||||||
|
super(componentRep);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isUseKerberosForPasswordAuthentication() {
|
public boolean isUseKerberosForPasswordAuthentication() {
|
||||||
return Boolean.valueOf(componentModel.getConfig().getFirst(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION));
|
return Boolean.valueOf(getConfig().getFirst(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.keycloak.exportimport.ExportImportConfig.PROVIDER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -656,6 +658,13 @@ public class TestingResourceProvider implements RealmResourceProvider {
|
||||||
return session.getContext().getRealm().getIdentityProviderByAlias(alias).getConfig();
|
return session.getContext().getRealm().getIdentityProviderByAlias(alias).getConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/set-krb5-conf-file")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void setKrb5ConfFile(@QueryParam("krb5-conf-file") String krb5ConfFile) {
|
||||||
|
System.setProperty("java.security.krb5.conf", krb5ConfFile);
|
||||||
|
}
|
||||||
|
|
||||||
private RealmModel getRealmByName(String realmName) {
|
private RealmModel getRealmByName(String realmName) {
|
||||||
RealmProvider realmProvider = session.getProvider(RealmProvider.class);
|
RealmProvider realmProvider = session.getProvider(RealmProvider.class);
|
||||||
return realmProvider.getRealmByName(realmName);
|
return realmProvider.getRealmByName(realmName);
|
||||||
|
|
|
@ -256,4 +256,9 @@ public interface TestingResource {
|
||||||
@Path("/component")
|
@Path("/component")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
MultivaluedHashMap<String, String> getComponentConfig(@QueryParam("componentId") String componentId);
|
MultivaluedHashMap<String, String> getComponentConfig(@QueryParam("componentId") String componentId);
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/set-krb5-conf-file")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
void setKrb5ConfFile(@QueryParam("krb5-conf-file") String krb5ConfFile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,17 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.testsuite.rule;
|
package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.testsuite.federation.ldap.LDAPTestConfiguration;
|
|
||||||
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
|
||||||
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.testsuite.client.resources.TestingResource;
|
||||||
|
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||||
|
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
|
@ -36,18 +36,24 @@ public class KerberosRule extends LDAPRule {
|
||||||
private final String configLocation;
|
private final String configLocation;
|
||||||
|
|
||||||
public KerberosRule(String configLocation) {
|
public KerberosRule(String configLocation) {
|
||||||
this(configLocation, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KerberosRule(String configLocation, LDAPRuleCondition condition) {
|
|
||||||
super(condition);
|
|
||||||
this.configLocation = configLocation;
|
this.configLocation = configLocation;
|
||||||
|
|
||||||
// Global kerberos configuration
|
// Global kerberos configuration
|
||||||
|
String krb5ConfPath = getKrb5ConfPath();
|
||||||
|
System.setProperty("java.security.krb5.conf", krb5ConfPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getKrb5ConfPath() {
|
||||||
URL krb5ConfURL = LDAPTestConfiguration.class.getResource("/kerberos/test-krb5.conf");
|
URL krb5ConfURL = LDAPTestConfiguration.class.getResource("/kerberos/test-krb5.conf");
|
||||||
String krb5ConfPath = new File(krb5ConfURL.getFile()).getAbsolutePath();
|
String krb5ConfPath = new File(krb5ConfURL.getFile()).getAbsolutePath();
|
||||||
log.info("Krb5.conf file location is: " + krb5ConfPath);
|
log.info("Krb5.conf file location is: " + krb5ConfPath);
|
||||||
|
return krb5ConfPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKrb5ConfPath(TestingResource testingResource) {
|
||||||
|
String krb5ConfPath = getKrb5ConfPath();
|
||||||
System.setProperty("java.security.krb5.conf", krb5ConfPath);
|
System.setProperty("java.security.krb5.conf", krb5ConfPath);
|
||||||
|
testingResource.setKrb5ConfFile(krb5ConfPath); // Needs to set it on wildfly server too
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,4 +69,8 @@ public class KerberosRule extends LDAPRule {
|
||||||
|
|
||||||
return new KerberosEmbeddedServer(defaultProperties);
|
return new KerberosEmbeddedServer(defaultProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCaseSensitiveLogin() {
|
||||||
|
return ldapTestConfiguration.isCaseSensitiveLogin();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -28,6 +28,7 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ public class LDAPTestConfiguration {
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
|
DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
|
DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
|
DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
|
||||||
String keyTabPath = getResource("http.keytab");
|
String keyTabPath = getResource("/kerberos/http.keytab");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
|
DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
|
||||||
DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
|
DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
|
DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
|
||||||
|
@ -102,8 +103,10 @@ public class LDAPTestConfiguration {
|
||||||
return ldapTestConfiguration;
|
return ldapTestConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getResource(String resourceName) {
|
public static String getResource(String resourcePath) {
|
||||||
return new File(PROJECT_BUILD_DIRECTORY, "dependency/kerberos/" + resourceName).getAbsolutePath();
|
URL urlPath = LDAPTestConfiguration.class.getResource(resourcePath);
|
||||||
|
String absolutePath = new File(urlPath.getFile()).getAbsolutePath();
|
||||||
|
return absolutePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadConnectionProperties(String connectionPropertiesLocation) {
|
protected void loadConnectionProperties(String connectionPropertiesLocation) {
|
||||||
|
|
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.federation.kerberos;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.naming.Context;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.directory.Attributes;
|
||||||
|
import javax.naming.directory.DirContext;
|
||||||
|
import javax.naming.directory.InitialDirContext;
|
||||||
|
import javax.security.sasl.Sasl;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.Credentials;
|
||||||
|
import org.apache.http.client.params.AuthPolicy;
|
||||||
|
import org.apache.http.client.utils.URLEncodedUtils;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.ietf.jgss.GSSCredential;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.adapters.HttpClientBuilder;
|
||||||
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
|
import org.keycloak.common.util.KerberosSerializationUtils;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.events.Details;
|
||||||
|
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
|
import org.keycloak.testsuite.Assert;
|
||||||
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||||
|
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||||
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
|
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||||
|
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
||||||
|
|
||||||
|
protected KeycloakSPNegoSchemeFactory spnegoSchemeFactory;
|
||||||
|
|
||||||
|
protected ResteasyClient client;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public AssertEvents events = new AssertEvents(this);
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected AccountPasswordPage changePasswordPage;
|
||||||
|
|
||||||
|
protected abstract CommonKerberosConfig getKerberosConfig();
|
||||||
|
|
||||||
|
protected abstract ComponentRepresentation getUserStorageConfiguration();
|
||||||
|
|
||||||
|
protected abstract void setKrb5ConfPath();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
|
RealmRepresentation realmRep = loadJson(getClass().getResourceAsStream("/kerberos/kerberosrealm.json"), RealmRepresentation.class);
|
||||||
|
testRealms.add(realmRep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforeAbstractKeycloakTest() throws Exception {
|
||||||
|
super.beforeAbstractKeycloakTest();
|
||||||
|
|
||||||
|
testRealmPage.setAuthRealm(AuthRealm.TEST);
|
||||||
|
changePasswordPage.realm(AuthRealm.TEST);
|
||||||
|
|
||||||
|
setKrb5ConfPath();
|
||||||
|
|
||||||
|
spnegoSchemeFactory = new KeycloakSPNegoSchemeFactory(getKerberosConfig());
|
||||||
|
initHttpClient(true);
|
||||||
|
removeAllUsers();
|
||||||
|
|
||||||
|
oauth.clientId("kerberos-app");
|
||||||
|
|
||||||
|
ComponentRepresentation rep = getUserStorageConfiguration();
|
||||||
|
testRealmResource().components().add(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void afterAbstractKeycloakTest() {
|
||||||
|
cleanupApacheHttpClient();
|
||||||
|
|
||||||
|
super.afterAbstractKeycloakTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupApacheHttpClient() {
|
||||||
|
client.close();
|
||||||
|
client = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// public void sleepTest() throws Exception {
|
||||||
|
// String kcLoginPageLocation = oauth.getLoginFormUrl();
|
||||||
|
// Thread.sleep(10000000);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void spnegoNotAvailableTest() throws Exception {
|
||||||
|
initHttpClient(false);
|
||||||
|
|
||||||
|
String kcLoginPageLocation = oauth.getLoginFormUrl();
|
||||||
|
|
||||||
|
Response response = client.target(kcLoginPageLocation).request().get();
|
||||||
|
Assert.assertEquals(401, response.getStatus());
|
||||||
|
Assert.assertEquals(KerberosConstants.NEGOTIATE, response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
|
||||||
|
String responseText = response.readEntity(String.class);
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected OAuthClient.AccessTokenResponse spnegoLoginTestImpl() throws Exception {
|
||||||
|
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
||||||
|
Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||||
|
|
||||||
|
List<UserRepresentation> users = testRealmResource().users().search("hnelson", 0, 1);
|
||||||
|
String userId = users.get(0).getId();
|
||||||
|
events.expectLogin()
|
||||||
|
.client("kerberos-app")
|
||||||
|
.user(userId)
|
||||||
|
.detail(Details.USERNAME, "hnelson")
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
|
String codeUrl = spnegoResponse.getLocation().toString();
|
||||||
|
|
||||||
|
return assertAuthenticationSuccess(codeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract boolean isCaseSensitiveLogin();
|
||||||
|
|
||||||
|
// KEYCLOAK-2102
|
||||||
|
@Test
|
||||||
|
public void spnegoCaseInsensitiveTest() throws Exception {
|
||||||
|
Response spnegoResponse = spnegoLogin(isCaseSensitiveLogin() ? "MyDuke" : "myduke", "theduke");
|
||||||
|
Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||||
|
List<UserRepresentation> users = testRealmResource().users().search("myduke", 0, 1);
|
||||||
|
String userId = users.get(0).getId();
|
||||||
|
events.expectLogin()
|
||||||
|
.client("kerberos-app")
|
||||||
|
.user(userId)
|
||||||
|
.detail(Details.USERNAME, "myduke")
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
|
String codeUrl = spnegoResponse.getLocation().toString();
|
||||||
|
|
||||||
|
assertAuthenticationSuccess(codeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void usernamePasswordLoginTest() throws Exception {
|
||||||
|
// Change editMode to READ_ONLY
|
||||||
|
updateProviderEditMode(UserStorageProvider.EditMode.READ_ONLY);
|
||||||
|
|
||||||
|
// Login with username/password from kerberos
|
||||||
|
changePasswordPage.open();
|
||||||
|
loginPage.assertCurrent();
|
||||||
|
loginPage.login("jduke", "theduke");
|
||||||
|
changePasswordPage.assertCurrent();
|
||||||
|
|
||||||
|
// Bad existing password
|
||||||
|
changePasswordPage.changePassword("theduke-invalid", "newPass", "newPass");
|
||||||
|
Assert.assertTrue(driver.getPageSource().contains("Invalid existing password."));
|
||||||
|
|
||||||
|
// Change password is not possible as editMode is READ_ONLY
|
||||||
|
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
||||||
|
Assert.assertTrue(
|
||||||
|
driver.getPageSource().contains("You can't update your password as your account is read only"));
|
||||||
|
|
||||||
|
// Change editMode to UNSYNCED
|
||||||
|
updateProviderEditMode(UserStorageProvider.EditMode.UNSYNCED);
|
||||||
|
|
||||||
|
// Successfully change password now
|
||||||
|
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
||||||
|
Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
|
||||||
|
changePasswordPage.logout();
|
||||||
|
|
||||||
|
// Login with old password doesn't work, but with new password works
|
||||||
|
loginPage.login("jduke", "theduke");
|
||||||
|
loginPage.assertCurrent();
|
||||||
|
loginPage.login("jduke", "newPass");
|
||||||
|
changePasswordPage.assertCurrent();
|
||||||
|
changePasswordPage.logout();
|
||||||
|
|
||||||
|
// Assert SPNEGO login still with the old password as mode is unsynced
|
||||||
|
events.clear();
|
||||||
|
Response spnegoResponse = spnegoLogin("jduke", "theduke");
|
||||||
|
Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||||
|
List<UserRepresentation> users = testRealmResource().users().search("jduke", 0, 1);
|
||||||
|
String userId = users.get(0).getId();
|
||||||
|
events.expectLogin()
|
||||||
|
.client("kerberos-app")
|
||||||
|
.user(userId)
|
||||||
|
.detail(Details.USERNAME, "jduke")
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
|
String codeUrl = spnegoResponse.getLocation().toString();
|
||||||
|
|
||||||
|
assertAuthenticationSuccess(codeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void credentialDelegationTest() throws Exception {
|
||||||
|
// Add kerberos delegation credential mapper
|
||||||
|
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||||
|
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
||||||
|
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
||||||
|
true, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||||
|
true, false);
|
||||||
|
ProtocolMapperRepresentation protocolMapperRep = ModelToRepresentation.toRepresentation(protocolMapper);
|
||||||
|
ClientResource clientResource = findClientByClientId(testRealmResource(), "kerberos-app");
|
||||||
|
Response response = clientResource.getProtocolMappers().createMapper(protocolMapperRep);
|
||||||
|
String protocolMapperId = ApiUtil.getCreatedId(response);
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
// SPNEGO login
|
||||||
|
OAuthClient.AccessTokenResponse tokenResponse = spnegoLoginTestImpl();
|
||||||
|
|
||||||
|
// Assert kerberos ticket in the accessToken can be re-used to authenticate against other 3rd party kerberos service (ApacheDS Server in this case)
|
||||||
|
String accessToken = tokenResponse.getAccessToken();
|
||||||
|
AccessToken token = oauth.verifyToken(accessToken);
|
||||||
|
|
||||||
|
String serializedGssCredential = (String) token.getOtherClaims().get(KerberosConstants.GSS_DELEGATION_CREDENTIAL);
|
||||||
|
Assert.assertNotNull(serializedGssCredential);
|
||||||
|
GSSCredential gssCredential = KerberosSerializationUtils.deserializeCredential(serializedGssCredential);
|
||||||
|
String ldapResponse = invokeLdap(gssCredential, token.getPreferredUsername());
|
||||||
|
Assert.assertEquals("Horatio Nelson", ldapResponse);
|
||||||
|
|
||||||
|
// Logout
|
||||||
|
oauth.openLogout();
|
||||||
|
|
||||||
|
// Remove protocolMapper
|
||||||
|
clientResource.getProtocolMappers().delete(protocolMapperId);
|
||||||
|
|
||||||
|
// Login and assert delegated credential not anymore
|
||||||
|
tokenResponse = spnegoLoginTestImpl();
|
||||||
|
accessToken = tokenResponse.getAccessToken();
|
||||||
|
token = oauth.verifyToken(accessToken);
|
||||||
|
Assert.assertFalse(token.getOtherClaims().containsKey(KerberosConstants.GSS_DELEGATION_CREDENTIAL));
|
||||||
|
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String invokeLdap(GSSCredential gssCredential, String username) throws NamingException {
|
||||||
|
Hashtable env = new Hashtable(11);
|
||||||
|
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||||
|
env.put(Context.PROVIDER_URL, "ldap://localhost:10389");
|
||||||
|
|
||||||
|
if (gssCredential != null) {
|
||||||
|
env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
|
||||||
|
env.put(Sasl.CREDENTIALS, gssCredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirContext ctx = new InitialDirContext(env);
|
||||||
|
try {
|
||||||
|
Attributes attrs = ctx.getAttributes("uid=" + username + ",ou=People,dc=keycloak,dc=org");
|
||||||
|
String cn = (String) attrs.get("cn").get();
|
||||||
|
String sn = (String) attrs.get("sn").get();
|
||||||
|
return cn + " " + sn;
|
||||||
|
} finally {
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Response spnegoLogin(String username, String password) {
|
||||||
|
String kcLoginPageLocation = oauth.getLoginFormUrl();
|
||||||
|
|
||||||
|
// Request for SPNEGO login sent with Resteasy client
|
||||||
|
spnegoSchemeFactory.setCredentials(username, password);
|
||||||
|
Response response = client.target(kcLoginPageLocation).request().get();
|
||||||
|
if (response.getStatus() == 302) {
|
||||||
|
if (response.getLocation() == null)
|
||||||
|
return response;
|
||||||
|
String uri = response.getLocation().toString();
|
||||||
|
if (uri.contains("login-actions/required-action")) {
|
||||||
|
response = client.target(uri).request().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void initHttpClient(boolean useSpnego) {
|
||||||
|
if (client != null) {
|
||||||
|
cleanupApacheHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
|
||||||
|
httpClient.getAuthSchemes().register(AuthPolicy.SPNEGO, spnegoSchemeFactory);
|
||||||
|
|
||||||
|
if (useSpnego) {
|
||||||
|
Credentials fake = new Credentials() {
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Principal getUserPrincipal() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
httpClient.getCredentialsProvider().setCredentials(
|
||||||
|
new AuthScope(null, -1, null),
|
||||||
|
fake);
|
||||||
|
}
|
||||||
|
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
|
||||||
|
client = new ResteasyClientBuilder().httpEngine(engine).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void removeAllUsers() {
|
||||||
|
RealmResource realm = testRealmResource();
|
||||||
|
List<UserRepresentation> users = realm.users().search("", 0, Integer.MAX_VALUE);
|
||||||
|
for (UserRepresentation user : users) {
|
||||||
|
if (!user.getUsername().equals(AssertEvents.DEFAULT_USERNAME)) {
|
||||||
|
realm.users().get(user.getId()).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertEquals(1, realm.users().search("", 0, Integer.MAX_VALUE).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void assertUser(String expectedUsername, String expectedEmail, String expectedFirstname,
|
||||||
|
String expectedLastname, boolean updateProfileActionExpected) {
|
||||||
|
try {
|
||||||
|
UserRepresentation user = ApiUtil.findUserByUsername(testRealmResource(), expectedUsername);
|
||||||
|
Assert.assertNotNull(user);
|
||||||
|
Assert.assertEquals(expectedEmail, user.getEmail());
|
||||||
|
Assert.assertEquals(expectedFirstname, user.getFirstName());
|
||||||
|
Assert.assertEquals(expectedLastname, user.getLastName());
|
||||||
|
|
||||||
|
if (updateProfileActionExpected) {
|
||||||
|
Assert.assertEquals(UserModel.RequiredAction.UPDATE_PROFILE.toString(),
|
||||||
|
user.getRequiredActions().iterator().next());
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue(user.getRequiredActions().isEmpty());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected OAuthClient.AccessTokenResponse assertAuthenticationSuccess(String codeUrl) throws Exception {
|
||||||
|
List<NameValuePair> pairs = URLEncodedUtils.parse(new URI(codeUrl), "UTF-8");
|
||||||
|
String code = null;
|
||||||
|
String state = null;
|
||||||
|
for (NameValuePair pair : pairs) {
|
||||||
|
if (pair.getName().equals(OAuth2Constants.CODE)) {
|
||||||
|
code = pair.getValue();
|
||||||
|
} else if (pair.getName().equals(OAuth2Constants.STATE)) {
|
||||||
|
state = pair.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertNotNull(code);
|
||||||
|
Assert.assertNotNull(state);
|
||||||
|
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||||
|
Assert.assertNotNull(response.getAccessToken());
|
||||||
|
events.clear();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void updateProviderEditMode(UserStorageProvider.EditMode editMode) {
|
||||||
|
List<ComponentRepresentation> reps = testRealmResource().components().query("test", UserStorageProvider.class.getName());
|
||||||
|
Assert.assertEquals(1, reps.size());
|
||||||
|
ComponentRepresentation kerberosProvider = reps.get(0);
|
||||||
|
kerberosProvider.getConfig().putSingle(LDAPConstants.EDIT_MODE, editMode.toString());
|
||||||
|
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmResource testRealmResource() {
|
||||||
|
return adminClient.realm("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Use LDAPTestUtils.toComponentConfig once it's migrated to new testsuite
|
||||||
|
public static MultivaluedHashMap<String, String> toComponentConfig(Map<String, String> ldapConfig) {
|
||||||
|
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
|
||||||
|
for (Map.Entry<String, String> entry : ldapConfig.entrySet()) {
|
||||||
|
config.add(entry.getKey(), entry.getValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.federation.kerberos;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.events.Details;
|
||||||
|
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||||
|
import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
|
||||||
|
import org.keycloak.testsuite.util.KerberosRule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class KerberosLdapTest extends AbstractKerberosTest {
|
||||||
|
|
||||||
|
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-ldap-connection.properties";
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommonKerberosConfig getKerberosConfig() {
|
||||||
|
return new LDAPProviderKerberosConfig(getUserStorageConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ComponentRepresentation getUserStorageConfiguration() {
|
||||||
|
Map<String,String> kerberosConfig = kerberosRule.getConfig();
|
||||||
|
MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setLastSync(0);
|
||||||
|
model.setChangedSyncPeriod(-1);
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setName("kerberos-ldap");
|
||||||
|
model.setPriority(0);
|
||||||
|
model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setConfig(config);
|
||||||
|
|
||||||
|
ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isCaseSensitiveLogin() {
|
||||||
|
return kerberosRule.isCaseSensitiveLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setKrb5ConfPath() {
|
||||||
|
kerberosRule.setKrb5ConfPath(testingClient.testing());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void spnegoLoginTest() throws Exception {
|
||||||
|
spnegoLoginTestImpl();
|
||||||
|
|
||||||
|
// Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
|
||||||
|
assertUser("hnelson", "hnelson@keycloak.org", "Horatio", "Nelson", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writableEditModeTest() throws Exception {
|
||||||
|
// Change editMode to WRITABLE
|
||||||
|
updateProviderEditMode(UserStorageProvider.EditMode.WRITABLE);
|
||||||
|
|
||||||
|
// Login with username/password from kerberos
|
||||||
|
changePasswordPage.open();
|
||||||
|
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
||||||
|
// to forward the user if kerberos isn't enabled.
|
||||||
|
//bypassPage.isCurrent();
|
||||||
|
//bypassPage.clickContinue();
|
||||||
|
loginPage.assertCurrent();
|
||||||
|
loginPage.login("jduke", "theduke");
|
||||||
|
Assert.assertTrue(changePasswordPage.isCurrent());
|
||||||
|
|
||||||
|
// Successfully change password now
|
||||||
|
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
||||||
|
Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
|
||||||
|
changePasswordPage.logout();
|
||||||
|
|
||||||
|
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
||||||
|
// to forward the user if kerberos isn't enabled.
|
||||||
|
//bypassPage.isCurrent();
|
||||||
|
//bypassPage.clickContinue();
|
||||||
|
|
||||||
|
// Login with old password doesn't work, but with new password works
|
||||||
|
loginPage.login("jduke", "theduke");
|
||||||
|
Assert.assertTrue(loginPage.isCurrent());
|
||||||
|
loginPage.login("jduke", "newPass");
|
||||||
|
changePasswordPage.assertCurrent();
|
||||||
|
changePasswordPage.logout();
|
||||||
|
|
||||||
|
// Assert SPNEGO login with the new password as mode is writable
|
||||||
|
events.clear();
|
||||||
|
Response spnegoResponse = spnegoLogin("jduke", "newPass");
|
||||||
|
org.keycloak.testsuite.Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||||
|
org.keycloak.testsuite.Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||||
|
List<UserRepresentation> users = testRealmResource().users().search("jduke", 0, 1);
|
||||||
|
String userId = users.get(0).getId();
|
||||||
|
events.expectLogin()
|
||||||
|
.client("kerberos-app")
|
||||||
|
.user(userId)
|
||||||
|
.detail(Details.USERNAME, "jduke")
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
|
String codeUrl = spnegoResponse.getLocation().toString();
|
||||||
|
|
||||||
|
assertAuthenticationSuccess(codeUrl);
|
||||||
|
|
||||||
|
// Change password back
|
||||||
|
changePasswordPage.open();
|
||||||
|
loginPage.login("jduke", "newPass");
|
||||||
|
changePasswordPage.assertCurrent();
|
||||||
|
changePasswordPage.changePassword("newPass", "theduke", "theduke");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.federation.kerberos;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||||
|
import org.keycloak.federation.kerberos.KerberosConfig;
|
||||||
|
import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.testsuite.util.KerberosRule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class KerberosStandaloneTest extends AbstractKerberosTest {
|
||||||
|
|
||||||
|
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-standalone-connection.properties";
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CommonKerberosConfig getKerberosConfig() {
|
||||||
|
return new KerberosConfig(getUserStorageConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ComponentRepresentation getUserStorageConfiguration() {
|
||||||
|
Map<String,String> kerberosConfig = kerberosRule.getConfig();
|
||||||
|
MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setLastSync(0);
|
||||||
|
model.setChangedSyncPeriod(-1);
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setName("kerberos-standalone");
|
||||||
|
model.setPriority(0);
|
||||||
|
model.setProviderId(KerberosFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setConfig(config);
|
||||||
|
|
||||||
|
ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isCaseSensitiveLogin() {
|
||||||
|
return kerberosRule.isCaseSensitiveLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setKrb5ConfPath() {
|
||||||
|
kerberosRule.setKrb5ConfPath(testingClient.testing());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void spnegoLoginTest() throws Exception {
|
||||||
|
spnegoLoginTestImpl();
|
||||||
|
|
||||||
|
// Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
|
||||||
|
assertUser("hnelson", "hnelson@keycloak.org", null, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateProfileEnabledTest() throws Exception {
|
||||||
|
// Switch updateProfileOnFirstLogin to on
|
||||||
|
List<ComponentRepresentation> reps = testRealmResource().components().query("test", UserStorageProvider.class.getName());
|
||||||
|
org.keycloak.testsuite.Assert.assertEquals(1, reps.size());
|
||||||
|
ComponentRepresentation kerberosProvider = reps.get(0);
|
||||||
|
kerberosProvider.getConfig().putSingle(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
|
||||||
|
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||||
|
|
||||||
|
// Assert update profile page is displayed
|
||||||
|
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
||||||
|
Assert.assertEquals(200, spnegoResponse.getStatus());
|
||||||
|
String responseText = spnegoResponse.readEntity(String.class);
|
||||||
|
Assert.assertTrue(responseText.contains("You need to update your user profile to activate your account."));
|
||||||
|
Assert.assertTrue(responseText.contains("hnelson@keycloak.org"));
|
||||||
|
spnegoResponse.close();
|
||||||
|
|
||||||
|
// Assert user was imported and has required action on him
|
||||||
|
assertUser("hnelson", "hnelson@keycloak.org", null, null, true);
|
||||||
|
|
||||||
|
// Switch updateProfileOnFirstLogin to off
|
||||||
|
kerberosProvider.getConfig().putSingle(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "false");
|
||||||
|
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEYCLOAK-3451
|
||||||
|
*
|
||||||
|
* Test that if there is no User Storage Provider that can handle kerberos we can still login
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void noProvider() throws Exception {
|
||||||
|
List<ComponentRepresentation> reps = testRealmResource().components().query("test", UserStorageProvider.class.getName());
|
||||||
|
org.keycloak.testsuite.Assert.assertEquals(1, reps.size());
|
||||||
|
ComponentRepresentation kerberosProvider = reps.get(0);
|
||||||
|
testRealmResource().components().component(kerberosProvider.getId()).remove();
|
||||||
|
|
||||||
|
/*
|
||||||
|
To do this we do a valid kerberos login. The authenticator will obtain a valid token, but there will
|
||||||
|
be no user storage provider that can process it. This means we should be on the login page.
|
||||||
|
We do this through a JAX-RS client request. We extract the action URL from the login page, and stuff it
|
||||||
|
into selenium then just perform a regular login.
|
||||||
|
*/
|
||||||
|
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
||||||
|
String context = spnegoResponse.readEntity(String.class);
|
||||||
|
spnegoResponse.close();
|
||||||
|
Pattern pattern = Pattern.compile("action=\"([^\"]+)\"");
|
||||||
|
Matcher m = pattern.matcher(context);
|
||||||
|
Assert.assertTrue(m.find());
|
||||||
|
String url = m.group(1);
|
||||||
|
driver.navigate().to(url);
|
||||||
|
Assert.assertTrue(loginPage.isCurrent());
|
||||||
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
String pageSource = driver.getPageSource();
|
||||||
|
assertAuthenticationSuccess(driver.getCurrentUrl());
|
||||||
|
|
||||||
|
events.clear();
|
||||||
|
testRealmResource().components().add(kerberosProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.testsuite.adapter.federation;
|
package org.keycloak.testsuite.federation.kerberos;
|
||||||
|
|
||||||
import org.apache.http.auth.AuthScheme;
|
import org.apache.http.auth.AuthScheme;
|
||||||
import org.apache.http.auth.Credentials;
|
import org.apache.http.auth.Credentials;
|
|
@ -1,20 +0,0 @@
|
||||||
<!--
|
|
||||||
~ Copyright 2016 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<Context path="/kerberos-portal">
|
|
||||||
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
|
||||||
</Context>
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright 2016 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
|
||||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
|
||||||
<Get name="securityHandler">
|
|
||||||
<Set name="authenticator">
|
|
||||||
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
|
|
||||||
</New>
|
|
||||||
</Set>
|
|
||||||
</Get>
|
|
||||||
</Configure>
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"realm" : "test",
|
|
||||||
"resource" : "kerberos-app",
|
|
||||||
"auth-server-url" : "/auth",
|
|
||||||
"ssl-required" : "external",
|
|
||||||
"credentials" : {
|
|
||||||
"secret": "password"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"realm": "test",
|
|
||||||
"resource": "kerberos-app",
|
|
||||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
|
||||||
"auth-server-url": "http://localhost:8081/auth",
|
|
||||||
"ssl-required" : "external",
|
|
||||||
"credentials": {
|
|
||||||
"secret": "password"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright 2016 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
|
||||||
version="3.0">
|
|
||||||
|
|
||||||
<module-name>kerberos-portal</module-name>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>Servlet</servlet-name>
|
|
||||||
<servlet-class>org.keycloak.testsuite.adapter.servlet.KerberosCredDelegServlet</servlet-class>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>Servlet</servlet-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
|
|
||||||
<security-constraint>
|
|
||||||
<web-resource-collection>
|
|
||||||
<web-resource-name>Users</web-resource-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</web-resource-collection>
|
|
||||||
<auth-constraint>
|
|
||||||
<role-name>user</role-name>
|
|
||||||
</auth-constraint>
|
|
||||||
</security-constraint>
|
|
||||||
|
|
||||||
<login-config>
|
|
||||||
<auth-method>KEYCLOAK</auth-method>
|
|
||||||
<realm-name>test</realm-name>
|
|
||||||
</login-config>
|
|
||||||
|
|
||||||
<security-role>
|
|
||||||
<role-name>admin</role-name>
|
|
||||||
</security-role>
|
|
||||||
<security-role>
|
|
||||||
<role-name>user</role-name>
|
|
||||||
</security-role>
|
|
||||||
</web-app>
|
|
|
@ -37,7 +37,8 @@
|
||||||
"adminUrl": "/kerberos-portal/logout",
|
"adminUrl": "/kerberos-portal/logout",
|
||||||
"baseUrl": "/kerberos-portal",
|
"baseUrl": "/kerberos-portal",
|
||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"/kerberos-portal/*"
|
"/kerberos-portal/*",
|
||||||
|
"/auth/realms/master/app/*"
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password"
|
||||||
}
|
}
|
|
@ -1,398 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation;
|
|
||||||
|
|
||||||
import org.apache.http.auth.AuthScope;
|
|
||||||
import org.apache.http.auth.Credentials;
|
|
||||||
import org.apache.http.client.params.AuthPolicy;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.adapters.HttpClientBuilder;
|
|
||||||
import org.keycloak.authentication.authenticators.browser.SpnegoAuthenticator;
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.events.Details;
|
|
||||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.LDAPConstants;
|
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
|
||||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
|
||||||
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
|
||||||
import org.keycloak.testsuite.pages.BypassKerberosPage;
|
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
|
||||||
import org.openqa.selenium.WebDriver;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public abstract class AbstractKerberosTest {
|
|
||||||
|
|
||||||
protected String KERBEROS_APP_URL = "http://localhost:8081/kerberos-portal";
|
|
||||||
|
|
||||||
protected KeycloakSPNegoSchemeFactory spnegoSchemeFactory;
|
|
||||||
protected ResteasyClient client;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected OAuthClient oauth;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected WebDriver driver;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected LoginPage loginPage;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected BypassKerberosPage bypassPage;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected AccountPasswordPage changePasswordPage;
|
|
||||||
|
|
||||||
protected abstract CommonKerberosConfig getKerberosConfig();
|
|
||||||
protected abstract KeycloakRule getKeycloakRule();
|
|
||||||
protected abstract AssertEvents getAssertEvents();
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
CommonKerberosConfig kerberosConfig = getKerberosConfig();
|
|
||||||
spnegoSchemeFactory = new KeycloakSPNegoSchemeFactory(kerberosConfig);
|
|
||||||
initHttpClient(true);
|
|
||||||
removeAllUsers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() {
|
|
||||||
client.close();
|
|
||||||
client = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void spnegoNotAvailableTest() throws Exception {
|
|
||||||
initHttpClient(false);
|
|
||||||
|
|
||||||
SpnegoAuthenticator.bypassChallengeJavascript = true;
|
|
||||||
driver.navigate().to(KERBEROS_APP_URL);
|
|
||||||
String kcLoginPageLocation = driver.getCurrentUrl();
|
|
||||||
|
|
||||||
Response response = client.target(kcLoginPageLocation).request().get();
|
|
||||||
Assert.assertEquals(401, response.getStatus());
|
|
||||||
Assert.assertEquals(KerberosConstants.NEGOTIATE, response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
|
|
||||||
String responseText = response.readEntity(String.class);
|
|
||||||
responseText.contains("Log in to test");
|
|
||||||
response.close();
|
|
||||||
SpnegoAuthenticator.bypassChallengeJavascript = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void spnegoLoginTestImpl() throws Exception {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
AssertEvents events = getAssertEvents();
|
|
||||||
|
|
||||||
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
|
||||||
Assert.assertEquals(302, spnegoResponse.getStatus());
|
|
||||||
|
|
||||||
events.expectLogin()
|
|
||||||
.client("kerberos-app")
|
|
||||||
.user(keycloakRule.getUser("test", "hnelson").getId())
|
|
||||||
.detail(Details.REDIRECT_URI, KERBEROS_APP_URL)
|
|
||||||
//.detail(Details.AUTH_METHOD, "spnego")
|
|
||||||
.detail(Details.USERNAME, "hnelson")
|
|
||||||
.assertEvent();
|
|
||||||
|
|
||||||
String location = spnegoResponse.getLocation().toString();
|
|
||||||
driver.navigate().to(location);
|
|
||||||
|
|
||||||
String pageSource = driver.getPageSource();
|
|
||||||
Assert.assertTrue(pageSource.contains("Kerberos Test") && pageSource.contains("Kerberos servlet secured content"));
|
|
||||||
|
|
||||||
spnegoResponse.close();
|
|
||||||
events.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// KEYCLOAK-2102
|
|
||||||
@Test
|
|
||||||
public void spnegoCaseInsensitiveTest() throws Exception {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
AssertEvents events = getAssertEvents();
|
|
||||||
|
|
||||||
Response spnegoResponse = spnegoLogin("MyDuke", "theduke");
|
|
||||||
Assert.assertEquals(302, spnegoResponse.getStatus());
|
|
||||||
|
|
||||||
events.expectLogin()
|
|
||||||
.client("kerberos-app")
|
|
||||||
.user(keycloakRule.getUser("test", "myduke").getId())
|
|
||||||
.detail(Details.REDIRECT_URI, KERBEROS_APP_URL)
|
|
||||||
//.detail(Details.AUTH_METHOD, "spnego")
|
|
||||||
.detail(Details.USERNAME, "myduke")
|
|
||||||
.assertEvent();
|
|
||||||
|
|
||||||
String location = spnegoResponse.getLocation().toString();
|
|
||||||
driver.navigate().to(location);
|
|
||||||
|
|
||||||
String pageSource = driver.getPageSource();
|
|
||||||
Assert.assertTrue(pageSource.contains("Kerberos Test") && pageSource.contains("Kerberos servlet secured content"));
|
|
||||||
|
|
||||||
spnegoResponse.close();
|
|
||||||
events.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void usernamePasswordLoginTest() throws Exception {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
AssertEvents events = getAssertEvents();
|
|
||||||
|
|
||||||
// Change editMode to READ_ONLY
|
|
||||||
updateProviderEditMode(UserStorageProvider.EditMode.READ_ONLY);
|
|
||||||
|
|
||||||
// Login with username/password from kerberos
|
|
||||||
changePasswordPage.open();
|
|
||||||
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
|
||||||
// to forward the user if kerberos isn't enabled.
|
|
||||||
//bypassPage.isCurrent();
|
|
||||||
//bypassPage.clickContinue();
|
|
||||||
loginPage.assertCurrent();
|
|
||||||
loginPage.login("jduke", "theduke");
|
|
||||||
changePasswordPage.assertCurrent();
|
|
||||||
|
|
||||||
// Bad existing password
|
|
||||||
changePasswordPage.changePassword("theduke-invalid", "newPass", "newPass");
|
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Invalid existing password."));
|
|
||||||
|
|
||||||
// Change password is not possible as editMode is READ_ONLY
|
|
||||||
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
|
||||||
Assert.assertTrue(driver.getPageSource().contains("You can't update your password as your account is read only"));
|
|
||||||
|
|
||||||
// Change editMode to UNSYNCED
|
|
||||||
updateProviderEditMode(UserStorageProvider.EditMode.UNSYNCED);
|
|
||||||
|
|
||||||
// Successfully change password now
|
|
||||||
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
|
|
||||||
changePasswordPage.logout();
|
|
||||||
|
|
||||||
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
|
||||||
// to forward the user if kerberos isn't enabled.
|
|
||||||
//bypassPage.isCurrent();
|
|
||||||
//bypassPage.clickContinue();
|
|
||||||
// Login with old password doesn't work, but with new password works
|
|
||||||
loginPage.login("jduke", "theduke");
|
|
||||||
loginPage.assertCurrent();
|
|
||||||
loginPage.login("jduke", "newPass");
|
|
||||||
changePasswordPage.assertCurrent();
|
|
||||||
changePasswordPage.logout();
|
|
||||||
|
|
||||||
// Assert SPNEGO login still with the old password as mode is unsynced
|
|
||||||
events.clear();
|
|
||||||
Response spnegoResponse = spnegoLogin("jduke", "theduke");
|
|
||||||
Assert.assertEquals(302, spnegoResponse.getStatus());
|
|
||||||
String redirect = spnegoResponse.getLocation().toString();
|
|
||||||
events.expectLogin()
|
|
||||||
.client("kerberos-app")
|
|
||||||
.user(keycloakRule.getUser("test", "jduke").getId())
|
|
||||||
.detail(Details.REDIRECT_URI, KERBEROS_APP_URL)
|
|
||||||
//.detail(Details.AUTH_METHOD, "spnego")
|
|
||||||
.detail(Details.USERNAME, "jduke")
|
|
||||||
.assertEvent();
|
|
||||||
spnegoResponse.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void credentialDelegationTest() throws Exception {
|
|
||||||
// Add kerberos delegation credential mapper
|
|
||||||
getKeycloakRule().update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
|
||||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
|
||||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
|
||||||
true, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
|
||||||
true, false);
|
|
||||||
|
|
||||||
ClientModel kerberosApp = appRealm.getClientByClientId("kerberos-app");
|
|
||||||
kerberosApp.addProtocolMapper(protocolMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// SPNEGO login
|
|
||||||
spnegoLoginTestImpl();
|
|
||||||
|
|
||||||
// Assert servlet authenticated to LDAP with delegated credential
|
|
||||||
driver.navigate().to(KERBEROS_APP_URL + KerberosCredDelegServlet.CRED_DELEG_TEST_PATH);
|
|
||||||
String pageSource = driver.getPageSource();
|
|
||||||
Assert.assertTrue(pageSource.contains("LDAP Data: Horatio Nelson"));
|
|
||||||
|
|
||||||
// Remove kerberos delegation credential mapper
|
|
||||||
getKeycloakRule().update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
ClientModel kerberosApp = appRealm.getClientByClientId("kerberos-app");
|
|
||||||
ProtocolMapperModel toRemove = kerberosApp.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
|
|
||||||
kerberosApp.removeProtocolMapper(toRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear driver and login again. I can't invoke LDAP now as GSS Credential is not in accessToken
|
|
||||||
driver.manage().deleteAllCookies();
|
|
||||||
spnegoLoginTestImpl();
|
|
||||||
driver.navigate().to(KERBEROS_APP_URL + KerberosCredDelegServlet.CRED_DELEG_TEST_PATH);
|
|
||||||
pageSource = driver.getPageSource();
|
|
||||||
Assert.assertFalse(pageSource.contains("LDAP Data: Horatio Nelson"));
|
|
||||||
Assert.assertTrue(pageSource.contains("LDAP Data: ERROR"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected Response spnegoLogin(String username, String password) {
|
|
||||||
SpnegoAuthenticator.bypassChallengeJavascript = true;
|
|
||||||
driver.navigate().to(KERBEROS_APP_URL);
|
|
||||||
String kcLoginPageLocation = driver.getCurrentUrl();
|
|
||||||
|
|
||||||
// Request for SPNEGO login sent with Resteasy client
|
|
||||||
spnegoSchemeFactory.setCredentials(username, password);
|
|
||||||
Response response = client.target(kcLoginPageLocation).request().get();
|
|
||||||
SpnegoAuthenticator.bypassChallengeJavascript = false;
|
|
||||||
if (response.getStatus() == 302) {
|
|
||||||
if (response.getLocation() == null) return response;
|
|
||||||
String uri = response.getLocation().toString();
|
|
||||||
if (uri.contains("login-actions/required-action")) {
|
|
||||||
response = client.target(uri).request().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void initHttpClient(boolean useSpnego) {
|
|
||||||
if (client != null) {
|
|
||||||
after();
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
|
|
||||||
httpClient.getAuthSchemes().register(AuthPolicy.SPNEGO, spnegoSchemeFactory);
|
|
||||||
|
|
||||||
if (useSpnego) {
|
|
||||||
Credentials fake = new Credentials() {
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Principal getUserPrincipal() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
httpClient.getCredentialsProvider().setCredentials(
|
|
||||||
new AuthScope(null, -1, null),
|
|
||||||
fake);
|
|
||||||
}
|
|
||||||
|
|
||||||
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
|
|
||||||
client = new ResteasyClientBuilder().httpEngine(engine).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void removeAllUsers() {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmManager manager = new RealmManager(session);
|
|
||||||
|
|
||||||
RealmModel appRealm = manager.getRealm("test");
|
|
||||||
List<UserModel> users = session.users().getUsers(appRealm, true);
|
|
||||||
for (UserModel user : users) {
|
|
||||||
if (!user.getUsername().equals(AssertEvents.DEFAULT_USERNAME)) {
|
|
||||||
session.users().removeUser(appRealm, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.assertEquals(1, session.users().getUsers(appRealm, true).size());
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void assertUser(String expectedUsername, String expectedEmail, String expectedFirstname, String expectedLastname, boolean updateProfileActionExpected) {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmManager manager = new RealmManager(session);
|
|
||||||
RealmModel appRealm = manager.getRealm("test");
|
|
||||||
|
|
||||||
UserModel user = session.users().getUserByUsername(expectedUsername, appRealm);
|
|
||||||
Assert.assertNotNull(user);
|
|
||||||
Assert.assertEquals(user.getEmail(), expectedEmail);
|
|
||||||
Assert.assertEquals(user.getFirstName(), expectedFirstname);
|
|
||||||
Assert.assertEquals(user.getLastName(), expectedLastname);
|
|
||||||
|
|
||||||
if (updateProfileActionExpected) {
|
|
||||||
Assert.assertEquals(UserModel.RequiredAction.UPDATE_PROFILE.toString(), user.getRequiredActions().iterator().next());
|
|
||||||
} else {
|
|
||||||
Assert.assertTrue(user.getRequiredActions().isEmpty());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void updateProviderEditMode(UserStorageProvider.EditMode editMode) {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
ComponentModel kerberosProviderModel = realm.getComponents(realm.getId(), UserStorageProvider.class.getName()).get(0);
|
|
||||||
kerberosProviderModel.getConfig().putSingle(LDAPConstants.EDIT_MODE, editMode.toString());
|
|
||||||
realm.updateComponent(kerberosProviderModel);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation;
|
|
||||||
|
|
||||||
import org.ietf.jgss.GSSCredential;
|
|
||||||
import org.keycloak.KeycloakPrincipal;
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
|
||||||
import org.keycloak.common.util.KerberosSerializationUtils;
|
|
||||||
|
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.directory.InitialDirContext;
|
|
||||||
import javax.security.sasl.Sasl;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class KerberosCredDelegServlet extends HttpServlet {
|
|
||||||
|
|
||||||
public static final String CRED_DELEG_TEST_PATH = "/cred-deleg-test";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
||||||
String ldapData = null;
|
|
||||||
|
|
||||||
if (req.getRequestURI().endsWith(CRED_DELEG_TEST_PATH)) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Retrieve kerberos credential from accessToken and deserialize it
|
|
||||||
KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) req.getUserPrincipal();
|
|
||||||
String serializedGssCredential = (String) keycloakPrincipal.getKeycloakSecurityContext().getToken().getOtherClaims().get(KerberosConstants.GSS_DELEGATION_CREDENTIAL);
|
|
||||||
GSSCredential gssCredential = KerberosSerializationUtils.deserializeCredential(serializedGssCredential);
|
|
||||||
|
|
||||||
// First try to invoke without gssCredential. It should fail
|
|
||||||
try {
|
|
||||||
invokeLdap(null);
|
|
||||||
throw new RuntimeException("Not expected to authenticate to LDAP without credential");
|
|
||||||
} catch (NamingException nse) {
|
|
||||||
System.out.println("Expected exception: " + nse.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
ldapData = invokeLdap(gssCredential);
|
|
||||||
} catch (KerberosSerializationUtils.KerberosSerializationException kse) {
|
|
||||||
System.err.println("KerberosSerializationUtils.KerberosSerializationException: " + kse.getMessage());
|
|
||||||
ldapData = "ERROR";
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.setContentType("text/html");
|
|
||||||
PrintWriter pw = resp.getWriter();
|
|
||||||
pw.printf("<html><head><title>%s</title></head><body>", "Kerberos Test");
|
|
||||||
pw.printf("Kerberos servlet secured content<br>");
|
|
||||||
|
|
||||||
if (ldapData != null) {
|
|
||||||
pw.printf("LDAP Data: " + ldapData + "<br>");
|
|
||||||
}
|
|
||||||
|
|
||||||
pw.print("</body></html>");
|
|
||||||
pw.flush();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String invokeLdap(GSSCredential gssCredential) throws NamingException {
|
|
||||||
Hashtable env = new Hashtable(11);
|
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
|
||||||
env.put(Context.PROVIDER_URL, "ldap://localhost:10389");
|
|
||||||
|
|
||||||
if (gssCredential != null) {
|
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
|
|
||||||
env.put(Sasl.CREDENTIALS, gssCredential);
|
|
||||||
}
|
|
||||||
|
|
||||||
DirContext ctx = new InitialDirContext(env);
|
|
||||||
try {
|
|
||||||
Attributes attrs = ctx.getAttributes("uid=hnelson,ou=People,dc=keycloak,dc=org");
|
|
||||||
String cn = (String) attrs.get("cn").get();
|
|
||||||
String sn = (String) attrs.get("sn").get();
|
|
||||||
return cn + " " + sn;
|
|
||||||
} finally {
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.FixMethodOrder;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.RuleChain;
|
|
||||||
import org.junit.rules.TestRule;
|
|
||||||
import org.junit.runners.MethodSorters;
|
|
||||||
import org.keycloak.authentication.authenticators.browser.SpnegoAuthenticator;
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
|
||||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
|
||||||
import org.keycloak.federation.kerberos.KerberosConfig;
|
|
||||||
import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
|
||||||
import org.keycloak.testsuite.federation.storage.ldap.LDAPTestUtils;
|
|
||||||
import org.keycloak.testsuite.rule.KerberosRule;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
|
||||||
import org.keycloak.utils.CredentialHelper;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test of KerberosFederationProvider (Kerberos not backed by LDAP)
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
|
||||||
public class KerberosStandaloneTest extends AbstractKerberosTest {
|
|
||||||
|
|
||||||
private static final String PROVIDER_CONFIG_LOCATION = "kerberos/kerberos-standalone-connection.properties";
|
|
||||||
|
|
||||||
private static UserStorageProviderModel kerberosModel;
|
|
||||||
|
|
||||||
private static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
|
||||||
|
|
||||||
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
|
|
||||||
CredentialHelper.setAlternativeCredential(manager.getSession(), CredentialRepresentation.KERBEROS, appRealm);
|
|
||||||
URL url = getClass().getResource("/kerberos-test/kerberos-app-keycloak.json");
|
|
||||||
keycloakRule.createApplicationDeployment()
|
|
||||||
.name("kerberos-portal").contextPath("/kerberos-portal")
|
|
||||||
.servletClass(KerberosCredDelegServlet.class).adapterConfigPath(url.getPath())
|
|
||||||
.role("user").deployApplication();
|
|
||||||
|
|
||||||
|
|
||||||
Map<String,String> kerberosConfig = kerberosRule.getConfig();
|
|
||||||
MultivaluedHashMap<String, String> config = LDAPTestUtils.toComponentConfig(kerberosConfig);
|
|
||||||
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setLastSync(0);
|
|
||||||
model.setChangedSyncPeriod(-1);
|
|
||||||
model.setFullSyncPeriod(-1);
|
|
||||||
model.setName("kerberos-standalone");
|
|
||||||
model.setPriority(0);
|
|
||||||
model.setProviderId(KerberosFederationProviderFactory.PROVIDER_NAME);
|
|
||||||
model.setConfig(config);
|
|
||||||
|
|
||||||
kerberosModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
|
||||||
}
|
|
||||||
|
|
||||||
}) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void importRealm() {
|
|
||||||
server.importRealm(getClass().getResourceAsStream("/kerberos-test/kerberosrealm.json"));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static TestRule chain = RuleChain
|
|
||||||
.outerRule(kerberosRule)
|
|
||||||
.around(keycloakRule);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public WebRule webRule = new WebRule(this);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CommonKerberosConfig getKerberosConfig() {
|
|
||||||
return new KerberosConfig(kerberosModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected KeycloakRule getKeycloakRule() {
|
|
||||||
return keycloakRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AssertEvents getAssertEvents() {
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void spnegoLoginTest() throws Exception {
|
|
||||||
spnegoLoginTestImpl();
|
|
||||||
|
|
||||||
// Assert user was imported and hasn't any required action on him
|
|
||||||
assertUser("hnelson", "hnelson@keycloak.org", null, null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
public void spnegoCaseInsensitiveTest() throws Exception {
|
|
||||||
super.spnegoCaseInsensitiveTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
public void credentialDelegationTest() throws Exception {
|
|
||||||
super.credentialDelegationTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
public void usernamePasswordLoginTest() throws Exception {
|
|
||||||
super.usernamePasswordLoginTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateProfileEnabledTest() throws Exception {
|
|
||||||
// Switch updateProfileOnFirstLogin to on
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
UserStorageProviderModel kerberosProviderModel = realm.getUserStorageProviders().get(0);
|
|
||||||
kerberosProviderModel.getConfig().putSingle(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
|
|
||||||
realm.updateComponent(kerberosProviderModel);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert update profile page is displayed
|
|
||||||
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
|
||||||
Assert.assertEquals(200, spnegoResponse.getStatus());
|
|
||||||
String responseText = spnegoResponse.readEntity(String.class);
|
|
||||||
Assert.assertTrue(responseText.contains("You need to update your user profile to activate your account."));
|
|
||||||
Assert.assertTrue(responseText.contains("hnelson@keycloak.org"));
|
|
||||||
spnegoResponse.close();
|
|
||||||
|
|
||||||
// Assert user was imported and has required action on him
|
|
||||||
assertUser("hnelson", "hnelson@keycloak.org", null, null, true);
|
|
||||||
|
|
||||||
// Switch updateProfileOnFirstLogin to off
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
UserStorageProviderModel kerberosProviderModel = realm.getUserStorageProviders().get(0);
|
|
||||||
kerberosProviderModel.getConfig().putSingle(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "false");
|
|
||||||
realm.updateComponent(kerberosProviderModel);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KEYCLOAK-3451
|
|
||||||
*
|
|
||||||
* Test that if there is no User Storage Provider that can handle kerberos we can still login
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void noProvider() throws Exception {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
realm.removeComponent(kerberosModel);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
To do this we do a valid kerberos login. The authenticator will obtain a valid token, but there will
|
|
||||||
be no user storage provider that can process it. This means we should be on the login page.
|
|
||||||
We do this through a JAX-RS client request. We extract the action URL from the login page, and stuff it
|
|
||||||
into selenium then just perform a regular login.
|
|
||||||
*/
|
|
||||||
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
|
||||||
String context = spnegoResponse.readEntity(String.class);
|
|
||||||
spnegoResponse.close();
|
|
||||||
Pattern pattern = Pattern.compile("action=\"([^\"]+)\"");
|
|
||||||
Matcher m = pattern.matcher(context);
|
|
||||||
Assert.assertTrue(m.find());
|
|
||||||
String url = m.group(1);
|
|
||||||
driver.navigate().to(url);
|
|
||||||
Assert.assertTrue(loginPage.isCurrent());
|
|
||||||
loginPage.login("test-user@localhost", "password");
|
|
||||||
String pageSource = driver.getPageSource();
|
|
||||||
Assert.assertTrue(pageSource.contains("Kerberos Test") && pageSource.contains("Kerberos servlet secured content"));
|
|
||||||
|
|
||||||
|
|
||||||
events.clear();
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
realm.addComponentModel(kerberosModel);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation;
|
|
||||||
|
|
||||||
import org.apache.http.auth.AuthScheme;
|
|
||||||
import org.apache.http.auth.Credentials;
|
|
||||||
import org.apache.http.impl.auth.SPNegoScheme;
|
|
||||||
import org.apache.http.impl.auth.SPNegoSchemeFactory;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
import org.ietf.jgss.GSSContext;
|
|
||||||
import org.ietf.jgss.GSSException;
|
|
||||||
import org.ietf.jgss.GSSManager;
|
|
||||||
import org.ietf.jgss.GSSName;
|
|
||||||
import org.ietf.jgss.Oid;
|
|
||||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
|
||||||
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
|
||||||
import java.security.PrivilegedExceptionAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Usable for testing only. Username and password are shared for the whole factory
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
|
|
||||||
|
|
||||||
private final CommonKerberosConfig kerberosConfig;
|
|
||||||
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
|
|
||||||
public KeycloakSPNegoSchemeFactory(CommonKerberosConfig kerberosConfig) {
|
|
||||||
super(true, false);
|
|
||||||
this.kerberosConfig = kerberosConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setCredentials(String username, String password) {
|
|
||||||
this.username = username;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthScheme newInstance(HttpParams params) {
|
|
||||||
return new KeycloakSPNegoScheme(isStripPort(), isUseCanonicalHostname());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class KeycloakSPNegoScheme extends SPNegoScheme {
|
|
||||||
|
|
||||||
public KeycloakSPNegoScheme(boolean stripPort, boolean useCanonicalHostname) {
|
|
||||||
super(stripPort, useCanonicalHostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer, Credentials credentials) throws GSSException {
|
|
||||||
KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
|
|
||||||
try {
|
|
||||||
Subject clientSubject = authenticator.authenticateSubject(username, password);
|
|
||||||
|
|
||||||
ByteArrayHolder holder = Subject.doAs(clientSubject, new ClientAcceptSecContext(input, oid, authServer));
|
|
||||||
|
|
||||||
return holder.bytes;
|
|
||||||
} catch (Exception le) {
|
|
||||||
throw new RuntimeException(le);
|
|
||||||
} finally {
|
|
||||||
authenticator.logoutSubject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class ClientAcceptSecContext implements PrivilegedExceptionAction<ByteArrayHolder> {
|
|
||||||
|
|
||||||
private final byte[] input;
|
|
||||||
private final Oid oid;
|
|
||||||
private final String authServer;
|
|
||||||
|
|
||||||
public ClientAcceptSecContext(byte[] input, Oid oid, String authServer) {
|
|
||||||
this.input = input;
|
|
||||||
this.oid = oid;
|
|
||||||
this.authServer = authServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ByteArrayHolder run() throws Exception {
|
|
||||||
byte[] token = input;
|
|
||||||
if (token == null) {
|
|
||||||
token = new byte[0];
|
|
||||||
}
|
|
||||||
GSSManager manager = getManager();
|
|
||||||
GSSName serverName = manager.createName("HTTP/" + authServer + "@" + kerberosConfig.getKerberosRealm(), null);
|
|
||||||
GSSContext gssContext = manager.createContext(
|
|
||||||
serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
|
|
||||||
gssContext.requestMutualAuth(true);
|
|
||||||
gssContext.requestCredDeleg(true);
|
|
||||||
byte[] outputToken = gssContext.initSecContext(token, 0, token.length);
|
|
||||||
|
|
||||||
ByteArrayHolder result = new ByteArrayHolder();
|
|
||||||
result.bytes = outputToken;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class ByteArrayHolder {
|
|
||||||
private byte[] bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -84,9 +84,9 @@ public class LDAPTestConfiguration {
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
|
DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
|
DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
|
DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
|
||||||
URL keytabUrl = LDAPTestConfiguration.class.getResource("/kerberos/http.keytab");
|
// URL keytabUrl = LDAPTestConfiguration.class.getResource("/kerberos/http.keytab");
|
||||||
String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
|
// String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
|
// DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
|
||||||
DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
|
DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
|
DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
|
||||||
DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
|
DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation.storage.ldap;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.RuleChain;
|
|
||||||
import org.junit.rules.TestRule;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
|
||||||
import org.keycloak.events.Details;
|
|
||||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
|
||||||
import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
|
||||||
import org.keycloak.testsuite.federation.AbstractKerberosTest;
|
|
||||||
import org.keycloak.testsuite.federation.KerberosCredDelegServlet;
|
|
||||||
import org.keycloak.testsuite.rule.KerberosRule;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
|
||||||
import org.keycloak.utils.CredentialHelper;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test of LDAPFederationProvider (Kerberos backed by LDAP)
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class KerberosLdapTest extends AbstractKerberosTest {
|
|
||||||
|
|
||||||
private static final String PROVIDER_CONFIG_LOCATION = "kerberos/kerberos-ldap-connection.properties";
|
|
||||||
|
|
||||||
private static UserStorageProviderModel ldapModel = null;
|
|
||||||
|
|
||||||
private static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
|
||||||
|
|
||||||
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
CredentialHelper.setAlternativeCredential(manager.getSession(), CredentialRepresentation.KERBEROS, appRealm);
|
|
||||||
URL url = getClass().getResource("/kerberos-test/kerberos-app-keycloak.json");
|
|
||||||
keycloakRule.createApplicationDeployment()
|
|
||||||
.name("kerberos-portal").contextPath("/kerberos-portal")
|
|
||||||
.servletClass(KerberosCredDelegServlet.class).adapterConfigPath(url.getPath())
|
|
||||||
.role("user").deployApplication();
|
|
||||||
|
|
||||||
MultivaluedHashMap<String, String> ldapConfig = LDAPTestUtils.toComponentConfig(kerberosRule.getConfig());
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setLastSync(0);
|
|
||||||
model.setChangedSyncPeriod(-1);
|
|
||||||
model.setFullSyncPeriod(-1);
|
|
||||||
model.setName("test-ldap");
|
|
||||||
model.setPriority(0);
|
|
||||||
model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME);
|
|
||||||
model.setConfig(ldapConfig);
|
|
||||||
|
|
||||||
ldapModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void importRealm() {
|
|
||||||
server.importRealm(getClass().getResourceAsStream("/kerberos-test/kerberosrealm.json"));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static TestRule chain = RuleChain
|
|
||||||
.outerRule(kerberosRule)
|
|
||||||
.around(keycloakRule);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public WebRule webRule = new WebRule(this);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CommonKerberosConfig getKerberosConfig() {
|
|
||||||
return new LDAPProviderKerberosConfig(ldapModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected KeycloakRule getKeycloakRule() {
|
|
||||||
return keycloakRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AssertEvents getAssertEvents() {
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void spnegoLoginTest() throws Exception {
|
|
||||||
spnegoLoginTestImpl();
|
|
||||||
|
|
||||||
// Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
|
|
||||||
assertUser("hnelson", "hnelson@keycloak.org", "Horatio", "Nelson", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Override
|
|
||||||
public void usernamePasswordLoginTest() throws Exception {
|
|
||||||
super.usernamePasswordLoginTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void writableEditModeTest() throws Exception {
|
|
||||||
KeycloakRule keycloakRule = getKeycloakRule();
|
|
||||||
AssertEvents events = getAssertEvents();
|
|
||||||
|
|
||||||
// Change editMode to WRITABLE
|
|
||||||
updateProviderEditMode(UserStorageProvider.EditMode.WRITABLE);
|
|
||||||
|
|
||||||
// Login with username/password from kerberos
|
|
||||||
changePasswordPage.open();
|
|
||||||
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
|
||||||
// to forward the user if kerberos isn't enabled.
|
|
||||||
//bypassPage.isCurrent();
|
|
||||||
//bypassPage.clickContinue();
|
|
||||||
loginPage.assertCurrent();
|
|
||||||
loginPage.login("jduke", "theduke");
|
|
||||||
changePasswordPage.assertCurrent();
|
|
||||||
|
|
||||||
// Successfully change password now
|
|
||||||
changePasswordPage.changePassword("theduke", "newPass", "newPass");
|
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
|
|
||||||
changePasswordPage.logout();
|
|
||||||
|
|
||||||
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
|
||||||
// to forward the user if kerberos isn't enabled.
|
|
||||||
//bypassPage.isCurrent();
|
|
||||||
//bypassPage.clickContinue();
|
|
||||||
|
|
||||||
// Login with old password doesn't work, but with new password works
|
|
||||||
loginPage.login("jduke", "theduke");
|
|
||||||
loginPage.assertCurrent();
|
|
||||||
loginPage.login("jduke", "newPass");
|
|
||||||
changePasswordPage.assertCurrent();
|
|
||||||
changePasswordPage.logout();
|
|
||||||
|
|
||||||
// Assert SPNEGO login with the new password as mode is writable
|
|
||||||
events.clear();
|
|
||||||
Response spnegoResponse = spnegoLogin("jduke", "newPass");
|
|
||||||
Assert.assertEquals(302, spnegoResponse.getStatus());
|
|
||||||
events.expectLogin()
|
|
||||||
.client("kerberos-app")
|
|
||||||
.user(keycloakRule.getUser("test", "jduke").getId())
|
|
||||||
.detail(Details.REDIRECT_URI, KERBEROS_APP_URL)
|
|
||||||
//.detail(Details.AUTH_METHOD, "spnego")
|
|
||||||
.detail(Details.USERNAME, "jduke")
|
|
||||||
.assertEvent();
|
|
||||||
|
|
||||||
// Change password back
|
|
||||||
changePasswordPage.open();
|
|
||||||
// Only needed if you are providing a click thru to bypass kerberos. Currently there is a javascript
|
|
||||||
// to forward the user if kerberos isn't enabled.
|
|
||||||
//bypassPage.isCurrent();
|
|
||||||
//bypassPage.clickContinue();
|
|
||||||
|
|
||||||
loginPage.login("jduke", "newPass");
|
|
||||||
changePasswordPage.assertCurrent();
|
|
||||||
changePasswordPage.changePassword("newPass", "theduke", "theduke");
|
|
||||||
Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
|
|
||||||
changePasswordPage.logout();
|
|
||||||
|
|
||||||
spnegoResponse.close();
|
|
||||||
events.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,149 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2016 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.federation.storage.ldap;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.common.constants.KerberosConstants;
|
|
||||||
import org.keycloak.models.LDAPConstants;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class LDAPTestConfiguration {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(LDAPTestConfiguration.class);
|
|
||||||
|
|
||||||
private String connectionPropertiesLocation;
|
|
||||||
private int sleepTime;
|
|
||||||
private boolean startEmbeddedLdapLerver = true;
|
|
||||||
private Map<String, String> config;
|
|
||||||
|
|
||||||
protected static final Map<String, String> PROP_MAPPINGS = new HashMap<String, String>();
|
|
||||||
protected static final Map<String, String> DEFAULT_VALUES = new HashMap<String, String>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.CONNECTION_URL, "idm.test.ldap.connection.url");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.BASE_DN, "idm.test.ldap.base.dn");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.USERS_DN, "idm.test.ldap.user.dn.suffix");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.BIND_DN, "idm.test.ldap.bind.dn");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.BIND_CREDENTIAL, "idm.test.ldap.bind.credential");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.VENDOR, "idm.test.ldap.vendor");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.CONNECTION_POOLING, "idm.test.ldap.connection.pooling");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.PAGINATION, "idm.test.ldap.pagination");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "idm.test.ldap.batch.size.for.sync");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "idm.test.ldap.username.ldap.attribute");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, "idm.test.ldap.rdn.ldap.attribute");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.USER_OBJECT_CLASSES, "idm.test.ldap.user.object.classes");
|
|
||||||
PROP_MAPPINGS.put(LDAPConstants.EDIT_MODE, "idm.test.ldap.edit.mode");
|
|
||||||
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "idm.test.kerberos.allow.kerberos.authentication");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.KERBEROS_REALM, "idm.test.kerberos.realm");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.SERVER_PRINCIPAL, "idm.test.kerberos.server.principal");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.KEYTAB, "idm.test.kerberos.keytab");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.DEBUG, "idm.test.kerberos.debug");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "idm.test.kerberos.allow.password.authentication");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "idm.test.kerberos.update.profile.first.login");
|
|
||||||
PROP_MAPPINGS.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "idm.test.kerberos.use.kerberos.for.password.authentication");
|
|
||||||
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.CONNECTION_URL, "ldap://localhost:10389");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.BASE_DN, "dc=keycloak,dc=org");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.USERS_DN, "ou=People,dc=keycloak,dc=org");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.BIND_DN, "uid=admin,ou=system");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.BIND_CREDENTIAL, "secret");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.VENDOR, LDAPConstants.VENDOR_OTHER);
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.CONNECTION_POOLING, "true");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.PAGINATION, "true");
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, String.valueOf(LDAPConstants.DEFAULT_BATCH_SIZE_FOR_SYNC));
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, null);
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.USER_OBJECT_CLASSES, null);
|
|
||||||
DEFAULT_VALUES.put(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.toString());
|
|
||||||
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
|
|
||||||
URL keytabUrl = LDAPTestConfiguration.class.getResource("/kerberos/http.keytab");
|
|
||||||
String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
|
|
||||||
DEFAULT_VALUES.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LDAPTestConfiguration readConfiguration(String connectionPropertiesLocation) {
|
|
||||||
LDAPTestConfiguration ldapTestConfiguration = new LDAPTestConfiguration();
|
|
||||||
ldapTestConfiguration.setConnectionPropertiesLocation(connectionPropertiesLocation);
|
|
||||||
ldapTestConfiguration.loadConnectionProperties();
|
|
||||||
return ldapTestConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void loadConnectionProperties() {
|
|
||||||
Properties p = new Properties();
|
|
||||||
try {
|
|
||||||
log.info("Reading LDAP configuration from: " + connectionPropertiesLocation);
|
|
||||||
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(connectionPropertiesLocation);
|
|
||||||
p.load(is);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
config = new HashMap<String, String>();
|
|
||||||
for (Map.Entry<String, String> property : PROP_MAPPINGS.entrySet()) {
|
|
||||||
String propertyName = property.getKey();
|
|
||||||
String configName = property.getValue();
|
|
||||||
|
|
||||||
String value = (String) p.get(configName);
|
|
||||||
if (value == null) {
|
|
||||||
value = DEFAULT_VALUES.get(propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
config.put(propertyName, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty("idm.test.ldap.start.embedded.ldap.server", "true"));
|
|
||||||
sleepTime = Integer.parseInt(p.getProperty("idm.test.ldap.sleepTime", "1000"));
|
|
||||||
log.info("Start embedded server: " + startEmbeddedLdapLerver);
|
|
||||||
log.info("Read config: " + config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String,String> getLDAPConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConnectionPropertiesLocation(String connectionPropertiesLocation) {
|
|
||||||
this.connectionPropertiesLocation = connectionPropertiesLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStartEmbeddedLdapLerver() {
|
|
||||||
return startEmbeddedLdapLerver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSleepTime() {
|
|
||||||
return sleepTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"realm": "test",
|
|
||||||
"resource": "kerberos-app",
|
|
||||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
|
||||||
"auth-server-url": "http://localhost:8081/auth",
|
|
||||||
"ssl-required" : "external",
|
|
||||||
"credentials": {
|
|
||||||
"secret": "password"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
{
|
|
||||||
"id": "test",
|
|
||||||
"realm": "test",
|
|
||||||
"enabled": true,
|
|
||||||
"sslRequired": "external",
|
|
||||||
"registrationAllowed": true,
|
|
||||||
"resetPasswordAllowed": true,
|
|
||||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
|
||||||
"requiredCredentials": [ "password", "kerberos" ],
|
|
||||||
"defaultRoles": [ "user" ],
|
|
||||||
"users" : [
|
|
||||||
{
|
|
||||||
"username" : "test-user@localhost",
|
|
||||||
"enabled": true,
|
|
||||||
"email" : "test-user@localhost",
|
|
||||||
"credentials" : [
|
|
||||||
{ "type" : "password",
|
|
||||||
"value" : "password" }
|
|
||||||
],
|
|
||||||
"realmRoles": ["user"],
|
|
||||||
"applicationRoles": {
|
|
||||||
"account": [ "view-profile", "manage-account" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"scopeMappings": [
|
|
||||||
{
|
|
||||||
"client": "kerberos-app",
|
|
||||||
"roles": ["user"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"applications": [
|
|
||||||
{
|
|
||||||
"name": "kerberos-app",
|
|
||||||
"enabled": true,
|
|
||||||
"baseUrl": "http://localhost:8081/kerberos-portal",
|
|
||||||
"redirectUris": [
|
|
||||||
"http://localhost:8081/kerberos-portal/*"
|
|
||||||
],
|
|
||||||
"adminUrl": "http://localhost:8081/kerberos-portal/logout",
|
|
||||||
"secret": "password"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"roles" : {
|
|
||||||
"realm" : [
|
|
||||||
{
|
|
||||||
"name": "user",
|
|
||||||
"description": "Have User privileges"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,34 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2016 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
idm.test.ldap.connection.url=ldap\://localhost\:10389
|
|
||||||
idm.test.ldap.base.dn=dc\=keycloak,dc\=org
|
|
||||||
idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=keycloak,dc\=org
|
|
||||||
idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=keycloak,dc\=org
|
|
||||||
idm.test.ldap.user.dn.suffix=ou\=People,dc\=keycloak,dc\=org
|
|
||||||
idm.test.ldap.start.embedded.ldap.server=true
|
|
||||||
idm.test.ldap.bind.dn=uid\=admin,ou\=system
|
|
||||||
idm.test.ldap.bind.credential=secret
|
|
||||||
idm.test.ldap.connection.pooling=true
|
|
||||||
idm.test.ldap.pagination=true
|
|
||||||
idm.test.ldap.batch.size.for.sync=3
|
|
||||||
|
|
||||||
idm.test.kerberos.allow.kerberos.authentication=true
|
|
||||||
idm.test.kerberos.realm=KEYCLOAK.ORG
|
|
||||||
idm.test.kerberos.server.principal=HTTP/localhost@KEYCLOAK.ORG
|
|
||||||
idm.test.kerberos.debug=false
|
|
||||||
idm.test.kerberos.use.kerberos.for.password.authentication=true
|
|
|
@ -1,23 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2016 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
idm.test.kerberos.allow.kerberos.authentication=true
|
|
||||||
idm.test.kerberos.realm=KEYCLOAK.ORG
|
|
||||||
idm.test.kerberos.server.principal=HTTP/localhost@KEYCLOAK.ORG
|
|
||||||
idm.test.kerberos.debug=false
|
|
||||||
idm.test.kerberos.allow.password.authentication=true
|
|
||||||
idm.test.kerberos.update.profile.first.login=false
|
|
|
@ -1,19 +0,0 @@
|
||||||
[libdefaults]
|
|
||||||
default_realm = KEYCLOAK.ORG
|
|
||||||
default_tgs_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
|
|
||||||
default_tkt_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
|
|
||||||
permitted_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
|
|
||||||
kdc_timeout = 30000
|
|
||||||
dns_lookup_realm = false
|
|
||||||
dns_lookup_kdc = false
|
|
||||||
dns_canonicalize_hostname = false
|
|
||||||
ignore_acceptor_hostname = true
|
|
||||||
forwardable = true
|
|
||||||
|
|
||||||
[realms]
|
|
||||||
KEYCLOAK.ORG = {
|
|
||||||
kdc = localhost:6088
|
|
||||||
}
|
|
||||||
|
|
||||||
[domain_realm]
|
|
||||||
localhost = KEYCLOAK.ORG
|
|
|
@ -1,104 +0,0 @@
|
||||||
dn: dc=keycloak,dc=org
|
|
||||||
objectclass: dcObject
|
|
||||||
objectclass: organization
|
|
||||||
o: Keycloak
|
|
||||||
dc: Keycloak
|
|
||||||
|
|
||||||
dn: ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: organizationalUnit
|
|
||||||
objectClass: top
|
|
||||||
ou: People
|
|
||||||
|
|
||||||
dn: uid=krbtgt,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: KDC Service
|
|
||||||
sn: Service
|
|
||||||
uid: krbtgt
|
|
||||||
userPassword: secret
|
|
||||||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=ldap,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: LDAP
|
|
||||||
sn: Service
|
|
||||||
uid: ldap
|
|
||||||
userPassword: randall
|
|
||||||
krb5PrincipalName: ${ldapSaslPrincipal}
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=HTTP,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: HTTP
|
|
||||||
sn: Service
|
|
||||||
uid: HTTP
|
|
||||||
userPassword: httppwd
|
|
||||||
krb5PrincipalName: HTTP/${hostname}@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=hnelson,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: Horatio
|
|
||||||
sn: Nelson
|
|
||||||
mail: hnelson@keycloak.org
|
|
||||||
uid: hnelson
|
|
||||||
userPassword: secret
|
|
||||||
krb5PrincipalName: hnelson@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=jduke,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: Java
|
|
||||||
sn: Duke
|
|
||||||
mail: jduke@keycloak.org
|
|
||||||
uid: jduke
|
|
||||||
userPassword: theduke
|
|
||||||
krb5PrincipalName: jduke@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=MyDuke,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: My
|
|
||||||
sn: Duke
|
|
||||||
mail: MyDuke@keycloak.org
|
|
||||||
uid: MyDuke
|
|
||||||
userPassword: theduke
|
|
||||||
krb5PrincipalName: MyDuke@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
||||||
|
|
||||||
dn: uid=gsstestserver,ou=People,dc=keycloak,dc=org
|
|
||||||
objectClass: top
|
|
||||||
objectClass: person
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
objectClass: krb5principal
|
|
||||||
objectClass: krb5kdcentry
|
|
||||||
cn: gsstestserver
|
|
||||||
sn: Service
|
|
||||||
uid: gsstestserver
|
|
||||||
userPassword: gsstestpwd
|
|
||||||
krb5PrincipalName: gsstestserver/xxx@KEYCLOAK.ORG
|
|
||||||
krb5KeyVersionNumber: 0
|
|
Loading…
Reference in a new issue