KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > unixauth > UNIXUserDatabase


1 package com.sslexplorer.unixauth;
2
3 import java.io.BufferedReader JavaDoc;
4 import java.io.File JavaDoc;
5 import java.io.FileInputStream JavaDoc;
6 import java.io.IOException JavaDoc;
7 import java.io.InputStream JavaDoc;
8 import java.io.InputStreamReader JavaDoc;
9 import java.io.OutputStream JavaDoc;
10 import java.io.PrintWriter JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collections JavaDoc;
13 import java.util.Date JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Properties JavaDoc;
18 import java.util.regex.Matcher JavaDoc;
19 import java.util.regex.Pattern JavaDoc;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 import com.sslexplorer.boot.ContextHolder;
25 import com.sslexplorer.boot.PropertyList;
26 import com.sslexplorer.boot.Util;
27 import com.sslexplorer.core.CoreServlet;
28 import com.sslexplorer.core.CoreUtil;
29 import com.sslexplorer.properties.Property;
30 import com.sslexplorer.properties.impl.realms.RealmKey;
31 import com.sslexplorer.realms.Realm;
32 import com.sslexplorer.security.AccountLockedException;
33 import com.sslexplorer.security.DefaultUserDatabase;
34 import com.sslexplorer.security.InvalidLoginCredentialsException;
35 import com.sslexplorer.security.Role;
36 import com.sslexplorer.security.User;
37 import com.sslexplorer.security.UserDatabaseException;
38 import com.sslexplorer.security.UserNotFoundException;
39
40 public class UNIXUserDatabase extends DefaultUserDatabase {
41
42     final static Log log = LogFactory.getLog(UNIXUserDatabase.class);
43
44     final static File JavaDoc GROUP_FILE = new File JavaDoc("/etc/group");
45     final static File JavaDoc PASSWD_FILE = new File JavaDoc("/etc/passwd");
46     final static File JavaDoc SHADOW_FILE = new File JavaDoc("/etc/shadow");
47     final static File JavaDoc USER_EMAIL_MAP_FILE = new File JavaDoc(ContextHolder.getContext().getConfDirectory(), "userEmailMap.properties");
48
49     private UNIXRole[] roles;
50     private UNIXUser[] users;
51     private HashMap JavaDoc shadowPasswords;
52     private Date JavaDoc lastGroupFileChange, lastPasswdFileChange, lastShadowFileChange;
53     private PropertyList administrators;
54     private Properties JavaDoc userEmailMap = new Properties JavaDoc();
55     private long userEmailMapLastModified = -1;
56
57     /**
58      * Constant for the database type.
59      */

60     public static final String JavaDoc DATABASE_TYPE = "unixAuth";
61
62     public UNIXUserDatabase() {
63         super("Unix", false, false);
64     }
65
66     /*
67      * (non-Javadoc)
68      *
69      * @see com.sslexplorer.core.Database#open(com.sslexplorer.core.CoreServlet)
70      */

71     public void open(CoreServlet controllingServlet, Realm realm) throws Exception JavaDoc {
72         administrators = Property.getPropertyList(new RealmKey("security.administrators", realm.getResourceId()));
73         String JavaDoc osName = System.getProperty("os.name", "").toLowerCase();
74         if (!osName.startsWith("linux") && !osName.startsWith("solaris")) {
75             log.warn("The UNIXAuth plugin will only be likely to work on Linux based systems, Solaris or other operating systems "
76                             + "that use /etc/passwd, /etc/group and /etc/shadow. OpenBSD and FreeBSD will definately *not* work.");
77         }
78         open = true;
79         if (System.getProperty("sslexplorer.unix.passwordChange", "false").equals("true")) {
80             if (new File JavaDoc("/usr/sbin/chpasswd").exists()) {
81                 if (log.isInfoEnabled())
82                     log.info("Found chpasswd, enabling experimental password change support.");
83                 supportsPasswordChange = true;
84             }
85         }
86         this.realm = realm;
87     }
88
89     /* (non-Javadoc)
90      * @see com.sslexplorer.security.UserDatabase#logon(java.lang.String, java.lang.String)
91      */

92     public User logon(String JavaDoc username, String JavaDoc password) throws UserDatabaseException, InvalidLoginCredentialsException,
93                     AccountLockedException {
94         if (!checkPassword(username, password)) {
95             throw new InvalidLoginCredentialsException();
96         }
97         try {
98             return getAccount(username);
99         } catch (Exception JavaDoc e) {
100             throw new UserDatabaseException("Failed to get user account.", e);
101         }
102     }
103
104     /* (non-Javadoc)
105      * @see com.sslexplorer.security.UserDatabase#checkPassword(java.lang.String, java.lang.String, int)
106      */

107     public boolean checkPassword(String JavaDoc username, String JavaDoc password) throws UserDatabaseException, InvalidLoginCredentialsException {
108         // Get the user account
109
UNIXUser user = null;
110         try {
111             user = (UNIXUser) getAccount(username);
112         } catch (Exception JavaDoc e) {
113             throw new UserDatabaseException("Could not get user account", e);
114         }
115
116         // Make sure the user exists
117
if (user == null) {
118             throw new InvalidLoginCredentialsException();
119         }
120
121         // Determine the password type
122
String JavaDoc pw = new String JavaDoc(user.getPassword());
123         try {
124             if (pw.startsWith("$1$")) {
125                 // MD5
126
return pw.substring(12).equals(MD5Crypt.crypt(password, pw.substring(3, 11)).substring(12));
127
128             } else {
129                 // DES
130
return DESCrypt.crypt(pw.substring(0, 2), password).equals(pw.substring(2));
131             }
132         } catch (Exception JavaDoc e) {
133             throw new UserDatabaseException("Invalid password format.", e);
134         }
135     }
136
137     public void logout(User user) {
138     }
139
140     public User[] listAllUsers(String JavaDoc filter) throws Exception JavaDoc {
141         checkPasswdFile();
142         if (!filter.equals("*")) {
143             List JavaDoc l = new ArrayList JavaDoc();
144             String JavaDoc wildCard = "^" + CoreUtil.replaceAllTokens(filter, "*", ".*") + "$";
145             Pattern JavaDoc p = Pattern.compile(wildCard, Pattern.CASE_INSENSITIVE);
146             for (int i = 0; i < users.length; i++) {
147                 Matcher JavaDoc matcher = p.matcher(users[i].getPrincipalName());
148                 if (matcher.matches()) {
149                     l.add(users[i]);
150                 }
151             }
152             User[] u = new User[l.size()];
153             l.toArray(u);
154             return u;
155         } else {
156             return users;
157         }
158     }
159
160     public com.sslexplorer.policyframework.Principal[] listAvailablePrincipals() throws Exception JavaDoc {
161         return listAllUsers("*");
162     }
163
164     public com.sslexplorer.policyframework.Principal getPrincipal(String JavaDoc principalName) throws Exception JavaDoc {
165         return getAccount(principalName);
166     }
167
168     public User getAccount(String JavaDoc username) throws UserNotFoundException, Exception JavaDoc {
169         try {
170             checkPasswdFile();
171             for (int i = 0; i < users.length; i++) {
172                 if (users[i].getPrincipalName().equals(username)) {
173                     return users[i];
174                 }
175             }
176             throw new UserNotFoundException("Could not find user " + username);
177         } catch (Exception JavaDoc e) {
178             e.printStackTrace();
179             throw e;
180         }
181     }
182
183     public boolean isDefaultAdministrator(com.sslexplorer.policyframework.Principal principal) throws Exception JavaDoc {
184         boolean found = false;
185         if (principal.getPrincipalName().equals("root")) {
186             found = true;
187         } else {
188             for (Iterator JavaDoc j = administrators.iterator(); !found && j.hasNext();) {
189                 found = principal.getPrincipalName().matches((String JavaDoc) j.next());
190             }
191         }
192         return found;
193     }
194
195     public Role getRole(String JavaDoc rolename) throws Exception JavaDoc {
196         checkGroupFile();
197         for (int i = 0; i < roles.length; i++) {
198             if (roles[i].getPrincipalName().equals(rolename)) {
199                 return roles[i];
200             }
201         }
202         return null;
203     }
204
205     public Role[] listAllRoles(String JavaDoc filter) throws Exception JavaDoc {
206         checkGroupFile();
207         if (!filter.equals("*")) {
208             List JavaDoc l = new ArrayList JavaDoc();
209             String JavaDoc wildCard = "^" + CoreUtil.replaceAllTokens(filter, "*", ".*") + "$";
210             Pattern JavaDoc p = Pattern.compile(wildCard, Pattern.CASE_INSENSITIVE);
211             for (int i = 0; i < roles.length; i++) {
212                 Matcher JavaDoc matcher = p.matcher(roles[i].getPrincipalName());
213                 if (matcher.matches()) {
214                     l.add(roles[i]);
215                 }
216             }
217             return (Role[]) l.toArray(new Role[l.size()]);
218         } else {
219             return roles;
220         }
221     }
222
223     private void checkGroupFile() throws Exception JavaDoc {
224         Date JavaDoc current = null;
225         if (GROUP_FILE.exists()) {
226             current = new Date JavaDoc(GROUP_FILE.lastModified());
227             if (lastGroupFileChange == null || !lastGroupFileChange.equals(current)) {
228                 lastGroupFileChange = current;
229                 String JavaDoc line = null;
230                 FileInputStream JavaDoc fin = new FileInputStream JavaDoc(GROUP_FILE);
231                 List JavaDoc rolesList = new ArrayList JavaDoc();
232                 try {
233                     BufferedReader JavaDoc r = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(fin));
234                     while ((line = r.readLine()) != null) {
235                         try {
236                             rolesList.add(new UNIXRole(getRealm(), line));
237                         }
238                         catch(IllegalArgumentException JavaDoc iae) {
239                         }
240                     }
241                 } finally {
242                     Util.closeStream(fin);
243                 }
244                 Collections.sort(rolesList);
245                 roles = new UNIXRole[rolesList.size()];
246                 rolesList.toArray(roles);
247             }
248         } else {
249             throw new IOException JavaDoc("Could not locate " + GROUP_FILE.getAbsolutePath());
250         }
251     }
252
253     private void checkPasswdFile() throws Exception JavaDoc {
254         Date JavaDoc current = null;
255         if (PASSWD_FILE.exists()) {
256             if (checkShadowFile()) {
257                 lastPasswdFileChange = null;
258             }
259             if (checkUserEmailMapFile()) {
260                 lastPasswdFileChange = null;
261             }
262             current = new Date JavaDoc(PASSWD_FILE.lastModified());
263             if (lastPasswdFileChange == null || !lastPasswdFileChange.equals(current)) {
264                 lastPasswdFileChange = current;
265                 String JavaDoc line = null;
266                 FileInputStream JavaDoc fin = new FileInputStream JavaDoc(PASSWD_FILE);
267                 List JavaDoc userList = new ArrayList JavaDoc();
268                 try {
269                     BufferedReader JavaDoc r = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(fin));
270                     while ((line = r.readLine()) != null) {
271                         String JavaDoc[] elements = line.split(":");
272                         String JavaDoc username = elements[0];
273                         if(elements.length > 5) {
274                             String JavaDoc password = elements[1];
275                             int uid = Integer.parseInt(elements[2]);
276                             int gid = Integer.parseInt(elements[3]);
277                             String JavaDoc fullname = elements[4];
278                             String JavaDoc home = elements[5];
279                             String JavaDoc shell = "";
280                             if (elements.length > 6) {
281                                 shell = elements[6];
282                             }
283                             List JavaDoc userRolesList = new ArrayList JavaDoc();
284                             Role primaryRole = getRoleByGID(gid);
285                             if (primaryRole == null) {
286                                 log.warn("No primary group for user " + username);
287                             } else {
288                                 userRolesList.add(primaryRole);
289                             }
290                             for (int i = 0; i < roles.length; i++) {
291                                 if (roles[i].containsMember(username)
292                                                 && !(primaryRole != null && roles[i].getPrincipalName().equals(
293                                                     primaryRole.getPrincipalName()))) {
294                                     userRolesList.add(roles[i]);
295                                 }
296                             }
297                             Role[] userRoles = new Role[userRolesList.size()];
298                             userRolesList.toArray(userRoles);
299                             char[] pw = null;
300                             if (password.equals("x")) {
301                                 pw = (char[]) shadowPasswords.get(username);
302                             } else {
303                                 pw = password.toCharArray();
304                             }
305                             UNIXUser user = new UNIXUser(username,userEmailMap == null ? "" : userEmailMap.getProperty(username, ""), pw, uid, gid, fullname, home, shell, userRoles, this.getRealm());
306                             userList.add(user);
307                         }
308                     }
309                 } finally {
310                     Util.closeStream(fin);
311                 }
312                 Collections.sort(userList);
313                 users = new UNIXUser[userList.size()];
314                 userList.toArray(users);
315             }
316         } else {
317             throw new IOException JavaDoc("Could not locate " + PASSWD_FILE.getAbsolutePath());
318         }
319     }
320
321     private synchronized boolean checkShadowFile() throws Exception JavaDoc {
322         Date JavaDoc current = null;
323         if (SHADOW_FILE.exists()) {
324             current = new Date JavaDoc(SHADOW_FILE.lastModified());
325             if (lastShadowFileChange == null || !lastShadowFileChange.equals(current)) {
326                 lastShadowFileChange = current;
327                 String JavaDoc line = null;
328                 FileInputStream JavaDoc fin = new FileInputStream JavaDoc(SHADOW_FILE);
329                 shadowPasswords = new HashMap JavaDoc();
330                 try {
331                     BufferedReader JavaDoc r = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(fin));
332                     while ((line = r.readLine()) != null) {
333                         String JavaDoc[] elements = line.split(":");
334                         String JavaDoc username = elements[0];
335                         if (elements.length > 1 && !username.equals("+")) {
336                             char[] password = elements[1].toCharArray();
337                             shadowPasswords.put(username, password);
338                         }
339                     }
340                 } finally {
341                     Util.closeStream(fin);
342                 }
343                 return true;
344             }
345         } else {
346             throw new IOException JavaDoc("Could not locate " + PASSWD_FILE.getAbsolutePath());
347         }
348         return false;
349     }
350
351     private synchronized boolean checkUserEmailMapFile() throws Exception JavaDoc {
352         if (!USER_EMAIL_MAP_FILE.exists()) {
353             if (userEmailMap != null) {
354                 userEmailMap = null;
355                 userEmailMapLastModified = -1;
356                 return true;
357             }
358         } else if (userEmailMap == null) {
359             userEmailMap = new Properties JavaDoc();
360         }
361         if (userEmailMap != null
362                         && (userEmailMapLastModified == -1 || userEmailMapLastModified != USER_EMAIL_MAP_FILE.lastModified())) {
363             FileInputStream JavaDoc fin = null;
364             try {
365                 fin = new FileInputStream JavaDoc(USER_EMAIL_MAP_FILE);
366                 userEmailMap.load(fin);
367             } catch (IOException JavaDoc ioe) {
368                 log.error("Failed to load user email map.");
369             } finally {
370                 Util.closeStream(fin);
371             }
372             userEmailMapLastModified = USER_EMAIL_MAP_FILE.lastModified();
373             return true;
374         }
375         return false;
376     }
377
378     /**
379      * @param gid
380      * @return
381      */

