[New] Allow to reload sessions for LDAP users
This commit is contained in:
parent
6e87ffc078
commit
30536cb11c
|
@ -1223,6 +1223,11 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user.getUserState() == UserState.DISABLED || user.getUserState() == UserState.EXPIRED) {
|
||||||
|
logger.error("Ignoring session data for disabled/expired user " + username);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> userRoles = user.getRoles();
|
Set<String> userRoles = user.getRoles();
|
||||||
if (userRoles.isEmpty()) {
|
if (userRoles.isEmpty()) {
|
||||||
logger.error("Ignoring session data for user " + username + " which has not roles defined!");
|
logger.error("Ignoring session data for user " + username + " which has not roles defined!");
|
||||||
|
|
|
@ -2,6 +2,7 @@ package li.strolch.privilege.handler;
|
||||||
|
|
||||||
import javax.naming.Context;
|
import javax.naming.Context;
|
||||||
import javax.naming.NamingEnumeration;
|
import javax.naming.NamingEnumeration;
|
||||||
|
import javax.naming.NamingException;
|
||||||
import javax.naming.directory.*;
|
import javax.naming.directory.*;
|
||||||
import javax.naming.ldap.LdapName;
|
import javax.naming.ldap.LdapName;
|
||||||
import javax.naming.ldap.Rdn;
|
import javax.naming.ldap.Rdn;
|
||||||
|
@ -49,28 +50,30 @@ public class LdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
throws InvalidCredentialsException, AccessDeniedException {
|
throws InvalidCredentialsException, AccessDeniedException {
|
||||||
|
|
||||||
// first see if this is a local user
|
// first see if this is a local user
|
||||||
if (this.persistenceHandler.getUser(username) != null)
|
User internalUser = this.persistenceHandler.getUser(username);
|
||||||
|
if (internalUser != null && internalUser.getUserState() != UserState.REMOTE)
|
||||||
return super.checkCredentialsAndUserState(username, password);
|
return super.checkCredentialsAndUserState(username, password);
|
||||||
|
|
||||||
// Set up the environment for creating the initial context
|
// Set up the environment for creating the initial context
|
||||||
Hashtable<String, String> env = new Hashtable<>();
|
Hashtable<String, String> env = new Hashtable<>();
|
||||||
|
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||||
env.put(Context.PROVIDER_URL, providerUrl);
|
env.put(Context.PROVIDER_URL, this.providerUrl);
|
||||||
|
|
||||||
// Authenticate
|
// Authenticate
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||||
env.put(Context.SECURITY_PRINCIPAL, username + domain);
|
env.put(Context.SECURITY_PRINCIPAL, username + this.domain);
|
||||||
env.put(Context.SECURITY_CREDENTIALS, new String(password));
|
env.put(Context.SECURITY_CREDENTIALS, new String(password));
|
||||||
|
|
||||||
logger.info("User {} tries to login on ldap", username + domain);
|
logger.info("User {} tries to login on ldap", username + this.domain);
|
||||||
|
|
||||||
String memberOfLdapString = "";
|
String memberOfLdapString = "";
|
||||||
Set<String> strolchRoles = new HashSet<>();
|
Set<String> strolchRoles = new HashSet<>();
|
||||||
|
|
||||||
// Create the initial context
|
// Create the initial context
|
||||||
|
DirContext ctx = null;
|
||||||
try {
|
try {
|
||||||
DirContext ctx = new InitialDirContext(env);
|
ctx = new InitialDirContext(env);
|
||||||
|
|
||||||
//Create the search controls
|
//Create the search controls
|
||||||
SearchControls searchCtls = new SearchControls();
|
SearchControls searchCtls = new SearchControls();
|
||||||
|
@ -79,18 +82,35 @@ public class LdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||||
|
|
||||||
String searchFilter =
|
String searchFilter =
|
||||||
"(&(objectCategory=person)(objectClass=user)(userPrincipalName=" + username + domain + "))";
|
"(&(objectCategory=person)(objectClass=user)(userPrincipalName=" + username + this.domain + "))";
|
||||||
|
|
||||||
// Search for objects using the filter
|
// Search for objects using the filter
|
||||||
NamingEnumeration<SearchResult> answer = ctx.search(searchBase, searchFilter, searchCtls);
|
NamingEnumeration<SearchResult> answer = ctx.search(this.searchBase, searchFilter, searchCtls);
|
||||||
|
|
||||||
|
if (!answer.hasMore())
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
"Could not login with user: " + username + this.domain + " on Ldap: no LDAP Data");
|
||||||
|
|
||||||
//Loop through the search results
|
|
||||||
while (answer.hasMoreElements()) {
|
|
||||||
SearchResult sr = (SearchResult) answer.next();
|
SearchResult sr = (SearchResult) answer.next();
|
||||||
|
if (answer.hasMore())
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
"Could not login with user: " + username + this.domain + " on Ldap: Multiple LDAP Data");
|
||||||
|
|
||||||
Attributes attrs = sr.getAttributes();
|
Attributes attrs = sr.getAttributes();
|
||||||
Attribute groupMembers = attrs.get("memberOf");
|
|
||||||
|
|
||||||
|
Attribute sAMAccountName = attrs.get("sAMAccountName");
|
||||||
|
if (sAMAccountName == null || !username.equals(sAMAccountName.get().toString()))
|
||||||
|
throw new AccessDeniedException(
|
||||||
|
"Could not login with user: " + username + this.domain + " on Ldap: Wrong LDAP Data");
|
||||||
|
|
||||||
|
Attribute givenName = attrs.get("givenName");
|
||||||
|
Attribute sn = attrs.get("sn");
|
||||||
|
|
||||||
|
String firstName = givenName == null ? username : givenName.get().toString();
|
||||||
|
String lastName = sn == null ? username : sn.get().toString();
|
||||||
|
|
||||||
|
// evaluate roles for this user
|
||||||
|
Attribute groupMembers = attrs.get("memberOf");
|
||||||
if (groupMembers != null) {
|
if (groupMembers != null) {
|
||||||
for (int i = 0; i < groupMembers.size(); i++) {
|
for (int i = 0; i < groupMembers.size(); i++) {
|
||||||
|
|
||||||
|
@ -101,7 +121,7 @@ public class LdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
for (Rdn rdn : memberOfName.getRdns()) {
|
for (Rdn rdn : memberOfName.getRdns()) {
|
||||||
if (rdn.getType().equalsIgnoreCase("CN")) {
|
if (rdn.getType().equalsIgnoreCase("CN")) {
|
||||||
String groupName = rdn.getValue().toString();
|
String groupName = rdn.getValue().toString();
|
||||||
Set<String> foundStrolchRoles = rolesForLdapGroups.get(groupName);
|
Set<String> foundStrolchRoles = this.rolesForLdapGroups.get(groupName);
|
||||||
if (foundStrolchRoles != null)
|
if (foundStrolchRoles != null)
|
||||||
strolchRoles.addAll(foundStrolchRoles);
|
strolchRoles.addAll(foundStrolchRoles);
|
||||||
break;
|
break;
|
||||||
|
@ -111,26 +131,42 @@ public class LdapPrivilegeHandler extends DefaultPrivilegeHandler {
|
||||||
logger.info("User " + username + " is member of groups: " + memberOfLdapString);
|
logger.info("User " + username + " is member of groups: " + memberOfLdapString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ctx.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Could not login with user: " + username + domain + " on Ldap", e);
|
|
||||||
throw new AccessDeniedException("Could not login with user: " + username + domain + " on Ldap", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
|
|
||||||
// this must be changed, because the location param must be taken from the logged in person
|
// this must be changed, because the location param must be taken from the logged in person
|
||||||
properties.put("location", location);
|
properties.put("location", this.location);
|
||||||
|
|
||||||
if (adminUsers.contains(username)) {
|
// see if this is an admin user
|
||||||
strolchRoles = rolesForLdapGroups.get("admin");
|
if (this.adminUsers.contains(username))
|
||||||
}
|
strolchRoles = this.rolesForLdapGroups.get("admin");
|
||||||
|
|
||||||
return new User(username, username, null, null, null, -1, -1, username, username, UserState.ENABLED,
|
User user = new User(username, username, null, null, null, -1, -1, firstName, lastName, UserState.REMOTE,
|
||||||
strolchRoles, Locale.GERMAN, properties);
|
strolchRoles, Locale.GERMAN, properties);
|
||||||
|
|
||||||
|
// persist this user
|
||||||
|
if (internalUser == null)
|
||||||
|
this.persistenceHandler.addUser(user);
|
||||||
|
else
|
||||||
|
this.persistenceHandler.replaceUser(user);
|
||||||
|
|
||||||
|
if (this.autoPersistOnUserChangesData)
|
||||||
|
this.persistenceHandler.persist();
|
||||||
|
|
||||||
|
return user;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Could not login with user: " + username + domain + " on Ldap", e);
|
||||||
|
throw new AccessDeniedException("Could not login with user: " + username + domain + " on Ldap", e);
|
||||||
|
} finally {
|
||||||
|
if (ctx != null) {
|
||||||
|
try {
|
||||||
|
ctx.close();
|
||||||
|
} catch (NamingException e) {
|
||||||
|
logger.error("Failed to close DirContext", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Set<String>> getLdapGroupToRolesMappingFromConfig(Map<String, String> params) {
|
private Map<String, Set<String>> getLdapGroupToRolesMappingFromConfig(Map<String, String> params) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ import li.strolch.privilege.model.internal.User;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum UserState {
|
public enum UserState {
|
||||||
/**
|
/**
|
||||||
|
@ -40,6 +39,10 @@ public enum UserState {
|
||||||
* thus login
|
* thus login
|
||||||
*/
|
*/
|
||||||
ENABLED,
|
ENABLED,
|
||||||
|
/**
|
||||||
|
* the user is only available remotely, e.g. over LDAP, but allows for session restoration
|
||||||
|
*/
|
||||||
|
REMOTE,
|
||||||
/**
|
/**
|
||||||
* the user been disabled by an administrator
|
* the user been disabled by an administrator
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
package li.strolch.privilege.xml;
|
package li.strolch.privilege.xml;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
import li.strolch.privilege.helper.XmlConstants;
|
import li.strolch.privilege.helper.XmlConstants;
|
||||||
import li.strolch.privilege.model.IPrivilege;
|
import li.strolch.privilege.model.IPrivilege;
|
||||||
import li.strolch.privilege.model.internal.Role;
|
import li.strolch.privilege.model.internal.Role;
|
||||||
import li.strolch.utils.helper.XmlHelper;
|
import li.strolch.utils.helper.XmlHelper;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -34,11 +34,6 @@ public class PrivilegeRolesDomWriter {
|
||||||
private List<Role> roles;
|
private List<Role> roles;
|
||||||
private File modelFile;
|
private File modelFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param users
|
|
||||||
* @param roles
|
|
||||||
* @param modelFile
|
|
||||||
*/
|
|
||||||
public PrivilegeRolesDomWriter(List<Role> roles, File modelFile) {
|
public PrivilegeRolesDomWriter(List<Role> roles, File modelFile) {
|
||||||
this.roles = roles;
|
this.roles = roles;
|
||||||
this.modelFile = modelFile;
|
this.modelFile = modelFile;
|
||||||
|
@ -51,7 +46,7 @@ public class PrivilegeRolesDomWriter {
|
||||||
Element rootElement = doc.createElement(XmlConstants.XML_ROLES);
|
Element rootElement = doc.createElement(XmlConstants.XML_ROLES);
|
||||||
doc.appendChild(rootElement);
|
doc.appendChild(rootElement);
|
||||||
|
|
||||||
this.roles.stream().sorted((r1, r2) -> r1.getName().compareTo(r2.getName())).forEach(role -> {
|
this.roles.stream().sorted(Comparator.comparing(Role::getName)).forEach(role -> {
|
||||||
|
|
||||||
// create the role element
|
// create the role element
|
||||||
Element roleElement = doc.createElement(XmlConstants.XML_ROLE);
|
Element roleElement = doc.createElement(XmlConstants.XML_ROLE);
|
||||||
|
|
Loading…
Reference in New Issue