package org.keycloak.testsuite.forms;
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.OAuth2Constants;
import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
import org.keycloak.federation.ldap.LDAPUtils;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelReadOnlyException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.picketlink.PartitionManagerProvider;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AccountPasswordPage;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.LDAPRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.keycloak.testutils.LDAPEmbeddedServer;
import org.openqa.selenium.WebDriver;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.model.basic.User;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class FederationProvidersIntegrationTest {
private static LDAPRule ldapRule = new LDAPRule();
private static UserFederationProviderModel ldapModel = null;
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
addUser(manager.getSession(), appRealm, "mary", "mary@test.com", "password-app");
LDAPEmbeddedServer ldapServer = ldapRule.getEmbeddedServer();
Map<String,String> ldapConfig = ldapServer.getLDAPConfig();
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true");
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap", -1, -1, 0);
// Delete all LDAP users and add some new for testing
PartitionManager partitionManager = getPartitionManager(manager.getSession(), ldapModel);
LDAPUtils.removeAllUsers(partitionManager);
User john = LDAPUtils.addUser(partitionManager, "johnkeycloak", "John", "Doe", "john@email.org");
LDAPUtils.updatePassword(partitionManager, john, "Password1");
User existing = LDAPUtils.addUser(partitionManager, "existing", "Existing", "Foo", "existing@email.org");
}
});
@ClassRule
public static TestRule chain = RuleChain
.outerRule(ldapRule)
.around(keycloakRule);
@Rule
public WebRule webRule = new WebRule(this);
@WebResource
protected OAuthClient oauth;
@WebResource
protected WebDriver driver;
@WebResource
protected AppPage appPage;
@WebResource
protected RegisterPage registerPage;
@WebResource
protected LoginPage loginPage;
@WebResource
protected AccountUpdateProfilePage profilePage;
@WebResource
protected AccountPasswordPage changePasswordPage;
// @Test
// @Ignore
// public void runit() throws Exception {
// Thread.sleep(10000000);
//
// }
static UserModel addUser(KeycloakSession session, RealmModel realm, String username, String email, String password) {
UserModel user = session.users().addUser(realm, username);
user.setEmail(email);
user.setEnabled(true);
UserCredentialModel creds = new UserCredentialModel();
creds.setType(CredentialRepresentation.PASSWORD);
creds.setValue(password);
user.updateCredential(creds);
return user;
}
@Test
public void caseSensitiveSearch() {
loginPage.open();
// This should fail for now due to case-sensitivity
loginPage.login("johnKeycloak", "Password1");
Assert.assertEquals("Invalid username or password.", loginPage.getError());
loginPage.login("John@email.org", "Password1");
Assert.assertEquals("Invalid username or password.", loginPage.getError());
}
@Test
public void deleteFederationLink() {
loginLdap();
{
KeycloakSession session = keycloakRule.startSession();
try {
RealmManager manager = new RealmManager(session);
RealmModel appRealm = manager.getRealm("test");
appRealm.removeUserFederationProvider(ldapModel);
Assert.assertEquals(0, appRealm.getUserFederationProviders().size());
} finally {
keycloakRule.stopSession(session, true);
}
}
loginPage.open();
loginPage.login("johnkeycloak", "Password1");
loginPage.assertCurrent();
Assert.assertEquals("Invalid username or password.", loginPage.getError());
{
KeycloakSession session = keycloakRule.startSession();
try {
RealmManager manager = new RealmManager(session);
RealmModel appRealm = manager.getRealm("test");
ldapModel = appRealm.addUserFederationProvider(ldapModel.getProviderName(), ldapModel.getConfig(), ldapModel.getPriority(), ldapModel.getDisplayName(), -1, -1, 0);
} finally {
keycloakRule.stopSession(session, true);
}
}
loginLdap();
}
@Test
public void loginClassic() {
loginPage.open();
loginPage.login("mary", "password-app");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
}
@Test
public void loginLdap() {
loginPage.open();
loginPage.login("johnkeycloak", "Password1");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
profilePage.open();
Assert.assertEquals("John", profilePage.getFirstName());
Assert.assertEquals("Doe", profilePage.getLastName());
Assert.assertEquals("john@email.org", profilePage.getEmail());
}
@Test
public void loginLdapWithEmail() {
loginPage.open();
loginPage.login("john@email.org", "Password1");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
}
@Test
public void passwordChangeLdap() throws Exception {
changePasswordPage.open();
loginPage.login("johnkeycloak", "Password1");
changePasswordPage.changePassword("Password1", "New-password1", "New-password1");
Assert.assertEquals("Your password has been updated", profilePage.getSuccess());
changePasswordPage.logout();
loginPage.open();
loginPage.login("johnkeycloak", "Bad-password1");
Assert.assertEquals("Invalid username or password.", loginPage.getError());
loginPage.open();
loginPage.login("johnkeycloak", "New-password1");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
// Change password back to previous value
changePasswordPage.open();
changePasswordPage.changePassword("New-password1", "Password1", "Password1");
Assert.assertEquals("Your password has been updated", profilePage.getSuccess());
}
@Test
public void registerExistingLdapUser() {
loginPage.open();
loginPage.clickRegister();
registerPage.assertCurrent();
// check existing username
registerPage.register("firstName", "lastName", "email@mail.cz", "existing", "Password1", "Password1");
registerPage.assertCurrent();
Assert.assertEquals("Username already exists", registerPage.getError());
// Check existing email
registerPage.register("firstName", "lastName", "existing@email.org", "nonExisting", "Password1", "Password1");
registerPage.assertCurrent();
Assert.assertEquals("Email already exists", registerPage.getError());
}
@Test
public void registerUserLdapSuccess() {
loginPage.open();
loginPage.clickRegister();
registerPage.assertCurrent();
registerPage.register("firstName", "lastName", "email2@check.cz", "registerUserSuccess2", "Password1", "Password1");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("registerUserSuccess2", appRealm);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getFederationLink());
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
} finally {
keycloakRule.stopSession(session, false);
}
}
@Test
public void testReadonly() {
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
UserFederationProviderModel model = new UserFederationProviderModel(ldapModel.getId(), ldapModel.getProviderName(), ldapModel.getConfig(),
ldapModel.getPriority(), ldapModel.getDisplayName(), -1, -1, 0);
model.getConfig().put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.READ_ONLY.toString());
appRealm.updateUserFederationProvider(model);
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getFederationLink());
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
try {
user.setEmail("error@error.com");
Assert.fail("should fail");
} catch (ModelReadOnlyException e) {
}
try {
user.setLastName("Berk");
Assert.fail("should fail");
} catch (ModelReadOnlyException e) {
}
try {
user.setFirstName("Bilbo");
Assert.fail("should fail");
} catch (ModelReadOnlyException e) {
}
try {
UserCredentialModel cred = UserCredentialModel.password("PoopyPoop1");
user.updateCredential(cred);
Assert.fail("should fail");
} catch (ModelReadOnlyException e) {
}
Assert.assertFalse(session.users().removeUser(appRealm, user));
} finally {
keycloakRule.stopSession(session, false);
}
session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
Assert.assertEquals(UserFederationProvider.EditMode.WRITABLE.toString(), appRealm.getUserFederationProviders().get(0).getConfig().get(LDAPFederationProvider.EDIT_MODE));
} finally {
keycloakRule.stopSession(session, false);
}
}
@Test
public void testRemoveFederatedUser() {
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("registerUserSuccess2", appRealm);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getFederationLink());
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
Assert.assertTrue(session.users().removeUser(appRealm, user));
Assert.assertNull(session.users().getUserByUsername("registerUserSuccess2", appRealm));
} finally {
keycloakRule.stopSession(session, true);
}
}
@Test
public void testSearch() {
KeycloakSession session = keycloakRule.startSession();
PartitionManager partitionManager = getPartitionManager(session, ldapModel);
try {
RealmModel appRealm = session.realms().getRealmByName("test");
LDAPUtils.addUser(partitionManager, "username1", "John1", "Doel1", "user1@email.org");
LDAPUtils.addUser(partitionManager, "username2", "John2", "Doel2", "user2@email.org");
LDAPUtils.addUser(partitionManager, "username3", "John3", "Doel3", "user3@email.org");
LDAPUtils.addUser(partitionManager, "username4", "John4", "Doel4", "user4@email.org");
// Users are not at local store at this moment
Assert.assertNull(session.userStorage().getUserByUsername("username1", appRealm));
Assert.assertNull(session.userStorage().getUserByUsername("username2", appRealm));
Assert.assertNull(session.userStorage().getUserByUsername("username3", appRealm));
Assert.assertNull(session.userStorage().getUserByUsername("username4", appRealm));
// search by username
session.users().searchForUser("username1", appRealm);
SyncProvidersTest.assertUserImported(session.userStorage(), appRealm, "username1", "John1", "Doel1", "user1@email.org");
// search by email
session.users().searchForUser("user2@email.org", appRealm);
SyncProvidersTest.assertUserImported(session.userStorage(), appRealm, "username2", "John2", "Doel2", "user2@email.org");
// search by lastName
session.users().searchForUser("Doel3", appRealm);
SyncProvidersTest.assertUserImported(session.userStorage(), appRealm, "username3", "John3", "Doel3", "user3@email.org");
// search by firstName + lastName
session.users().searchForUser("John4 Doel4", appRealm);
SyncProvidersTest.assertUserImported(session.userStorage(), appRealm, "username4", "John4", "Doel4", "user4@email.org");
} finally {
keycloakRule.stopSession(session, true);
}
}
@Test
public void testUnsynced() {
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
UserFederationProviderModel model = new UserFederationProviderModel(ldapModel.getId(), ldapModel.getProviderName(), ldapModel.getConfig(), ldapModel.getPriority(),
ldapModel.getDisplayName(), -1, -1, 0);
model.getConfig().put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.UNSYNCED.toString());
appRealm.updateUserFederationProvider(model);
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getFederationLink());
Assert.assertEquals(user.getFederationLink(), ldapModel.getId());
UserCredentialModel cred = UserCredentialModel.password("Candycand1");
user.updateCredential(cred);
UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0);
Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType());
Assert.assertTrue(session.users().validCredentials(appRealm, user, cred));
// LDAP password is still unchanged
Assert.assertTrue(LDAPUtils.validatePassword(getPartitionManager(session, model), "johnkeycloak", "Password1"));
// ATM it's not permitted to delete user in unsynced mode. Should be user deleted just locally instead?
Assert.assertFalse(session.users().removeUser(appRealm, user));
} finally {
keycloakRule.stopSession(session, false);
}
session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
Assert.assertEquals(UserFederationProvider.EditMode.WRITABLE.toString(), appRealm.getUserFederationProviders().get(0).getConfig().get(LDAPFederationProvider.EDIT_MODE));
} finally {
keycloakRule.stopSession(session, false);
}
}
static PartitionManager getPartitionManager(KeycloakSession keycloakSession, UserFederationProviderModel ldapFedModel) {
PartitionManagerProvider partitionManagerProvider = keycloakSession.getProvider(PartitionManagerProvider.class);
return partitionManagerProvider.getPartitionManager(ldapFedModel);
}
}