]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
Introduce directory content provider
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / osgi / useradmin / AbstractUserDirectory.java
index 7279877e0e8ec46690a7f95b72ba062b234f8a34..889f9cfa79fd3829bf4ab6ed6aee79b09626fc7b 100644 (file)
@@ -1,11 +1,11 @@
 package org.argeo.osgi.useradmin;
 
-import static org.argeo.naming.LdapAttrs.objectClass;
-import static org.argeo.naming.LdapObjs.extensibleObject;
-import static org.argeo.naming.LdapObjs.inetOrgPerson;
-import static org.argeo.naming.LdapObjs.organizationalPerson;
-import static org.argeo.naming.LdapObjs.person;
-import static org.argeo.naming.LdapObjs.top;
+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.io.File;
 import java.net.URI;
@@ -17,10 +17,12 @@ import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 
 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;
@@ -28,8 +30,8 @@ import javax.naming.directory.BasicAttributes;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
 
-import org.argeo.naming.LdapAttrs;
 import org.argeo.osgi.transaction.WorkControl;
+import org.argeo.util.naming.LdapAttrs;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
@@ -39,7 +41,7 @@ import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
 /** Base class for a {@link UserDirectory}. */
-public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
+abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
        static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
 
@@ -67,6 +69,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        private WorkControl transactionControl;
        private WcXaResource xaResource = new WcXaResource(this);
 
+       private String forcedPassword;
+
        AbstractUserDirectory(URI uriArg, Dictionary<String, ?> props, boolean scoped) {
                this.scoped = scoped;
                properties = new Hashtable<String, Object>();
@@ -86,6 +90,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                                uri = uriStr;
                }
 
+               forcedPassword = UserAdminConf.forcedPassword.getValue(properties);
+
                userObjectClass = UserAdminConf.userObjectClass.getValue(properties);
                userBase = UserAdminConf.userBase.getValue(properties);
                groupObjectClass = UserAdminConf.groupObjectClass.getValue(properties);
@@ -95,7 +101,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                        userBaseDn = new LdapName(userBase + "," + baseDn);
                        groupBaseDn = new LdapName(groupBase + "," + baseDn);
                } catch (InvalidNameException e) {
-                       throw new UserDirectoryException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties), e);
+                       throw new IllegalArgumentException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties),
+                                       e);
                }
                String readOnlyStr = UserAdminConf.readOnly.getValue(properties);
                if (readOnlyStr == null) {
@@ -117,7 +124,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        protected abstract DirectoryUser daoGetRole(LdapName key) throws NameNotFoundException;
 
-       protected abstract List<DirectoryUser> doGetRoles(Filter f);
+       protected abstract List<DirectoryUser> doGetRoles(LdapName searchBase, Filter f, boolean deep);
 
        protected abstract AbstractUserDirectory scope(User user);
 
@@ -129,6 +136,19 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        }
 
+       @Override
+       public String getBasePath() {
+               return getBaseDn().toString();
+       }
+
+       @Override
+       public Optional<String> getRealm() {
+               Object realm = getProperties().get(UserAdminConf.realm.name());
+               if (realm == null)
+                       return Optional.empty();
+               return Optional.of(realm.toString());
+       }
+
        protected boolean isEditing() {
                return xaResource.wc() != null;
        }
@@ -141,20 +161,11 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        }
 
        protected void checkEdit() {
-//             Transaction transaction;
-//             try {
-//                     transaction = transactionManager.getTransaction();
-//             } catch (SystemException e) {
-//                     throw new UserDirectoryException("Cannot get transaction", e);
-//             }
-//             if (transaction == null)
-//                     throw new UserDirectoryException("A transaction needs to be active in order to edit");
                if (xaResource.wc() == null) {
                        try {
-//                             transaction.enlistResource(xaResource);
                                transactionControl.getWorkContext().registerXAResource(xaResource, null);
                        } catch (Exception e) {
-                               throw new UserDirectoryException("Cannot enlist " + xaResource, e);
+                               throw new IllegalStateException("Cannot enlist " + xaResource, e);
                        }
                } else {
                }
@@ -185,8 +196,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                                        if (group != null)
                                                allRoles.add(group);
                                }