382     private Role getRoleByGID(int gid) throws Exception JavaDoc {
383         checkGroupFile();
384         for (int i = 0; i < roles.length; i++) {
385             if (roles[i].getGid() == gid) {
386                 return roles[i];
387             }
388         }
389         return null;
390     }
391
392     public void cleanup() throws Exception JavaDoc {
393     }
394
395     public int getInstallationPropertyCategory() {
396         return -1;
397     }
398
399     public boolean isOpen() {
400         return open;
401     }
402
403     public User[] getUsersInRole(Role role) throws Exception JavaDoc {
404         return CoreUtil.getUsersInRole(role, this);
405     }
406
407     public void changePassword(String JavaDoc username, String JavaDoc oldPassword, String JavaDoc password, boolean forcePasswordChangeAtLogon) throws UserDatabaseException,
408                     InvalidLoginCredentialsException {
409         if (!supportsPasswordChange()) {
410             throw new InvalidLoginCredentialsException("Database doesn't support password change.");
411         }
412         if (forcePasswordChangeAtLogon) {
413             log.warn("Password change function of UNIX user database does not support forcePassswordChangeAtLogon.");
414         }
415         Process JavaDoc p = null;
416         try {
417             p = Runtime.getRuntime().exec(
418                 "true".equals(System.getProperty("sslexplorer.useDevConfig", "false")) ? "sudo /usr/sbin/chpasswd"
419                                 : "/usr/sbin/chpasswd");
420             new StreamReaderThread(p.getInputStream());
421             new StreamReaderThread(p.getErrorStream());
422             OutputStream JavaDoc out = p.getOutputStream();
423             PrintWriter JavaDoc pw = new PrintWriter JavaDoc(out);
424             pw.println(username + ":" + password);
425             pw.flush();
426             out.close();
427             try {
428                 p.waitFor();
429             } catch (InterruptedException JavaDoc ie) {
430
431             }
432             int ret = p.exitValue();
433             if (ret != 0) {
434                 throw new UserDatabaseException("Failed to change password. chpasswd returned exit code " + ret + ".");
435             }
436
437         } catch (IOException JavaDoc e) {
438             throw new UserDatabaseException("Failed to change password.", e);
439         } finally {
440             if (p != null) {
441                 Util.closeStream(p.getOutputStream());
442                 Util.closeStream(p.getInputStream());
443                 Util.closeStream(p.getErrorStream());
444             }
445         }
446     }
447
448     class StreamReaderThread extends Thread JavaDoc {
449         InputStream JavaDoc in;
450
451         StreamReaderThread(InputStream JavaDoc in) {
452             this.in = in;
453         }
454
455         public void run() {
456             try {
457                 BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(in));
458                 String JavaDoc line = null;
459                 while ((line = reader.readLine()) != null) {
460                     if (log.isInfoEnabled())
461                         log.info("Output from chpasswd: '" + line + "'");
462                 }
463             } catch (IOException JavaDoc ioe) {
464             }
465         }
466     }
467
468 }
Popular Tags