1 package org
.argeo
.util
.directory
.ldap
;
3 import static org
.argeo
.util
.naming
.LdapAttrs
.objectClass
;
5 import java
.util
.ArrayList
;
8 import javax
.naming
.AuthenticationNotSupportedException
;
9 import javax
.naming
.Binding
;
10 import javax
.naming
.InvalidNameException
;
11 import javax
.naming
.NameNotFoundException
;
12 import javax
.naming
.NamingEnumeration
;
13 import javax
.naming
.NamingException
;
14 import javax
.naming
.directory
.Attribute
;
15 import javax
.naming
.directory
.Attributes
;
16 import javax
.naming
.directory
.SearchControls
;
17 import javax
.naming
.directory
.SearchResult
;
18 import javax
.naming
.ldap
.LdapName
;
19 import javax
.naming
.ldap
.Rdn
;
21 import org
.argeo
.util
.directory
.HierarchyUnit
;
22 import org
.argeo
.util
.naming
.LdapObjs
;
24 /** A user admin based on a LDAP server. */
25 public class LdapDao
extends AbstractLdapDirectoryDao
{
26 private LdapConnection ldapConnection
;
28 // public LdapUserAdmin(Dictionary<String, ?> properties) {
29 // this(properties, false);
32 public LdapDao(AbstractLdapDirectory directory
) {
38 ldapConnection
= new LdapConnection(getDirectory().getUri().toString(), getDirectory().getProperties());
41 public void destroy() {
42 ldapConnection
.destroy();
46 // protected AbstractUserDirectory scope(User user) {
47 // Dictionary<String, Object> credentials = user.getCredentials();
48 // String username = (String) credentials.get(SHARED_STATE_USERNAME);
49 // if (username == null)
50 // username = user.getName();
51 // Dictionary<String, Object> properties = cloneProperties();
52 // properties.put(Context.SECURITY_PRINCIPAL, username.toString());
53 // Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
54 // byte[] pwd = (byte[]) pwdCred;
56 // char[] password = DirectoryDigestUtils.bytesToChars(pwd);
57 // properties.put(Context.SECURITY_CREDENTIALS, new String(password));
59 // properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
61 // return new LdapUserAdmin(properties, true);
64 // protected InitialLdapContext getLdapContext() {
65 // return initialLdapContext;
69 public Boolean
daoHasEntry(LdapName dn
) {
71 return daoGetEntry(dn
) != null;
72 } catch (NameNotFoundException e
) {
78 public LdapEntry
daoGetEntry(LdapName name
) throws NameNotFoundException
{
80 Attributes attrs
= ldapConnection
.getAttributes(name
);
81 if (attrs
.size() == 0)
83 // int roleType = roleType(name);
86 res
= newGroup(name
, attrs
);
88 res
= newUser(name
, attrs
);
90 // throw new IllegalArgumentException("Unsupported LDAP type for " + name);
92 } catch (NameNotFoundException e
) {
94 } catch (NamingException e
) {
99 protected boolean isGroup(LdapName dn
) {
100 Rdn technicalRdn
= LdapNameUtils
.getParentRdn(dn
);
101 if (getDirectory().getGroupBaseRdn().equals(technicalRdn
)
102 || getDirectory().getSystemRoleBaseRdn().equals(technicalRdn
))
104 else if (getDirectory().getUserBaseRdn().equals(technicalRdn
))
107 throw new IllegalArgumentException(
108 "Cannot dind role type, " + technicalRdn
+ " is not a technical RDN for " + dn
);
112 public List
<LdapEntry
> doGetEntries(LdapName searchBase
, String f
, boolean deep
) {
113 ArrayList
<LdapEntry
> res
= new ArrayList
<>();
115 String searchFilter
= f
!= null ? f
.toString()
116 : "(|(" + objectClass
+ "=" + getDirectory().getUserObjectClass() + ")(" + objectClass
+ "="
117 + getDirectory().getGroupObjectClass() + "))";
118 SearchControls searchControls
= new SearchControls();
119 // FIXME make one level consistent with deep
120 searchControls
.setSearchScope(deep ? SearchControls
.SUBTREE_SCOPE
: SearchControls
.ONELEVEL_SCOPE
);
122 // LdapName searchBase = getBaseDn();
123 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
125 results
: while (results
.hasMoreElements()) {
126 SearchResult searchResult
= results
.next();
127 Attributes attrs
= searchResult
.getAttributes();
128 Attribute objectClassAttr
= attrs
.get(objectClass
.name());
129 LdapName dn
= toDn(searchBase
, searchResult
);
131 if (objectClassAttr
.contains(getDirectory().getGroupObjectClass())
132 || objectClassAttr
.contains(getDirectory().getGroupObjectClass().toLowerCase()))
133 role
= newGroup(dn
, attrs
);
134 else if (objectClassAttr
.contains(getDirectory().getUserObjectClass())
135 || objectClassAttr
.contains(getDirectory().getUserObjectClass().toLowerCase()))
136 role
= newUser(dn
, attrs
);
138 // log.warn("Unsupported LDAP type for " + searchResult.getName());
144 } catch (AuthenticationNotSupportedException e
) {
145 // ignore (typically an unsupported anonymous bind)
146 // TODO better logging
148 } catch (NamingException e
) {
149 throw new IllegalStateException("Cannot get roles for filter " + f
, e
);
153 private LdapName
toDn(LdapName baseDn
, Binding binding
) throws InvalidNameException
{
154 return new LdapName(binding
.isRelative() ? binding
.getName() + "," + baseDn
: binding
.getName());
158 public List
<LdapName
> getDirectGroups(LdapName dn
) {
159 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
161 String searchFilter
= "(&(" + objectClass
+ "=" + getDirectory().getGroupObjectClass() + ")("
162 + getDirectory().getMemberAttributeId() + "=" + dn
+ "))";
164 SearchControls searchControls
= new SearchControls();
165 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
167 LdapName searchBase
= getDirectory().getBaseDn();
168 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
170 while (results
.hasMoreElements()) {
171 SearchResult searchResult
= (SearchResult
) results
.nextElement();
172 directGroups
.add(toDn(searchBase
, searchResult
));
175 } catch (NamingException e
) {
176 throw new IllegalStateException("Cannot populate direct members of " + dn
, e
);
181 public void prepare(LdapEntryWorkingCopy wc
) {
183 ldapConnection
.prepareChanges(wc
);
184 } catch (NamingException e
) {
185 throw new IllegalStateException("Cannot prepare LDAP", e
);
190 public void commit(LdapEntryWorkingCopy wc
) {
192 ldapConnection
.commitChanges(wc
);
193 } catch (NamingException e
) {
194 throw new IllegalStateException("Cannot commit LDAP", e
);
199 public void rollback(LdapEntryWorkingCopy wc
) {
200 // prepare not impacting
208 public Iterable
<HierarchyUnit
> doGetDirectHierarchyUnits(LdapName searchBase
, boolean functionalOnly
) {
209 List
<HierarchyUnit
> res
= new ArrayList
<>();
211 String searchFilter
= "(|(" + objectClass
+ "=" + LdapObjs
.organizationalUnit
.name() + ")(" + objectClass
212 + "=" + LdapObjs
.organization
.name() + "))";
214 SearchControls searchControls
= new SearchControls();
215 searchControls
.setSearchScope(SearchControls
.ONELEVEL_SCOPE
);
217 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
219 while (results
.hasMoreElements()) {
220 SearchResult searchResult
= (SearchResult
) results
.nextElement();
221 LdapName dn
= toDn(searchBase
, searchResult
);
222 Attributes attrs
= searchResult
.getAttributes();
223 LdapHierarchyUnit hierarchyUnit
= new LdapHierarchyUnit(getDirectory(), dn
, attrs
);
224 if (functionalOnly
) {
225 if (hierarchyUnit
.isFunctional())
226 res
.add(hierarchyUnit
);
228 res
.add(hierarchyUnit
);
232 } catch (NamingException e
) {
233 throw new IllegalStateException("Cannot get direct hierarchy units ", e
);
238 public HierarchyUnit
doGetHierarchyUnit(LdapName dn
) {
240 Attributes attrs
= ldapConnection
.getAttributes(dn
);
241 return new LdapHierarchyUnit(getDirectory(), dn
, attrs
);
242 } catch (NamingException e
) {
243 throw new IllegalStateException("Cannot get hierarchy unit " + dn
, e
);