-                       } catch (Exception e) {
-                               throw new UserDirectoryException("Cannot get memberOf groups for " + user, e);
+                       } catch (NamingException e) {
+                               throw new IllegalStateException("Cannot get memberOf groups for " + user, e);
                        }
                } else {
                        for (LdapName groupDn : getDirectGroups(user.getDn())) {
@@ -207,7 +218,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        // USER ADMIN
        @Override
        public Role getRole(String name) {
-               return doGetRole(toDn(name));
+               return doGetRole(toLdapName(name));
        }
 
        protected DirectoryUser doGetRole(LdapName dn) {
@@ -229,9 +240,31 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        @Override
        public Role[] getRoles(String filter) throws InvalidSyntaxException {
+//             UserDirectoryWorkingCopy wc = getWorkingCopy();
+//             Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
+//             List<DirectoryUser> res = doGetRoles(getBaseDn(), f, true);
+//             if (wc != null) {
+//                     for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
+//                             DirectoryUser user = it.next();
+//                             LdapName dn = user.getDn();
+//                             if (wc.getDeletedUsers().containsKey(dn))
+//                                     it.remove();
+//                     }
+//                     for (DirectoryUser user : wc.getNewUsers().values()) {
+//                             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
+//             }
+               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 {
                UserDirectoryWorkingCopy wc = getWorkingCopy();
                Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
-               List<DirectoryUser> res = doGetRoles(f);
+               List<DirectoryUser> res = doGetRoles(searchBase, f, deep);
                if (wc != null) {
                        for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
                                DirectoryUser user = it.next();
@@ -246,7 +279,22 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                        // no need to check modified users,
                        // since doGetRoles was already based on the modified attributes
                }
-               return res.toArray(new Role[res.size()]);
+
+               // 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
@@ -256,7 +304,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                if (key != null) {
                        doGetUser(key, value, collectedUsers);
                } else {
-                       throw new UserDirectoryException("Key cannot be null");
+                       throw new IllegalArgumentException("Key cannot be null");
                }
 
                if (collectedUsers.size() == 1) {
@@ -271,10 +319,10 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        protected void doGetUser(String key, String value, List<DirectoryUser> collectedUsers) {
                try {
                        Filter f = FrameworkUtil.createFilter("(" + key + "=" + value + ")");
-                       List<DirectoryUser> users = doGetRoles(f);
+                       List<DirectoryUser> users = doGetRoles(getBaseDn(), f, true);
                        collectedUsers.addAll(users);
                } catch (InvalidSyntaxException e) {
-                       throw new UserDirectoryException("Cannot get user with " + key + "=" + value, e);
+                       throw new IllegalArgumentException("Cannot get user with " + key + "=" + value, e);
                }
        }
 
@@ -288,7 +336,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                        try {
                                DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName());
                                if (directoryUser == null)
-                                       throw new UserDirectoryException("No scoped user found for " + user);
+                                       throw new IllegalStateException("No scoped user found for " + user);
                                LdifAuthorization authorization = new LdifAuthorization(directoryUser,
                                                scopedUserAdmin.getAllRoles(directoryUser));
                                return authorization;
@@ -302,9 +350,9 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        public Role createRole(String name, int type) {
                checkEdit();
                UserDirectoryWorkingCopy wc = getWorkingCopy();
-               LdapName dn = toDn(name);
+               LdapName dn = toLdapName(name);
                if ((daoHasRole(dn) && !wc.getDeletedUsers().containsKey(dn)) || wc.getNewUsers().containsKey(dn))
-                       throw new UserDirectoryException("Already a role " + name);
+                       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);
@@ -346,7 +394,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                        attrs.put(objClass);
                        newRole = new LdifGroup(this, dn, attrs);
                } else
-                       throw new UserDirectoryException("Unsupported type " + type);
+                       throw new IllegalArgumentException("Unsupported type " + type);
                return newRole;
        }
 
@@ -354,7 +402,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
        public boolean removeRole(String name) {
                checkEdit();
                UserDirectoryWorkingCopy wc = getWorkingCopy();
-               LdapName dn = toDn(name);
+               LdapName dn = toLdapName(name);
                boolean actuallyDeleted;
                if (daoHasRole(dn) || wc.getNewUsers().containsKey(dn)) {
                        DirectoryUser user = (DirectoryUser) getRole(name);
@@ -383,12 +431,52 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 
        }
 
-       // UTILITIES
-       protected LdapName toDn(String name) {
+       /*
+        * HIERARCHY
+        */
+       @Override
+       public int getHierarchyChildCount() {
+               return 0;
+       }
+
+       @Override
+       public HierarchyUnit getHierarchyChild(int i) {
+               throw new IllegalArgumentException("No child hierarchy unit available");
+       }
+
+       @Override
+       public HierarchyUnit getParent() {
+               return null;
+       }
+
+       @Override
+       public int getHierarchyUnitType() {
+               return 0;
+       }
+
+       @Override
+       public String getHierarchyUnitName() {
+               String name = LdapNameUtils.getLastRdnAsString(baseDn);
+               // TODO check ou, o, etc.
+               return name;
+       }
+
+       @Override
+       public HierarchyUnit getHierarchyUnit(String path) {
+               return null;
+       }
+
+       @Override
+       public HierarchyUnit getHierarchyUnit(Role role) {
+               return null;
+       }
+
+       @Override
+       public List<? extends Role> getRoles(String filter, boolean deep) {
                try {
-                       return new LdapName(name);
-               } catch (InvalidNameException e) {
-                       throw new UserDirectoryException("Badly formatted name", e);
+                       return getRoles(getBaseDn(), filter, deep);
+               } catch (InvalidSyntaxException e) {
+                       throw new IllegalArgumentException("Cannot filter " + filter + " " + getBaseDn(), e);
                }
        }
 
@@ -494,6 +582,10 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
 //             this.transactionManager = transactionManager;
 //     }
 
+       public String getForcedPassword() {
+               return forcedPassword;
+       }
+
        public void setTransactionControl(WorkControl transactionControl) {
                this.transactionControl = transactionControl;
        }
@@ -506,4 +598,24 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory
                return scoped;
        }
 
+       @Override
+       public int hashCode() {
+               return baseDn.hashCode();
+       }
+
+       @Override
+       public String toString() {
+               return "User Directory " + baseDn.toString();
+       }
+
+       /*
+        * 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);
+               }
+       }
 }