Source code: gov/lanl/Web/UserMgr.java
1 // Login.java
2 /*************************************
3 * Copyright Notice
4 * Copyright (c) 2000, Regents of the University of California. All rights reserved.
5 *
6 * DISCLAIMER
7 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
8 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
10 * SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
13 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
14 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
15 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 ***************************************/
18 package gov.lanl.Web;
19
20 import gov.lanl.Utility.ConfigProperties;
21 import jdbm.JDBMEnumeration;
22 import jdbm.JDBMHashtable;
23 import jdbm.JDBMRecordManager;
24
25 import java.io.*;
26 import java.util.*;
27
28 /**
29 * This class manages a persistent storage of Users. It can add users from a file in
30 * LDAP's LDIF format. The values required are dn (Distinguished Name), cn (Common Name), userPassword, email,
31 * and role
32 * This is intended as an interface for LDAP, but provides a simple persistent Hashtables using JDBM.
33 *
34 * The id Hashtable (name "userids") contains the User objects with the email address as the key
35 * The country (name "countries") Hashtable contains a HashSet of all the organizations in a given country
36 * To get a list of all supported countries simply get the keys of the countries Hashtable
37 * There also is a persistent Hashtable for each organization with is LDAP "o" value as its name
38 * It returns a Hashtable of users within that organization, with key the "cn" (Username) and value "email"
39 * Thus a user can be looked up by username and organization and return the "key" email address from which
40 * the full User object can be obtained from the id Hashtable
41 *
42 * When a new organization is encountered (with a user with "o" and "c" dn parameters, it is registered
43 * into the list of organizations for that country in the country Hashtable
44 *
45 * JDBM (http://jdbm.sourceforge.net) persistent hashtable implemenation is used for persistence
46 *
47 * @author $Author: dwforslund $
48 * @version $Id: UserMgr.java,v 1.7 2002/06/10 03:02:54 dwforslund Exp $
49 */
50
51 public class UserMgr {
52
53
54 //private JDBMHashtable dn;
55 private JDBMHashtable id = null;
56 private JDBMHashtable users;
57 private JDBMHashtable country;
58 private String username = "";
59 // private String password = "";
60 // private String email = "";
61 private static String userfile = "login.users";
62 private String userdb = "users";
63 private static String configFile = "test";
64 private JDBMRecordManager recman;
65 private static ConfigProperties props = new ConfigProperties();
66 private Vector profile_vec = null;
67 // private Hashtable users = null;
68 private User user;
69 private static org.apache.log4j.Logger cat = org.apache.log4j.Logger.getLogger(UserMgr.class.getName());
70
71 /**
72 * Public default constructor
73 */
74 public UserMgr() {
75 // Defer initialization for servlets
76 // init();
77 }
78
79 /**
80 * Constructor which specifies the configProperties to be read
81 */
82 public UserMgr(String configProperties) {
83 setConfigFile(configProperties);
84 init();
85 }
86
87 /**
88 * Initialize Persistent storage
89 * There are two primary hashtables. The first (country) contains a list of the organizations which are keys
90 * to user hashtables for each organization. The organization hashtable is a map from the username
91 * key to the userId (email address). The second (id) is the hashtable based on the email address
92 * which is used as a userId since the email address is supposed to be unique. For each organization
93 * there is a separate hashtable of the users for that organization. Thus one can look a user up
94 * across organizations or within an organization. All the user objects are contained in the second (id) hashtable.
95 *
96 */
97 public void init() {
98 ResourceBundle bundle = ResourceBundle.getBundle(configFile);
99 props.setProperties(bundle);
100 cat.debug("read: " + configFile);
101 userdb = props.getProperty("users", userdb);
102 try {
103 recman = new JDBMRecordManager(userdb);
104 //dn = recman.getHashtable("usernames");
105 id = recman.getHashtable("userids");
106 country = recman.getHashtable("countries");
107 } catch (IOException e) {
108 cat.error("init: " + e);
109 }
110 }
111
112 /**
113 * add Users from previously defined userfile
114 */
115 public void addUsers() {
116 addUsers(userfile);
117 }
118
119 /**
120 * Add users from an input file
121 * @param userfile
122 */
123 public void addUsers(String userfile) {
124
125
126 // Query using JNDI to get list of users, not implemented correctly yet.
127
128
129 // Read from file to get users (in ldif format)
130 // e.g.:
131 // dn: cn= David Forslund, o=LANL, c=US
132 // cn: David Forslund
133 // email: dwf@lanl.gov
134 // userPassword: test
135 // Results are put into a User object and the User into a hashtable with email/userId
136 // as the key
137 // various arrays are created for listing the users as needed.
138
139
140 // userfile = props.getProperty("login.users", userfile);
141 // String country = props.getProperty("country","US");
142
143 try {
144
145 // orgs = recman.getHashtable(country);
146 // Read in user list if not already done ###
147
148 String line = null;
149 InputStream is = getClass().getResourceAsStream(userfile);
150 //if (theFile.exists()) {
151 if (is != null) {
152 cat.debug("Reading " + userfile);
153
154 // FileReader inFile = new FileReader(theFile);
155 InputStreamReader inFile = new InputStreamReader(is);
156 BufferedReader inReader = new BufferedReader(inFile);
157 profile_vec = new Vector();
158 user = null;
159 HashSet set = null; // unique set of organizations in a country
160 while (((line = inReader.readLine()) != null)) {
161 parseLine(line);
162 }
163 //HashSet set = (HashSet) orgs.get(country);
164
165 //if (set == null) set = new HashSet();
166 inReader.close();
167 if ((profile_vec != null)) {
168 addProfile();
169 for (int i = 0; i < profile_vec.size(); i++) {
170 User u = (User) profile_vec.elementAt(i);
171 String c = u.getCountry();
172 // cat.debug("addUsers: "+u.toString());
173 String org = u.getOrg();
174 if (c != null) set = (HashSet) country.get(c);
175 if (set == null) set = new HashSet();
176 // get the hashtable for that organization
177 // Update list of organizations for a country
178 set.add(org);
179
180 // cat.debug("organization = " + org);
181 JDBMHashtable users = recman.getHashtable(org);
182 // insert userID in users table with userName as key
183 users.put(u.getUserName(), u.getUserId()); // put userId in dn with dn as key
184
185 id.put(u.getUserId(), u); // put user in id with mail as key
186
187 country.put(c, set);
188 }
189 // put the list of names into the organization hashtable
190 // cat.debug(set.size() + " organizations");
191
192 }
193
194 }
195
196 } catch (IOException e) {
197 cat.error("UserMgr reading error adding users " + e, e);
198
199 }
200
201
202 //}
203 }
204
205 /**
206 * parse the line and add the user to the list
207 * @param line to be parsed
208 */
209 public void parseLine(String line) {
210
211 try {
212 //user = null;
213 if (line.startsWith("#") || line.startsWith("//")) return;
214 StringTokenizer tmp_st = new StringTokenizer(line, ":");
215 if (tmp_st.countTokens() == 0) return;
216 String tmp_tok = tmp_st.nextToken();
217 // System.out.println("parseLine: "+tmp_tok);
218 if (tmp_tok.equals("dn")) {
219 // We have a new defined person so save old data and reset
220 if (user == null) {
221 user = new User();
222 } else { // user is complete so store it
223 addProfile();
224
225 }
226 user.setDN(tmp_st.nextToken().trim());
227 // user.setDN(tmp_st.nextToken().trim());
228 } else if (tmp_tok.equals("cn")) {
229
230 user.setUserName(tmp_st.nextToken().trim());
231 } else if (tmp_tok.equals("email")) {
232
233 user.setUserId(tmp_st.nextToken().trim());
234 } else if (tmp_tok.equals("userPassword")) {
235
236 user.setPassword(tmp_st.nextToken().trim());
237 } else if (tmp_tok.equals("role")) {
238
239 user.setRole(tmp_st.nextToken().trim());
240 } else if (tmp_tok.equals("sn")) {
241 user.setSurName(tmp_st.nextToken().trim());
242 }
243 } catch (Exception e) {
244 cat.error("parseLine failed:" + e);
245 }
246
247 }
248
249 /**
250 * Add the user profile
251 */
252 private void addProfile() {
253 profile_vec.addElement(user);
254 // cat.debug("name: "+user.getUserName()+", email: "+user.getUserId()+", passwd: "+user.getPassword());
255 user = new User();
256 }
257
258 /**
259 * addUser
260 * @param u String with multiple lines with all the data for a user
261 */
262 public void addUser(String u) {
263 BufferedReader reader = new BufferedReader(new StringReader(u));
264 String line = null;
265 User saveUser = user;
266 try {
267 while ((line = reader.readLine()) != null)
268 parseLine(line);
269 if (user != null) addUser(user);
270 } catch (IOException e) {
271 cat.error("addUser: " + e);
272 }
273 user = saveUser;
274
275 }
276
277 /**
278 * add User to the Persistent Hashtable
279 * @param theDN The distinguished name (cn= "name", o="organization", c="country")
280 * @param cn LDAP username
281 * @param sn LDAP surname
282 * @param email LDAP email address (userId)
283 * @param role
284 * @param password
285 */
286 public void addUser(String theDN, String cn, String sn, String email, String role, String password) {
287 User newUser = new User(email, cn);
288 newUser.setRole(role);
289 newUser.setPassword(password);
290 newUser.setSurName(sn);
291 newUser.setDN(theDN);
292 addUser(newUser);
293 }
294
295 /**
296 * Add a User already constructed
297 * @param newUser
298 */
299
300 public void addUser(User newUser) {
301
302 String c = newUser.getCountry();
303 String org = newUser.getOrg();
304 String userName = newUser.getUserName();
305 String email = newUser.getUserId();
306 cat.debug("addUser: " + newUser.toString());
307 User oldUser = getUser(newUser);
308 if (oldUser == null) oldUser = new User();
309
310 oldUser.update(newUser);
311 try {
312 // First make sure the organization is in the country list
313 HashSet set = (HashSet) country.get(c);
314 if (set == null) set = new HashSet();
315 set.add(org);
316 country.put(c, set);
317 // get the users Hashtable based on the organization
318 users = recman.getHashtable(org);
319
320 users.put(userName, email);
321 id.put(email, oldUser);
322 cat.debug("User: " + oldUser.toString() + " added!");
323 } catch (IOException e) {
324 cat.error("addUser: " + e);
325 }
326 }
327
328
329 /**
330 * delete User based on the unique UserId
331 * @param userId corresponding to email address
332 */
333 public void delUser(String userId) {
334 try {
335 cat.debug("delUser trying to remove: " + userId);
336 User delUser = (User) id.get(userId);
337 if (delUser != null) {
338 id.remove(userId);
339 cat.debug("delUser removed from id: " + userId);
340 String uName = delUser.getUserName();
341 users = recman.getHashtable(delUser.getOrg());
342 cat.debug("removing " + uName + " from dn");
343 String u = (String) users.get(uName);
344 if (u != null) {
345 users.remove(uName);
346 cat.debug("delUser removed from dn: " + uName);
347 }
348 } else
349 cat.debug("delUser: id='" + userId + "' not found");
350 } catch (IOException e) {
351 cat.error("delUser: " + userId + " " + e);
352 }
353
354
355 }
356
357 /**
358 * get the User based on name and organization
359 * @param userName
360 * @param org
361 * @return User
362 */
363 public User getUser(String userName, String org) {
364 User user = null;
365 try {
366 users = recman.getHashtable(org);
367 String userId = (String) users.get(username);
368 if (userId != null) user = (User) id.get(userId);
369 if (user == null) cat.warn("getUser(" + userName + "," + org + "): not found");
370 } catch (IOException e) {
371 cat.error("getUser: " + e);
372 }
373 return user;
374 }
375
376 /**
377 * get User by the unique userId (email)
378 * @param userId
379 * @return User
380 */
381 public User getUser(String userId) {
382 User user = null;
383 try {
384 user = (User) id.get(userId);
385 } catch (IOException e) {
386 cat.error("setUserId: " + e);
387 }
388 return user;
389 }
390
391 /**
392 * get User with username, org and email
393 * @param username cn variable
394 * @param org o variable
395 * @param email email variable
396 * @return User
397 */
398 public User getUser(String username, String org, String email) {
399 User user = null;
400 try {
401 // try unique email first (this should always return the user)
402 if (email != null && !email.equals(""))
403 user = (User) id.get(email);
404 if ((user == null) && (org != null) && (username != null)) {
405 // get the user list for the organization
406 users = recman.getHashtable(org);
407 if (users != null) {
408 String userid = (String) users.get(username);
409 if (userid != null) user = (User) id.get(userid);
410 }
411 }
412 if (user == null) cat.warn("getUser(" + username + "," + org + "," + email + "): user not found, ");
413 } catch (IOException e) {
414 cat.error("getUser: " + e);
415 }
416 return user;
417 }
418
419 /**
420 * Find a User given a partially completed User object as a template
421 * @param findUser
422 * @return User
423 */
424 public User getUser(User findUser) {
425 User user = new User();
426 String email = findUser.getUserId();
427 try {
428 if (email != null && !email.equals(""))
429 user = (User) id.get(email);
430 if ((user == null) && (findUser.getOrg() != null) && findUser.getUserName() != null) {
431 users = recman.getHashtable(findUser.getOrg());
432 if (users != null) {
433 String userid = (String) users.get(username);
434 if (userid != null) user = (User) id.get(userid);
435 }
436 }
437 if (user == null) {
438 cat.warn("getUser(" + findUser.toString() + "): user not found");
439
440 }
441 } catch (IOException e) {
442 cat.error("getUser: " + e);
443 }
444 return user;
445
446 }
447
448 /**
449 * Get all the userNames for a given organization
450 * @param org the organization name (o field in LDAP);
451 * @return String[] list of names within the organization
452 */
453 public String[] getNamesbyOrg(String org) {
454 Vector v = new Vector();
455 try {
456 JDBMHashtable users = recman.getHashtable(org);
457 JDBMEnumeration e = users.keys();
458 while (e.hasMoreElements()) {
459 v.addElement(e.nextElement());
460 }
461 } catch (IOException e1) {
462 cat.error("getNamesbyOrg: " + e1);
463 }
464 String[] s = new String[v.size()];
465 v.copyInto(s);
466 return s;
467 }
468
469 /**
470 * get the email addresses of all users in an organization
471 * @param org name of the organization (o LDAP field)
472 * @return String[] array of email addresses
473 */
474 public String[] getMailbyOrg(String org) {
475 Vector v = new Vector();
476 try {
477 JDBMHashtable users = recman.getHashtable(org);
478 JDBMEnumeration e = users.values();
479 while (e.hasMoreElements()) {
480 v.addElement(e.nextElement());
481 }
482 } catch (IOException e1) {
483 cat.error("getMailbyOrg: " + e1);
484 }
485 String[] s = new String[v.size()];
486 v.copyInto(s);
487 return s;
488 }
489
490 /**
491 * get list of all UserIds in DB
492 * @return String[] list of UserIds
493 */
494 public String[] getUserIds() {
495 String[] mail;
496 if (id == null) init();
497 ArrayList v = null;
498 try {
499 JDBMEnumeration e = id.keys();
500 v = new ArrayList();
501 while (e.hasMoreElements()) {
502 v.add(e.nextElement());
503 }
504 } catch (IOException e1) {
505 cat.error("getUserIds: " + e1);
506 return new String[0];
507 }
508 mail = new String[v.size()];
509 v.toArray(mail);
510 // cat.debug("getUserIds: "+mail.length +" mail: "+mail[0]);
511 return mail;
512 }
513
514 /** obtain list of valid users
515 * @return String[] list of known users
516 */
517 public String[] getUserNames() {
518 String[] names;
519 if (id == null) init();
520 ArrayList v = null;
521 try {
522 JDBMEnumeration e = id.values();
523 v = new ArrayList();
524 while (e.hasMoreElements()) {
525 v.add(((User) e.nextElement()).getUserName());
526 }
527 } catch (IOException e1) {
528 cat.error("getUserNames: " + e1);
529 return new String[0];
530 }
531 // for (int i = 0;i< v.size(); i++)
532 // cat.debug("name: "+v.get(i));
533 names = new String[v.size()];
534 cat.debug("getUserNames: found " + names.length + " elements");
535 v.toArray(names);
536
537
538 return names;
539 }
540
541 /**
542 * Bean setter and getter methods
543 * @param theConfigFile the properties file
544 */
545
546 public static void setConfigFile(String theConfigFile) {
547 configFile = theConfigFile;
548 }
549
550
551 /**
552 * set the file of users to be read.
553 * @param file to be read
554 */
555 public static void setUserfile(String file) {
556 userfile = file;
557 }
558
559 /**
560 * get all the users in in the persistent hashtable
561 * @return String
562 */
563 public String export() {
564 try {
565 JDBMEnumeration c = id.values();
566 StringBuffer buff = new StringBuffer();
567 while (c.hasMoreElements()) {
568 buff.append(c.nextElement().toString() + '\n');
569 }
570 return buff.toString();
571 } catch (IOException e) {
572 cat.error("getUsers: " + e);
573 return null;
574 }
575 }
576
577 public static void main(String[] argv) {
578 if (argv.length < 1) {
579 System.out.println("usage: UserMgr 'file' where 'file' is a ResourceBundle (file.properties) '\n"
580 + "and has a property: 'login.users' which is a file containing the users \n"
581 + "and optionally the property 'users' which is the name of the database to be created or read");
582 System.exit(0);
583 }
584 UserMgr.setConfigFile(argv[0]);
585 UserMgr userMgr = new UserMgr();
586 userMgr.init();
587 String file = props.getProperty("login.users");
588 if (file != null && file != "") userMgr.addUsers(props.getProperty("login.users"));
589 System.out.println(userMgr.export());
590
591
592 }
593 }