Merge pull request #605 from mposolda/master
LDAP testing and improvements
This commit is contained in:
commit
b96f8aef6d
12 changed files with 220 additions and 182 deletions
|
@ -117,15 +117,9 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
public UserModel register(RealmModel realm, UserModel user) {
|
public UserModel register(RealmModel realm, UserModel user) {
|
||||||
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) throw new IllegalStateException("Registration is not supported by this ldap server");;
|
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) throw new IllegalStateException("Registration is not supported by this ldap server");;
|
||||||
if (!synchronizeRegistrations()) throw new IllegalStateException("Registration is not supported by this ldap server");
|
if (!synchronizeRegistrations()) throw new IllegalStateException("Registration is not supported by this ldap server");
|
||||||
IdentityManager identityManager = getIdentityManager();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
User picketlinkUser = new User(user.getUsername());
|
User picketlinkUser = LDAPUtils.addUser(this.partitionManager, user.getUsername(), user.getFirstName(), user.getLastName(), user.getEmail());
|
||||||
picketlinkUser.setFirstName(user.getFirstName());
|
|
||||||
picketlinkUser.setLastName(user.getLastName());
|
|
||||||
picketlinkUser.setEmail(user.getEmail());
|
|
||||||
picketlinkUser.setAttribute(new Attribute("fullName", getFullName(user)));
|
|
||||||
identityManager.add(picketlinkUser);
|
|
||||||
user.setAttribute(LDAP_ID, picketlinkUser.getId());
|
user.setAttribute(LDAP_ID, picketlinkUser.getId());
|
||||||
return proxy(user);
|
return proxy(user);
|
||||||
} catch (IdentityManagementException ie) {
|
} catch (IdentityManagementException ie) {
|
||||||
|
@ -138,15 +132,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||||
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) return false;
|
if (editMode == EditMode.READ_ONLY || editMode == EditMode.UNSYNCED) return false;
|
||||||
|
|
||||||
IdentityManager identityManager = getIdentityManager();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
User picketlinkUser = BasicModel.getUser(identityManager, user.getUsername());
|
return LDAPUtils.removeUser(partitionManager, user.getUsername());
|
||||||
if (picketlinkUser == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
identityManager.remove(picketlinkUser);
|
|
||||||
return true;
|
|
||||||
} catch (IdentityManagementException ie) {
|
} catch (IdentityManagementException ie) {
|
||||||
throw convertIDMException(ie);
|
throw convertIDMException(ie);
|
||||||
}
|
}
|
||||||
|
@ -192,10 +179,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid(UserModel local) {
|
public boolean isValid(UserModel local) {
|
||||||
IdentityManager identityManager = getIdentityManager();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
User picketlinkUser = BasicModel.getUser(identityManager, local.getUsername());
|
User picketlinkUser = LDAPUtils.getUser(partitionManager, local.getUsername());
|
||||||
if (picketlinkUser == null) {
|
if (picketlinkUser == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -207,10 +192,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByUsername(RealmModel realm, String username) {
|
public UserModel getUserByUsername(RealmModel realm, String username) {
|
||||||
IdentityManager identityManager = getIdentityManager();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
User picketlinkUser = LDAPUtils.getUser(partitionManager, username);
|
||||||
if (picketlinkUser == null) {
|
if (picketlinkUser == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -277,18 +260,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validPassword(String username, String password) {
|
public boolean validPassword(String username, String password) {
|
||||||
IdentityManager identityManager = getIdentityManager();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
return LDAPUtils.validatePassword(partitionManager, username, password);
|
||||||
credential.setUsername(username);
|
|
||||||
credential.setPassword(new Password(password.toCharArray()));
|
|
||||||
identityManager.validateCredentials(credential);
|
|
||||||
if (credential.getStatus() == Credentials.Status.VALID) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (IdentityManagementException ie) {
|
} catch (IdentityManagementException ie) {
|
||||||
throw convertIDMException(ie);
|
throw convertIDMException(ie);
|
||||||
}
|
}
|
||||||
|
@ -323,23 +296,4 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
||||||
public void close() {
|
public void close() {
|
||||||
//To change body of implemented methods use File | Settings | File Templates.
|
//To change body of implemented methods use File | Settings | File Templates.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed for ActiveDirectory updates
|
|
||||||
protected String getFullName(UserModel user) {
|
|
||||||
String fullName;
|
|
||||||
if (user.getFirstName() != null && user.getLastName() != null) {
|
|
||||||
fullName = user.getFirstName() + " " + user.getLastName();
|
|
||||||
} else if (user.getFirstName() != null && user.getFirstName().trim().length() > 0) {
|
|
||||||
fullName = user.getFirstName();
|
|
||||||
} else {
|
|
||||||
fullName = user.getLastName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to loginName
|
|
||||||
if (fullName == null || fullName.trim().length() == 0) {
|
|
||||||
fullName = user.getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fullName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
106
federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
Executable file
106
federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
Executable file
|
@ -0,0 +1,106 @@
|
||||||
|
package org.keycloak.federation.ldap;
|
||||||
|
|
||||||
|
import org.picketlink.idm.IdentityManager;
|
||||||
|
import org.picketlink.idm.PartitionManager;
|
||||||
|
import org.picketlink.idm.credential.Credentials;
|
||||||
|
import org.picketlink.idm.credential.Password;
|
||||||
|
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
||||||
|
import org.picketlink.idm.model.Attribute;
|
||||||
|
import org.picketlink.idm.model.basic.BasicModel;
|
||||||
|
import org.picketlink.idm.model.basic.User;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow to directly call some operations against Picketlink IDM PartitionManager (hence LDAP).
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class LDAPUtils {
|
||||||
|
|
||||||
|
public static User addUser(PartitionManager partitionManager, String username, String firstName, String lastName, String email) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
User picketlinkUser = new User(username);
|
||||||
|
picketlinkUser.setFirstName(firstName);
|
||||||
|
picketlinkUser.setLastName(lastName);
|
||||||
|
picketlinkUser.setEmail(email);
|
||||||
|
picketlinkUser.setAttribute(new Attribute("fullName", getFullName(username, firstName, lastName)));
|
||||||
|
idmManager.add(picketlinkUser);
|
||||||
|
return picketlinkUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updatePassword(PartitionManager partitionManager, User picketlinkUser, String password) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
idmManager.updateCredential(picketlinkUser, new Password(password.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validatePassword(PartitionManager partitionManager, String username, String password) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
|
||||||
|
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
||||||
|
credential.setUsername(username);
|
||||||
|
credential.setPassword(new Password(password.toCharArray()));
|
||||||
|
idmManager.validateCredentials(credential);
|
||||||
|
if (credential.getStatus() == Credentials.Status.VALID) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isUserExists(PartitionManager partitionManager, String username) {
|
||||||
|
return getUser(partitionManager, username) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User getUser(PartitionManager partitionManager, String username) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
return BasicModel.getUser(idmManager, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean removeUser(PartitionManager partitionManager, String username) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
User picketlinkUser = BasicModel.getUser(idmManager, username);
|
||||||
|
if (picketlinkUser == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
idmManager.remove(picketlinkUser);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeAllUsers(PartitionManager partitionManager) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
List<User> users = idmManager.createIdentityQuery(User.class).getResultList();
|
||||||
|
|
||||||
|
for (User user : users) {
|
||||||
|
idmManager.remove(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<User> getAllUsers(PartitionManager partitionManager) {
|
||||||
|
IdentityManager idmManager = getIdentityManager(partitionManager);
|
||||||
|
return idmManager.createIdentityQuery(User.class).getResultList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IdentityManager getIdentityManager(PartitionManager partitionManager) {
|
||||||
|
return partitionManager.createIdentityManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed for ActiveDirectory updates
|
||||||
|
private static String getFullName(String username, String firstName, String lastName) {
|
||||||
|
String fullName;
|
||||||
|
if (firstName != null && lastName != null) {
|
||||||
|
fullName = firstName + " " + lastName;
|
||||||
|
} else if (firstName != null && firstName.trim().length() > 0) {
|
||||||
|
fullName = firstName;
|
||||||
|
} else {
|
||||||
|
fullName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to loginName
|
||||||
|
if (fullName == null || fullName.trim().length() == 0) {
|
||||||
|
fullName = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -445,11 +445,20 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
||||||
$scope.instance.config = {};
|
$scope.instance.config = {};
|
||||||
$scope.instance.priority = 0;
|
$scope.instance.priority = 0;
|
||||||
$scope.syncRegistrations = false;
|
$scope.syncRegistrations = false;
|
||||||
|
|
||||||
$scope.userAccountControlsAfterPasswordUpdate = true;
|
$scope.userAccountControlsAfterPasswordUpdate = true;
|
||||||
$scope.instance.config.userAccountControlsAfterPasswordUpdate = true;
|
$scope.instance.config.userAccountControlsAfterPasswordUpdate = "true";
|
||||||
|
|
||||||
|
$scope.connectionPooling = true;
|
||||||
|
$scope.instance.config.connectionPooling = "true";
|
||||||
|
|
||||||
|
$scope.pagination = true;
|
||||||
|
$scope.instance.config.pagination = "true";
|
||||||
} else {
|
} else {
|
||||||
$scope.syncRegistrations = instance.config.syncRegistrations && instance.config.syncRegistrations == "true";
|
$scope.syncRegistrations = instance.config.syncRegistrations && instance.config.syncRegistrations == "true";
|
||||||
$scope.userAccountControlsAfterPasswordUpdate = instance.config.userAccountControlsAfterPasswordUpdate && instance.config.userAccountControlsAfterPasswordUpdate == "true";
|
$scope.userAccountControlsAfterPasswordUpdate = instance.config.userAccountControlsAfterPasswordUpdate && instance.config.userAccountControlsAfterPasswordUpdate == "true";
|
||||||
|
$scope.connectionPooling = instance.config.connectionPooling && instance.config.connectionPooling == "true";
|
||||||
|
$scope.pagination = instance.config.pagination && instance.config.pagination == "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.ldapVendors = [
|
$scope.ldapVendors = [
|
||||||
|
@ -469,21 +478,20 @@ module.controller('LDAPCtrl', function($scope, $location, Notifications, Dialog,
|
||||||
|
|
||||||
$scope.lastVendor = $scope.instance.config.vendor;
|
$scope.lastVendor = $scope.instance.config.vendor;
|
||||||
|
|
||||||
$scope.$watch('syncRegistrations', function() {
|
function watchBooleanProperty(propertyName) {
|
||||||
if ($scope.syncRegistrations) {
|
$scope.$watch(propertyName, function() {
|
||||||
$scope.instance.config.syncRegistrations = "true";
|
if ($scope[propertyName]) {
|
||||||
|
$scope.instance.config[propertyName] = "true";
|
||||||
} else {
|
} else {
|
||||||
$scope.instance.config.syncRegistrations = "false";
|
$scope.instance.config[propertyName] = "false";
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
$scope.$watch('userAccountControlsAfterPasswordUpdate', function() {
|
watchBooleanProperty('syncRegistrations');
|
||||||
if ($scope.userAccountControlsAfterPasswordUpdate) {
|
watchBooleanProperty('userAccountControlsAfterPasswordUpdate');
|
||||||
$scope.instance.config.userAccountControlsAfterPasswordUpdate = "true";
|
watchBooleanProperty('connectionPooling');
|
||||||
} else {
|
watchBooleanProperty('pagination');
|
||||||
$scope.instance.config.userAccountControlsAfterPasswordUpdate = "false";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
$scope.$watch('instance', function() {
|
$scope.$watch('instance', function() {
|
||||||
if (!angular.equals($scope.instance, instance)) {
|
if (!angular.equals($scope.instance, instance)) {
|
||||||
|
|
|
@ -116,6 +116,18 @@
|
||||||
<a class="btn btn-primary" data-ng-click="testAuthentication()">Test authentication</a>
|
<a class="btn btn-primary" data-ng-click="testAuthentication()">Test authentication</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="connectionPooling">Connection pooling</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="connectionPooling" name="connectionPooling" id="connectionPooling" onoffswitch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-sm-2 control-label" for="pagination">Pagination</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input ng-model="pagination" name="pagination" id="pagination" onoffswitch />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group clearfix" data-ng-show="instance.config.vendor === 'ad' ">
|
<div class="form-group clearfix" data-ng-show="instance.config.vendor === 'ad' ">
|
||||||
<label class="col-sm-2 control-label" for="userAccountControlsAfterPasswordUpdate">Enable Account After Password Update</label>
|
<label class="col-sm-2 control-label" for="userAccountControlsAfterPasswordUpdate">Enable Account After Password Update</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
|
|
@ -19,5 +19,8 @@ public class LDAPConstants {
|
||||||
public static final String BIND_DN = "bindDn";
|
public static final String BIND_DN = "bindDn";
|
||||||
public static final String BIND_CREDENTIAL = "bindCredential";
|
public static final String BIND_CREDENTIAL = "bindCredential";
|
||||||
|
|
||||||
|
public static final String CONNECTION_POOLING = "connectionPooling";
|
||||||
|
public static final String PAGINATION = "pagination";
|
||||||
|
|
||||||
public static final String USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "userAccountControlsAfterPasswordUpdate";
|
public static final String USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "userAccountControlsAfterPasswordUpdate";
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,9 @@ public class PartitionManagerRegistry {
|
||||||
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
|
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
|
||||||
|
|
||||||
Properties connectionProps = new Properties();
|
Properties connectionProps = new Properties();
|
||||||
connectionProps.put("com.sun.jndi.ldap.connect.pool", "true");
|
if (ldapConfig.containsKey(LDAPConstants.CONNECTION_POOLING)) {
|
||||||
|
connectionProps.put("com.sun.jndi.ldap.connect.pool", ldapConfig.get(LDAPConstants.CONNECTION_POOLING));
|
||||||
|
}
|
||||||
|
|
||||||
checkSystemProperty("com.sun.jndi.ldap.connect.pool.authentication", "none simple");
|
checkSystemProperty("com.sun.jndi.ldap.connect.pool.authentication", "none simple");
|
||||||
checkSystemProperty("com.sun.jndi.ldap.connect.pool.initsize", "1");
|
checkSystemProperty("com.sun.jndi.ldap.connect.pool.initsize", "1");
|
||||||
|
@ -83,6 +85,8 @@ public class PartitionManagerRegistry {
|
||||||
String ldapFirstNameMapping = activeDirectory ? "givenName" : CN;
|
String ldapFirstNameMapping = activeDirectory ? "givenName" : CN;
|
||||||
String[] userObjectClasses = getUserObjectClasses(ldapConfig);
|
String[] userObjectClasses = getUserObjectClasses(ldapConfig);
|
||||||
|
|
||||||
|
boolean pagination = ldapConfig.containsKey(LDAPConstants.PAGINATION) ? Boolean.parseBoolean(ldapConfig.get(LDAPConstants.PAGINATION)) : false;
|
||||||
|
|
||||||
// Use same mapping for User and Agent for now
|
// Use same mapping for User and Agent for now
|
||||||
LDAPStoreConfigurationBuilder ldapStoreBuilder =
|
LDAPStoreConfigurationBuilder ldapStoreBuilder =
|
||||||
builder
|
builder
|
||||||
|
@ -96,7 +100,8 @@ public class PartitionManagerRegistry {
|
||||||
.bindCredential(ldapConfig.get(LDAPConstants.BIND_CREDENTIAL))
|
.bindCredential(ldapConfig.get(LDAPConstants.BIND_CREDENTIAL))
|
||||||
.url(ldapConfig.get(LDAPConstants.CONNECTION_URL))
|
.url(ldapConfig.get(LDAPConstants.CONNECTION_URL))
|
||||||
.activeDirectory(activeDirectory)
|
.activeDirectory(activeDirectory)
|
||||||
.supportAllFeatures();
|
.supportAllFeatures()
|
||||||
|
.pagination(pagination);
|
||||||
|
|
||||||
// RHDS is using "nsuniqueid" as unique identifier instead of "entryUUID"
|
// RHDS is using "nsuniqueid" as unique identifier instead of "entryUUID"
|
||||||
if (vendor != null && vendor.equals(LDAPConstants.VENDOR_RHDS)) {
|
if (vendor != null && vendor.equals(LDAPConstants.VENDOR_RHDS)) {
|
||||||
|
|
|
@ -107,7 +107,7 @@ public class KeycloakServer {
|
||||||
//bootstrapLdap(); Can't seem to get this to work.
|
//bootstrapLdap(); Can't seem to get this to work.
|
||||||
bootstrapKeycloakServer(args);
|
bootstrapKeycloakServer(args);
|
||||||
}
|
}
|
||||||
private static LDAPEmbeddedServer embeddedServer;
|
/*private static LDAPEmbeddedServer embeddedServer;
|
||||||
public static void bootstrapLdap() throws Exception {
|
public static void bootstrapLdap() throws Exception {
|
||||||
embeddedServer = new LDAPEmbeddedServer();
|
embeddedServer = new LDAPEmbeddedServer();
|
||||||
embeddedServer.setup();
|
embeddedServer.setup();
|
||||||
|
@ -124,7 +124,7 @@ public class KeycloakServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
} */
|
||||||
|
|
||||||
public static KeycloakServer bootstrapKeycloakServer(String[] args) throws Throwable {
|
public static KeycloakServer bootstrapKeycloakServer(String[] args) throws Throwable {
|
||||||
KeycloakServerConfig config = new KeycloakServerConfig();
|
KeycloakServerConfig config = new KeycloakServerConfig();
|
||||||
|
|
|
@ -29,26 +29,20 @@ import java.util.Properties;
|
||||||
*/
|
*/
|
||||||
public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
|
|
||||||
public static final String BASE_DN = "dc=keycloak,dc=org";
|
|
||||||
public static final String LDAP_URL = "ldap://localhost:10389";
|
|
||||||
public static final String ROLES_DN_SUFFIX = "ou=Roles,dc=keycloak,dc=org";
|
|
||||||
public static final String GROUP_DN_SUFFIX = "ou=Groups,dc=keycloak,dc=org";
|
|
||||||
public static final String USER_DN_SUFFIX = "ou=People,dc=keycloak,dc=org";
|
|
||||||
public static final String AGENT_DN_SUFFIX = "ou=Agent,dc=keycloak,dc=org";
|
|
||||||
public static final String CUSTOM_ACCOUNT_DN_SUFFIX = "ou=CustomAccount,dc=keycloak,dc=org";
|
|
||||||
|
|
||||||
public static final String CONNECTION_PROPERTIES = "ldap/ldap-connection.properties";
|
public static final String CONNECTION_PROPERTIES = "ldap/ldap-connection.properties";
|
||||||
|
|
||||||
protected String connectionUrl = LDAP_URL;
|
protected String connectionUrl = "ldap://localhost:10389";
|
||||||
protected String baseDn = BASE_DN;
|
protected String baseDn = "dc=keycloak,dc=org";
|
||||||
protected String userDnSuffix = USER_DN_SUFFIX;
|
protected String userDnSuffix = "ou=People,dc=keycloak,dc=org";
|
||||||
protected String rolesDnSuffix = ROLES_DN_SUFFIX;
|
protected String rolesDnSuffix = "ou=Roles,dc=keycloak,dc=org";
|
||||||
protected String groupDnSuffix = GROUP_DN_SUFFIX;
|
protected String groupDnSuffix = "ou=Groups,dc=keycloak,dc=org";
|
||||||
protected String agentDnSuffix = AGENT_DN_SUFFIX;
|
protected String agentDnSuffix = "ou=Agent,dc=keycloak,dc=org";
|
||||||
protected boolean startEmbeddedLdapLerver = true;
|
protected boolean startEmbeddedLdapLerver = true;
|
||||||
protected String bindDn = "uid=admin,ou=system";
|
protected String bindDn = "uid=admin,ou=system";
|
||||||
protected String bindCredential = "secret";
|
protected String bindCredential = "secret";
|
||||||
protected String vendor;
|
protected String vendor = LDAPConstants.VENDOR_OTHER;
|
||||||
|
protected boolean connectionPooling = true;
|
||||||
|
protected boolean pagination = true;
|
||||||
|
|
||||||
public static String IDM_TEST_LDAP_CONNECTION_URL = "idm.test.ldap.connection.url";
|
public static String IDM_TEST_LDAP_CONNECTION_URL = "idm.test.ldap.connection.url";
|
||||||
public static String IDM_TEST_LDAP_BASE_DN = "idm.test.ldap.base.dn";
|
public static String IDM_TEST_LDAP_BASE_DN = "idm.test.ldap.base.dn";
|
||||||
|
@ -60,6 +54,8 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
public static String IDM_TEST_LDAP_BIND_DN = "idm.test.ldap.bind.dn";
|
public static String IDM_TEST_LDAP_BIND_DN = "idm.test.ldap.bind.dn";
|
||||||
public static String IDM_TEST_LDAP_BIND_CREDENTIAL = "idm.test.ldap.bind.credential";
|
public static String IDM_TEST_LDAP_BIND_CREDENTIAL = "idm.test.ldap.bind.credential";
|
||||||
public static String IDM_TEST_LDAP_VENDOR = "idm.test.ldap.vendor";
|
public static String IDM_TEST_LDAP_VENDOR = "idm.test.ldap.vendor";
|
||||||
|
public static String IDM_TEST_LDAP_CONNECTION_POOLING = "idm.test.ldap.connection.pooling";
|
||||||
|
public static String IDM_TEST_LDAP_PAGINATION = "idm.test.ldap.pagination";
|
||||||
|
|
||||||
|
|
||||||
public LDAPEmbeddedServer() {
|
public LDAPEmbeddedServer() {
|
||||||
|
@ -77,16 +73,18 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionUrl = p.getProperty(IDM_TEST_LDAP_CONNECTION_URL, LDAP_URL);
|
connectionUrl = p.getProperty(IDM_TEST_LDAP_CONNECTION_URL, connectionUrl);
|
||||||
baseDn = p.getProperty(IDM_TEST_LDAP_BASE_DN, BASE_DN);
|
baseDn = p.getProperty(IDM_TEST_LDAP_BASE_DN, baseDn);
|
||||||
userDnSuffix = p.getProperty(IDM_TEST_LDAP_USER_DN_SUFFIX, USER_DN_SUFFIX);
|
userDnSuffix = p.getProperty(IDM_TEST_LDAP_USER_DN_SUFFIX, userDnSuffix);
|
||||||
rolesDnSuffix = p.getProperty(IDM_TEST_LDAP_ROLES_DN_SUFFIX, ROLES_DN_SUFFIX);
|
rolesDnSuffix = p.getProperty(IDM_TEST_LDAP_ROLES_DN_SUFFIX, rolesDnSuffix);
|
||||||
groupDnSuffix = p.getProperty(IDM_TEST_LDAP_GROUP_DN_SUFFIX, GROUP_DN_SUFFIX);
|
groupDnSuffix = p.getProperty(IDM_TEST_LDAP_GROUP_DN_SUFFIX, groupDnSuffix);
|
||||||
agentDnSuffix = p.getProperty(IDM_TEST_LDAP_AGENT_DN_SUFFIX, AGENT_DN_SUFFIX);
|
agentDnSuffix = p.getProperty(IDM_TEST_LDAP_AGENT_DN_SUFFIX, agentDnSuffix);
|
||||||
startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_START_EMBEDDED_LDAP_SERVER, "true"));
|
startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_START_EMBEDDED_LDAP_SERVER, "true"));
|
||||||
bindDn = p.getProperty(IDM_TEST_LDAP_BIND_DN, bindDn);
|
bindDn = p.getProperty(IDM_TEST_LDAP_BIND_DN, bindDn);
|
||||||
bindCredential = p.getProperty(IDM_TEST_LDAP_BIND_CREDENTIAL, bindCredential);
|
bindCredential = p.getProperty(IDM_TEST_LDAP_BIND_CREDENTIAL, bindCredential);
|
||||||
vendor = p.getProperty(IDM_TEST_LDAP_VENDOR);
|
vendor = p.getProperty(IDM_TEST_LDAP_VENDOR);
|
||||||
|
connectionPooling = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_CONNECTION_POOLING, "true"));
|
||||||
|
pagination = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_PAGINATION, "true"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -95,7 +93,7 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
if (isStartEmbeddedLdapLerver()) {
|
if (isStartEmbeddedLdapLerver()) {
|
||||||
// On Windows, the directory may not be fully deleted from previous test
|
// On Windows, the directory may not be fully deleted from previous test
|
||||||
String tempDir = System.getProperty("java.io.tmpdir");
|
String tempDir = System.getProperty("java.io.tmpdir");
|
||||||
File workDir = new File(tempDir + "/server-work");
|
File workDir = new File(tempDir + File.separator + "server-work");
|
||||||
if (workDir.exists()) {
|
if (workDir.exists()) {
|
||||||
recursiveDeleteDir(workDir);
|
recursiveDeleteDir(workDir);
|
||||||
}
|
}
|
||||||
|
@ -106,13 +104,13 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
|
// suppress emb. LDAP server stop
|
||||||
|
if (isStartEmbeddedLdapLerver()) {
|
||||||
|
|
||||||
// clear data left in LDAP
|
// clear data left in LDAP
|
||||||
DirContext ctx = getDirContext();
|
DirContext ctx = getDirContext();
|
||||||
clearSubContexts(ctx, new CompositeName(baseDn));
|
clearSubContexts(ctx, new CompositeName(baseDn));
|
||||||
|
|
||||||
// suppress emb. LDAP server stop
|
|
||||||
if (isStartEmbeddedLdapLerver()) {
|
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +125,7 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupLdapInRealm(RealmModel realm) {
|
public Map<String,String> getLDAPConfig() {
|
||||||
Map<String,String> ldapConfig = new HashMap<String,String>();
|
Map<String,String> ldapConfig = new HashMap<String,String>();
|
||||||
ldapConfig.put(LDAPConstants.CONNECTION_URL, getConnectionUrl());
|
ldapConfig.put(LDAPConstants.CONNECTION_URL, getConnectionUrl());
|
||||||
ldapConfig.put(LDAPConstants.BASE_DN, getBaseDn());
|
ldapConfig.put(LDAPConstants.BASE_DN, getBaseDn());
|
||||||
|
@ -135,6 +133,9 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
ldapConfig.put(LDAPConstants.BIND_CREDENTIAL, getBindCredential());
|
ldapConfig.put(LDAPConstants.BIND_CREDENTIAL, getBindCredential());
|
||||||
ldapConfig.put(LDAPConstants.USER_DN_SUFFIX, getUserDnSuffix());
|
ldapConfig.put(LDAPConstants.USER_DN_SUFFIX, getUserDnSuffix());
|
||||||
ldapConfig.put(LDAPConstants.VENDOR, getVendor());
|
ldapConfig.put(LDAPConstants.VENDOR, getVendor());
|
||||||
|
ldapConfig.put(LDAPConstants.CONNECTION_POOLING, String.valueOf(isConnectionPooling()));
|
||||||
|
ldapConfig.put(LDAPConstants.PAGINATION, String.valueOf(isPagination()));
|
||||||
|
return ldapConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,6 +209,14 @@ public class LDAPEmbeddedServer extends AbstractLDAPTest {
|
||||||
return vendor;
|
return vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isConnectionPooling() {
|
||||||
|
return connectionPooling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPagination() {
|
||||||
|
return pagination;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void importLDIF(String fileName) throws Exception {
|
public void importLDIF(String fileName) throws Exception {
|
||||||
// import LDIF only in case we are running against embedded LDAP server
|
// import LDIF only in case we are running against embedded LDAP server
|
||||||
|
|
|
@ -7,3 +7,5 @@ idm.test.ldap.agent.dn.suffix=ou\=Agent,dc\=keycloak,dc\=org
|
||||||
idm.test.ldap.start.embedded.ldap.server=true
|
idm.test.ldap.start.embedded.ldap.server=true
|
||||||
idm.test.ldap.bind.dn=uid\=admin,ou\=system
|
idm.test.ldap.bind.dn=uid\=admin,ou\=system
|
||||||
idm.test.ldap.bind.credential=secret
|
idm.test.ldap.bind.credential=secret
|
||||||
|
idm.test.ldap.connection.pooling=true
|
||||||
|
idm.test.ldap.pagination=true
|
|
@ -19,22 +19,3 @@ objectclass: top
|
||||||
objectclass: organizationalUnit
|
objectclass: organizationalUnit
|
||||||
ou: Groups
|
ou: Groups
|
||||||
|
|
||||||
dn: uid=johnkeycloak,ou=People,dc=keycloak,dc=org
|
|
||||||
objectclass: top
|
|
||||||
objectclass: uidObject
|
|
||||||
objectclass: person
|
|
||||||
objectclass: inetOrgPerson
|
|
||||||
uid: johnkeycloak
|
|
||||||
cn: John
|
|
||||||
sn: Doe
|
|
||||||
mail: john@email.org
|
|
||||||
|
|
||||||
dn: uid=existing,ou=People,dc=keycloak,dc=org
|
|
||||||
objectclass: top
|
|
||||||
objectclass: uidObject
|
|
||||||
objectclass: person
|
|
||||||
objectclass: inetOrgPerson
|
|
||||||
uid: existing
|
|
||||||
cn: Existing
|
|
||||||
sn: Foo
|
|
||||||
mail: existing@email.org
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package org.keycloak.testsuite;
|
|
||||||
|
|
||||||
import org.keycloak.picketlink.ldap.PartitionManagerRegistry;
|
|
||||||
import org.picketlink.idm.IdentityManager;
|
|
||||||
import org.picketlink.idm.PartitionManager;
|
|
||||||
import org.picketlink.idm.credential.Password;
|
|
||||||
import org.picketlink.idm.model.basic.BasicModel;
|
|
||||||
import org.picketlink.idm.model.basic.User;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class LDAPTestUtils {
|
|
||||||
|
|
||||||
public static void setLdapPassword(Map<String, String> ldapConfig, String username, String password) {
|
|
||||||
// Update password directly in ldap. It's workaround, but LDIF import doesn't seem to work on windows for ApacheDS
|
|
||||||
try {
|
|
||||||
PartitionManager partitionManager = PartitionManagerRegistry.createPartitionManager(ldapConfig);
|
|
||||||
IdentityManager identityManager = partitionManager.createIdentityManager();
|
|
||||||
User user = BasicModel.getUser(identityManager, username);
|
|
||||||
identityManager.updateCredential(user, new Password(password.toCharArray()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,22 +9,16 @@ import org.junit.Test;
|
||||||
import org.junit.rules.RuleChain;
|
import org.junit.rules.RuleChain;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||||
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||||
import org.keycloak.models.ApplicationModel;
|
|
||||||
import org.keycloak.models.Constants;
|
|
||||||
import org.keycloak.models.UserCredentialValueModel;
|
import org.keycloak.models.UserCredentialValueModel;
|
||||||
import org.keycloak.models.UserFederationProvider;
|
import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.federation.ldap.LDAPUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.picketlink.PartitionManagerProvider;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
|
||||||
import org.keycloak.testutils.LDAPEmbeddedServer;
|
import org.keycloak.testutils.LDAPEmbeddedServer;
|
||||||
import org.keycloak.testsuite.LDAPTestUtils;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.LDAPConstants;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -41,8 +35,9 @@ import org.keycloak.testsuite.rule.LDAPRule;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.picketlink.idm.PartitionManager;
|
||||||
|
import org.picketlink.idm.model.basic.User;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,8 +48,6 @@ public class FederationProvidersIntegrationTest {
|
||||||
|
|
||||||
private static LDAPRule ldapRule = new LDAPRule();
|
private static LDAPRule ldapRule = new LDAPRule();
|
||||||
|
|
||||||
private static Map<String,String> ldapConfig = null;
|
|
||||||
|
|
||||||
private static UserFederationProviderModel ldapModel = null;
|
private static UserFederationProviderModel ldapModel = null;
|
||||||
|
|
||||||
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||||
|
@ -62,27 +55,22 @@ public class FederationProvidersIntegrationTest {
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
addUser(manager.getSession(), appRealm, "mary", "mary@test.com", "password-app");
|
addUser(manager.getSession(), appRealm, "mary", "mary@test.com", "password-app");
|
||||||
addUser(manager.getSession(), adminstrationRealm, "mary-admin", "mary@admin.com", "password-admin");
|
|
||||||
|
|
||||||
LDAPEmbeddedServer ldapServer = ldapRule.getEmbeddedServer();
|
LDAPEmbeddedServer ldapServer = ldapRule.getEmbeddedServer();
|
||||||
ldapConfig = new HashMap<String,String>();
|
Map<String,String> ldapConfig = ldapServer.getLDAPConfig();
|
||||||
ldapConfig.put(LDAPConstants.CONNECTION_URL, ldapServer.getConnectionUrl());
|
|
||||||
ldapConfig.put(LDAPConstants.BASE_DN, ldapServer.getBaseDn());
|
|
||||||
ldapConfig.put(LDAPConstants.BIND_DN, ldapServer.getBindDn());
|
|
||||||
ldapConfig.put(LDAPConstants.BIND_CREDENTIAL, ldapServer.getBindCredential());
|
|
||||||
ldapConfig.put(LDAPConstants.USER_DN_SUFFIX, ldapServer.getUserDnSuffix());
|
|
||||||
String vendor = ldapServer.getVendor();
|
|
||||||
ldapConfig.put(LDAPConstants.VENDOR, vendor);
|
|
||||||
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true");
|
ldapConfig.put(LDAPFederationProvider.SYNC_REGISTRATIONS, "true");
|
||||||
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
|
ldapConfig.put(LDAPFederationProvider.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap");
|
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap");
|
||||||
|
|
||||||
// Configure LDAP
|
// Delete all LDAP users and add some new for testing
|
||||||
ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm);
|
PartitionManager partitionManager = getPartitionManager(manager.getSession(), ldapModel);
|
||||||
LDAPTestUtils.setLdapPassword(ldapConfig, "johnkeycloak", "password");
|
LDAPUtils.removeAllUsers(partitionManager);
|
||||||
|
|
||||||
|
User john = LDAPUtils.addUser(partitionManager, "johnkeycloak", "John", "Doe", "john@email.org");
|
||||||
|
LDAPUtils.updatePassword(partitionManager, john, "password");
|
||||||
|
|
||||||
|
User existing = LDAPUtils.addUser(partitionManager, "existing", "Existing", "Foo", "existing@email.org");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -128,16 +116,6 @@ public class FederationProvidersIntegrationTest {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
public void runit() throws Exception {
|
|
||||||
System.out.println("*** ldap config ***");
|
|
||||||
for (Map.Entry<String, String> entry : ldapConfig.entrySet()) {
|
|
||||||
System.out.println("key: " + entry.getKey() + " value: " + entry.getValue());
|
|
||||||
}
|
|
||||||
Thread.sleep(10000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loginClassic() {
|
public void loginClassic() {
|
||||||
loginPage.open();
|
loginPage.open();
|
||||||
|
@ -163,7 +141,7 @@ public class FederationProvidersIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void XdeleteLink() { // make sure this happens after loginLdap()
|
public void XdeleteLink() {
|
||||||
loginLdap();
|
loginLdap();
|
||||||
{
|
{
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
@ -320,6 +298,9 @@ public class FederationProvidersIntegrationTest {
|
||||||
UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0);
|
UserCredentialValueModel userCredentialValueModel = user.getCredentialsDirectly().get(0);
|
||||||
Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType());
|
Assert.assertEquals(UserCredentialModel.PASSWORD, userCredentialValueModel.getType());
|
||||||
Assert.assertTrue(session.users().validCredentials(appRealm, user, cred));
|
Assert.assertTrue(session.users().validCredentials(appRealm, user, cred));
|
||||||
|
|
||||||
|
// LDAP password is still unchanged
|
||||||
|
Assert.assertTrue(LDAPUtils.validatePassword(getPartitionManager(session, model), "johnkeycloak", "new-password"));
|
||||||
} finally {
|
} finally {
|
||||||
keycloakRule.stopSession(session, false);
|
keycloakRule.stopSession(session, false);
|
||||||
}
|
}
|
||||||
|
@ -333,4 +314,9 @@ public class FederationProvidersIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PartitionManager getPartitionManager(KeycloakSession keycloakSession, UserFederationProviderModel ldapFedModel) {
|
||||||
|
PartitionManagerProvider partitionManagerProvider = keycloakSession.getProvider(PartitionManagerProvider.class);
|
||||||
|
return partitionManagerProvider.getPartitionManager(ldapFedModel);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue