1 package org
.argeo
.osgi
.useradmin
;
3 import static org
.argeo
.osgi
.useradmin
.LdifName
.inetOrgPerson
;
4 import static org
.argeo
.osgi
.useradmin
.LdifName
.objectClass
;
7 import java
.io
.FileOutputStream
;
8 import java
.io
.IOException
;
9 import java
.io
.InputStream
;
10 import java
.io
.OutputStream
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Dictionary
;
13 import java
.util
.HashSet
;
14 import java
.util
.Hashtable
;
15 import java
.util
.List
;
17 import java
.util
.SortedMap
;
18 import java
.util
.TreeMap
;
20 import javax
.naming
.NamingEnumeration
;
21 import javax
.naming
.directory
.Attributes
;
22 import javax
.naming
.ldap
.LdapName
;
23 import javax
.transaction
.TransactionManager
;
25 import org
.apache
.commons
.io
.IOUtils
;
26 import org
.argeo
.util
.naming
.LdifParser
;
27 import org
.argeo
.util
.naming
.LdifWriter
;
28 import org
.osgi
.framework
.Filter
;
29 import org
.osgi
.service
.useradmin
.Role
;
32 * A user admin based on a LDIF files. Requires a {@link TransactionManager} and
33 * an open transaction for write access.
35 public class LdifUserAdmin
extends AbstractUserDirectory
{
36 private SortedMap
<LdapName
, DirectoryUser
> users
= new TreeMap
<LdapName
, DirectoryUser
>();
37 private SortedMap
<LdapName
, DirectoryGroup
> groups
= new TreeMap
<LdapName
, DirectoryGroup
>();
39 public LdifUserAdmin(String uri
, String baseDn
) {
40 this(fromUri(uri
, baseDn
));
43 public LdifUserAdmin(Dictionary
<String
, ?
> properties
) {
47 public LdifUserAdmin(InputStream in
) {
48 super(new Hashtable
<String
, Object
>());
52 private static Dictionary
<String
, Object
> fromUri(String uri
, String baseDn
) {
53 Hashtable
<String
, Object
> res
= new Hashtable
<String
, Object
>();
54 res
.put(UserAdminConf
.uri
.name(), uri
);
55 res
.put(UserAdminConf
.baseDn
.name(), baseDn
);
61 if (getUri().getScheme().equals("file")) {
62 File file
= new File(getUri());
66 load(getUri().toURL().openStream());
67 } catch (Exception e
) {
68 throw new UserDirectoryException("Cannot open URL " + getUri(), e
);
74 throw new UserDirectoryException(
75 "Cannot save LDIF user admin: no URI is set");
77 throw new UserDirectoryException("Cannot save LDIF user admin: "
78 + getUri() + " is read-only");
79 try (FileOutputStream out
= new FileOutputStream(new File(getUri()))) {
81 } catch (IOException e
) {
82 throw new UserDirectoryException("Cannot save user admin to "
87 public void save(OutputStream out
) throws IOException
{
89 LdifWriter ldifWriter
= new LdifWriter(out
);
90 for (LdapName name
: groups
.keySet())
91 ldifWriter
.writeEntry(name
, groups
.get(name
).getAttributes());
92 for (LdapName name
: users
.keySet())
93 ldifWriter
.writeEntry(name
, users
.get(name
).getAttributes());
95 IOUtils
.closeQuietly(out
);
99 protected void load(InputStream in
) {
104 LdifParser ldifParser
= new LdifParser();
105 SortedMap
<LdapName
, Attributes
> allEntries
= ldifParser
.read(in
);
106 for (LdapName key
: allEntries
.keySet()) {
107 Attributes attributes
= allEntries
.get(key
);
108 // check for inconsistency
109 Set
<String
> lowerCase
= new HashSet
<String
>();
110 NamingEnumeration
<String
> ids
= attributes
.getIDs();
111 while (ids
.hasMoreElements()) {
112 String id
= ids
.nextElement().toLowerCase();
113 if (lowerCase
.contains(id
))
114 throw new UserDirectoryException(key
115 + " has duplicate id " + id
);
119 // analyse object classes
120 NamingEnumeration
<?
> objectClasses
= attributes
.get(
121 objectClass
.name()).getAll();
122 // System.out.println(key);
123 objectClasses
: while (objectClasses
.hasMore()) {
124 String objectClass
= objectClasses
.next().toString();
125 // System.out.println(" " + objectClass);
126 if (objectClass
.equals(inetOrgPerson
.name())) {
127 users
.put(key
, new LdifUser(this, key
, attributes
));
129 } else if (objectClass
.equals(getGroupObjectClass())) {
130 groups
.put(key
, new LdifGroup(this, key
, attributes
));
135 } catch (Exception e
) {
136 throw new UserDirectoryException(
137 "Cannot load user admin service from LDIF", e
);
141 public void destroy() {
148 protected DirectoryUser
daoGetRole(LdapName key
) {
149 if (groups
.containsKey(key
))
150 return groups
.get(key
);
151 if (users
.containsKey(key
))
152 return users
.get(key
);
156 protected Boolean
daoHasRole(LdapName dn
) {
157 return users
.containsKey(dn
) || groups
.containsKey(dn
);
160 @SuppressWarnings("unchecked")
161 protected List
<DirectoryUser
> doGetRoles(Filter f
) {
162 ArrayList
<DirectoryUser
> res
= new ArrayList
<DirectoryUser
>();
164 res
.addAll(users
.values());
165 res
.addAll(groups
.values());
167 for (DirectoryUser user
: users
.values()) {
168 // System.out.println("\n" + user.getName());
169 // Dictionary<String, Object> props = user.getProperties();
170 // for (Enumeration<String> keys = props.keys(); keys
171 // .hasMoreElements();) {
172 // String key = keys.nextElement();
173 // System.out.println(" " + key + "=" + props.get(key));
175 if (f
.match(user
.getProperties()))
178 for (DirectoryUser group
: groups
.values())
179 if (f
.match(group
.getProperties()))
186 protected List
<LdapName
> getDirectGroups(LdapName dn
) {
187 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
188 for (LdapName name
: groups
.keySet()) {
189 DirectoryGroup group
= groups
.get(name
);
190 if (group
.getMemberNames().contains(dn
))
191 directGroups
.add(group
.getDn());
197 protected void prepare(UserDirectoryWorkingCopy wc
) {
199 for (LdapName dn
: wc
.getDeletedUsers().keySet()) {
200 if (users
.containsKey(dn
))
202 else if (groups
.containsKey(dn
))
205 throw new UserDirectoryException("User to delete not found "
209 for (LdapName dn
: wc
.getNewUsers().keySet()) {
210 DirectoryUser user
= wc
.getNewUsers().get(dn
);
211 if (users
.containsKey(dn
) || groups
.containsKey(dn
))
212 throw new UserDirectoryException("User to create found " + dn
);
213 else if (Role
.USER
== user
.getType())
215 else if (Role
.GROUP
== user
.getType())
216 groups
.put(dn
, (DirectoryGroup
) user
);
218 throw new UserDirectoryException("Unsupported role type "
219 + user
.getType() + " for new user " + dn
);
222 for (LdapName dn
: wc
.getModifiedUsers().keySet()) {
223 Attributes modifiedAttrs
= wc
.getModifiedUsers().get(dn
);
225 if (users
.containsKey(dn
))
226 user
= users
.get(dn
);
227 else if (groups
.containsKey(dn
))
228 user
= groups
.get(dn
);
230 throw new UserDirectoryException("User to modify no found "
232 user
.publishAttributes(modifiedAttrs
);
237 protected void commit(UserDirectoryWorkingCopy wc
) {
242 protected void rollback(UserDirectoryWorkingCopy wc
) {