1 package org
.argeo
.osgi
.useradmin
;
3 import static org
.argeo
.util
.naming
.LdapAttrs
.objectClass
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Dictionary
;
9 import javax
.naming
.AuthenticationNotSupportedException
;
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
.SearchControls
;
19 import javax
.naming
.directory
.SearchResult
;
20 import javax
.naming
.ldap
.LdapName
;
22 import org
.osgi
.framework
.Filter
;
23 import org
.osgi
.service
.useradmin
.Role
;
24 import org
.osgi
.service
.useradmin
.User
;
26 /** A user admin based on a LDAP server. */
27 public class LdapUserAdmin
extends AbstractUserDirectory
{
28 private LdapConnection ldapConnection
;
30 public LdapUserAdmin(Dictionary
<String
, ?
> properties
) {
31 this(properties
, false);
34 public LdapUserAdmin(Dictionary
<String
, ?
> properties
, boolean scoped
) {
35 super(null, properties
, scoped
);
36 ldapConnection
= new LdapConnection(getUri().toString(), properties
);
39 public void destroy() {
40 ldapConnection
.destroy();
44 protected AbstractUserDirectory
scope(User user
) {
45 Dictionary
<String
, Object
> credentials
= user
.getCredentials();
46 String username
= (String
) credentials
.get(SHARED_STATE_USERNAME
);
48 username
= user
.getName();
49 Dictionary
<String
, Object
> properties
= cloneProperties();
50 properties
.put(Context
.SECURITY_PRINCIPAL
, username
.toString());
51 Object pwdCred
= credentials
.get(SHARED_STATE_PASSWORD
);
52 byte[] pwd
= (byte[]) pwdCred
;
54 char[] password
= DigestUtils
.bytesToChars(pwd
);
55 properties
.put(Context
.SECURITY_CREDENTIALS
, new String(password
));
57 properties
.put(Context
.SECURITY_AUTHENTICATION
, "GSSAPI");
59 return new LdapUserAdmin(properties
, true);
62 // protected InitialLdapContext getLdapContext() {
63 // return initialLdapContext;
67 protected Boolean
daoHasRole(LdapName dn
) {
69 return daoGetRole(dn
) != null;
70 } catch (NameNotFoundException e
) {
76 protected DirectoryUser
daoGetRole(LdapName name
) throws NameNotFoundException
{
78 Attributes attrs
= ldapConnection
.getAttributes(name
);
79 if (attrs
.size() == 0)
81 int roleType
= roleType(name
);
83 if (roleType
== Role
.GROUP
)
84 res
= new LdifGroup(this, name
, attrs
);
85 else if (roleType
== Role
.USER
)
86 res
= new LdifUser(this, name
, attrs
);
88 throw new UserDirectoryException("Unsupported LDAP type for " + name
);
90 } catch (NameNotFoundException e
) {
92 } catch (NamingException e
) {
98 protected List
<DirectoryUser
> doGetRoles(LdapName searchBase
, Filter f
, boolean deep
) {
99 ArrayList
<DirectoryUser
> res
= new ArrayList
<DirectoryUser
>();
101 String searchFilter
= f
!= null ? f
.toString()
102 : "(|(" + objectClass
+ "=" + getUserObjectClass() + ")(" + objectClass
+ "="
103 + getGroupObjectClass() + "))";
104 SearchControls searchControls
= new SearchControls();
105 // FIXME make one level consistent with deep
106 searchControls
.setSearchScope(deep ? SearchControls
.SUBTREE_SCOPE
: SearchControls
.ONELEVEL_SCOPE
);
108 // LdapName searchBase = getBaseDn();
109 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
111 results
: while (results
.hasMoreElements()) {
112 SearchResult searchResult
= results
.next();
113 Attributes attrs
= searchResult
.getAttributes();
114 Attribute objectClassAttr
= attrs
.get(objectClass
.name());
115 LdapName dn
= toDn(searchBase
, searchResult
);
117 if (objectClassAttr
.contains(getGroupObjectClass())
118 || objectClassAttr
.contains(getGroupObjectClass().toLowerCase()))
119 role
= new LdifGroup(this, dn
, attrs
);
120 else if (objectClassAttr
.contains(getUserObjectClass())
121 || objectClassAttr
.contains(getUserObjectClass().toLowerCase()))
122 role
= new LdifUser(this, dn
, attrs
);
124 // log.warn("Unsupported LDAP type for " + searchResult.getName());
130 } catch (AuthenticationNotSupportedException e
) {
131 // ignore (typically an unsupported anonymous bind)
132 // TODO better logging
134 } catch (Exception e
) {
136 throw new UserDirectoryException("Cannot get roles for filter " + f
, e
);
140 private LdapName
toDn(LdapName baseDn
, Binding binding
) throws InvalidNameException
{
141 return new LdapName(binding
.isRelative() ? binding
.getName() + "," + baseDn
: binding
.getName());
145 protected List
<LdapName
> getDirectGroups(LdapName dn
) {
146 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
148 String searchFilter
= "(&(" + objectClass
+ "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
151 SearchControls searchControls
= new SearchControls();
152 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
154 LdapName searchBase
= getBaseDn();
155 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
157 while (results
.hasMoreElements()) {
158 SearchResult searchResult
= (SearchResult
) results
.nextElement();
159 directGroups
.add(toDn(searchBase
, searchResult
));
162 } catch (Exception e
) {
163 throw new UserDirectoryException("Cannot populate direct members of " + dn
, e
);
168 protected void prepare(UserDirectoryWorkingCopy wc
) {
170 ldapConnection
.prepareChanges(wc
);
171 } catch (NamingException e
) {
172 throw new UserDirectoryException("Cannot prepare LDAP", e
);
177 protected void commit(UserDirectoryWorkingCopy wc
) {
179 ldapConnection
.commitChanges(wc
);
180 } catch (NamingException e
) {
181 throw new UserDirectoryException("Cannot commit LDAP", e
);
186 protected void rollback(UserDirectoryWorkingCopy wc
) {
187 // prepare not impacting
191 // public HierarchyUnit getHierarchyUnit(String path) {
192 // LdapName dn = LdapNameUtils.toLdapName(path);
193 // Attributes attrs = ldapConnection.getAttributes(dn);