KEYCLOAK-6038 Kerberos cross-realm trust test
This commit is contained in:
parent
060b3b8d0f
commit
575851d45c
25 changed files with 844 additions and 268 deletions
|
@ -40,7 +40,7 @@ public class KerberosUsernamePasswordAuthenticator {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(KerberosUsernamePasswordAuthenticator.class);
|
||||
|
||||
private final CommonKerberosConfig config;
|
||||
protected final CommonKerberosConfig config;
|
||||
private LoginContext loginContext;
|
||||
|
||||
public KerberosUsernamePasswordAuthenticator(CommonKerberosConfig config) {
|
||||
|
|
|
@ -113,6 +113,13 @@ To start a ApacheDS based Kerberos server for testing Kerberos + LDAP sending ru
|
|||
There are additional system properties you can use to configure (See LDAPEmbeddedServer and KerberosEmbeddedServer class for details) but for testing purposes default values should be good.
|
||||
By default ApacheDS LDAP server will be running on localhost:10389 and Kerberos KDC on localhost:6088 .
|
||||
|
||||
The alternative is to start Kerberos with the alternative realm KC2.COM instead of default KEYCLOAK.ORG.
|
||||
The ApacheDS server will be then started with all ports shifted by 1000 (EG. LDAP on 11389, Kerberos KDC on 7088).
|
||||
This allows to start 2 kerberos servers in parallel to test things like Kerberos cross-realm trust:
|
||||
|
||||
mvn exec:java -Pkerberos -Dkeycloak.kerberos.realm=KC2.COM
|
||||
|
||||
|
||||
Once kerberos is running, you can create LDAP Federation provider in Keycloak admin console with same settings like mentioned in previous LDAP section.
|
||||
But additionally you can enable Kerberos authentication in LDAP provider with the settings like:
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.testsuite.rest.resource;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
|
@ -161,4 +162,20 @@ public class TestLDAPResource {
|
|||
LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910");
|
||||
LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove specified user directly just from the LDAP server
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/remove-ldap-user")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void removeLDAPUser(@QueryParam("username") String ldapUsername) {
|
||||
ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(session, realm);
|
||||
UserStorageProviderModel ldapModel = new UserStorageProviderModel(ldapCompModel);
|
||||
LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
|
||||
|
||||
LDAPTestUtils.removeLDAPUserByUsername(ldapProvider, realm,
|
||||
ldapProvider.getLdapIdentityStore().getConfig(), ldapUsername);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
|
|||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||
import org.keycloak.storage.ldap.LDAPConfig;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||
import org.keycloak.storage.ldap.LDAPUtils;
|
||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||
import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
|
||||
|
@ -120,7 +121,7 @@ public class LDAPTestUtils {
|
|||
public static ComponentModel getLdapProviderModel(KeycloakSession session, RealmModel realm) {
|
||||
List<ComponentModel> components = realm.getComponents(realm.getId(), UserStorageProvider.class.getName());
|
||||
for (ComponentModel component : components) {
|
||||
if ("test-ldap".equals(component.getName())) {
|
||||
if (LDAPStorageProviderFactory.PROVIDER_NAME.equals(component.getProviderId())) {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.testsuite.client.resources;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
|
@ -53,4 +54,13 @@ public interface TestingLDAPResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void prepareGroupsLDAPTest();
|
||||
|
||||
|
||||
/**
|
||||
* Remove specified user directly just from the LDAP server
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/remove-ldap-user")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void removeLDAPUser(@QueryParam("username") String ldapUsername);
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ public class KerberosRule extends LDAPRule {
|
|||
private static final Logger log = Logger.getLogger(KerberosRule.class);
|
||||
|
||||
private final String configLocation;
|
||||
private final String kerberosRealm;
|
||||
|
||||
public KerberosRule(String configLocation) {
|
||||
public KerberosRule(String configLocation, String kerberosRealm) {
|
||||
this.configLocation = configLocation;
|
||||
this.kerberosRealm = kerberosRealm;
|
||||
|
||||
// Global kerberos configuration
|
||||
String krb5ConfPath = getKrb5ConfPath();
|
||||
|
@ -61,11 +63,25 @@ public class KerberosRule extends LDAPRule {
|
|||
return configLocation;
|
||||
}
|
||||
|
||||
|
||||
public String getKerberosRealm() {
|
||||
return kerberosRealm;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected LDAPEmbeddedServer createServer() {
|
||||
Properties defaultProperties = new Properties();
|
||||
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
|
||||
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos.ldif");
|
||||
|
||||
KerberosEmbeddedServer.configureDefaultPropertiesForRealm(this.kerberosRealm, defaultProperties);
|
||||
|
||||
// Improve if more flexibility is needed
|
||||
if ("KEYCLOAK.ORG".equals(kerberosRealm)) {
|
||||
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos.ldif");
|
||||
} else if ("KC2.COM".equals(kerberosRealm)) {
|
||||
defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos-kc2.ldif");
|
||||
}
|
||||
|
||||
return new KerberosEmbeddedServer(defaultProperties);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright 2017 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 javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.common.constants.KerberosConstants;
|
||||
import org.keycloak.common.util.KerberosSerializationUtils;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
|
||||
|
||||
/**
|
||||
* Contains just test methods
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractKerberosSingleRealmTest extends AbstractKerberosTest {
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
// KEYCLOAK-7823
|
||||
@Test
|
||||
public void spnegoLoginWithRequiredKerberosAuthExecutionTest() {
|
||||
AuthenticationExecutionModel.Requirement oldRequirement = updateKerberosAuthExecutionRequirement(
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
Response response = spnegoLogin("hnelson", "secret");
|
||||
updateKerberosAuthExecutionRequirement(oldRequirement);
|
||||
|
||||
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
// KEYCLOAK-2102
|
||||
@Test
|
||||
public void spnegoCaseInsensitiveTest() throws Exception {
|
||||
assertSuccessfulSpnegoLogin(getKerberosRule().isCaseSensitiveLogin() ? "MyDuke" : "myduke", "myduke", "theduke");
|
||||
}
|
||||
|
||||
|
||||
@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 {
|
||||
Assume.assumeTrue("Ignoring test as the embedded server is not started", getKerberosRule().isStartEmbeddedLdapServer());
|
||||
// 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, 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
|
||||
AccessToken token = assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
|
||||
|
||||
// Assert kerberos ticket in the accessToken can be re-used to authenticate against other 3rd party kerberos service (ApacheDS Server in this case)
|
||||
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
|
||||
token = assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
|
||||
Assert.assertFalse(token.getOtherClaims().containsKey(KerberosConstants.GSS_DELEGATION_CREDENTIAL));
|
||||
|
||||
events.clear();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
package org.keycloak.testsuite.federation.kerberos;
|
||||
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
|
@ -34,7 +33,6 @@ 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;
|
||||
|
@ -49,34 +47,27 @@ 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.Assume;
|
||||
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.authentication.authenticators.browser.SpnegoAuthenticatorFactory;
|
||||
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.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
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.storage.UserStorageProviderModel;
|
||||
import org.keycloak.testsuite.AbstractAuthTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
|
@ -84,9 +75,12 @@ 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.KerberosRule;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
/**
|
||||
* Contains just helper methods. No test methods.
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
||||
|
@ -104,13 +98,30 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
@Page
|
||||
protected AccountPasswordPage changePasswordPage;
|
||||
|
||||
protected abstract KerberosRule getKerberosRule();
|
||||
|
||||
protected abstract CommonKerberosConfig getKerberosConfig();
|
||||
|
||||
protected abstract ComponentRepresentation getUserStorageConfiguration();
|
||||
|
||||
protected abstract void setKrb5ConfPath();
|
||||
|
||||
protected abstract boolean isStartEmbeddedLdapServer();
|
||||
protected ComponentRepresentation getUserStorageConfiguration(String providerName, String providerId) {
|
||||
Map<String,String> kerberosConfig = getKerberosRule().getConfig();
|
||||
MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
|
||||
|
||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||
model.setLastSync(0);
|
||||
model.setChangedSyncPeriod(-1);
|
||||
model.setFullSyncPeriod(-1);
|
||||
model.setName(providerName);
|
||||
model.setPriority(0);
|
||||
model.setProviderId(providerId);
|
||||
model.setConfig(config);
|
||||
|
||||
ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
|
@ -118,6 +129,11 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
testRealms.add(realmRep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmResource testRealmResource() {
|
||||
return adminClient.realm("test");
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
@Override
|
||||
|
@ -127,7 +143,7 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
testRealmPage.setAuthRealm(AuthRealm.TEST);
|
||||
changePasswordPage.realm(AuthRealm.TEST);
|
||||
|
||||
setKrb5ConfPath();
|
||||
getKerberosRule().setKrb5ConfPath(testingClient.testing());
|
||||
|
||||
spnegoSchemeFactory = new KeycloakSPNegoSchemeFactory(getKerberosConfig());
|
||||
initHttpClient(true);
|
||||
|
@ -161,164 +177,31 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
// }
|
||||
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
// KEYCLOAK-7823
|
||||
@Test
|
||||
public void spnegoLoginWithRequiredKerberosAuthExecutionTest() {
|
||||
AuthenticationExecutionModel.Requirement oldRequirement = updateKerberosAuthExecutionRequirement(
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED);
|
||||
Response response = spnegoLogin("hnelson", "secret");
|
||||
updateKerberosAuthExecutionRequirement(oldRequirement);
|
||||
|
||||
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||
}
|
||||
|
||||
protected OAuthClient.AccessTokenResponse spnegoLoginTestImpl() throws Exception {
|
||||
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
||||
protected AccessToken assertSuccessfulSpnegoLogin(String loginUsername, String expectedUsername, String password) throws Exception {
|
||||
Response spnegoResponse = spnegoLogin(loginUsername, password);
|
||||
Assert.assertEquals(302, spnegoResponse.getStatus());
|
||||
|
||||
List<UserRepresentation> users = testRealmResource().users().search("hnelson", 0, 1);
|
||||
List<UserRepresentation> users = testRealmResource().users().search(expectedUsername, 0, 1);
|
||||
String userId = users.get(0).getId();
|
||||
events.expectLogin()
|
||||
.client("kerberos-app")
|
||||
.user(userId)
|
||||
.detail(Details.USERNAME, "hnelson")
|
||||
.detail(Details.USERNAME, expectedUsername)
|
||||
.assertEvent();
|
||||
|
||||
String codeUrl = spnegoResponse.getLocation().toString();
|
||||
|
||||
return assertAuthenticationSuccess(codeUrl);
|
||||
OAuthClient.AccessTokenResponse tokenResponse = assertAuthenticationSuccess(codeUrl);
|
||||
|
||||
AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
|
||||
Assert.assertEquals(userId, token.getSubject());
|
||||
Assert.assertEquals(expectedUsername, token.getPreferredUsername());
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
Assume.assumeTrue("Ignoring test as the embedded server is not started", isStartEmbeddedLdapServer());
|
||||
// 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, 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 {
|
||||
protected 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");
|
||||
|
@ -462,7 +345,8 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||
}
|
||||
|
||||
private AuthenticationExecutionModel.Requirement updateKerberosAuthExecutionRequirement(AuthenticationExecutionModel.Requirement requirement) {
|
||||
|
||||
protected AuthenticationExecutionModel.Requirement updateKerberosAuthExecutionRequirement(AuthenticationExecutionModel.Requirement requirement) {
|
||||
Optional<AuthenticationExecutionInfoRepresentation> kerberosAuthExecutionOpt = testRealmResource()
|
||||
.flows()
|
||||
.getExecutions(DefaultAuthenticationFlows.BROWSER_FLOW)
|
||||
|
@ -484,14 +368,8 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
|||
return oldRequirement;
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
private 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());
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2017 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 javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.arquillian.container.test.api.TargetsContainer;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||
import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.federation.ldap.LDAPTestContext;
|
||||
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||
import org.keycloak.testsuite.util.KerberosRule;
|
||||
import org.keycloak.testsuite.util.LDAPTestUtils;
|
||||
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||
import org.keycloak.util.ldap.LDAPEmbeddedServer;
|
||||
|
||||
import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class KerberosLdapCrossRealmTrustTest extends AbstractKerberosTest {
|
||||
|
||||
@Deployment
|
||||
@TargetsContainer(AUTH_SERVER_CURRENT)
|
||||
public static WebArchive deploy() {
|
||||
return RunOnServerDeployment.create(UserResource.class, LDAPEmbeddedServer.class, KerberosEmbeddedServer.class)
|
||||
.addPackages(true,
|
||||
"org.keycloak.testsuite",
|
||||
"org.keycloak.testsuite.federation.ldap",
|
||||
"org.keycloak.testsuite.federation.kerberos");
|
||||
}
|
||||
|
||||
|
||||
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-ldap-crt-connection.properties";
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule2 = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM_2);
|
||||
|
||||
|
||||
@Override
|
||||
protected KerberosRule getKerberosRule() {
|
||||
return kerberosRule;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonKerberosConfig getKerberosConfig() {
|
||||
return new LDAPProviderKerberosConfig(getUserStorageConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentRepresentation getUserStorageConfiguration() {
|
||||
return getUserStorageConfiguration("kerberos-ldap", LDAPStorageProviderFactory.PROVIDER_NAME);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test01SpnegoLoginCRTSuccess() throws Exception {
|
||||
// Login as user from realm KC2.COM . Realm KEYCLOAK.ORG will trust us
|
||||
AccessToken token = assertSuccessfulSpnegoLogin("hnelson2@KC2.COM", "hnelson2", "secret");
|
||||
|
||||
Assert.assertEquals(token.getEmail(), "hnelson2@kc2.com");
|
||||
assertUser("hnelson2", "hnelson2@kc2.com", "Horatio", "Nelson", false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test02DisableTrust() throws Exception {
|
||||
// Remove the LDAP entry corresponding to the Kerberos principal krbtgt/KEYCLOAK.ORG@KC2.COM
|
||||
// This will effectively disable kerberos cross-realm trust
|
||||
testingClient.testing().ldap("test").removeLDAPUser("krbtgt2");
|
||||
|
||||
|
||||
// There is no trust among kerberos realms anymore. SPNEGO shouldn't work. There would be failure even on Apache HTTP client side
|
||||
// as it's not possible to start GSS context ( initSecContext ) due the missing trust among realms.
|
||||
try {
|
||||
Response spnegoResponse = spnegoLogin("hnelson2@KC2.COM", "secret");
|
||||
Assert.fail("Not expected to successfully login");
|
||||
} catch (Exception e) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -17,40 +17,41 @@
|
|||
|
||||
package org.keycloak.testsuite.federation.kerberos;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
|
||||
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.PasswordPolicy;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
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;
|
||||
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||
|
||||
/**
|
||||
* Test for the LDAPStorageProvider with kerberos enabled (kerberos with LDAP integration)
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class KerberosLdapTest extends AbstractKerberosTest {
|
||||
public class KerberosLdapTest extends AbstractKerberosSingleRealmTest {
|
||||
|
||||
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-ldap-connection.properties";
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
|
||||
|
||||
|
||||
@Override
|
||||
protected KerberosRule getKerberosRule() {
|
||||
return kerberosRule;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonKerberosConfig getKerberosConfig() {
|
||||
|
@ -59,43 +60,14 @@ public class KerberosLdapTest extends AbstractKerberosTest {
|
|||
|
||||
@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;
|
||||
return getUserStorageConfiguration("kerberos-ldap", LDAPStorageProviderFactory.PROVIDER_NAME);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isCaseSensitiveLogin() {
|
||||
return kerberosRule.isCaseSensitiveLogin();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isStartEmbeddedLdapServer() {
|
||||
return kerberosRule.isStartEmbeddedLdapServer();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setKrb5ConfPath() {
|
||||
kerberosRule.setKrb5ConfPath(testingClient.testing());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void spnegoLoginTest() throws Exception {
|
||||
spnegoLoginTestImpl();
|
||||
assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2017 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 org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.arquillian.container.test.api.TargetsContainer;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||
import org.keycloak.federation.kerberos.KerberosConfig;
|
||||
import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.testsuite.federation.ldap.AbstractLDAPTest;
|
||||
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||
import org.keycloak.testsuite.util.KerberosRule;
|
||||
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||
|
||||
import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class KerberosStandaloneCrossRealmTrustTest extends AbstractKerberosTest {
|
||||
|
||||
@Deployment
|
||||
@TargetsContainer(AUTH_SERVER_CURRENT)
|
||||
public static WebArchive deploy() {
|
||||
return RunOnServerDeployment.create(UserResource.class, AbstractLDAPTest.class, AbstractKerberosTest.class)
|
||||
.addPackages(true,
|
||||
"org.keycloak.testsuite",
|
||||
"org.keycloak.testsuite.federation.ldap",
|
||||
"org.keycloak.testsuite.federation.kerberos");
|
||||
}
|
||||
|
||||
|
||||
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-standalone-connection.properties";
|
||||
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
|
||||
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule2 = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM_2);
|
||||
|
||||
|
||||
@Override
|
||||
protected KerberosRule getKerberosRule() {
|
||||
return kerberosRule;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonKerberosConfig getKerberosConfig() {
|
||||
return new KerberosConfig(getUserStorageConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentRepresentation getUserStorageConfiguration() {
|
||||
return getUserStorageConfiguration("kerberos-standalone", KerberosFederationProviderFactory.PROVIDER_NAME);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test01spnegoLoginSameRealmTest() throws Exception {
|
||||
assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
|
||||
assertUser("hnelson", "hnelson@keycloak.org", null, null, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test02spnegoLoginDifferentRealmTest() throws Exception {
|
||||
// Cross-realm trust login. Realm KEYCLOAK.ORG trusts realm KC2.COM.
|
||||
// TODO: email hnelson2@keycloak.org is not very good. Will be better to have more flexibility for mapping of kerberos principals to Keycloak UserModel in KerberosFederationProvider (if needed)
|
||||
assertSuccessfulSpnegoLogin("hnelson2@KC2.COM", "hnelson2", "secret");
|
||||
assertUser("hnelson2", "hnelson2@keycloak.org", null, null, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,11 +18,7 @@
|
|||
package org.keycloak.testsuite.federation.kerberos;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
import javax.ws.rs.client.Entity;
|
||||
|
@ -33,28 +29,34 @@ import org.junit.Assert;
|
|||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.constants.KerberosConstants;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
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.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.testsuite.ActionURIUtils;
|
||||
import org.keycloak.testsuite.util.KerberosRule;
|
||||
import org.keycloak.util.ldap.KerberosEmbeddedServer;
|
||||
|
||||
/**
|
||||
* Test for the KerberosFederationProvider (kerberos without LDAP integration)
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class KerberosStandaloneTest extends AbstractKerberosTest {
|
||||
public class KerberosStandaloneTest extends AbstractKerberosSingleRealmTest {
|
||||
|
||||
private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-standalone-connection.properties";
|
||||
|
||||
@ClassRule
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
|
||||
public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
|
||||
|
||||
|
||||
@Override
|
||||
protected KerberosRule getKerberosRule() {
|
||||
return kerberosRule;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonKerberosConfig getKerberosConfig() {
|
||||
|
@ -63,44 +65,15 @@ public class KerberosStandaloneTest extends AbstractKerberosTest {
|
|||
|
||||
@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;
|
||||
return getUserStorageConfiguration("kerberos-standalone", KerberosFederationProviderFactory.PROVIDER_NAME);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isCaseSensitiveLogin() {
|
||||
return kerberosRule.isCaseSensitiveLogin();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isStartEmbeddedLdapServer() {
|
||||
return kerberosRule.isStartEmbeddedLdapServer();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setKrb5ConfPath() {
|
||||
kerberosRule.setKrb5ConfPath(testingClient.testing());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spnegoLoginTest() throws Exception {
|
||||
spnegoLoginTestImpl();
|
||||
assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
|
||||
|
||||
// Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
|
||||
// Assert user was imported and hasn't any required action on him. Profile info is NOT synced from LDAP. Just username is filled and email is "guessed"
|
||||
assertUser("hnelson", "hnelson@" + kerberosRule.getConfig().get(KerberosConstants.KERBEROS_REALM).toLowerCase(), null, null, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
|||
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
|
||||
/**
|
||||
|
@ -74,7 +76,19 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
|
|||
|
||||
@Override
|
||||
protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer, Credentials credentials) throws GSSException {
|
||||
KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
|
||||
KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig) {
|
||||
|
||||
// Disable strict check for the configured kerberos realm, which is on super-method
|
||||
@Override
|
||||
protected String getKerberosPrincipal(String username) throws LoginException {
|
||||
if (username.contains("@")) {
|
||||
return username;
|
||||
} else {
|
||||
return username + "@" + config.getKerberosRealm();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
Subject clientSubject = authenticator.authenticateSubject(username, password);
|
||||
|
||||
|
@ -109,7 +123,8 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
|
|||
token = new byte[0];
|
||||
}
|
||||
GSSManager manager = getManager();
|
||||
GSSName serverName = manager.createName("HTTP/" + authServer + "@" + kerberosConfig.getKerberosRealm(), null);
|
||||
String httPrincipal = kerberosConfig.getServerPrincipal().replaceFirst("/.*@", "/" + authServer + "@");
|
||||
GSSName serverName = manager.createName(httPrincipal, null);
|
||||
GSSContext gssContext = manager.createContext(
|
||||
serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
|
||||
gssContext.requestMutualAuth(true);
|
||||
|
|
|
@ -24,20 +24,12 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||
import org.keycloak.storage.ldap.LDAPUtils;
|
||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||
import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode;
|
||||
import org.keycloak.storage.ldap.mappers.membership.MembershipType;
|
||||
import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory;
|
||||
import org.keycloak.storage.ldap.mappers.membership.group.GroupMapperConfig;
|
||||
import org.keycloak.models.GroupModel;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# Copyright 2017 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.
|
||||
#
|
||||
|
||||
# Using LDAP from "kc2" domain, but HTTP principal is configured to use KEYCLOAK.ORG domain.
|
||||
# Realm KC2.COM has the purpose just for the client side login (KerberosUsernamePasswordAuthenticator used by Apache HTTP client in the test)
|
||||
idm.test.ldap.connection.url=ldap\://localhost\:11389
|
||||
idm.test.ldap.base.dn=dc\=kc2,dc\=com
|
||||
idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=kc2,dc\=com
|
||||
idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=kc2,dc\=com
|
||||
idm.test.ldap.user.dn.suffix=ou\=People,dc\=kc2,dc\=com
|
||||
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=KC2.COM
|
||||
idm.test.kerberos.server.principal=HTTP/localhost@KEYCLOAK.ORG
|
||||
idm.test.kerberos.debug=true
|
||||
idm.test.kerberos.use.kerberos.for.password.authentication=true
|
|
@ -14,6 +14,9 @@
|
|||
KEYCLOAK.ORG = {
|
||||
kdc = localhost:6088
|
||||
}
|
||||
KC2.COM = {
|
||||
kdc = localhost:7088
|
||||
}
|
||||
|
||||
[domain_realm]
|
||||
localhost = KEYCLOAK.ORG
|
|
@ -0,0 +1,104 @@
|
|||
dn: dc=kc2,dc=com
|
||||
objectclass: dcObject
|
||||
objectclass: organization
|
||||
o: Kc2
|
||||
dc: Kc2
|
||||
|
||||
dn: ou=People,dc=kc2,dc=com
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: People
|
||||
|
||||
dn: uid=krbtgt,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KC2.COM@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
|
||||
dn: uid=krbtgt2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=ldap,ou=People,dc=kc2,dc=com
|
||||
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=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: HTTP
|
||||
sn: Service
|
||||
uid: HTTP
|
||||
userPassword: httppwd
|
||||
krb5PrincipalName: HTTP/${hostname}@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=hnelson2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: Horatio
|
||||
sn: Nelson
|
||||
mail: hnelson2@kc2.com
|
||||
uid: hnelson2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: hnelson2@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=jduke2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: Java
|
||||
sn: Duke
|
||||
mail: jduke2@keycloak.org
|
||||
uid: jduke2
|
||||
userPassword: theduke
|
||||
krb5PrincipalName: jduke2@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=gsstestserver,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: gsstestserver
|
||||
sn: Service
|
||||
uid: gsstestserver
|
||||
userPassword: gsstestpwd
|
||||
krb5PrincipalName: gsstestserver/xxx@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
|
@ -22,6 +22,20 @@ userPassword: secret
|
|||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
|
||||
dn: uid=krbtgt2,ou=People,dc=keycloak,dc=org
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=ldap,ou=People,dc=keycloak,dc=org
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<module name="org.keycloak.keycloak-services"/>
|
||||
<module name="org.keycloak.keycloak-model-infinispan"/>
|
||||
<module name="org.keycloak.keycloak-model-jpa"/>
|
||||
<module name="org.keycloak.keycloak-kerberos-federation"/>
|
||||
<module name="org.keycloak.keycloak-ldap-federation"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
@ -106,7 +106,8 @@ class InMemoryDirectoryServiceFactory implements DirectoryServiceFactory {
|
|||
|
||||
// EhCache in disabled-like-mode
|
||||
Configuration ehCacheConfig = new Configuration();
|
||||
CacheConfiguration defaultCache = new CacheConfiguration("default", 1).eternal(false).timeToIdleSeconds(30)
|
||||
ehCacheConfig.setName(name);
|
||||
CacheConfiguration defaultCache = new CacheConfiguration(name + "-default", 1).eternal(false).timeToIdleSeconds(30)
|
||||
.timeToLiveSeconds(30).overflowToDisk(false);
|
||||
ehCacheConfig.addDefaultCache(defaultCache);
|
||||
CacheService cacheService = new CacheService(new CacheManager(ehCacheConfig));
|
||||
|
|
|
@ -60,7 +60,9 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
|
|||
|
||||
private static final String DEFAULT_KERBEROS_LDIF_FILE = "classpath:kerberos/default-users.ldif";
|
||||
|
||||
private static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG";
|
||||
public static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG";
|
||||
public static final String DEFAULT_KERBEROS_REALM_2 = "KC2.COM";
|
||||
|
||||
private static final String DEFAULT_KDC_PORT = "6088";
|
||||
private static final String DEFAULT_KDC_ENCRYPTION_TYPES = "aes128-cts-hmac-sha1-96, des-cbc-md5, des3-cbc-sha1-kd";
|
||||
|
||||
|
@ -75,9 +77,31 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
|
|||
Properties defaultProperties = new Properties();
|
||||
defaultProperties.put(PROPERTY_DSF, DSF_FILE);
|
||||
|
||||
String kerberosRealm = System.getProperty("keycloak.kerberos.realm", DEFAULT_KERBEROS_REALM);
|
||||
configureDefaultPropertiesForRealm(kerberosRealm, defaultProperties);
|
||||
|
||||
execute(args, defaultProperties);
|
||||
}
|
||||
|
||||
|
||||
public static void configureDefaultPropertiesForRealm(String kerberosRealm, Properties properties) {
|
||||
log.infof("Using kerberos realm: %s", kerberosRealm);
|
||||
if (DEFAULT_KERBEROS_REALM.equals(kerberosRealm)) {
|
||||
// No more configs
|
||||
} else if (DEFAULT_KERBEROS_REALM_2.equals(kerberosRealm)) {
|
||||
properties.put(PROPERTY_BASE_DN, "dc=kc2,dc=com");
|
||||
properties.put(PROPERTY_BIND_PORT, "11389");
|
||||
properties.put(PROPERTY_BIND_LDAPS_PORT, "11636");
|
||||
properties.put(PROPERTY_LDIF_FILE, "classpath:kerberos/default-users-kc2.ldif");
|
||||
properties.put(PROPERTY_KERBEROS_REALM, DEFAULT_KERBEROS_REALM_2);
|
||||
properties.put(PROPERTY_KDC_PORT, "7088");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Valid values for kerberos realm are [ " + DEFAULT_KERBEROS_REALM + " , "
|
||||
+ DEFAULT_KERBEROS_REALM_2 + " ]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void execute(String[] args, Properties defaultProperties) throws Exception {
|
||||
final KerberosEmbeddedServer kerberosEmbeddedServer = new KerberosEmbeddedServer(defaultProperties);
|
||||
kerberosEmbeddedServer.init();
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
dn: dc=kc2,dc=com
|
||||
objectclass: dcObject
|
||||
objectclass: organization
|
||||
o: Kc2
|
||||
dc: Kc2
|
||||
|
||||
dn: ou=People,dc=kc2,dc=com
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: People
|
||||
|
||||
dn: uid=krbtgt,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KC2.COM@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
|
||||
dn: uid=krbtgt2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=ldap,ou=People,dc=kc2,dc=com
|
||||
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=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: HTTP
|
||||
sn: Service
|
||||
uid: HTTP
|
||||
userPassword: httppwd
|
||||
krb5PrincipalName: HTTP/${hostname}@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=hnelson2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: Horatio
|
||||
sn: Nelson
|
||||
mail: hnelson2@kc2.com
|
||||
uid: hnelson2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: hnelson2@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=jduke2,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: Java
|
||||
sn: Duke
|
||||
mail: jduke2@keycloak.org
|
||||
uid: jduke2
|
||||
userPassword: theduke
|
||||
krb5PrincipalName: jduke2@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=gsstestserver,ou=People,dc=kc2,dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: gsstestserver
|
||||
sn: Service
|
||||
uid: gsstestserver
|
||||
userPassword: gsstestpwd
|
||||
krb5PrincipalName: gsstestserver/xxx@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
|
@ -22,6 +22,20 @@ userPassword: secret
|
|||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
|
||||
dn: uid=krbtgt2,ou=People,dc=keycloak,dc=org
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: krb5principal
|
||||
objectClass: krb5kdcentry
|
||||
cn: KDC Service
|
||||
sn: Service
|
||||
uid: krbtgt2
|
||||
userPassword: secret
|
||||
krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
|
||||
krb5KeyVersionNumber: 0
|
||||
|
||||
dn: uid=ldap,ou=People,dc=keycloak,dc=org
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
|
|
|
@ -24,3 +24,6 @@ log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
|
|||
log4j.logger.org.keycloak=info
|
||||
log4j.logger.org.apache.directory.api=warn
|
||||
log4j.logger.org.apache.directory.server.core=warn
|
||||
|
||||
# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
|
||||
#log4j.logger.org.apache.directory.server.kerberos=debug
|
Loading…
Reference in a new issue