import org.argeo.api.cms.CmsLog;
import org.argeo.cms.internal.http.client.HttpCredentialProvider;
import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
+import org.argeo.osgi.useradmin.DirectoryUserAdmin;
import org.argeo.osgi.useradmin.AggregatingUserAdmin;
-import org.argeo.osgi.useradmin.LdapUserAdmin;
-import org.argeo.osgi.useradmin.LdifUserAdmin;
-import org.argeo.osgi.useradmin.OsUserDirectory;
import org.argeo.osgi.useradmin.UserDirectory;
import org.argeo.util.directory.DirectoryConf;
import org.argeo.util.naming.dns.DnsBrowser;
}
// Create
- UserDirectory userDirectory;
- if (realm != null || DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
- || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
- userDirectory = new LdapUserAdmin(properties);
- } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
- userDirectory = new LdifUserAdmin(u, properties);
- } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
- userDirectory = new OsUserDirectory(u, properties);
- singleUser = true;
- } else {
- throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
- }
+ UserDirectory userDirectory = new DirectoryUserAdmin(u, properties);
+// if (realm != null || DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
+// || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
+// userDirectory = new LdapUserAdmin(properties);
+// } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
+// userDirectory = new LdifUserAdmin(u, properties);
+// } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
+// userDirectory = new OsUserDirectory(u, properties);
+// singleUser = true;
+// } else {
+// throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+// }
String basePath = userDirectory.getContext();
addUserDirectory(userDirectory);
+++ /dev/null
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-import static org.argeo.util.naming.LdapObjs.extensibleObject;
-import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
-import static org.argeo.util.naming.LdapObjs.organizationalPerson;
-import static org.argeo.util.naming.LdapObjs.person;
-import static org.argeo.util.naming.LdapObjs.top;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.naming.InvalidNameException;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.AbstractLdapDirectory;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
-import org.argeo.util.directory.ldap.LdapNameUtils;
-import org.argeo.util.naming.LdapAttrs;
-import org.argeo.util.naming.LdapObjs;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/** Base class for a {@link UserDirectory}. */
-abstract class AbstractUserDirectory extends AbstractLdapDirectory implements UserAdmin, UserDirectory {
-
- private UserAdmin externalRoles;
- // private List<String> indexedUserProperties = Arrays
- // .asList(new String[] { LdapAttrs.uid.name(), LdapAttrs.mail.name(),
- // LdapAttrs.cn.name() });
-
- // Transaction
-// private TransactionManager transactionManager;
- AbstractUserDirectory(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
- super(uriArg, props, scoped);
- }
-
- /*
- * ABSTRACT METHODS
- */
-
- protected abstract AbstractLdapDirectory scope(User user);
-
- /** Returns the groups this user is a direct member of. */
- protected abstract List<LdapName> getDirectGroups(LdapName dn);
-
- /*
- * INITIALIZATION
- */
-
- public void init() {
-
- }
-
- public void destroy() {
-
- }
-
- @Override
- public String getRolePath(Role role) {
- return nameToRelativePath(((DirectoryUser) role).getDn());
- }
-
- @Override
- public String getRoleSimpleName(Role role) {
- LdapName dn = LdapNameUtils.toLdapName(role.getName());
- String name = LdapNameUtils.getLastRdnValue(dn);
- return name;
- }
-
- @Override
- public Role getRoleByPath(String path) {
- return doGetRole(pathToName(path));
- }
-
- protected List<Role> getAllRoles(DirectoryUser user) {
- List<Role> allRoles = new ArrayList<Role>();
- if (user != null) {
- collectRoles(user, allRoles);
- allRoles.add(user);
- } else
- collectAnonymousRoles(allRoles);
- return allRoles;
- }
-
- private void collectRoles(DirectoryUser user, List<Role> allRoles) {
- Attributes attrs = user.getAttributes();
- // TODO centralize attribute name
- Attribute memberOf = attrs.get(LdapAttrs.memberOf.name());
- // if user belongs to this directory, we only check meberOf
- if (memberOf != null && user.getDn().startsWith(getBaseDn())) {
- try {
- NamingEnumeration<?> values = memberOf.getAll();
- while (values.hasMore()) {
- Object value = values.next();
- LdapName groupDn = new LdapName(value.toString());
- DirectoryUser group = doGetRole(groupDn);
- if (group != null)
- allRoles.add(group);
- }
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
- }
- } else {
- for (LdapName groupDn : getDirectGroups(user.getDn())) {
- // TODO check for loops
- DirectoryUser group = doGetRole(groupDn);
- if (group != null) {
- allRoles.add(group);
- collectRoles(group, allRoles);
- }
- }
- }
- }
-
- private void collectAnonymousRoles(List<Role> allRoles) {
- // TODO gather anonymous roles
- }
-
- // USER ADMIN
- @Override
- public Role getRole(String name) {
- return doGetRole(toLdapName(name));
- }
-
- protected DirectoryUser doGetRole(LdapName dn) {
- LdapEntryWorkingCopy wc = getWorkingCopy();
- DirectoryUser user;
- try {
- user = (DirectoryUser) daoGetEntry(dn);
- } catch (NameNotFoundException e) {
- user = null;
- }
- if (wc != null) {
- if (user == null && wc.getNewData().containsKey(dn))
- user = (DirectoryUser) wc.getNewData().get(dn);
- else if (wc.getDeletedData().containsKey(dn))
- user = null;
- }
- return user;
- }
-
- @Override
- public Role[] getRoles(String filter) throws InvalidSyntaxException {
- List<? extends Role> res = getRoles(getBaseDn(), filter, true);
- return res.toArray(new Role[res.size()]);
- }
-
- List<DirectoryUser> getRoles(LdapName searchBase, String filter, boolean deep) throws InvalidSyntaxException {
- LdapEntryWorkingCopy wc = getWorkingCopy();
- Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
- List<LdapEntry> searchRes = doGetEntries(searchBase, f, deep);
- List<DirectoryUser> res = new ArrayList<>();
- for (LdapEntry entry : searchRes)
- res.add((DirectoryUser) entry);
- if (wc != null) {
- for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
- DirectoryUser user = (DirectoryUser) it.next();
- LdapName dn = user.getDn();
- if (wc.getDeletedData().containsKey(dn))
- it.remove();
- }
- for (LdapEntry ldapEntry : wc.getNewData().values()) {
- DirectoryUser user = (DirectoryUser) ldapEntry;
- if (f == null || f.match(user.getProperties()))
- res.add(user);
- }
- // no need to check modified users,
- // since doGetRoles was already based on the modified attributes
- }
-
- // if non deep we also search users and groups
-// if (!deep) {
-// try {
-// if (!(searchBase.endsWith(new LdapName(getUserBase()))
-// || searchBase.endsWith(new LdapName(getGroupBase())))) {
-// LdapName usersBase = (LdapName) ((LdapName) searchBase.clone()).add(getUserBase());
-// res.addAll(getRoles(usersBase, filter, false));
-// LdapName groupsBase = (LdapName) ((LdapName) searchBase.clone()).add(getGroupBase());
-// res.addAll(getRoles(groupsBase, filter, false));
-// }
-// } catch (InvalidNameException e) {
-// throw new IllegalStateException("Cannot search users and groups", e);
-// }
-// }
- return res;
- }
-
- @Override
- public User getUser(String key, String value) {
- // TODO check value null or empty
- List<DirectoryUser> collectedUsers = new ArrayList<DirectoryUser>();
- if (key != null) {
- doGetUser(key, value, collectedUsers);
- } else {
- throw new IllegalArgumentException("Key cannot be null");
- }
-
- if (collectedUsers.size() == 1) {
- return collectedUsers.get(0);
- } else if (collectedUsers.size() > 1) {
- // log.warn(collectedUsers.size() + " users for " + (key != null ? key + "=" :
- // "") + value);
- }
- return null;
- }
-
- protected void doGetUser(String key, String value, List<DirectoryUser> collectedUsers) {
- try {
- Filter f = FrameworkUtil.createFilter("(" + key + "=" + value + ")");
- List<LdapEntry> users = doGetEntries(getBaseDn(), f, true);
- for (LdapEntry entry : users)
- collectedUsers.add((DirectoryUser) entry);
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException("Cannot get user with " + key + "=" + value, e);
- }
- }
-
- @Override
- public Authorization getAuthorization(User user) {
- if (user == null || user instanceof DirectoryUser) {
- return new LdifAuthorization(user, getAllRoles((DirectoryUser) user));
- } else {
- // bind
- AbstractUserDirectory scopedUserAdmin = (AbstractUserDirectory) scope(user);
- try {
- DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName());
- if (directoryUser == null)
- throw new IllegalStateException("No scoped user found for " + user);
- LdifAuthorization authorization = new LdifAuthorization(directoryUser,
- scopedUserAdmin.getAllRoles(directoryUser));
- return authorization;
- } finally {
- scopedUserAdmin.destroy();
- }
- }
- }
-
- @Override
- public Role createRole(String name, int type) {
- checkEdit();
- LdapEntryWorkingCopy wc = getWorkingCopy();
- LdapName dn = toLdapName(name);
- if ((daoHasEntry(dn) && !wc.getDeletedData().containsKey(dn)) || wc.getNewData().containsKey(dn))
- throw new IllegalArgumentException("Already a role " + name);
- BasicAttributes attrs = new BasicAttributes(true);
- // attrs.put(LdifName.dn.name(), dn.toString());
- Rdn nameRdn = dn.getRdn(dn.size() - 1);
- // TODO deal with multiple attr RDN
- attrs.put(nameRdn.getType(), nameRdn.getValue());
- if (wc.getDeletedData().containsKey(dn)) {
- wc.getDeletedData().remove(dn);
- wc.getModifiedData().put(dn, attrs);
- return getRole(name);
- } else {
- wc.getModifiedData().put(dn, attrs);
- DirectoryUser newRole = newRole(dn, type, attrs);
- wc.getNewData().put(dn, newRole);
- return newRole;
- }
- }
-
- protected DirectoryUser newRole(LdapName dn, int type, Attributes attrs) {
- DirectoryUser newRole;
- BasicAttribute objClass = new BasicAttribute(objectClass.name());
- if (type == Role.USER) {
- String userObjClass = newUserObjectClass(dn);
- objClass.add(userObjClass);
- if (inetOrgPerson.name().equals(userObjClass)) {
- objClass.add(organizationalPerson.name());
- objClass.add(person.name());
- } else if (organizationalPerson.name().equals(userObjClass)) {
- objClass.add(person.name());
- }
- objClass.add(top.name());
- objClass.add(extensibleObject.name());
- attrs.put(objClass);
- newRole = newUser(dn, attrs);
- } else if (type == Role.GROUP) {
- String groupObjClass = getGroupObjectClass();
- objClass.add(groupObjClass);
- // objClass.add(LdifName.extensibleObject.name());
- objClass.add(top.name());
- attrs.put(objClass);
- newRole = newGroup(dn, attrs);
- } else
- throw new IllegalArgumentException("Unsupported type " + type);
- return newRole;
- }
-
- @Override
- public boolean removeRole(String name) {
- checkEdit();
- LdapEntryWorkingCopy wc = getWorkingCopy();
- LdapName dn = toLdapName(name);
- boolean actuallyDeleted;
- if (daoHasEntry(dn) || wc.getNewData().containsKey(dn)) {
- DirectoryUser user = (DirectoryUser) getRole(name);
- wc.getDeletedData().put(dn, user);
- actuallyDeleted = true;
- } else {// just removing from groups (e.g. system roles)
- actuallyDeleted = false;
- }
- for (LdapName groupDn : getDirectGroups(dn)) {
- DirectoryUser group = doGetRole(groupDn);
- group.getAttributes().get(getMemberAttributeId()).remove(dn.toString());
- }
- return actuallyDeleted;
- }
-
- /*
- * HIERARCHY
- */
- @Override
- public HierarchyUnit getHierarchyUnit(Role role) {
- LdapName dn = LdapNameUtils.toLdapName(role.getName());
- LdapName huDn = LdapNameUtils.getParent(dn);
- HierarchyUnit hierarchyUnit = doGetHierarchyUnit(huDn);
- if (hierarchyUnit == null)
- throw new IllegalStateException("No hierarchy unit found for " + role);
- return hierarchyUnit;
- }
-
- @Override
- public Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep) {
- LdapName dn = LdapNameUtils.toLdapName(hierarchyUnit.getContext());
- try {
- return getRoles(dn, filter, deep);
- } catch (InvalidSyntaxException e) {
- throw new IllegalArgumentException("Cannot filter " + filter + " " + dn, e);
- }
- }
-
- /*
- * ROLES CREATION
- */
- protected DirectoryUser newUser(LdapName name, Attributes attrs) {
- // TODO support devices, applications, etc.
- return new LdifUser.LdifPerson(this, name, attrs);
- }
-
- protected DirectoryGroup newGroup(LdapName name, Attributes attrs) {
- if (LdapNameUtils.getParentRdn(name).equals(getSystemRoleBaseRdn()))
- return new LdifGroup.LdifSystemPermissions(this, name, attrs);
-
- if (hasObjectClass(attrs, LdapObjs.organization))
- return new LdifGroup.LdifOrganization(this, name, attrs);
- else
- return new LdifGroup.LdifFunctionalGroup(this, name, attrs);
-
- }
-
- // GETTERS
- protected UserAdmin getExternalRoles() {
- return externalRoles;
- }
-
- protected int roleType(LdapName dn) {
- Rdn technicalRdn = LdapNameUtils.getParentRdn(dn);
- if (getGroupBaseRdn().equals(technicalRdn) || getSystemRoleBaseRdn().equals(technicalRdn))
- return Role.GROUP;
- else if (getUserBaseRdn().equals(technicalRdn))
- return Role.USER;
- else
- throw new IllegalArgumentException(
- "Cannot dind role type, " + technicalRdn + " is not a technical RDN for " + dn);
- }
-
- public void setExternalRoles(UserAdmin externalRoles) {
- this.externalRoles = externalRoles;
- }
-
-// public void setTransactionManager(TransactionManager transactionManager) {
-// this.transactionManager = transactionManager;
-// }
-
- /*
- * STATIC UTILITIES
- */
- static LdapName toLdapName(String name) {
- try {
- return new LdapName(name);
- } catch (InvalidNameException e) {
- throw new IllegalArgumentException(name + " is not an LDAP name", e);
- }
- }
-}
package org.argeo.osgi.useradmin;
-import static org.argeo.osgi.useradmin.AbstractUserDirectory.toLdapName;
+import static org.argeo.osgi.useradmin.DirectoryUserAdmin.toLdapName;
import java.util.ArrayList;
import java.util.Arrays;
private final LdapName tokensBaseDn;
// DAOs
- private AbstractUserDirectory systemRoles = null;
- private AbstractUserDirectory tokens = null;
- private Map<LdapName, AbstractUserDirectory> businessRoles = new HashMap<LdapName, AbstractUserDirectory>();
+ private DirectoryUserAdmin systemRoles = null;
+ private DirectoryUserAdmin tokens = null;
+ private Map<LdapName, DirectoryUserAdmin> businessRoles = new HashMap<LdapName, DirectoryUserAdmin>();
// TODO rather use an empty constructor and an init method
public AggregatingUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
if (user == null) {// anonymous
return systemRoles.getAuthorization(null);
}
- AbstractUserDirectory userReferentialOfThisUser = findUserAdmin(user.getName());
+ DirectoryUserAdmin userReferentialOfThisUser = findUserAdmin(user.getName());
Authorization rawAuthorization = userReferentialOfThisUser.getAuthorization(user);
String usernameToUse;
String displayNameToUse;
}
// gather roles from other referentials
- final AbstractUserDirectory userAdminToUse;// possibly scoped when authenticating
+ final DirectoryUserAdmin userAdminToUse;// possibly scoped when authenticating
if (user instanceof DirectoryUser) {
userAdminToUse = userReferentialOfThisUser;
} else if (user instanceof AuthenticatingUser) {
- userAdminToUse = (AbstractUserDirectory) userReferentialOfThisUser.scope(user);
+ userAdminToUse = (DirectoryUserAdmin) userReferentialOfThisUser.scope(user);
} else {
throw new IllegalArgumentException("Unsupported user type " + user.getClass());
}
// USER ADMIN AGGREGATOR
//
protected void addUserDirectory(UserDirectory ud) {
- if (!(ud instanceof AbstractUserDirectory))
- throw new IllegalArgumentException("Only " + AbstractUserDirectory.class.getName() + " is supported");
- AbstractUserDirectory userDirectory = (AbstractUserDirectory) ud;
+ if (!(ud instanceof DirectoryUserAdmin))
+ throw new IllegalArgumentException("Only " + DirectoryUserAdmin.class.getName() + " is supported");
+ DirectoryUserAdmin userDirectory = (DirectoryUserAdmin) ud;
String basePath = userDirectory.getContext();
if (isSystemRolesBaseDn(basePath)) {
this.systemRoles = userDirectory;
protected void postAdd(UserDirectory userDirectory) {
}
- private AbstractUserDirectory findUserAdmin(String name) {
+ private DirectoryUserAdmin findUserAdmin(String name) {
try {
return findUserAdmin(new LdapName(name));
} catch (InvalidNameException e) {
}
}
- private AbstractUserDirectory findUserAdmin(LdapName name) {
+ private DirectoryUserAdmin findUserAdmin(LdapName name) {
if (name.startsWith(systemRolesBaseDn))
return systemRoles;
if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
return tokens;
- List<AbstractUserDirectory> res = new ArrayList<>(1);
+ List<DirectoryUserAdmin> res = new ArrayList<>(1);
userDirectories: for (LdapName baseDn : businessRoles.keySet()) {
- AbstractUserDirectory userDirectory = businessRoles.get(baseDn);
+ DirectoryUserAdmin userDirectory = businessRoles.get(baseDn);
if (name.startsWith(baseDn)) {
if (userDirectory.isDisabled())
continue userDirectories;
public void destroy() {
for (LdapName name : businessRoles.keySet()) {
- AbstractUserDirectory userDirectory = businessRoles.get(name);
+ DirectoryUserAdmin userDirectory = businessRoles.get(name);
destroy(userDirectory);
}
businessRoles.clear();
systemRoles = null;
}
- private void destroy(AbstractUserDirectory userDirectory) {
+ private void destroy(DirectoryUserAdmin userDirectory) {
preDestroy(userDirectory);
userDirectory.destroy();
}
LdapName baseDn = toLdapName(basePath);
if (!businessRoles.containsKey(baseDn))
throw new IllegalStateException("No user directory registered for " + baseDn);
- AbstractUserDirectory userDirectory = businessRoles.remove(baseDn);
+ DirectoryUserAdmin userDirectory = businessRoles.remove(baseDn);
destroy(userDirectory);
}
package org.argeo.osgi.useradmin;
-import java.util.List;
-
-import javax.naming.ldap.LdapName;
-
import org.osgi.service.useradmin.Group;
/** A group in a user directroy. */
interface DirectoryGroup extends Group, DirectoryUser {
- List<LdapName> getMemberNames();
+// List<LdapName> getMemberNames();
}
package org.argeo.osgi.useradmin;
-import org.argeo.util.directory.ldap.LdapEntry;
import org.osgi.service.useradmin.User;
/** A user in a user directory. */
-interface DirectoryUser extends User, LdapEntry {
+interface DirectoryUser extends User {
}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import static org.argeo.util.naming.LdapAttrs.objectClass;
+import static org.argeo.util.naming.LdapObjs.extensibleObject;
+import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
+import static org.argeo.util.naming.LdapObjs.organizationalPerson;
+import static org.argeo.util.naming.LdapObjs.person;
+import static org.argeo.util.naming.LdapObjs.top;
+
+import java.net.URI;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.directory.DirectoryDigestUtils;
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.directory.ldap.AbstractLdapDirectory;
+import org.argeo.util.directory.ldap.LdapEntry;
+import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
+import org.argeo.util.directory.ldap.LdapNameUtils;
+import org.argeo.util.directory.ldap.LdifDao;
+import org.argeo.util.naming.LdapObjs;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Base class for a {@link UserDirectory}. */
+public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdmin, UserDirectory {
+
+ private UserAdmin externalRoles;
+ // private List<String> indexedUserProperties = Arrays
+ // .asList(new String[] { LdapAttrs.uid.name(), LdapAttrs.mail.name(),
+ // LdapAttrs.cn.name() });
+
+ // Transaction
+// private TransactionManager transactionManager;
+ public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props) {
+ this(uriArg, props, false);
+ }
+
+ public DirectoryUserAdmin(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
+ super(uriArg, props, scoped);
+ }
+
+ public DirectoryUserAdmin(Dictionary<String, ?> props) {
+ this(null, props);
+ }
+
+ /*
+ * ABSTRACT METHODS
+ */
+
+ protected AbstractLdapDirectory scope(User user) {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ protected DirectoryUserAdmin scopeLdap(User user) {
+ Dictionary<String, Object> credentials = user.getCredentials();
+ String username = (String) credentials.get(SHARED_STATE_USERNAME);
+ if (username == null)
+ username = user.getName();
+ Dictionary<String, Object> properties = cloneProperties();
+ properties.put(Context.SECURITY_PRINCIPAL, username.toString());
+ Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+ byte[] pwd = (byte[]) pwdCred;
+ if (pwd != null) {
+ char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+ properties.put(Context.SECURITY_CREDENTIALS, new String(password));
+ } else {
+ properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
+ }
+ return new DirectoryUserAdmin(null, properties, true);
+ }
+
+ protected DirectoryUserAdmin scopeLdif(User user) {
+ Dictionary<String, Object> credentials = user.getCredentials();
+ String username = (String) credentials.get(SHARED_STATE_USERNAME);
+ if (username == null)
+ username = user.getName();
+ Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+ byte[] pwd = (byte[]) pwdCred;
+ if (pwd != null) {
+ char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+ User directoryUser = (User) getRole(username);
+ if (!directoryUser.hasCredential(null, password))
+ throw new IllegalStateException("Invalid credentials");
+ } else {
+ throw new IllegalStateException("Password is required");
+ }
+ Dictionary<String, Object> properties = cloneProperties();
+ properties.put(DirectoryConf.readOnly.name(), "true");
+ DirectoryUserAdmin scopedUserAdmin = new DirectoryUserAdmin(null, properties, true);
+// scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups);
+// scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users);
+ // FIXME do it better
+ ((LdifDao) getDirectoryDao()).scope((LdifDao) scopedUserAdmin.getDirectoryDao());
+ return scopedUserAdmin;
+ }
+
+ @Override
+ public String getRolePath(Role role) {
+ return nameToRelativePath(LdapNameUtils.toLdapName(role.getName()));
+ }
+
+ @Override
+ public String getRoleSimpleName(Role role) {
+ LdapName dn = LdapNameUtils.toLdapName(role.getName());
+ String name = LdapNameUtils.getLastRdnValue(dn);
+ return name;
+ }
+
+ @Override
+ public Role getRoleByPath(String path) {
+ return (Role) doGetRole(pathToName(path));
+ }
+
+ protected List<Role> getAllRoles(DirectoryUser user) {
+ List<Role> allRoles = new ArrayList<Role>();
+ if (user != null) {
+ collectRoles(user, allRoles);
+ allRoles.add(user);
+ } else
+ collectAnonymousRoles(allRoles);
+ return allRoles;
+ }
+
+ private void collectRoles(DirectoryUser user, List<Role> allRoles) {
+ List<LdapEntry> allEntries = new ArrayList<>();
+ LdapEntry entry = (LdapEntry) user;
+ collectGroups(entry, allEntries);
+ for (LdapEntry e : allEntries) {
+ allRoles.add((Role) e);
+ }
+// Attributes attrs = user.getAttributes();
+// // TODO centralize attribute name
+// Attribute memberOf = attrs.get(LdapAttrs.memberOf.name());
+// // if user belongs to this directory, we only check memberOf
+// if (memberOf != null && user.getDn().startsWith(getBaseDn())) {
+// try {
+// NamingEnumeration<?> values = memberOf.getAll();
+// while (values.hasMore()) {
+// Object value = values.next();
+// LdapName groupDn = new LdapName(value.toString());
+// DirectoryUser group = doGetRole(groupDn);
+// if (group != null)
+// allRoles.add(group);
+// }
+// } catch (NamingException e) {
+// throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
+// }
+// } else {
+// for (LdapName groupDn : getDirectoryDao().getDirectGroups(user.getDn())) {
+// // TODO check for loops
+// DirectoryUser group = doGetRole(groupDn);
+// if (group != null) {
+// allRoles.add(group);
+// collectRoles(group, allRoles);
+// }
+// }
+// }
+ }
+
+ private void collectAnonymousRoles(List<Role> allRoles) {
+ // TODO gather anonymous roles
+ }
+
+ // USER ADMIN
+ @Override
+ public Role getRole(String name) {
+ return (Role) doGetRole(toLdapName(name));
+ }
+
+ @Override
+ public Role[] getRoles(String filter) throws InvalidSyntaxException {
+ List<? extends Role> res = getRoles(getBaseDn(), filter, true);
+ return res.toArray(new Role[res.size()]);
+ }
+
+ List<DirectoryUser> getRoles(LdapName searchBase, String filter, boolean deep) throws InvalidSyntaxException {
+ LdapEntryWorkingCopy wc = getWorkingCopy();
+// Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
+ List<LdapEntry> searchRes = getDirectoryDao().doGetEntries(searchBase, filter, deep);
+ List<DirectoryUser> res = new ArrayList<>();
+ for (LdapEntry entry : searchRes)
+ res.add((DirectoryUser) entry);
+ if (wc != null) {
+ for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
+ DirectoryUser user = (DirectoryUser) it.next();
+ LdapName dn = LdapNameUtils.toLdapName(user.getName());
+ if (wc.getDeletedData().containsKey(dn))
+ it.remove();
+ }
+ Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
+ for (LdapEntry ldapEntry : wc.getNewData().values()) {
+ DirectoryUser user = (DirectoryUser) ldapEntry;
+ if (f == null || f.match(user.getProperties()))
+ res.add(user);
+ }
+ // no need to check modified users,
+ // since doGetRoles was already based on the modified attributes
+ }
+
+ // if non deep we also search users and groups
+// if (!deep) {
+// try {
+// if (!(searchBase.endsWith(new LdapName(getUserBase()))
+// || searchBase.endsWith(new LdapName(getGroupBase())))) {
+// LdapName usersBase = (LdapName) ((LdapName) searchBase.clone()).add(getUserBase());
+// res.addAll(getRoles(usersBase, filter, false));
+// LdapName groupsBase = (LdapName) ((LdapName) searchBase.clone()).add(getGroupBase());
+// res.addAll(getRoles(groupsBase, filter, false));
+// }
+// } catch (InvalidNameException e) {
+// throw new IllegalStateException("Cannot search users and groups", e);
+// }
+// }
+ return res;
+ }
+
+ @Override
+ public User getUser(String key, String value) {
+ // TODO check value null or empty
+ List<DirectoryUser> collectedUsers = new ArrayList<DirectoryUser>();
+ if (key != null) {
+ doGetUser(key, value, collectedUsers);
+ } else {
+ throw new IllegalArgumentException("Key cannot be null");
+ }
+
+ if (collectedUsers.size() == 1) {
+ return collectedUsers.get(0);
+ } else if (collectedUsers.size() > 1) {
+ // log.warn(collectedUsers.size() + " users for " + (key != null ? key + "=" :
+ // "") + value);
+ }
+ return null;
+ }
+
+ protected void doGetUser(String key, String value, List<DirectoryUser> collectedUsers) {
+ String f = "(" + key + "=" + value + ")";
+ List<LdapEntry> users = getDirectoryDao().doGetEntries(getBaseDn(), f, true);
+ for (LdapEntry entry : users)
+ collectedUsers.add((DirectoryUser) entry);
+ }
+
+ @Override
+ public Authorization getAuthorization(User user) {
+ if (user == null || user instanceof DirectoryUser) {
+ return new LdifAuthorization(user, getAllRoles((DirectoryUser) user));
+ } else {
+ // bind
+ DirectoryUserAdmin scopedUserAdmin = (DirectoryUserAdmin) scope(user);
+ try {
+ DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName());
+ if (directoryUser == null)
+ throw new IllegalStateException("No scoped user found for " + user);
+ LdifAuthorization authorization = new LdifAuthorization(directoryUser,
+ scopedUserAdmin.getAllRoles(directoryUser));
+ return authorization;
+ } finally {
+ scopedUserAdmin.destroy();
+ }
+ }
+ }
+
+ @Override
+ public Role createRole(String name, int type) {
+ checkEdit();
+ LdapEntryWorkingCopy wc = getWorkingCopy();
+ LdapName dn = toLdapName(name);
+ if ((getDirectoryDao().daoHasEntry(dn) && !wc.getDeletedData().containsKey(dn))
+ || wc.getNewData().containsKey(dn))
+ throw new IllegalArgumentException("Already a role " + name);
+ BasicAttributes attrs = new BasicAttributes(true);
+ // attrs.put(LdifName.dn.name(), dn.toString());
+ Rdn nameRdn = dn.getRdn(dn.size() - 1);
+ // TODO deal with multiple attr RDN
+ attrs.put(nameRdn.getType(), nameRdn.getValue());
+ if (wc.getDeletedData().containsKey(dn)) {
+ wc.getDeletedData().remove(dn);
+ wc.getModifiedData().put(dn, attrs);
+ return getRole(name);
+ } else {
+ wc.getModifiedData().put(dn, attrs);
+ LdapEntry newRole = newRole(dn, type, attrs);
+ wc.getNewData().put(dn, newRole);
+ return (Role) newRole;
+ }
+ }
+
+ protected LdapEntry newRole(LdapName dn, int type, Attributes attrs) {
+ LdapEntry newRole;
+ BasicAttribute objClass = new BasicAttribute(objectClass.name());
+ if (type == Role.USER) {
+ String userObjClass = getUserObjectClass();
+ objClass.add(userObjClass);
+ if (inetOrgPerson.name().equals(userObjClass)) {
+ objClass.add(organizationalPerson.name());
+ objClass.add(person.name());
+ } else if (organizationalPerson.name().equals(userObjClass)) {
+ objClass.add(person.name());
+ }
+ objClass.add(top.name());
+ objClass.add(extensibleObject.name());
+ attrs.put(objClass);
+ newRole = newUser(dn, attrs);
+ } else if (type == Role.GROUP) {
+ String groupObjClass = getGroupObjectClass();
+ objClass.add(groupObjClass);
+ // objClass.add(LdifName.extensibleObject.name());
+ objClass.add(top.name());
+ attrs.put(objClass);
+ newRole = newGroup(dn, attrs);
+ } else
+ throw new IllegalArgumentException("Unsupported type " + type);
+ return newRole;
+ }
+
+ @Override
+ public boolean removeRole(String name) {
+ return removeEntry(LdapNameUtils.toLdapName(name));
+// checkEdit();
+// LdapEntryWorkingCopy wc = getWorkingCopy();
+// LdapName dn = toLdapName(name);
+// boolean actuallyDeleted;
+// if (getDirectoryDao().daoHasEntry(dn) || wc.getNewData().containsKey(dn)) {
+// DirectoryUser user = (DirectoryUser) getRole(name);
+// wc.getDeletedData().put(dn, user);
+// actuallyDeleted = true;
+// } else {// just removing from groups (e.g. system roles)
+// actuallyDeleted = false;
+// }
+// for (LdapName groupDn : getDirectoryDao().getDirectGroups(dn)) {
+// LdapEntry group = doGetRole(groupDn);
+// group.getAttributes().get(getMemberAttributeId()).remove(dn.toString());
+// }
+// return actuallyDeleted;
+ }
+
+ /*
+ * HIERARCHY
+ */
+ @Override
+ public HierarchyUnit getHierarchyUnit(Role role) {
+ LdapName dn = LdapNameUtils.toLdapName(role.getName());
+ LdapName huDn = LdapNameUtils.getParent(dn);
+ HierarchyUnit hierarchyUnit = getDirectoryDao().doGetHierarchyUnit(huDn);
+ if (hierarchyUnit == null)
+ throw new IllegalStateException("No hierarchy unit found for " + role);
+ return hierarchyUnit;
+ }
+
+ @Override
+ public Iterable<? extends Role> getHierarchyUnitRoles(HierarchyUnit hierarchyUnit, String filter, boolean deep) {
+ LdapName dn = LdapNameUtils.toLdapName(hierarchyUnit.getContext());
+ try {
+ return getRoles(dn, filter, deep);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Cannot filter " + filter + " " + dn, e);
+ }
+ }
+
+ /*
+ * ROLES CREATION
+ */
+ protected LdapEntry newUser(LdapName name, Attributes attrs) {
+ // TODO support devices, applications, etc.
+ return new LdifUser.LdifPerson(this, name, attrs);
+ }
+
+ protected LdapEntry newGroup(LdapName name, Attributes attrs) {
+ if (LdapNameUtils.getParentRdn(name).equals(getSystemRoleBaseRdn()))
+ return new LdifGroup.LdifSystemPermissions(this, name, attrs);
+
+ if (hasObjectClass(attrs, LdapObjs.organization))
+ return new LdifGroup.LdifOrganization(this, name, attrs);
+ else
+ return new LdifGroup.LdifFunctionalGroup(this, name, attrs);
+
+ }
+
+ // GETTERS
+ protected UserAdmin getExternalRoles() {
+ return externalRoles;
+ }
+
+ public void setExternalRoles(UserAdmin externalRoles) {
+ this.externalRoles = externalRoles;
+ }
+
+// public void setTransactionManager(TransactionManager transactionManager) {
+// this.transactionManager = transactionManager;
+// }
+
+ /*
+ * STATIC UTILITIES
+ */
+ static LdapName toLdapName(String name) {
+ try {
+ return new LdapName(name);
+ } catch (InvalidNameException e) {
+ throw new IllegalArgumentException(name + " is not an LDAP name", e);
+ }
+ }
+}
+++ /dev/null
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.List;
-
-import javax.naming.AuthenticationNotSupportedException;
-import javax.naming.Binding;
-import javax.naming.Context;
-import javax.naming.InvalidNameException;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.DirectoryDigestUtils;
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.LdapConnection;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
-import org.argeo.util.directory.ldap.LdapHierarchyUnit;
-import org.argeo.util.naming.LdapObjs;
-import org.osgi.framework.Filter;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/** A user admin based on a LDAP server. */
-public class LdapUserAdmin extends AbstractUserDirectory {
- private LdapConnection ldapConnection;
-
- public LdapUserAdmin(Dictionary<String, ?> properties) {
- this(properties, false);
- }
-
- public LdapUserAdmin(Dictionary<String, ?> properties, boolean scoped) {
- super(null, properties, scoped);
- ldapConnection = new LdapConnection(getUri().toString(), properties);
- }
-
- public void destroy() {
- ldapConnection.destroy();
- }
-
- @Override
- protected AbstractUserDirectory scope(User user) {
- Dictionary<String, Object> credentials = user.getCredentials();
- String username = (String) credentials.get(SHARED_STATE_USERNAME);
- if (username == null)
- username = user.getName();
- Dictionary<String, Object> properties = cloneProperties();
- properties.put(Context.SECURITY_PRINCIPAL, username.toString());
- Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
- byte[] pwd = (byte[]) pwdCred;
- if (pwd != null) {
- char[] password = DirectoryDigestUtils.bytesToChars(pwd);
- properties.put(Context.SECURITY_CREDENTIALS, new String(password));
- } else {
- properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
- }
- return new LdapUserAdmin(properties, true);
- }
-
-// protected InitialLdapContext getLdapContext() {
-// return initialLdapContext;
-// }
-
- @Override
- protected Boolean daoHasEntry(LdapName dn) {
- try {
- return daoGetEntry(dn) != null;
- } catch (NameNotFoundException e) {
- return false;
- }
- }
-
- @Override
- protected DirectoryUser daoGetEntry(LdapName name) throws NameNotFoundException {
- try {
- Attributes attrs = ldapConnection.getAttributes(name);
- if (attrs.size() == 0)
- return null;
- int roleType = roleType(name);
- DirectoryUser res;
- if (roleType == Role.GROUP)
- res = newGroup(name, attrs);
- else if (roleType == Role.USER)
- res = newUser(name, attrs);
- else
- throw new IllegalArgumentException("Unsupported LDAP type for " + name);
- return res;
- } catch (NameNotFoundException e) {
- throw e;
- } catch (NamingException e) {
- return null;
- }
- }
-
- @Override
- protected List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep) {
- ArrayList<LdapEntry> res = new ArrayList<>();
- try {
- String searchFilter = f != null ? f.toString()
- : "(|(" + objectClass + "=" + getUserObjectClass() + ")(" + objectClass + "="
- + getGroupObjectClass() + "))";
- SearchControls searchControls = new SearchControls();
- // FIXME make one level consistent with deep
- searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
-
- // LdapName searchBase = getBaseDn();
- NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
- results: while (results.hasMoreElements()) {
- SearchResult searchResult = results.next();
- Attributes attrs = searchResult.getAttributes();
- Attribute objectClassAttr = attrs.get(objectClass.name());
- LdapName dn = toDn(searchBase, searchResult);
- DirectoryUser role;
- if (objectClassAttr.contains(getGroupObjectClass())
- || objectClassAttr.contains(getGroupObjectClass().toLowerCase()))
- role = newGroup(dn, attrs);
- else if (objectClassAttr.contains(getUserObjectClass())
- || objectClassAttr.contains(getUserObjectClass().toLowerCase()))
- role = newUser(dn, attrs);
- else {
-// log.warn("Unsupported LDAP type for " + searchResult.getName());
- continue results;
- }
- res.add(role);
- }
- return res;
- } catch (AuthenticationNotSupportedException e) {
- // ignore (typically an unsupported anonymous bind)
- // TODO better logging
- return res;
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot get roles for filter " + f, e);
- }
- }
-
- private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
- return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
- }
-
- @Override
- protected List<LdapName> getDirectGroups(LdapName dn) {
- List<LdapName> directGroups = new ArrayList<LdapName>();
- try {
- String searchFilter = "(&(" + objectClass + "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
- + "=" + dn + "))";
-
- SearchControls searchControls = new SearchControls();
- searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
- LdapName searchBase = getBaseDn();
- NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
- while (results.hasMoreElements()) {
- SearchResult searchResult = (SearchResult) results.nextElement();
- directGroups.add(toDn(searchBase, searchResult));
- }
- return directGroups;
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot populate direct members of " + dn, e);
- }
- }
-
- @Override
- public void prepare(LdapEntryWorkingCopy wc) {
- try {
- ldapConnection.prepareChanges(wc);
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot prepare LDAP", e);
- }
- }
-
- @Override
- public void commit(LdapEntryWorkingCopy wc) {
- try {
- ldapConnection.commitChanges(wc);
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot commit LDAP", e);
- }
- }
-
- @Override
- public void rollback(LdapEntryWorkingCopy wc) {
- // prepare not impacting
- }
-
- /*
- * HIERARCHY
- */
-
- @Override
- public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
- List<HierarchyUnit> res = new ArrayList<>();
- try {
- String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
- + "=" + LdapObjs.organization.name() + "))";
-
- SearchControls searchControls = new SearchControls();
- searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
-
- NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
-
- while (results.hasMoreElements()) {
- SearchResult searchResult = (SearchResult) results.nextElement();
- LdapName dn = toDn(searchBase, searchResult);
- Attributes attrs = searchResult.getAttributes();
- LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(this, dn, attrs);
- if (functionalOnly) {
- if (hierarchyUnit.isFunctional())
- res.add(hierarchyUnit);
- } else {
- res.add(hierarchyUnit);
- }
- }
- return res;
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot get direct hierarchy units ", e);
- }
- }
-
- @Override
- public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
- try {
- Attributes attrs = ldapConnection.getAttributes(dn);
- return new LdapHierarchyUnit(this, dn, attrs);
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
- }
- }
-
-}
import java.util.List;
import javax.naming.InvalidNameException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import org.argeo.util.directory.FunctionalGroup;
import org.argeo.util.directory.Organization;
import org.argeo.util.directory.SystemPermissions;
+import org.argeo.util.directory.ldap.AbstractLdapDirectory;
import org.osgi.service.useradmin.Role;
/** Directory group implementation */
abstract class LdifGroup extends LdifUser implements DirectoryGroup {
private final String memberAttributeId;
- LdifGroup(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ LdifGroup(AbstractLdapDirectory userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
memberAttributeId = userAdmin.getMemberAttributeId();
}
@Override
public Role[] getMembers() {
List<Role> directMembers = new ArrayList<Role>();
- for (LdapName ldapName : getMemberNames()) {
+ for (LdapName ldapName : getReferences(memberAttributeId)) {
Role role = findRole(ldapName);
if (role == null) {
throw new IllegalStateException("Role " + ldapName + " not found.");
return role;
}
- @Override
- public List<LdapName> getMemberNames() {
- Attribute memberAttribute = getAttributes().get(memberAttributeId);
- if (memberAttribute == null)
- return new ArrayList<LdapName>();
- try {
- List<LdapName> roles = new ArrayList<LdapName>();
- NamingEnumeration<?> values = memberAttribute.getAll();
- while (values.hasMore()) {
- LdapName dn = new LdapName(values.next().toString());
- roles.add(dn);
- }
- return roles;
- } catch (NamingException e) {
- throw new IllegalStateException("Cannot get members", e);
- }
- }
+// @Override
+// public List<LdapName> getMemberNames() {
+// Attribute memberAttribute = getAttributes().get(memberAttributeId);
+// if (memberAttribute == null)
+// return new ArrayList<LdapName>();
+// try {
+// List<LdapName> roles = new ArrayList<LdapName>();
+// NamingEnumeration<?> values = memberAttribute.getAll();
+// while (values.hasMore()) {
+// LdapName dn = new LdapName(values.next().toString());
+// roles.add(dn);
+// }
+// return roles;
+// } catch (NamingException e) {
+// throw new IllegalStateException("Cannot get members", e);
+// }
+// }
@Override
public Role[] getRequiredMembers() {
*/
static class LdifFunctionalGroup extends LdifGroup implements FunctionalGroup {
- public LdifFunctionalGroup(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ public LdifFunctionalGroup(DirectoryUserAdmin userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
}
static class LdifOrganization extends LdifGroup implements Organization {
- public LdifOrganization(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ public LdifOrganization(DirectoryUserAdmin userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
}
static class LdifSystemPermissions extends LdifGroup implements SystemPermissions {
- public LdifSystemPermissions(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ public LdifSystemPermissions(DirectoryUserAdmin userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
}
import org.argeo.util.directory.DirectoryDigestUtils;
import org.argeo.util.directory.Person;
+import org.argeo.util.directory.ldap.AbstractLdapDirectory;
import org.argeo.util.directory.ldap.AbstractLdapEntry;
import org.argeo.util.directory.ldap.AuthPassword;
import org.argeo.util.naming.LdapAttrs;
private final AttributeDictionary properties;
private final AttributeDictionary credentials;
- LdifUser(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ LdifUser(AbstractLdapDirectory userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
properties = new AttributeDictionary(false);
credentials = new AttributeDictionary(true);
// return hashedPassword;
// }
- protected AbstractUserDirectory getUserAdmin() {
- return (AbstractUserDirectory) getDirectory();
+ protected DirectoryUserAdmin getUserAdmin() {
+ return (DirectoryUserAdmin) getDirectory();
}
private class AttributeDictionary extends Dictionary<String, Object> {
static class LdifPerson extends LdifUser implements Person {
- public LdifPerson(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+ public LdifPerson(DirectoryUserAdmin userAdmin, LdapName dn, Attributes attributes) {
super(userAdmin, dn, attributes);
}
+++ /dev/null
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.util.naming.LdapAttrs.objectClass;
-import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-
-import org.argeo.util.directory.DirectoryConf;
-import org.argeo.util.directory.DirectoryDigestUtils;
-import org.argeo.util.directory.HierarchyUnit;
-import org.argeo.util.directory.ldap.LdapEntry;
-import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
-import org.argeo.util.directory.ldap.LdapHierarchyUnit;
-import org.argeo.util.directory.ldap.LdifParser;
-import org.argeo.util.directory.ldap.LdifWriter;
-import org.argeo.util.naming.LdapObjs;
-import org.osgi.framework.Filter;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-
-/** A user admin based on a LDIF files. */
-public class LdifUserAdmin extends AbstractUserDirectory {
- private NavigableMap<LdapName, LdapEntry> users = new TreeMap<>();
- private NavigableMap<LdapName, LdapEntry> groups = new TreeMap<>();
-
- private NavigableMap<LdapName, LdapHierarchyUnit> hierarchy = new TreeMap<>();
-// private List<HierarchyUnit> rootHierarchyUnits = new ArrayList<>();
-
- public LdifUserAdmin(String uri, String baseDn) {
- this(fromUri(uri, baseDn), false);
- }
-
- public LdifUserAdmin(Dictionary<String, ?> properties) {
- this(properties, false);
- }
-
- protected LdifUserAdmin(Dictionary<String, ?> properties, boolean scoped) {
- super(null, properties, scoped);
- }
-
- public LdifUserAdmin(URI uri, Dictionary<String, ?> properties) {
- super(uri, properties, false);
- }
-
- @Override
- protected AbstractUserDirectory scope(User user) {
- Dictionary<String, Object> credentials = user.getCredentials();
- String username = (String) credentials.get(SHARED_STATE_USERNAME);
- if (username == null)
- username = user.getName();
- Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
- byte[] pwd = (byte[]) pwdCred;
- if (pwd != null) {
- char[] password = DirectoryDigestUtils.bytesToChars(pwd);
- User directoryUser = (User) getRole(username);
- if (!directoryUser.hasCredential(null, password))
- throw new IllegalStateException("Invalid credentials");
- } else {
- throw new IllegalStateException("Password is required");
- }
- Dictionary<String, Object> properties = cloneProperties();
- properties.put(DirectoryConf.readOnly.name(), "true");
- LdifUserAdmin scopedUserAdmin = new LdifUserAdmin(properties, true);
- scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups);
- scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users);
- return scopedUserAdmin;
- }
-
- private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
- Hashtable<String, Object> res = new Hashtable<String, Object>();
- res.put(DirectoryConf.uri.name(), uri);
- res.put(DirectoryConf.baseDn.name(), baseDn);
- return res;
- }
-
- public void init() {
-
- try {
- URI u = new URI(getUri());
- if (u.getScheme().equals("file")) {
- File file = new File(u);
- if (!file.exists())
- return;
- }
- load(u.toURL().openStream());
- } catch (IOException | URISyntaxException e) {
- throw new IllegalStateException("Cannot open URL " + getUri(), e);
- }
- }
-
- public void save() {
- if (getUri() == null)
- throw new IllegalStateException("Cannot save LDIF user admin: no URI is set");
- if (isReadOnly())
- throw new IllegalStateException("Cannot save LDIF user admin: " + getUri() + " is read-only");
- try (FileOutputStream out = new FileOutputStream(new File(new URI(getUri())))) {
- save(out);
- } catch (IOException | URISyntaxException e) {
- throw new IllegalStateException("Cannot save user admin to " + getUri(), e);
- }
- }
-
- public void save(OutputStream out) throws IOException {
- try {
- LdifWriter ldifWriter = new LdifWriter(out);
- for (LdapName name : hierarchy.keySet())
- ldifWriter.writeEntry(name, hierarchy.get(name).getAttributes());
- for (LdapName name : groups.keySet())
- ldifWriter.writeEntry(name, groups.get(name).getAttributes());
- for (LdapName name : users.keySet())
- ldifWriter.writeEntry(name, users.get(name).getAttributes());
- } finally {
- out.close();
- }
- }
-
- protected void load(InputStream in) {
- try {
- users.clear();
- groups.clear();
- hierarchy.clear();
-
- LdifParser ldifParser = new LdifParser();
- SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
- for (LdapName key : allEntries.keySet()) {
- Attributes attributes = allEntries.get(key);
- // check for inconsistency
- Set<String> lowerCase = new HashSet<String>();
- NamingEnumeration<String> ids = attributes.getIDs();
- while (ids.hasMoreElements()) {
- String id = ids.nextElement().toLowerCase();
- if (lowerCase.contains(id))
- throw new IllegalStateException(key + " has duplicate id " + id);
- lowerCase.add(id);
- }
-
- // analyse object classes
- NamingEnumeration<?> objectClasses = attributes.get(objectClass.name()).getAll();
- // System.out.println(key);
- objectClasses: while (objectClasses.hasMore()) {
- String objectClass = objectClasses.next().toString();
- // System.out.println(" " + objectClass);
- if (objectClass.toLowerCase().equals(inetOrgPerson.name().toLowerCase())) {
- users.put(key, newUser(key, attributes));
- break objectClasses;
- } else if (objectClass.toLowerCase().equals(getGroupObjectClass().toLowerCase())) {
- groups.put(key, newGroup(key, attributes));
- break objectClasses;
-// } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
-// // we only consider organizations which are not groups
-// hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.ORGANIZATION, attributes));
-// break objectClasses;
- } else if (objectClass.equalsIgnoreCase(LdapObjs.organizationalUnit.name())) {
-// String name = key.getRdn(key.size() - 1).toString();
-// if (getUserBase().equalsIgnoreCase(name) || getGroupBase().equalsIgnoreCase(name))
-// break objectClasses; // skip
- // TODO skip if it does not contain groups or users
- hierarchy.put(key, new LdapHierarchyUnit(this, key, attributes));
- break objectClasses;
- }
- }
- }
-
- // link hierarchy
-// hierachyUnits: for (LdapName dn : hierarchy.keySet()) {
-// LdifHierarchyUnit unit = hierarchy.get(dn);
-// LdapName parentDn = (LdapName) dn.getPrefix(dn.size() - 1);
-// LdifHierarchyUnit parent = hierarchy.get(parentDn);
-// if (parent == null) {
-// rootHierarchyUnits.add(unit);
-// unit.parent = null;
-// continue hierachyUnits;
-// }
-// parent.children.add(unit);
-// unit.parent = parent;
-// }
- } catch (NamingException | IOException e) {
- throw new IllegalStateException("Cannot load user admin service from LDIF", e);
- }
- }
-
- public void destroy() {
- if (users == null || groups == null)
- throw new IllegalStateException("User directory " + getBaseDn() + " is already destroyed");
- users = null;
- groups = null;
- }
-
- /*
- * USER ADMIN
- */
-
- @Override
- protected DirectoryUser daoGetEntry(LdapName key) throws NameNotFoundException {
- if (groups.containsKey(key))
- return (DirectoryUser) groups.get(key);
- if (users.containsKey(key))
- return (DirectoryUser) users.get(key);
- throw new NameNotFoundException(key + " not persisted");
- }
-
- @Override
- protected Boolean daoHasEntry(LdapName dn) {
- return users.containsKey(dn) || groups.containsKey(dn);
- }
-
- @Override
- protected List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep) {
- Objects.requireNonNull(searchBase);
- ArrayList<LdapEntry> res = new ArrayList<>();
- if (f == null && deep && getBaseDn().equals(searchBase)) {
- res.addAll(users.values());
- res.addAll(groups.values());
- } else {
- filterRoles(users, searchBase, f, deep, res);
- filterRoles(groups, searchBase, f, deep, res);
- }
- return res;
- }
-
- private void filterRoles(SortedMap<LdapName, ? extends LdapEntry> map, LdapName searchBase, Filter f, boolean deep,
- List<LdapEntry> res) {
- // TODO reduce map with search base ?
- roles: for (LdapEntry user : map.values()) {
- LdapName dn = user.getDn();
- if (dn.startsWith(searchBase)) {
- if (!deep && dn.size() != (searchBase.size() + 1))
- continue roles;
- if (f == null)
- res.add(user);
- else {
- if (f.match(((DirectoryUser) user).getProperties()))
- res.add(user);
- }
- }
- }
-
- }
-
- @Override
- protected List<LdapName> getDirectGroups(LdapName dn) {
- List<LdapName> directGroups = new ArrayList<LdapName>();
- for (LdapName name : groups.keySet()) {
- DirectoryGroup group;
- try {
- group = (DirectoryGroup) daoGetEntry(name);
- } catch (NameNotFoundException e) {
- throw new IllegalArgumentException("Group " + dn + " not found", e);
- }
- if (group.getMemberNames().contains(dn))
- directGroups.add(group.getDn());
- }
- return directGroups;
- }
-
- @Override
- public void prepare(LdapEntryWorkingCopy wc) {
- // delete
- for (LdapName dn : wc.getDeletedData().keySet()) {
- if (users.containsKey(dn))
- users.remove(dn);
- else if (groups.containsKey(dn))
- groups.remove(dn);
- else
- throw new IllegalStateException("User to delete not found " + dn);
- }
- // add
- for (LdapName dn : wc.getNewData().keySet()) {
- DirectoryUser user = (DirectoryUser) wc.getNewData().get(dn);
- if (users.containsKey(dn) || groups.containsKey(dn))
- throw new IllegalStateException("User to create found " + dn);
- else if (Role.USER == user.getType())
- users.put(dn, user);
- else if (Role.GROUP == user.getType())
- groups.put(dn, (DirectoryGroup) user);
- else
- throw new IllegalStateException("Unsupported role type " + user.getType() + " for new user " + dn);
- }
- // modify
- for (LdapName dn : wc.getModifiedData().keySet()) {
- Attributes modifiedAttrs = wc.getModifiedData().get(dn);
- DirectoryUser user;
- try {
- user = daoGetEntry(dn);
- } catch (NameNotFoundException e) {
- throw new IllegalStateException("User to modify no found " + dn, e);
- }
- if (user == null)
- throw new IllegalStateException("User to modify no found " + dn);
- user.publishAttributes(modifiedAttrs);
- }
- }
-
- @Override
- public void commit(LdapEntryWorkingCopy wc) {
- save();
- }
-
- @Override
- public void rollback(LdapEntryWorkingCopy wc) {
- init();
- }
-
- /*
- * HIERARCHY
- */
-
-// @Override
-// public int getHierarchyChildCount() {
-// return rootHierarchyUnits.size();
-// }
-//
-// @Override
-// public HierarchyUnit getHierarchyChild(int i) {
-// return rootHierarchyUnits.get(i);
-// }
- @Override
- public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
- return hierarchy.get(dn);
- }
-
- @Override
- public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
- List<HierarchyUnit> res = new ArrayList<>();
- for (LdapName n : hierarchy.keySet()) {
- if (n.size() == searchBase.size() + 1) {
- if (n.startsWith(searchBase)) {
- HierarchyUnit hu = hierarchy.get(n);
- if (functionalOnly) {
- if (hu.isFunctional())
- res.add(hu);
- } else {
- res.add(hu);
- }
- }
- }
- }
- return res;
- }
-
-// @Override
-// public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
-// if (functionalOnly) {
-// List<HierarchyUnit> res = new ArrayList<>();
-// for (HierarchyUnit hu : rootHierarchyUnits) {
-// if (hu.isFunctional())
-// res.add(hu);
-// }
-// return res;
-//
-// } else {
-// return rootHierarchyUnits;
-// }
-// }
-
-}
package org.argeo.osgi.useradmin;
-import java.net.URI;
import java.util.ArrayList;
-import java.util.Dictionary;
import java.util.List;
import javax.naming.NameNotFoundException;
import javax.naming.ldap.LdapName;
import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.directory.ldap.AbstractLdapDirectory;
+import org.argeo.util.directory.ldap.AbstractLdapDirectoryDao;
import org.argeo.util.directory.ldap.LdapEntry;
import org.argeo.util.directory.ldap.LdapEntryWorkingCopy;
import org.argeo.util.naming.LdapAttrs;
-import org.osgi.framework.Filter;
-import org.osgi.service.useradmin.User;
/** Pseudo user directory to be used when logging in as OS user. */
-public class OsUserDirectory extends AbstractUserDirectory {
+public class OsUserDirectory extends AbstractLdapDirectoryDao {
private final String osUsername = System.getProperty("user.name");
private final LdapName osUserDn;
- private final DirectoryUser osUser;
+ private final LdapEntry osUser;
- public OsUserDirectory(URI uriArg, Dictionary<String, ?> props) {
- super(uriArg, props, false);
+ public OsUserDirectory(AbstractLdapDirectory directory) {
+ super(directory);
try {
- osUserDn = new LdapName(
- LdapAttrs.uid.name() + "=" + osUsername + "," + getUserBaseRdn() + "," + getBaseDn());
+ osUserDn = new LdapName(LdapAttrs.uid.name() + "=" + osUsername + "," + directory.getUserBaseRdn() + ","
+ + directory.getBaseDn());
Attributes attributes = new BasicAttributes();
attributes.put(LdapAttrs.uid.name(), osUsername);
osUser = newUser(osUserDn, attributes);
}
@Override
- protected List<LdapName> getDirectGroups(LdapName dn) {
+ public List<LdapName> getDirectGroups(LdapName dn) {
return new ArrayList<>();
}
@Override
- protected Boolean daoHasEntry(LdapName dn) {
+ public Boolean daoHasEntry(LdapName dn) {
return osUserDn.equals(dn);
}
@Override
- protected DirectoryUser daoGetEntry(LdapName key) throws NameNotFoundException {
+ public LdapEntry daoGetEntry(LdapName key) throws NameNotFoundException {
if (osUserDn.equals(key))
return osUser;
else
}
@Override
- protected List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep) {
+ public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
List<LdapEntry> res = new ArrayList<>();
- if (f == null || f.match(osUser.getProperties()))
- res.add(osUser);
+// if (f == null || f.match(osUser.getProperties()))
+ res.add(osUser);
return res;
}
- @Override
- protected AbstractUserDirectory scope(User user) {
- throw new UnsupportedOperationException();
- }
-
@Override
public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
return null;
}
+ @Override
+ public void init() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+
+
}
boolean isDisabled();
- String getUserObjectClass();
-
- String getGroupObjectClass();
-
Optional<String> getRealm();
void setTransactionControl(WorkControl transactionControl);
import javax.naming.ldap.Rdn;
import javax.transaction.xa.XAResource;
+import org.argeo.osgi.useradmin.OsUserDirectory;
import org.argeo.util.directory.Directory;
import org.argeo.util.directory.DirectoryConf;
import org.argeo.util.directory.HierarchyUnit;
import org.argeo.util.naming.LdapAttrs;
import org.argeo.util.naming.LdapObjs;
import org.argeo.util.transaction.WorkControl;
-import org.argeo.util.transaction.WorkingCopyProcessor;
import org.argeo.util.transaction.WorkingCopyXaResource;
import org.argeo.util.transaction.XAResourceProvider;
-import org.osgi.framework.Filter;
-public abstract class AbstractLdapDirectory
- implements Directory, WorkingCopyProcessor<LdapEntryWorkingCopy>, XAResourceProvider {
+public abstract class AbstractLdapDirectory implements Directory, XAResourceProvider {
protected static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
protected static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
protected final Hashtable<String, Object> properties;
private final Rdn userBaseRdn, groupBaseRdn, systemRoleBaseRdn;
private final String userObjectClass, groupObjectClass;
+ private String memberAttributeId = "member";
private final boolean readOnly;
private final boolean disabled;
private final boolean scoped;
- private String memberAttributeId = "member";
private List<String> credentialAttributeIds = Arrays
.asList(new String[] { LdapAttrs.userPassword.name(), LdapAttrs.authPassword.name() });
private WorkControl transactionControl;
- private WorkingCopyXaResource<LdapEntryWorkingCopy> xaResource = new WorkingCopyXaResource<>(this);
+ private WorkingCopyXaResource<LdapEntryWorkingCopy> xaResource;
+
+ private LdapDirectoryDao directoryDao;
public AbstractLdapDirectory(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
this.properties = new Hashtable<String, Object>();
forcedPassword = DirectoryConf.forcedPassword.getValue(properties);
userObjectClass = DirectoryConf.userObjectClass.getValue(properties);
- String userBase = DirectoryConf.userBase.getValue(properties);
groupObjectClass = DirectoryConf.groupObjectClass.getValue(properties);
+
+ String userBase = DirectoryConf.userBase.getValue(properties);
String groupBase = DirectoryConf.groupBase.getValue(properties);
String systemRoleBase = DirectoryConf.systemRoleBase.getValue(properties);
try {
disabled = Boolean.parseBoolean(disabledStr);
else
disabled = false;
+
+ URI u = URI.create(uri);
+ if (!getRealm().isEmpty() || DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
+ || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
+ directoryDao = new LdapDao(this);
+ } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
+ directoryDao = new LdifDao(this);
+ } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
+ directoryDao = new OsUserDirectory(this);
+ // singleUser = true;
+ } else {
+ throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+ }
+ xaResource = new WorkingCopyXaResource<>(directoryDao);
}
/*
* ABSTRACT METHODS
*/
- public abstract HierarchyUnit doGetHierarchyUnit(LdapName dn);
+// public abstract HierarchyUnit doGetHierarchyUnit(LdapName dn);
+//
+// public abstract Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
+//
+// protected abstract Boolean daoHasEntry(LdapName dn);
+//
+// protected abstract LdapEntry daoGetEntry(LdapName key) throws NameNotFoundException;
+//
+// protected abstract List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep);
+//
+// /** Returns the groups this user is a direct member of. */
+// protected abstract List<LdapName> getDirectGroups(LdapName dn);
+ /*
+ * INITIALIZATION
+ */
- public abstract Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
+ public void init() {
+ getDirectoryDao().init();
+ }
- protected abstract Boolean daoHasEntry(LdapName dn);
+ public void destroy() {
+ getDirectoryDao().destroy();
+ }
- protected abstract LdapEntry daoGetEntry(LdapName key) throws NameNotFoundException;
+ /*
+ * CREATION
+ */
+ protected abstract LdapEntry newUser(LdapName name, Attributes attrs);
- protected abstract List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep);
+ protected abstract LdapEntry newGroup(LdapName name, Attributes attrs);
/*
* EDITION
return xaResource;
}
- @Override
- public LdapEntryWorkingCopy newWorkingCopy() {
- return new LdapEntryWorkingCopy();
+ public boolean removeEntry(LdapName dn) {
+ checkEdit();
+ LdapEntryWorkingCopy wc = getWorkingCopy();
+ boolean actuallyDeleted;
+ if (getDirectoryDao().daoHasEntry(dn) || wc.getNewData().containsKey(dn)) {
+ LdapEntry user = doGetRole(dn);
+ wc.getDeletedData().put(dn, user);
+ actuallyDeleted = true;
+ } else {// just removing from groups (e.g. system roles)
+ actuallyDeleted = false;
+ }
+ for (LdapName groupDn : getDirectoryDao().getDirectGroups(dn)) {
+ LdapEntry group = doGetRole(groupDn);
+ group.getAttributes().get(getMemberAttributeId()).remove(dn.toString());
+ }
+ return actuallyDeleted;
+ }
+
+ /*
+ * RETRIEVAL
+ */
+
+ protected LdapEntry doGetRole(LdapName dn) {
+ LdapEntryWorkingCopy wc = getWorkingCopy();
+ LdapEntry user;
+ try {
+ user = getDirectoryDao().daoGetEntry(dn);
+ } catch (NameNotFoundException e) {
+ user = null;
+ }
+ if (wc != null) {
+ if (user == null && wc.getNewData().containsKey(dn))
+ user = wc.getNewData().get(dn);
+ else if (wc.getDeletedData().containsKey(dn))
+ user = null;
+ }
+ return user;
+ }
+
+ protected void collectGroups(LdapEntry user, List<LdapEntry> allRoles) {
+ Attributes attrs = user.getAttributes();
+ // TODO centralize attribute name
+ Attribute memberOf = attrs.get(LdapAttrs.memberOf.name());
+ // if user belongs to this directory, we only check memberOf
+ if (memberOf != null && user.getDn().startsWith(getBaseDn())) {
+ try {
+ NamingEnumeration<?> values = memberOf.getAll();
+ while (values.hasMore()) {
+ Object value = values.next();
+ LdapName groupDn = new LdapName(value.toString());
+ LdapEntry group = doGetRole(groupDn);
+ if (group != null)
+ allRoles.add(group);
+ }
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
+ }
+ } else {
+ for (LdapName groupDn : getDirectoryDao().getDirectGroups(user.getDn())) {
+ // TODO check for loops
+ LdapEntry group = doGetRole(groupDn);
+ if (group != null) {
+ allRoles.add(group);
+ collectGroups(group, allRoles);
+ }
+ }
+ }
}
/*
@Override
public HierarchyUnit getHierarchyUnit(String path) {
LdapName dn = pathToName(path);
- return doGetHierarchyUnit(dn);
+ return directoryDao.doGetHierarchyUnit(dn);
}
@Override
public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
- return doGetDirectHierarchyUnits(baseDn, functionalOnly);
+ return directoryDao.doGetDirectHierarchyUnits(baseDn, functionalOnly);
}
/*
/*
* UTILITIES
*/
-
protected static boolean hasObjectClass(Attributes attrs, LdapObjs objectClass) {
+ return hasObjectClass(attrs, objectClass.name());
+ }
+
+ protected static boolean hasObjectClass(Attributes attrs, String objectClass) {
try {
Attribute attr = attrs.get(LdapAttrs.objectClass.name());
NamingEnumeration<?> en = attr.getAll();
while (en.hasMore()) {
String v = en.next().toString();
- if (v.equalsIgnoreCase(objectClass.name()))
+ if (v.equalsIgnoreCase(objectClass))
return true;
}
return false;
} catch (NamingException e) {
- throw new IllegalStateException("Cannot search for objectClass " + objectClass.name(), e);
+ throw new IllegalStateException("Cannot search for objectClass " + objectClass, e);
}
}
return Optional.of(realm.toString());
}
- protected LdapName getBaseDn() {
+ public LdapName getBaseDn() {
return (LdapName) baseDn.clone();
}
return disabled;
}
- /** dn can be null, in that case a default should be returned. */
- public String getUserObjectClass() {
- return userObjectClass;
- }
-
public Rdn getUserBaseRdn() {
return userBaseRdn;
}
- protected String newUserObjectClass(LdapName dn) {
- return getUserObjectClass();
- }
-
- public String getGroupObjectClass() {
- return groupObjectClass;
- }
-
public Rdn getGroupBaseRdn() {
return groupBaseRdn;
}
return scoped;
}
- public String getMemberAttributeId() {
- return memberAttributeId;
- }
-
public List<String> getCredentialAttributeIds() {
return credentialAttributeIds;
}
- protected String getUri() {
+ public String getUri() {
return uri;
}
+ public LdapDirectoryDao getDirectoryDao() {
+ return directoryDao;
+ }
+
+ /** dn can be null, in that case a default should be returned. */
+ public String getUserObjectClass() {
+ return userObjectClass;
+ }
+
+ public String getGroupObjectClass() {
+ return groupObjectClass;
+ }
+
+ public String getMemberAttributeId() {
+ return memberAttributeId;
+ }
+
/*
* OBJECT METHODS
*/
--- /dev/null
+package org.argeo.util.directory.ldap;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+public abstract class AbstractLdapDirectoryDao implements LdapDirectoryDao {
+
+ private AbstractLdapDirectory directory;
+
+ public AbstractLdapDirectoryDao(AbstractLdapDirectory directory) {
+ this.directory = directory;
+
+ }
+
+ public AbstractLdapDirectory getDirectory() {
+ return directory;
+ }
+
+ @Override
+ public LdapEntryWorkingCopy newWorkingCopy() {
+ return new LdapEntryWorkingCopy();
+ }
+
+ @Override
+ public LdapEntry newUser(LdapName name, Attributes attrs) {
+ return getDirectory().newUser(name, attrs);
+ }
+
+ @Override
+ public LdapEntry newGroup(LdapName name, Attributes attrs) {
+ return getDirectory().newGroup(name, attrs);
+ }
+
+}
package org.argeo.util.directory.ldap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
+/** An entry in an LDAP (or LDIF) directory. */
public abstract class AbstractLdapEntry implements LdapEntry {
private final AbstractLdapDirectory directory;
private Attributes publishedAttributes;
- protected AbstractLdapEntry(AbstractLdapDirectory userAdmin, LdapName dn, Attributes attributes) {
- this.directory = userAdmin;
+ protected AbstractLdapEntry(AbstractLdapDirectory directory, LdapName dn, Attributes attributes) {
+ Objects.requireNonNull(directory);
+ Objects.requireNonNull(dn);
+ this.directory = directory;
this.dn = dn;
this.publishedAttributes = attributes;
}
public synchronized Attributes getAttributes() {
return isEditing() ? getModifiedAttributes() : publishedAttributes;
}
+
+ @Override
+ public List<LdapName> getReferences(String attributeId){
+ Attribute memberAttribute = getAttributes().get(attributeId);
+ if (memberAttribute == null)
+ return new ArrayList<LdapName>();
+ try {
+ List<LdapName> roles = new ArrayList<LdapName>();
+ NamingEnumeration<?> values = memberAttribute.getAll();
+ while (values.hasMore()) {
+ LdapName dn = new LdapName(values.next().toString());
+ roles.add(dn);
+ }
+ return roles;
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot get members", e);
+ }
+
+ }
/** Should only be called from working copy thread. */
protected synchronized Attributes getModifiedAttributes() {
publishedAttributes = modifiedAttributes;
}
- protected AbstractLdapDirectory getDirectory() {
+ public AbstractLdapDirectory getDirectory() {
return directory;
}
+ public LdapDirectoryDao getDirectoryDao() {
+ return directory.getDirectoryDao();
+ }
+
@Override
public int hashCode() {
return dn.hashCode();
--- /dev/null
+package org.argeo.util.directory.ldap;
+
+import static org.argeo.util.naming.LdapAttrs.objectClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.AuthenticationNotSupportedException;
+import javax.naming.Binding;
+import javax.naming.InvalidNameException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.naming.LdapObjs;
+
+/** A user admin based on a LDAP server. */
+public class LdapDao extends AbstractLdapDirectoryDao {
+ private LdapConnection ldapConnection;
+
+// public LdapUserAdmin(Dictionary<String, ?> properties) {
+// this(properties, false);
+// }
+
+ public LdapDao(AbstractLdapDirectory directory) {
+ super(directory);
+ }
+
+ @Override
+ public void init() {
+ ldapConnection = new LdapConnection(getDirectory().getUri().toString(), getDirectory().getProperties());
+ }
+
+ public void destroy() {
+ ldapConnection.destroy();
+ }
+
+// @Override
+// protected AbstractUserDirectory scope(User user) {
+// Dictionary<String, Object> credentials = user.getCredentials();
+// String username = (String) credentials.get(SHARED_STATE_USERNAME);
+// if (username == null)
+// username = user.getName();
+// Dictionary<String, Object> properties = cloneProperties();
+// properties.put(Context.SECURITY_PRINCIPAL, username.toString());
+// Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+// byte[] pwd = (byte[]) pwdCred;
+// if (pwd != null) {
+// char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+// properties.put(Context.SECURITY_CREDENTIALS, new String(password));
+// } else {
+// properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
+// }
+// return new LdapUserAdmin(properties, true);
+// }
+
+// protected InitialLdapContext getLdapContext() {
+// return initialLdapContext;
+// }
+
+ @Override
+ public Boolean daoHasEntry(LdapName dn) {
+ try {
+ return daoGetEntry(dn) != null;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public LdapEntry daoGetEntry(LdapName name) throws NameNotFoundException {
+ try {
+ Attributes attrs = ldapConnection.getAttributes(name);
+ if (attrs.size() == 0)
+ return null;
+// int roleType = roleType(name);
+ LdapEntry res;
+ if (isGroup(name))
+ res = newGroup(name, attrs);
+ else
+ res = newUser(name, attrs);
+// else
+// throw new IllegalArgumentException("Unsupported LDAP type for " + name);
+ return res;
+ } catch (NameNotFoundException e) {
+ throw e;
+ } catch (NamingException e) {
+ return null;
+ }
+ }
+
+ protected boolean isGroup(LdapName dn) {
+ Rdn technicalRdn = LdapNameUtils.getParentRdn(dn);
+ if (getDirectory().getGroupBaseRdn().equals(technicalRdn)
+ || getDirectory().getSystemRoleBaseRdn().equals(technicalRdn))
+ return true;
+ else if (getDirectory().getUserBaseRdn().equals(technicalRdn))
+ return false;
+ else
+ throw new IllegalArgumentException(
+ "Cannot dind role type, " + technicalRdn + " is not a technical RDN for " + dn);
+ }
+
+ @Override
+ public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
+ ArrayList<LdapEntry> res = new ArrayList<>();
+ try {
+ String searchFilter = f != null ? f.toString()
+ : "(|(" + objectClass + "=" + getDirectory().getUserObjectClass() + ")(" + objectClass + "="
+ + getDirectory().getGroupObjectClass() + "))";
+ SearchControls searchControls = new SearchControls();
+ // FIXME make one level consistent with deep
+ searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
+
+ // LdapName searchBase = getBaseDn();
+ NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+ results: while (results.hasMoreElements()) {
+ SearchResult searchResult = results.next();
+ Attributes attrs = searchResult.getAttributes();
+ Attribute objectClassAttr = attrs.get(objectClass.name());
+ LdapName dn = toDn(searchBase, searchResult);
+ LdapEntry role;
+ if (objectClassAttr.contains(getDirectory().getGroupObjectClass())
+ || objectClassAttr.contains(getDirectory().getGroupObjectClass().toLowerCase()))
+ role = newGroup(dn, attrs);
+ else if (objectClassAttr.contains(getDirectory().getUserObjectClass())
+ || objectClassAttr.contains(getDirectory().getUserObjectClass().toLowerCase()))
+ role = newUser(dn, attrs);
+ else {
+// log.warn("Unsupported LDAP type for " + searchResult.getName());
+ continue results;
+ }
+ res.add(role);
+ }
+ return res;
+ } catch (AuthenticationNotSupportedException e) {
+ // ignore (typically an unsupported anonymous bind)
+ // TODO better logging
+ return res;
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot get roles for filter " + f, e);
+ }
+ }
+
+ private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
+ return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
+ }
+
+ @Override
+ public List<LdapName> getDirectGroups(LdapName dn) {
+ List<LdapName> directGroups = new ArrayList<LdapName>();
+ try {
+ String searchFilter = "(&(" + objectClass + "=" + getDirectory().getGroupObjectClass() + ")("
+ + getDirectory().getMemberAttributeId() + "=" + dn + "))";
+
+ SearchControls searchControls = new SearchControls();
+ searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ LdapName searchBase = getDirectory().getBaseDn();
+ NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+ while (results.hasMoreElements()) {
+ SearchResult searchResult = (SearchResult) results.nextElement();
+ directGroups.add(toDn(searchBase, searchResult));
+ }
+ return directGroups;
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot populate direct members of " + dn, e);
+ }
+ }
+
+ @Override
+ public void prepare(LdapEntryWorkingCopy wc) {
+ try {
+ ldapConnection.prepareChanges(wc);
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot prepare LDAP", e);
+ }
+ }
+
+ @Override
+ public void commit(LdapEntryWorkingCopy wc) {
+ try {
+ ldapConnection.commitChanges(wc);
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot commit LDAP", e);
+ }
+ }
+
+ @Override
+ public void rollback(LdapEntryWorkingCopy wc) {
+ // prepare not impacting
+ }
+
+ /*
+ * HIERARCHY
+ */
+
+ @Override
+ public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
+ List<HierarchyUnit> res = new ArrayList<>();
+ try {
+ String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
+ + "=" + LdapObjs.organization.name() + "))";
+
+ SearchControls searchControls = new SearchControls();
+ searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+
+ NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
+
+ while (results.hasMoreElements()) {
+ SearchResult searchResult = (SearchResult) results.nextElement();
+ LdapName dn = toDn(searchBase, searchResult);
+ Attributes attrs = searchResult.getAttributes();
+ LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(getDirectory(), dn, attrs);
+ if (functionalOnly) {
+ if (hierarchyUnit.isFunctional())
+ res.add(hierarchyUnit);
+ } else {
+ res.add(hierarchyUnit);
+ }
+ }
+ return res;
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot get direct hierarchy units ", e);
+ }
+ }
+
+ @Override
+ public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
+ try {
+ Attributes attrs = ldapConnection.getAttributes(dn);
+ return new LdapHierarchyUnit(getDirectory(), dn, attrs);
+ } catch (NamingException e) {
+ throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
+ }
+ }
+
+}
--- /dev/null
+package org.argeo.util.directory.ldap;
+
+import java.util.List;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.transaction.WorkingCopyProcessor;
+
+public interface LdapDirectoryDao extends WorkingCopyProcessor<LdapEntryWorkingCopy> {
+ Boolean daoHasEntry(LdapName dn);
+
+ LdapEntry daoGetEntry(LdapName name) throws NameNotFoundException;
+
+ List<LdapEntry> doGetEntries(LdapName searchBase, String filter, boolean deep);
+
+ List<LdapName> getDirectGroups(LdapName dn);
+
+ Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
+
+ HierarchyUnit doGetHierarchyUnit(LdapName dn);
+
+ LdapEntry newUser(LdapName name, Attributes attrs);
+
+ LdapEntry newGroup(LdapName name, Attributes attrs);
+
+ void init();
+
+ void destroy();
+}
package org.argeo.util.directory.ldap;
+import java.util.List;
+
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
void publishAttributes(Attributes modifiedAttributes);
+ public List<LdapName> getReferences(String attributeId);
}
package org.argeo.util.directory.ldap;
-import java.util.Objects;
-
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
-import org.argeo.util.directory.Directory;
import org.argeo.util.directory.HierarchyUnit;
/** LDIF/LDAP based implementation of {@link HierarchyUnit}. */
-public class LdapHierarchyUnit implements HierarchyUnit {
- private final AbstractLdapDirectory directory;
-
- private final LdapName dn;
+public class LdapHierarchyUnit extends AbstractLdapEntry implements HierarchyUnit {
private final boolean functional;
- private final Attributes attributes;
-
-// HierarchyUnit parent;
-// List<HierarchyUnit> children = new ArrayList<>();
public LdapHierarchyUnit(AbstractLdapDirectory directory, LdapName dn, Attributes attributes) {
- Objects.requireNonNull(directory);
- Objects.requireNonNull(dn);
-
- this.directory = directory;
- this.dn = dn;
- this.attributes = attributes;
+ super(directory, dn, attributes);
Rdn rdn = LdapNameUtils.getLastRdn(dn);
functional = !(directory.getUserBaseRdn().equals(rdn) || directory.getGroupBaseRdn().equals(rdn)
@Override
public HierarchyUnit getParent() {
- return directory.doGetHierarchyUnit(LdapNameUtils.getParent(dn));
+ return getDirectoryDao().doGetHierarchyUnit(LdapNameUtils.getParent(getDn()));
}
@Override
public Iterable<HierarchyUnit> getDirectHierachyUnits(boolean functionalOnly) {
-// List<HierarchyUnit> res = new ArrayList<>();
-// if (functionalOnly)
-// for (HierarchyUnit hu : children) {
-// if (hu.isFunctional())
-// res.add(hu);
-// }
-// else
-// res.addAll(children);
-// return Collections.unmodifiableList(res);
- return directory.doGetDirectHierarchyUnits(dn, functionalOnly);
+ return getDirectoryDao().doGetDirectHierarchyUnits(getDn(), functionalOnly);
}
@Override
@Override
public String getHierarchyUnitName() {
- String name = LdapNameUtils.getLastRdnValue(dn);
+ String name = LdapNameUtils.getLastRdnValue(getDn());
// TODO check ou, o, etc.
return name;
}
- public Attributes getAttributes() {
- return attributes;
- }
-
@Override
public String getContext() {
- return dn.toString();
- }
-
- @Override
- public Directory getDirectory() {
- return directory;
- }
-
- @Override
- public int hashCode() {
- return dn.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof LdapHierarchyUnit))
- return false;
- return ((LdapHierarchyUnit) obj).dn.equals(dn);
+ return getDn().toString();
}
@Override
public String toString() {
- return "Hierarchy Unit " + dn.toString();
+ return "Hierarchy Unit " + getDn().toString();
}
}
--- /dev/null
+package org.argeo.util.directory.ldap;
+
+import static org.argeo.util.naming.LdapAttrs.objectClass;
+import static org.argeo.util.naming.LdapObjs.inetOrgPerson;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.naming.LdapObjs;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+
+/** A user admin based on a LDIF files. */
+public class LdifDao extends AbstractLdapDirectoryDao {
+// private NavigableMap<LdapName, LdapEntry> users = new TreeMap<>();
+// private NavigableMap<LdapName, LdapEntry> groups = new TreeMap<>();
+ private NavigableMap<LdapName, LdapEntry> entries = new TreeMap<>();
+
+ private NavigableMap<LdapName, LdapHierarchyUnit> hierarchy = new TreeMap<>();
+// private List<HierarchyUnit> rootHierarchyUnits = new ArrayList<>();
+
+// public LdifUserAdmin(String uri, String baseDn) {
+// this(fromUri(uri, baseDn), false);
+// }
+
+ public LdifDao(AbstractLdapDirectory directory) {
+ super(directory);
+ }
+
+// protected LdifUserAdmin(Hashtable<String, ?> properties, boolean scoped) {
+// super( properties, scoped);
+// }
+
+// public LdifUserAdmin(URI uri, Dictionary<String, ?> properties) {
+// super(uri, properties, false);
+// }
+
+// @Override
+// protected AbstractUserDirectory scope(User user) {
+// Dictionary<String, Object> credentials = user.getCredentials();
+// String username = (String) credentials.get(SHARED_STATE_USERNAME);
+// if (username == null)
+// username = user.getName();
+// Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
+// byte[] pwd = (byte[]) pwdCred;
+// if (pwd != null) {
+// char[] password = DirectoryDigestUtils.bytesToChars(pwd);
+// User directoryUser = (User) getRole(username);
+// if (!directoryUser.hasCredential(null, password))
+// throw new IllegalStateException("Invalid credentials");
+// } else {
+// throw new IllegalStateException("Password is required");
+// }
+// Dictionary<String, Object> properties = cloneProperties();
+// properties.put(DirectoryConf.readOnly.name(), "true");
+// LdifUserAdmin scopedUserAdmin = new LdifUserAdmin(properties, true);
+//// scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups);
+//// scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users);
+// scopedUserAdmin.entries = Collections.unmodifiableNavigableMap(entries);
+// return scopedUserAdmin;
+// }
+
+ private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
+ Hashtable<String, Object> res = new Hashtable<String, Object>();
+ res.put(DirectoryConf.uri.name(), uri);
+ res.put(DirectoryConf.baseDn.name(), baseDn);
+ return res;
+ }
+
+ public void init() {
+
+ try {
+ URI u = new URI(getDirectory().getUri());
+ if (u.getScheme().equals("file")) {
+ File file = new File(u);
+ if (!file.exists())
+ return;
+ }
+ load(u.toURL().openStream());
+ } catch (IOException | URISyntaxException e) {
+ throw new IllegalStateException("Cannot open URL " + getDirectory().getUri(), e);
+ }
+ }
+
+ public void save() {
+ if (getDirectory().getUri() == null)
+ throw new IllegalStateException("Cannot save LDIF user admin: no URI is set");
+ if (getDirectory().isReadOnly())
+ throw new IllegalStateException(
+ "Cannot save LDIF user admin: " + getDirectory().getUri() + " is read-only");
+ try (FileOutputStream out = new FileOutputStream(new File(new URI(getDirectory().getUri())))) {
+ save(out);
+ } catch (IOException | URISyntaxException e) {
+ throw new IllegalStateException("Cannot save user admin to " + getDirectory().getUri(), e);
+ }
+ }
+
+ public void save(OutputStream out) throws IOException {
+ try {
+ LdifWriter ldifWriter = new LdifWriter(out);
+ for (LdapName name : hierarchy.keySet())
+ ldifWriter.writeEntry(name, hierarchy.get(name).getAttributes());
+// for (LdapName name : groups.keySet())
+// ldifWriter.writeEntry(name, groups.get(name).getAttributes());
+// for (LdapName name : users.keySet())
+// ldifWriter.writeEntry(name, users.get(name).getAttributes());
+ for (LdapName name : entries.keySet())
+ ldifWriter.writeEntry(name, entries.get(name).getAttributes());
+ } finally {
+ out.close();
+ }
+ }
+
+ public void load(InputStream in) {
+ try {
+// users.clear();
+// groups.clear();
+ entries.clear();
+ hierarchy.clear();
+
+ LdifParser ldifParser = new LdifParser();
+ SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
+ for (LdapName key : allEntries.keySet()) {
+ Attributes attributes = allEntries.get(key);
+ // check for inconsistency
+ Set<String> lowerCase = new HashSet<String>();
+ NamingEnumeration<String> ids = attributes.getIDs();
+ while (ids.hasMoreElements()) {
+ String id = ids.nextElement().toLowerCase();
+ if (lowerCase.contains(id))
+ throw new IllegalStateException(key + " has duplicate id " + id);
+ lowerCase.add(id);
+ }
+
+ // analyse object classes
+ NamingEnumeration<?> objectClasses = attributes.get(objectClass.name()).getAll();
+ // System.out.println(key);
+ objectClasses: while (objectClasses.hasMore()) {
+ String objectClass = objectClasses.next().toString();
+ // System.out.println(" " + objectClass);
+ if (objectClass.toLowerCase().equals(inetOrgPerson.name().toLowerCase())) {
+ entries.put(key, newUser(key, attributes));
+ break objectClasses;
+ } else if (objectClass.toLowerCase().equals(getDirectory().getGroupObjectClass().toLowerCase())) {
+ entries.put(key, newGroup(key, attributes));
+ break objectClasses;
+// } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
+// // we only consider organizations which are not groups
+// hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.ORGANIZATION, attributes));
+// break objectClasses;
+ } else if (objectClass.equalsIgnoreCase(LdapObjs.organizationalUnit.name())) {
+// String name = key.getRdn(key.size() - 1).toStrindirectoryDaog();
+// if (getUserBase().equalsIgnoreCase(name) || getGroupBase().equalsIgnoreCase(name))
+// break objectClasses; // skip
+ // TODO skip if it does not contain groups or users
+ hierarchy.put(key, new LdapHierarchyUnit(getDirectory(), key, attributes));
+ break objectClasses;
+ }
+ }
+ }
+
+ // link hierarchy
+// hierachyUnits: for (LdapName dn : hierarchy.keySet()) {
+// LdifHierarchyUnit unit = hierarchy.get(dn);
+// LdapName parentDn = (LdapName) dn.getPrefix(dn.size() - 1);
+// LdifHierarchyUnit parent = hierarchy.get(parentDn);
+// if (parent == null) {
+// rootHierarchyUnits.add(unit);
+// unit.parent = null;
+// continue hierachyUnits;
+// }
+// parent.children.add(unit);
+// unit.parent = parent;
+// }
+ } catch (NamingException | IOException e) {
+ throw new IllegalStateException("Cannot load user admin service from LDIF", e);
+ }
+ }
+
+ public void destroy() {
+// if (users == null || groups == null)
+ if (entries == null)
+ throw new IllegalStateException("User directory " + getDirectory().getBaseDn() + " is already destroyed");
+// users = null;
+// groups = null;
+ entries = null;
+ }
+
+ /*
+ * USER ADMIN
+ */
+
+ @Override
+ public LdapEntry daoGetEntry(LdapName key) throws NameNotFoundException {
+// if (groups.containsKey(key))
+// return groups.get(key);
+// if (users.containsKey(key))
+// return users.get(key);
+ if (entries.containsKey(key))
+ return entries.get(key);
+ throw new NameNotFoundException(key + " not persisted");
+ }
+
+ @Override
+ public Boolean daoHasEntry(LdapName dn) {
+ return entries.containsKey(dn);// || groups.containsKey(dn);
+ }
+
+ @Override
+ public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
+ Objects.requireNonNull(searchBase);
+ ArrayList<LdapEntry> res = new ArrayList<>();
+ if (f == null && deep && getDirectory().getBaseDn().equals(searchBase)) {
+// res.addAll(users.values());
+// res.addAll(groups.values());
+ res.addAll(entries.values());
+ } else {
+// filterRoles(users, searchBase, f, deep, res);
+// filterRoles(groups, searchBase, f, deep, res);
+ filterRoles(entries, searchBase, f, deep, res);
+ }
+ return res;
+ }
+
+ private void filterRoles(SortedMap<LdapName, ? extends LdapEntry> map, LdapName searchBase, String f, boolean deep,
+ List<LdapEntry> res) {
+ // FIXME get rid of OSGi references
+ try {
+ // TODO reduce map with search base ?
+ Filter filter = f != null ? FrameworkUtil.createFilter(f) : null;
+ roles: for (LdapEntry user : map.values()) {
+ LdapName dn = user.getDn();
+ if (dn.startsWith(searchBase)) {
+ if (!deep && dn.size() != (searchBase.size() + 1))
+ continue roles;
+ if (filter == null)
+ res.add(user);
+ else {
+ if (user instanceof Role) {
+ if (filter.match(((Role) user).getProperties()))
+ res.add(user);
+ }
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Cannot create filter " + f, e);
+ }
+
+ }
+
+ @Override
+ public List<LdapName> getDirectGroups(LdapName dn) {
+ List<LdapName> directGroups = new ArrayList<LdapName>();
+ entries: for (LdapName name : entries.keySet()) {
+ LdapEntry group;
+ try {
+ LdapEntry entry = daoGetEntry(name);
+ if (AbstractLdapDirectory.hasObjectClass(entry.getAttributes(), getDirectory().getGroupObjectClass())) {
+ group = entry;
+ } else {
+ continue entries;
+ }
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("Group " + dn + " not found", e);
+ }
+ if (group.getReferences(getDirectory().getMemberAttributeId()).contains(dn)) {
+ directGroups.add(group.getDn());
+ }
+ }
+ return directGroups;
+ }
+
+ @Override
+ public void prepare(LdapEntryWorkingCopy wc) {
+ // delete
+ for (LdapName dn : wc.getDeletedData().keySet()) {
+ if (entries.containsKey(dn))
+ entries.remove(dn);
+// if (users.containsKey(dn))
+// users.remove(dn);
+// else if (groups.containsKey(dn))
+// groups.remove(dn);
+ else
+ throw new IllegalStateException("User to delete not found " + dn);
+ }
+ // add
+ for (LdapName dn : wc.getNewData().keySet()) {
+ LdapEntry user = (LdapEntry) wc.getNewData().get(dn);
+// if (users.containsKey(dn) || groups.containsKey(dn))
+ if (entries.containsKey(dn))
+ throw new IllegalStateException("User to create found " + dn);
+ entries.put(dn, user);
+// else if (Role.USER == user.getType())
+// users.put(dn, user);
+// else if (Role.GROUP == user.getType())
+// groups.put(dn, (DirectoryGroup) user);
+// else
+// throw new IllegalStateException("Unsupported role type " + user.getType() + " for new user " + dn);
+ }
+ // modify
+ for (LdapName dn : wc.getModifiedData().keySet()) {
+ Attributes modifiedAttrs = wc.getModifiedData().get(dn);
+ LdapEntry user;
+ try {
+ user = daoGetEntry(dn);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException("User to modify no found " + dn, e);
+ }
+ if (user == null)
+ throw new IllegalStateException("User to modify no found " + dn);
+ user.publishAttributes(modifiedAttrs);
+ }
+ }
+
+ @Override
+ public void commit(LdapEntryWorkingCopy wc) {
+ save();
+ }
+
+ @Override
+ public void rollback(LdapEntryWorkingCopy wc) {
+ init();
+ }
+
+ /*
+ * HIERARCHY
+ */
+
+// @Override
+// public int getHierarchyChildCount() {
+// return rootHierarchyUnits.size();
+// }
+//
+// @Override
+// public HierarchyUnit getHierarchyChild(int i) {
+// return rootHierarchyUnits.get(i);
+// }
+ @Override
+ public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
+ return hierarchy.get(dn);
+ }
+
+ @Override
+ public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
+ List<HierarchyUnit> res = new ArrayList<>();
+ for (LdapName n : hierarchy.keySet()) {
+ if (n.size() == searchBase.size() + 1) {
+ if (n.startsWith(searchBase)) {
+ HierarchyUnit hu = hierarchy.get(n);
+ if (functionalOnly) {
+ if (hu.isFunctional())
+ res.add(hu);
+ } else {
+ res.add(hu);
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+ public void scope(LdifDao scoped) {
+ scoped.entries = Collections.unmodifiableNavigableMap(entries);
+ }
+
+// @Override
+// public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
+// if (functionalOnly) {
+// List<HierarchyUnit> res = new ArrayList<>();
+// for (HierarchyUnit hu : rootHierarchyUnits) {
+// if (hu.isFunctional())
+// res.add(hu);
+// }
+// return res;
+//
+// } else {
+// return rootHierarchyUnits;
+// }
+// }
+
+}