]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
Change the approach for releases
[lgpl/argeo-commons.git] / org.argeo.enterprise / src / org / argeo / osgi / useradmin / LdapUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import static org.argeo.naming.LdapAttrs.objectClass;
4
5 import java.util.ArrayList;
6 import java.util.Dictionary;
7 import java.util.List;
8
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;
21 import javax.transaction.TransactionManager;
22
23 import org.osgi.framework.Filter;
24 import org.osgi.service.useradmin.Role;
25 import org.osgi.service.useradmin.User;
26
27 /**
28 * A user admin based on a LDAP server. Requires a {@link TransactionManager}
29 * and an open transaction for write access.
30 */
31 public class LdapUserAdmin extends AbstractUserDirectory {
32 private LdapConnection ldapConnection;
33
34 public LdapUserAdmin(Dictionary<String, ?> properties) {
35 this(properties, false);
36 }
37
38 public LdapUserAdmin(Dictionary<String, ?> properties, boolean scoped) {
39 super(null, properties, scoped);
40 ldapConnection = new LdapConnection(getUri().toString(), properties);
41 }
42
43 public void destroy() {
44 ldapConnection.destroy();
45 }
46
47 @Override
48 protected AbstractUserDirectory scope(User user) {
49 Dictionary<String, Object> credentials = user.getCredentials();
50 String username = (String) credentials.get(SHARED_STATE_USERNAME);
51 if (username == null)
52 username = user.getName();
53 Dictionary<String, Object> properties = cloneProperties();
54 properties.put(Context.SECURITY_PRINCIPAL, username.toString());
55 Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
56 byte[] pwd = (byte[]) pwdCred;
57 if (pwd != null) {
58 char[] password = DigestUtils.bytesToChars(pwd);
59 properties.put(Context.SECURITY_CREDENTIALS, new String(password));
60 } else {
61 properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
62 }
63 return new LdapUserAdmin(properties, true);
64 }
65
66 // protected InitialLdapContext getLdapContext() {
67 // return initialLdapContext;
68 // }
69
70 @Override
71 protected Boolean daoHasRole(LdapName dn) {
72 try {
73 return daoGetRole(dn) != null;
74 } catch (NameNotFoundException e) {
75 return false;
76 }
77 }
78
79 @Override
80 protected DirectoryUser daoGetRole(LdapName name) throws NameNotFoundException {
81 try {
82 Attributes attrs = ldapConnection.getAttributes(name);
83 if (attrs.size() == 0)
84 return null;
85 int roleType = roleType(name);
86 LdifUser res;
87 if (roleType == Role.GROUP)
88 res = new LdifGroup(this, name, attrs);
89 else if (roleType == Role.USER)
90 res = new LdifUser(this, name, attrs);
91 else
92 throw new UserDirectoryException("Unsupported LDAP type for " + name);
93 return res;
94 } catch (NameNotFoundException e) {
95 throw e;
96 } catch (NamingException e) {
97 return null;
98 }
99 }
100
101 @Override
102 protected List<DirectoryUser> doGetRoles(Filter f) {
103 ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
104 try {
105 String searchFilter = f != null ? f.toString()
106 : "(|(" + objectClass + "=" + getUserObjectClass() + ")(" + objectClass + "="
107 + getGroupObjectClass() + "))";
108 SearchControls searchControls = new SearchControls();
109 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
110
111 LdapName searchBase = getBaseDn();
112 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
113
114 results: while (results.hasMoreElements()) {
115 SearchResult searchResult = results.next();
116 Attributes attrs = searchResult.getAttributes();
117 Attribute objectClassAttr = attrs.get(objectClass.name());
118 LdapName dn = toDn(searchBase, searchResult);
119 LdifUser role;
120 if (objectClassAttr.contains(getGroupObjectClass())
121 || objectClassAttr.contains(getGroupObjectClass().toLowerCase()))
122 role = new LdifGroup(this, dn, attrs);
123 else if (objectClassAttr.contains(getUserObjectClass())
124 || objectClassAttr.contains(getUserObjectClass().toLowerCase()))
125 role = new LdifUser(this, dn, attrs);
126 else {
127 // log.warn("Unsupported LDAP type for " + searchResult.getName());
128 continue results;
129 }
130 res.add(role);
131 }
132 return res;
133 } catch (AuthenticationNotSupportedException e) {
134 // ignore (typically an unsupported anonymous bind)
135 // TODO better logging
136 return res;
137 } catch (Exception e) {
138 e.printStackTrace();
139 throw new UserDirectoryException("Cannot get roles for filter " + f, e);
140 }
141 }
142
143 private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
144 return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
145 }
146
147 @Override
148 protected List<LdapName> getDirectGroups(LdapName dn) {
149 List<LdapName> directGroups = new ArrayList<LdapName>();
150 try {
151 String searchFilter = "(&(" + objectClass + "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
152 + "=" + dn + "))";
153
154 SearchControls searchControls = new SearchControls();
155 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
156
157 LdapName searchBase = getBaseDn();
158 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
159
160 while (results.hasMoreElements()) {
161 SearchResult searchResult = (SearchResult) results.nextElement();
162 directGroups.add(toDn(searchBase, searchResult));
163 }
164 return directGroups;
165 } catch (Exception e) {
166 throw new UserDirectoryException("Cannot populate direct members of " + dn, e);
167 }
168 }
169
170 @Override
171 protected void prepare(UserDirectoryWorkingCopy wc) {
172 try {
173 ldapConnection.prepareChanges(wc);
174 } catch (NamingException e) {
175 throw new UserDirectoryException("Cannot prepare LDAP", e);
176 }
177 }
178
179 @Override
180 protected void commit(UserDirectoryWorkingCopy wc) {
181 try {
182 ldapConnection.commitChanges(wc);
183 } catch (NamingException e) {
184 throw new UserDirectoryException("Cannot commit LDAP", e);
185 }
186 }
187
188 @Override
189 protected void rollback(UserDirectoryWorkingCopy wc) {
190 // prepare not impacting
191 }
192
193 }