1
2
3
4
5
6
7 package gov.bnl.gums;
8
9 import java.util.*;
10 import javax.naming.*;
11 import javax.naming.directory.*;
12 import org.apache.commons.logging.*;
13
14 /*** A group of users defined by an LDAP VO.
15 * <p>
16 * The query should be :
17 * <ul>
18 * <li>A People ou (i.e. ou=People,o=atlas,dc=eu-datagrid,dc=org). All the
19 * object found in that category will have to have a 'description' attribute
20 * which will contain the certificate DN</li>
21 * <li>A group ou (i.e. ou=usatlas,o=atlas,dc=eu-datagrid,dc=org). The ou
22 * object will need to have a 'member' property with the list of people in
23 * the VO that are in the group. Each member will be an object in
24 * ou=People</li>
25 * <li>A root o (i.e. o=atlas,dc=eu-datagrid,dc=org). A ou=People object will
26 * be expected, and it will behave like the first option</li>
27 * </ul>
28 *
29 * @author carcassi
30 */
31 public class LDAPGroup implements UserGroup {
32 private Log log = LogFactory.getLog(LDAPGroup.class);
33 private Log resourceAdminLog = LogFactory.getLog(GUMS.resourceAdminLog);
34
35 private UserGroupDB db;
36 private String name;
37 private PersistenceFactory persistanceFactory;
38
39 public java.util.List getMemberList() {
40 return db.retrieveMembers();
41 }
42
43 public String getName() {
44 return name;
45 }
46
47 public void setName(String name) {
48 this.name = name;
49 }
50
51 public boolean isInGroup(GridUser user) {
52 return db.isMemberInGroup(user);
53 }
54
55 public void updateMembers() {
56 db.loadUpdatedList(retrieveMembers());
57 }
58
59 private String server;
60 private String query;
61
62 /***
63 * Returns the list of member retrieved from the LDAP server. The members are not saved in the database.
64 * @return A list of VOEntry objects representing the members.
65 */
66 private List retrieveMembers() {
67 java.util.Properties jndiProperties = new java.util.Properties();
68 jndiProperties.put("java.naming.provider.url","ldap://"+server);
69 jndiProperties.put("java.naming.factory.initial","com.sun.jndi.ldap.LdapCtxFactory");
70 log.info("Retrieving members from '" + jndiProperties.getProperty("java.naming.provider.url") +
71 "' '" + query + "'");
72 try {
73 javax.naming.directory.DirContext jndiCtx = new javax.naming.directory.InitialDirContext(jndiProperties);
74
75 if (query.startsWith("ou=People,")) {
76 String voRoot = query.substring(query.indexOf(',')+1);
77 DirContext rootCtx = (DirContext) jndiCtx.lookup(voRoot);
78 return retrieveVOMembers(rootCtx);
79 } else if (query.startsWith("ou=")) {
80 Attributes atts = jndiCtx.getAttributes(query);
81 Attribute members = atts.get("member");
82 if (members == null) {
83 throw new RuntimeException("Couldn't retrieve the list of members from the LDAP group: missing attribute member");
84 }
85 String voRoot = query.substring(query.indexOf(',')+1);
86 DirContext rootCtx = (DirContext) jndiCtx.lookup(voRoot);
87 return retrieveGroupMembers(rootCtx, members);
88 } else if (query.startsWith("o=")) {
89 DirContext rootCtx = (DirContext) jndiCtx.lookup(query);
90 return retrieveVOMembers(rootCtx);
91 } else {
92 throw new IllegalArgumentException("The query is not understood by the LDAP group. It is expected to start with \"ou=...\" or \"o=...\"");
93 }
94
95 } catch (javax.naming.NamingException e) {
96 String message = "Couldn't retrieve users from LDAP server: " + e;
97
98
99
100 log.error("Couldn't retrieve LDAP users: ", e);
101 throw new RuntimeException(message, e);
102 }
103 }
104
105 private List retrieveVOMembers(DirContext rootCtx) throws NamingException {
106 Map people = retrievePeopleMap(rootCtx);
107 List list = new ArrayList(people.values());
108 if (list.isEmpty()) {
109 resourceAdminLog.warn("The following group returned no members: " + this);
110 }
111 Iterator iter = list.iterator();
112 List users = new ArrayList();
113 while (iter.hasNext()) {
114 String dn = (String) iter.next();
115 users.add(new GridUser(dn, null));
116 }
117 if (list.isEmpty()) {
118 resourceAdminLog.warn("The following group returned no members: " + this);
119 }
120 return users;
121 }
122
123 private List retrieveGroupMembers(DirContext rootCtx, Attribute members) throws javax.naming.NamingException {
124 Map people = retrievePeopleMap(rootCtx);
125 NamingEnumeration names = members.getAll();
126 List list = new ArrayList();
127 while (names.hasMore()) {
128
129 String ldapName = (String) names.next();
130 ldapName = ldapName.trim();
131 String certDN = (String) people.get(ldapName);
132 if (certDN == null) {
133 resourceAdminLog.warn("Member of a LDAP VO group not mapped to any certificate: '" + ldapName + "'");
134 } else {
135 list.add(new GridUser(certDN, null));
136 }
137 }
138 if (list.isEmpty()) {
139 resourceAdminLog.warn("The following group returned no members: " + this);
140 }
141 return list;
142 }
143
144 Map retrievePeopleMap(DirContext ldap) throws javax.naming.NamingException {
145 NamingEnumeration people = ldap.search("ou=People", "(description=subject=*)", null);
146 Map map = new Hashtable();
147 while (people.hasMore()) {
148 SearchResult person = (SearchResult) people.next();
149 Attributes personAtts = person.getAttributes();
150 String ldapDN = person.getName();
151 if (person.isRelative()) {
152 ldapDN = ldapDN + ",ou=People," + ldap.getNameInNamespace();
153 }
154
155 String certDN = (String) personAtts.get("description").get();
156 if (certDN.startsWith("subject=")) {
157 certDN = certDN.substring(8);
158 }
159 certDN = certDN.trim();
160 map.put(ldapDN, certDN);
161 }
162 return map;
163 }
164
165 /***
166 * Returns the name of the LDAP server used to retrieve the list of users.
167 * @return The name of the server server. i.e. "grid-vo.nikhef.nl"
168 */
169 public String getServer() {
170 return this.server;
171 }
172
173 /***
174 * Changes the LDAP server used to retrieve the list of users.
175 * @param server The name of the server server. i.e. "grid-vo.nikhef.nl"
176 */
177 public void setServer(String server) {
178 this.server = server;
179 }
180
181 /***
182 * The LDAP query used to retrieveGetter for property query.
183 * @return The LDAP query used. i.e. "ou=usatlas,o=atlas,dc=eu-datagrid,dc=org"
184 */
185 public String getQuery() {
186 return this.query;
187 }
188
189 /***
190 * Changes the LDAP query used to retrieveGetter for property query.
191 * @param query The LDAP query used. i.e. "ou=usatlas,o=atlas,dc=eu-datagrid,dc=org"
192 */
193 public void setQuery(String query) {
194 this.query = query;
195 }
196
197 public String getPersistenceFactory() {
198 return persistanceFactory.getName();
199 }
200
201 public void setPersistence(PersistenceFactory persistanceFactory, String name) {
202 this.persistanceFactory = persistanceFactory;
203 this.name = name;
204 db = persistanceFactory.retrieveUserGroupDB(name);
205 }
206
207 public int hashCode() {
208 return query.hashCode();
209 }
210
211 public String toString() {
212 return "LDAPGroup: ldap://"+server+"/"+query;
213 }
214
215 public boolean equals(Object obj) {
216 if (obj instanceof LDAPGroup) {
217 LDAPGroup group = (LDAPGroup) obj;
218 if ((server == null ? group.server == null : server.equals(group.server)) &&
219 (query == null ? group.query == null : query.equals(group.query)) &&
220 (name == null ? group.name == null : name.equals(group.name)) &&
221 (persistanceFactory == null ? group.persistanceFactory == null : persistanceFactory.getName().equals(group.persistanceFactory.getName()))) {
222 return true;
223 }
224 }
225 return false;
226 }
227
228 }