1
2
3
4
5
6
7 package gov.bnl.gums.userGroup;
8
9 import gov.bnl.gums.GUMS;
10 import gov.bnl.gums.GridUser;
11 import gov.bnl.gums.configuration.Configuration;
12
13 import java.util.*;
14
15 import javax.naming.*;
16 import javax.naming.directory.*;
17 import javax.persistence.Entity;
18 import javax.persistence.Transient;
19
20 import org.apache.log4j.Logger;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 @Entity
41 public class LDAPUserGroup extends UserGroup {
42 static protected Logger log = Logger.getLogger(LDAPUserGroup.class);
43 static protected Logger gumsAdminLog = Logger.getLogger(GUMS.gumsAdminLogName);
44
45 protected String peopleContext = null;
46
47
48 protected String server;
49 protected String certDNField = "description";
50 protected String memberUidField = "memberUid";
51 protected String uidField = "uid";
52 protected String peopleTree;
53 protected String peopleObject = "ou=People";
54 protected String groupTree;
55
56 public LDAPUserGroup() {
57 super();
58 hasCache = true;
59 }
60
61 public LDAPUserGroup(Configuration configuration, String name) {
62 super(configuration, name);
63 hasCache = true;
64 }
65
66
67
68
69
70
71 public String getCertDNField() {
72 return certDNField;
73 }
74
75
76
77
78
79
80 public String getGroupTree() {
81 return groupTree;
82 }
83
84 public String getMemberUidField() {
85 return memberUidField;
86 }
87
88
89
90
91
92
93 public String getPeopleTree() {
94 return peopleTree;
95 }
96
97
98
99
100
101
102 @Transient
103 public String getQuery() {
104 return peopleTree;
105 }
106
107
108
109
110
111
112 public String getServer() {
113 return this.server;
114 }
115
116 public String getUidField() {
117 return uidField;
118 }
119
120
121
122
123
124
125 @ConfigFieldAnnotation(label="Certificate DN Field", example="description")
126 public void setCertDNField(String certDNField) {
127 this.certDNField = certDNField;
128 }
129
130
131
132
133
134
135 @ConfigFieldAnnotation(label="Group Tree", example="ou=Group,dc=usatlas,dc=bnl,dc=gov")
136 public void setGroupTree(String groupTree) {
137 this.groupTree = groupTree;
138 }
139
140 @ConfigFieldAnnotation(label="Member Field", example="memberUid", help="field containing user ID in 'Group' object")
141 public void setMemberUidField(String memberUidField) {
142 this.memberUidField = memberUidField;
143 }
144
145
146
147
148
149
150 @ConfigFieldAnnotation(label="People Tree", example="ou=People,dc=usatlas,dc=bnl,dc=gov")
151 public void setPeopleTree(String peopleTree) {
152 if (peopleTree == null)
153 return;
154 this.peopleTree = peopleTree;
155 this.peopleObject = peopleTree.substring(0, peopleTree.indexOf(','));
156 this.peopleContext = peopleTree.substring(peopleTree.indexOf(',')+1);
157 }
158
159
160
161
162
163
164
165 public void setQuery(String query) {
166 if (query == null)
167 return;
168 if (query.startsWith(peopleObject+",")) {
169 peopleTree = query;
170 peopleObject = query.substring(0, query.indexOf(','));
171 peopleContext = query.substring(query.indexOf(',')+1);
172 } else if (query.startsWith("ou=")) {
173 peopleObject = "ou=People";
174 peopleContext = query.substring(query.indexOf(',')+1);
175 peopleTree = peopleObject + "," + peopleContext;
176 } else if (query.startsWith("o=")) {
177 peopleObject = "ou=People";
178 peopleContext = query;
179 peopleTree = peopleObject + "," + peopleContext;
180 } else {
181 throw new IllegalArgumentException("The query is not understood by the LDAP group. It is expected to start with \"ou=...\" or \"o=...\"");
182 }
183 }
184
185
186
187
188
189 @ConfigFieldAnnotation(label="LDAP Server", example="grid-vo.nikhef.nl")
190 public void setServer(String server) {
191 this.server = server;
192 }
193
194 @ConfigFieldAnnotation(label="Account UID Field", example="uid")
195 public void setUidField(String uidField) {
196 this.uidField = uidField;
197 }
198
199 private Set<GridUser> retrieveGroupMembers(DirContext rootCtx, Attribute members) throws javax.naming.NamingException {
200 Map<String, String> people = retrievePeopleMap(rootCtx);
201 NamingEnumeration<?> names = members.getAll();
202 Set<GridUser> users = new HashSet<GridUser>();
203 while (names.hasMore()) {
204
205 String ldapName = (String)names.next();
206 ldapName = ldapName.trim();
207 String certDN = people.get(ldapName);
208 if (certDN == null) {
209 gumsAdminLog.warn("Member of a LDAP VO group not mapped to any certificate: '" + ldapName + "'");
210 } else {
211 users.add(new GridUser(certDN));
212 }
213 }
214 if (users.isEmpty())
215 gumsAdminLog.warn("The following group returned no members: " + this);
216 return users;
217 }
218
219
220
221
222
223
224
225 protected synchronized Set<GridUser> retrieveMembers() {
226 java.util.Properties properties = retrieveProperties();
227 log.info("Retrieving members from '" + properties.getProperty("java.naming.provider.url") + "' '" + peopleTree + "' '" + groupTree + "'");
228 try {
229 javax.naming.directory.DirContext jndiCtx = new javax.naming.directory.InitialDirContext(properties);
230 if (!peopleTree.equals("") && groupTree.equals("")) {
231 DirContext rootCtx = (DirContext) jndiCtx.lookup(peopleContext);
232 return retrieveVOMembers(rootCtx);
233 }
234 else if (!groupTree.equals("") && !peopleTree.equals("")) {
235 Attributes atts = jndiCtx.getAttributes(groupTree);
236 Attribute members = atts.get(memberUidField);
237 if (members == null) {
238 String message = "Couldn't retrieve the list of members from the LDAP group: missing attribute member";
239 GUMS.gumsAdminEmailLog.put("ldapUpdateProblem", message, false);
240 throw new RuntimeException(message);
241 }
242 DirContext rootCtx = (DirContext) jndiCtx.lookup(peopleContext);
243 return retrieveGroupMembers(rootCtx, members);
244 }
245 } catch (javax.naming.NamingException e) {
246 String message = "Couldn't retrieve users from LDAP server: " + e;
247
248
249
250 log.error("Couldn't retrieve LDAP users: ", e);
251 throw new RuntimeException(message, e);
252 }
253 return null;
254 }
255
256 protected Map<String, String> retrievePeopleMap(DirContext ldap) throws javax.naming.NamingException {
257 NamingEnumeration<?> people = ldap.search(peopleObject, "("+certDNField+"=*)", null);
258 Map<String, String> map = new Hashtable<String, String>();
259 while (people.hasMore()) {
260 SearchResult person = (SearchResult) people.next();
261 Attributes personAtts = person.getAttributes();
262 String ldapDN = (String)personAtts.get(uidField).get();
263
264
265
266 String certDN = (String) personAtts.get(certDNField).get();
267 if (certDN.startsWith("subject=")) {
268 certDN = certDN.substring(8);
269 }
270 certDN = certDN.trim();
271 map.put(ldapDN, certDN);
272 }
273 return map;
274 }
275
276 private Properties retrieveProperties() {
277 Properties properties = new java.util.Properties();
278 properties.put(Context.PROVIDER_URL, "ldap://"+server);
279 properties.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
280 properties.put(Context.SECURITY_PROTOCOL, "none");
281 return properties;
282 }
283
284 private Set<GridUser> retrieveVOMembers(DirContext rootCtx) throws NamingException {
285 Map<String, String> people = retrievePeopleMap(rootCtx);
286 List<String> list = new ArrayList<String>(people.values());
287 if (list.isEmpty()) {
288 gumsAdminLog.warn("The following group returned no members: " + this);
289 }
290 Iterator<String> iter = list.iterator();
291 Set<GridUser> users = new HashSet<GridUser>();
292 while (iter.hasNext()) {
293 String dn = (String) iter.next();
294 users.add(new GridUser(dn));
295 }
296 if (list.isEmpty())
297 gumsAdminLog.warn("The following group returned no members: " + this);
298 return users;
299 }
300
301 }