1 package org
.argeo
.osgi
.useradmin
;
3 import static org
.argeo
.naming
.LdapAttrs
.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
.argeo
.naming
.LdapAttrs
;
26 import org
.osgi
.framework
.Filter
;
27 import org
.osgi
.service
.useradmin
.Role
;
28 import org
.osgi
.service
.useradmin
.User
;
31 * A user admin based on a LDAP server. Requires a {@link TransactionManager}
32 * and an open transaction for write access.
34 public class LdapUserAdmin
extends AbstractUserDirectory
{
35 private InitialLdapContext initialLdapContext
= null;
37 // private LdapName adminUserDn = null;
38 // private LdifUser adminUser = null;
40 public LdapUserAdmin(Dictionary
<String
, ?
> properties
) {
41 super(null, properties
);
43 Hashtable
<String
, Object
> connEnv
= new Hashtable
<String
, Object
>();
44 connEnv
.put(Context
.INITIAL_CONTEXT_FACTORY
, "com.sun.jndi.ldap.LdapCtxFactory");
45 connEnv
.put(Context
.PROVIDER_URL
, getUri().toString());
46 connEnv
.put("java.naming.ldap.attributes.binary", LdapAttrs
.userPassword
.name());
48 initialLdapContext
= new InitialLdapContext(connEnv
, null);
49 // StartTlsResponse tls = (StartTlsResponse) ctx
50 // .extendedOperation(new StartTlsRequest());
52 Object securityAuthentication
= properties
.get(Context
.SECURITY_AUTHENTICATION
);
53 if (securityAuthentication
!= null)
54 initialLdapContext
.addToEnvironment(Context
.SECURITY_AUTHENTICATION
, securityAuthentication
);
56 initialLdapContext
.addToEnvironment(Context
.SECURITY_AUTHENTICATION
, "simple");
57 Object principal
= properties
.get(Context
.SECURITY_PRINCIPAL
);
58 if (principal
!= null) {
59 initialLdapContext
.addToEnvironment(Context
.SECURITY_PRINCIPAL
, principal
.toString());
60 // adminUserDn = new LdapName(principal.toString());
61 // BasicAttributes adminUserAttrs = new BasicAttributes();
62 // adminUser = new LdifUser(this, adminUserDn, adminUserAttrs);
63 Object creds
= properties
.get(Context
.SECURITY_CREDENTIALS
);
65 initialLdapContext
.addToEnvironment(Context
.SECURITY_CREDENTIALS
, creds
.toString());
66 // adminUserAttrs.put(LdapAttrs.userPassword.name(), adminUser.hash(creds.toString().toCharArray()));
68 // adminUserAttrs.put(LdapAttrs.memberOf.name(), "cn=admin,ou=roles,ou=node");
70 } catch (Exception e
) {
71 throw new UserDirectoryException("Cannot connect to LDAP", e
);
75 public void destroy() {
78 initialLdapContext
.close();
79 } catch (NamingException e
) {
85 protected AbstractUserDirectory
scope(User user
) {
86 Dictionary
<String
, Object
> credentials
= user
.getCredentials();
87 String username
= (String
) credentials
.get(SHARED_STATE_USERNAME
);
89 username
= user
.getName();
90 Dictionary
<String
, Object
> properties
= cloneProperties();
91 properties
.put(Context
.SECURITY_PRINCIPAL
, username
.toString());
92 Object pwdCred
= credentials
.get(SHARED_STATE_PASSWORD
);
93 byte[] pwd
= (byte[]) pwdCred
;
95 char[] password
= DigestUtils
.bytesToChars(pwd
);
96 properties
.put(Context
.SECURITY_CREDENTIALS
, new String(password
));
98 properties
.put(Context
.SECURITY_AUTHENTICATION
, "GSSAPI");
100 return new LdapUserAdmin(properties
);
103 protected InitialLdapContext
getLdapContext() {
104 return initialLdapContext
;
108 protected Boolean
daoHasRole(LdapName dn
) {
110 return daoGetRole(dn
) != null;
111 } catch (NameNotFoundException e
) {
117 protected DirectoryUser
daoGetRole(LdapName name
) throws NameNotFoundException
{
119 Attributes attrs
= getLdapContext().getAttributes(name
);
120 if (attrs
.size() == 0)
122 int roleType
= roleType(name
);
124 if (roleType
== Role
.GROUP
)
125 res
= new LdifGroup(this, name
, attrs
);
126 else if (roleType
== Role
.USER
)
127 res
= new LdifUser(this, name
, attrs
);
129 throw new UserDirectoryException("Unsupported LDAP type for " + name
);
131 } catch (NameNotFoundException e
) {
132 // if (adminUserDn != null && adminUserDn.equals(name)) {
136 } catch (NamingException e
) {
142 protected List
<DirectoryUser
> doGetRoles(Filter f
) {
143 ArrayList
<DirectoryUser
> res
= new ArrayList
<DirectoryUser
>();
145 String searchFilter
= f
!= null ? f
.toString()
146 : "(|(" + objectClass
+ "=" + getUserObjectClass() + ")(" + objectClass
+ "="
147 + getGroupObjectClass() + "))";
148 SearchControls searchControls
= new SearchControls();
149 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
151 LdapName searchBase
= getBaseDn();
152 NamingEnumeration
<SearchResult
> results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
154 results
: while (results
.hasMoreElements()) {
155 SearchResult searchResult
= results
.next();
156 Attributes attrs
= searchResult
.getAttributes();
157 Attribute objectClassAttr
= attrs
.get(objectClass
.name());
158 LdapName dn
= toDn(searchBase
, searchResult
);
160 if (objectClassAttr
.contains(getGroupObjectClass())
161 || objectClassAttr
.contains(getGroupObjectClass().toLowerCase()))
162 role
= new LdifGroup(this, dn
, attrs
);
163 else if (objectClassAttr
.contains(getUserObjectClass())
164 || objectClassAttr
.contains(getUserObjectClass().toLowerCase()))
165 role
= new LdifUser(this, dn
, attrs
);
167 // log.warn("Unsupported LDAP type for " + searchResult.getName());
173 // } catch (NameNotFoundException e) {
175 } catch (Exception e
) {
176 throw new UserDirectoryException("Cannot get roles for filter " + f
, e
);
180 private LdapName
toDn(LdapName baseDn
, Binding binding
) throws InvalidNameException
{
181 return new LdapName(binding
.isRelative() ? binding
.getName() + "," + baseDn
: binding
.getName());
185 protected List
<LdapName
> getDirectGroups(LdapName dn
) {
186 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
188 String searchFilter
= "(&(" + objectClass
+ "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
191 SearchControls searchControls
= new SearchControls();
192 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
194 LdapName searchBase
= getBaseDn();
195 NamingEnumeration
<SearchResult
> results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
197 while (results
.hasMoreElements()) {
198 SearchResult searchResult
= (SearchResult
) results
.nextElement();
199 directGroups
.add(toDn(searchBase
, searchResult
));
202 } catch (Exception e
) {
203 throw new UserDirectoryException("Cannot populate direct members of " + dn
, e
);
208 protected void prepare(UserDirectoryWorkingCopy wc
) {
210 getLdapContext().reconnect(getLdapContext().getConnectControls());
212 for (LdapName dn
: wc
.getDeletedUsers().keySet()) {
213 if (!entryExists(dn
))
214 throw new UserDirectoryException("User to delete no found " + dn
);
217 for (LdapName dn
: wc
.getNewUsers().keySet()) {
219 throw new UserDirectoryException("User to create found " + dn
);
222 for (LdapName dn
: wc
.getModifiedUsers().keySet()) {
223 if (!wc
.getNewUsers().containsKey(dn
) && !entryExists(dn
))
224 throw new UserDirectoryException("User to modify not found " + dn
);
226 } catch (NamingException e
) {
227 throw new UserDirectoryException("Cannot prepare LDAP", e
);
231 private boolean entryExists(LdapName dn
) throws NamingException
{
233 return getLdapContext().getAttributes(dn
).size() != 0;
234 } catch (NameNotFoundException e
) {
240 protected void commit(UserDirectoryWorkingCopy wc
) {
243 for (LdapName dn
: wc
.getDeletedUsers().keySet()) {
244 getLdapContext().destroySubcontext(dn
);
247 for (LdapName dn
: wc
.getNewUsers().keySet()) {
248 DirectoryUser user
= wc
.getNewUsers().get(dn
);
249 getLdapContext().createSubcontext(dn
, user
.getAttributes());
252 for (LdapName dn
: wc
.getModifiedUsers().keySet()) {
253 Attributes modifiedAttrs
= wc
.getModifiedUsers().get(dn
);
254 getLdapContext().modifyAttributes(dn
, DirContext
.REPLACE_ATTRIBUTE
, modifiedAttrs
);
256 } catch (NamingException e
) {
257 throw new UserDirectoryException("Cannot commit LDAP", e
);
262 protected void rollback(UserDirectoryWorkingCopy wc
) {
263 // prepare not impacting