1 package org
.argeo
.osgi
.useradmin
;
3 import static org
.argeo
.osgi
.useradmin
.LdifName
.objectClass
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Dictionary
;
7 import java
.util
.Hashtable
;
10 import javax
.naming
.Binding
;
11 import javax
.naming
.Context
;
12 import javax
.naming
.InvalidNameException
;
13 import javax
.naming
.NameNotFoundException
;
14 import javax
.naming
.NamingEnumeration
;
15 import javax
.naming
.NamingException
;
16 import javax
.naming
.directory
.Attribute
;
17 import javax
.naming
.directory
.Attributes
;
18 import javax
.naming
.directory
.DirContext
;
19 import javax
.naming
.directory
.SearchControls
;
20 import javax
.naming
.directory
.SearchResult
;
21 import javax
.naming
.ldap
.InitialLdapContext
;
22 import javax
.naming
.ldap
.LdapName
;
23 import javax
.transaction
.TransactionManager
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.osgi
.framework
.Filter
;
30 * A user admin based on a LDAP server. Requires a {@link TransactionManager}
31 * and an open transaction for write access.
33 public class LdapUserAdmin
extends AbstractUserDirectory
{
34 private final static Log log
= LogFactory
.getLog(LdapUserAdmin
.class);
36 private InitialLdapContext initialLdapContext
= null;
38 public LdapUserAdmin(Dictionary
<String
, ?
> properties
) {
41 Hashtable
<String
, Object
> connEnv
= new Hashtable
<String
, Object
>();
42 connEnv
.put(Context
.INITIAL_CONTEXT_FACTORY
, "com.sun.jndi.ldap.LdapCtxFactory");
43 connEnv
.put(Context
.PROVIDER_URL
, getUri().toString());
44 connEnv
.put("java.naming.ldap.attributes.binary", LdifName
.userPassword
.name());
46 initialLdapContext
= new InitialLdapContext(connEnv
, null);
47 // StartTlsResponse tls = (StartTlsResponse) ctx
48 // .extendedOperation(new StartTlsRequest());
50 initialLdapContext
.addToEnvironment(Context
.SECURITY_AUTHENTICATION
, "simple");
51 Object principal
= properties
.get(Context
.SECURITY_PRINCIPAL
);
52 if (principal
!= null) {
53 initialLdapContext
.addToEnvironment(Context
.SECURITY_PRINCIPAL
, principal
.toString());
54 Object creds
= properties
.get(Context
.SECURITY_CREDENTIALS
);
56 initialLdapContext
.addToEnvironment(Context
.SECURITY_CREDENTIALS
, creds
.toString());
60 // initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
61 // "uid=admin,ou=system");
62 // initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
64 } catch (Exception e
) {
65 throw new UserDirectoryException("Cannot connect to LDAP", e
);
69 public void destroy() {
72 initialLdapContext
.close();
73 } catch (NamingException e
) {
74 log
.error("Cannot destroy LDAP user admin", e
);
78 protected InitialLdapContext
getLdapContext() {
79 return initialLdapContext
;
83 protected Boolean
daoHasRole(LdapName dn
) {
84 return daoGetRole(dn
) != null;
88 protected DirectoryUser
daoGetRole(LdapName name
) {
90 Attributes attrs
= getLdapContext().getAttributes(name
);
91 if (attrs
.size() == 0)
94 if (attrs
.get(objectClass
.name()).contains(getGroupObjectClass()))
95 res
= new LdifGroup(this, name
, attrs
);
96 else if (attrs
.get(objectClass
.name()).contains(getUserObjectClass()))
97 res
= new LdifUser(this, name
, attrs
);
99 throw new UserDirectoryException("Unsupported LDAP type for " + name
);
101 } catch (NamingException e
) {
107 protected List
<DirectoryUser
> doGetRoles(Filter f
) {
109 String searchFilter
= f
!= null ? f
.toString()
110 : "(|(" + objectClass
+ "=" + getUserObjectClass() + ")(" + objectClass
+ "="
111 + getGroupObjectClass() + "))";
112 SearchControls searchControls
= new SearchControls();
113 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
115 LdapName searchBase
= getBaseDn();
116 NamingEnumeration
<SearchResult
> results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
118 ArrayList
<DirectoryUser
> res
= new ArrayList
<DirectoryUser
>();
119 results
: while (results
.hasMoreElements()) {
120 SearchResult searchResult
= results
.next();
121 Attributes attrs
= searchResult
.getAttributes();
122 Attribute objectClassAttr
= attrs
.get(objectClass
.name());
123 LdapName dn
= toDn(searchBase
, searchResult
);
125 if (objectClassAttr
.contains(getGroupObjectClass()))
126 role
= new LdifGroup(this, dn
, attrs
);
127 else if (objectClassAttr
.contains(getUserObjectClass()))
128 role
= new LdifUser(this, dn
, attrs
);
130 log
.warn("Unsupported LDAP type for " + searchResult
.getName());
136 } catch (Exception e
) {
137 throw new UserDirectoryException("Cannot get roles for filter " + f
, e
);
141 private LdapName
toDn(LdapName baseDn
, Binding binding
) throws InvalidNameException
{
142 return new LdapName(binding
.isRelative() ? binding
.getName() + "," + baseDn
: binding
.getName());
146 protected List
<LdapName
> getDirectGroups(LdapName dn
) {
147 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
149 String searchFilter
= "(&(" + objectClass
+ "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
152 SearchControls searchControls
= new SearchControls();
153 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
155 LdapName searchBase
= getBaseDn();
156 NamingEnumeration
<SearchResult
> results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
158 while (results
.hasMoreElements()) {
159 SearchResult searchResult
= (SearchResult
) results
.nextElement();
160 directGroups
.add(toDn(searchBase
, searchResult
));
163 } catch (Exception e
) {
164 throw new UserDirectoryException("Cannot populate direct members of " + dn
, e
);
169 protected void prepare(UserDirectoryWorkingCopy wc
) {
171 getLdapContext().reconnect(getLdapContext().getConnectControls());
173 for (LdapName dn
: wc
.getDeletedUsers().keySet()) {
174 if (!entryExists(dn
))
175 throw new UserDirectoryException("User to delete no found " + dn
);
178 for (LdapName dn
: wc
.getNewUsers().keySet()) {
180 throw new UserDirectoryException("User to create found " + dn
);
183 for (LdapName dn
: wc
.getModifiedUsers().keySet()) {
184 if (!wc
.getNewUsers().containsKey(dn
) && !entryExists(dn
))
185 throw new UserDirectoryException("User to modify not found " + dn
);
187 } catch (NamingException e
) {
188 throw new UserDirectoryException("Cannot prepare LDAP", e
);
192 private boolean entryExists(LdapName dn
) throws NamingException
{
194 return getLdapContext().getAttributes(dn
).size() != 0;
195 } catch (NameNotFoundException e
) {
201 protected void commit(UserDirectoryWorkingCopy wc
) {
204 for (LdapName dn
: wc
.getDeletedUsers().keySet()) {
205 getLdapContext().destroySubcontext(dn
);
208 for (LdapName dn
: wc
.getNewUsers().keySet()) {
209 DirectoryUser user
= wc
.getNewUsers().get(dn
);
210 getLdapContext().createSubcontext(dn
, user
.getAttributes());
213 for (LdapName dn
: wc
.getModifiedUsers().keySet()) {
214 Attributes modifiedAttrs
= wc
.getModifiedUsers().get(dn
);
215 getLdapContext().modifyAttributes(dn
, DirContext
.REPLACE_ATTRIBUTE
, modifiedAttrs
);
217 } catch (NamingException e
) {
218 throw new UserDirectoryException("Cannot commit LDAP", e
);
223 protected void rollback(UserDirectoryWorkingCopy wc
) {
224 // prepare not impacting