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().cloneConfigProperties());
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
entryExists(LdapName dn
) {
71 return doGetEntry(dn
) != null;
72 } catch (NameNotFoundException e
) {
78 public LdapEntry
doGetEntry(LdapName name
) throws NameNotFoundException
{
80 Attributes attrs
= ldapConnection
.getAttributes(name
);
81 if (attrs
.size() == 0)
83 // int roleType = roleType(name);
85 Rdn technicalRdn
= LdapNameUtils
.getParentRdn(name
);
86 if (getDirectory().getGroupBaseRdn().equals(technicalRdn
))
87 res
= newGroup(name
, attrs
);
88 else if (getDirectory().getSystemRoleBaseRdn().equals(technicalRdn
))
89 res
= newGroup(name
, attrs
);
90 else if (getDirectory().getUserBaseRdn().equals(technicalRdn
))
91 res
= newUser(name
, attrs
);
93 res
= new DefaultLdapEntry(getDirectory(), name
, attrs
);
95 // res = newGroup(name, attrs);
97 // res = newUser(name, attrs);
99 // throw new IllegalArgumentException("Unsupported LDAP type for " + name);
101 } catch (NameNotFoundException e
) {
103 } catch (NamingException e
) {
108 // protected boolean isGroup(LdapName dn) {
109 // Rdn technicalRdn = LdapNameUtils.getParentRdn(dn);
110 // if (getDirectory().getGroupBaseRdn().equals(technicalRdn)
111 // || getDirectory().getSystemRoleBaseRdn().equals(technicalRdn))
113 // else if (getDirectory().getUserBaseRdn().equals(technicalRdn))
116 // throw new IllegalArgumentException(
117 // "Cannot find role type, " + technicalRdn + " is not a technical RDN for " + dn);
121 public List
<LdapEntry
> doGetEntries(LdapName searchBase
, String f
, boolean deep
) {
122 ArrayList
<LdapEntry
> res
= new ArrayList
<>();
124 String searchFilter
= f
!= null ? f
.toString()
125 : "(|(" + objectClass
+ "=" + getDirectory().getUserObjectClass() + ")(" + objectClass
+ "="
126 + getDirectory().getGroupObjectClass() + "))";
127 SearchControls searchControls
= new SearchControls();
128 // FIXME make one level consistent with deep
129 searchControls
.setSearchScope(deep ? SearchControls
.SUBTREE_SCOPE
: SearchControls
.ONELEVEL_SCOPE
);
131 // LdapName searchBase = getBaseDn();
132 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
134 results
: while (results
.hasMoreElements()) {
135 SearchResult searchResult
= results
.next();
136 Attributes attrs
= searchResult
.getAttributes();
137 Attribute objectClassAttr
= attrs
.get(objectClass
.name());
138 LdapName dn
= toDn(searchBase
, searchResult
);
140 if (objectClassAttr
.contains(getDirectory().getGroupObjectClass())
141 || objectClassAttr
.contains(getDirectory().getGroupObjectClass().toLowerCase()))
142 role
= newGroup(dn
, attrs
);
143 else if (objectClassAttr
.contains(getDirectory().getUserObjectClass())
144 || objectClassAttr
.contains(getDirectory().getUserObjectClass().toLowerCase()))
145 role
= newUser(dn
, attrs
);
147 // log.warn("Unsupported LDAP type for " + searchResult.getName());
153 } catch (AuthenticationNotSupportedException e
) {
154 // ignore (typically an unsupported anonymous bind)
155 // TODO better logging
157 } catch (NamingException e
) {
158 throw new IllegalStateException("Cannot get roles for filter " + f
, e
);
162 private LdapName
toDn(LdapName baseDn
, Binding binding
) throws InvalidNameException
{
163 return new LdapName(binding
.isRelative() ? binding
.getName() + "," + baseDn
: binding
.getName());
167 public List
<LdapName
> getDirectGroups(LdapName dn
) {
168 List
<LdapName
> directGroups
= new ArrayList
<LdapName
>();
170 String searchFilter
= "(&(" + objectClass
+ "=" + getDirectory().getGroupObjectClass() + ")("
171 + getDirectory().getMemberAttributeId() + "=" + dn
+ "))";
173 SearchControls searchControls
= new SearchControls();
174 searchControls
.setSearchScope(SearchControls
.SUBTREE_SCOPE
);
176 LdapName searchBase
= getDirectory().getBaseDn();
177 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
179 while (results
.hasMoreElements()) {
180 SearchResult searchResult
= (SearchResult
) results
.nextElement();
181 directGroups
.add(toDn(searchBase
, searchResult
));
184 } catch (NamingException e
) {
185 throw new IllegalStateException("Cannot populate direct members of " + dn
, e
);
190 public void prepare(LdapEntryWorkingCopy wc
) {
192 ldapConnection
.prepareChanges(wc
);
193 } catch (NamingException e
) {
194 throw new IllegalStateException("Cannot prepare LDAP", e
);
199 public void commit(LdapEntryWorkingCopy wc
) {
201 ldapConnection
.commitChanges(wc
);
202 } catch (NamingException e
) {
203 throw new IllegalStateException("Cannot commit LDAP", e
);
208 public void rollback(LdapEntryWorkingCopy wc
) {
209 // prepare not impacting
217 public Iterable
<HierarchyUnit
> doGetDirectHierarchyUnits(LdapName searchBase
, boolean functionalOnly
) {
218 List
<HierarchyUnit
> res
= new ArrayList
<>();
220 String searchFilter
= "(|(" + objectClass
+ "=" + LdapObjs
.organizationalUnit
.name() + ")(" + objectClass
221 + "=" + LdapObjs
.organization
.name() + "))";
222 // String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
223 // + "=" + LdapObjs.organization.name() + ")(cn=accounts)(cn=users)(cn=groups))";
225 SearchControls searchControls
= new SearchControls();
226 searchControls
.setSearchScope(SearchControls
.ONELEVEL_SCOPE
);
228 NamingEnumeration
<SearchResult
> results
= ldapConnection
.search(searchBase
, searchFilter
, searchControls
);
230 while (results
.hasMoreElements()) {
231 SearchResult searchResult
= (SearchResult
) results
.nextElement();
232 LdapName dn
= toDn(searchBase
, searchResult
);
233 Attributes attrs
= searchResult
.getAttributes();
234 LdapHierarchyUnit hierarchyUnit
= new LdapHierarchyUnit(getDirectory(), dn
, attrs
);
235 if (functionalOnly
) {
236 if (hierarchyUnit
.isFunctional())
237 res
.add(hierarchyUnit
);
239 res
.add(hierarchyUnit
);
243 } catch (NamingException e
) {
244 throw new IllegalStateException("Cannot get direct hierarchy units ", e
);
249 public HierarchyUnit
doGetHierarchyUnit(LdapName dn
) {
251 if (getDirectory().getBaseDn().equals(dn
))
252 return getDirectory();
253 if (!dn
.startsWith(getDirectory().getBaseDn()))
254 throw new IllegalArgumentException(dn
+ " does not start with base DN " + getDirectory().getBaseDn());
255 Attributes attrs
= ldapConnection
.getAttributes(dn
);
256 return new LdapHierarchyUnit(getDirectory(), dn
, attrs
);
257 } catch (NamingException e
) {
258 throw new IllegalStateException("Cannot get hierarchy unit " + dn
, e
);