View Javadoc

1   /* 
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.security.impl;
18  
19  import java.security.Principal;
20  import java.sql.Date;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.LinkedList;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.prefs.BackingStoreException;
29  import java.util.prefs.Preferences;
30  
31  import javax.security.auth.Subject;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.jetspeed.security.AuthenticationProviderProxy;
36  import org.apache.jetspeed.security.HierarchyResolver;
37  import org.apache.jetspeed.security.SecurityException;
38  import org.apache.jetspeed.security.SecurityProvider;
39  import org.apache.jetspeed.security.User;
40  import org.apache.jetspeed.security.UserManager;
41  import org.apache.jetspeed.security.UserPrincipal;
42  import org.apache.jetspeed.security.spi.SecurityMappingHandler;
43  import org.apache.jetspeed.util.ArgUtil;
44  
45  /***
46   * <p>
47   * Implementation for managing users and provides access to the {@link User}.
48   * </p>
49   * 
50   * @author <a href="mailto:dlestrat@apache.org">David Le Strat </a>
51   * @version $Id: UserManagerImpl.java 603894 2007-12-13 11:42:22Z woonsan $
52   */
53  public class UserManagerImpl implements UserManager
54  {
55  
56      private static final Log log = LogFactory.getLog(UserManagerImpl.class);
57  
58      /*** The authenticatino provider proxy. */
59      private AuthenticationProviderProxy atnProviderProxy = null;
60  
61      /*** The security mapping handler. */
62      private SecurityMappingHandler securityMappingHandler = null;
63  
64      private String anonymousUser = "guest";
65      private User guest = null;
66      
67      /*** 
68       * Flag whether the principals's user group matches the user group to which the role has been mapped. (See SRV.12.4) 
69       * If this flag is set to true, roles can be inherited to users via groups.
70       */
71      private boolean rolesInheritableViaGroups = true;
72      
73      /***
74       * @param securityProvider
75       *            The security provider.
76       */
77      public UserManagerImpl(SecurityProvider securityProvider)
78      {
79          this.atnProviderProxy = securityProvider
80                  .getAuthenticationProviderProxy();
81          this.securityMappingHandler = securityProvider
82                  .getSecurityMappingHandler();
83      }
84  
85      /***
86       * @param securityProvider
87       *            The security provider.
88       * @param anonymousUser
89       *            The anonymous user name
90       */
91      public UserManagerImpl(SecurityProvider securityProvider,
92              String anonymousUser)
93      {
94          this.atnProviderProxy = securityProvider
95                  .getAuthenticationProviderProxy();
96          this.securityMappingHandler = securityProvider
97                  .getSecurityMappingHandler();
98          if (anonymousUser != null)
99          {
100             this.anonymousUser = anonymousUser;
101         }
102     }
103 
104     /***
105      * @param securityProvider
106      *            The security provider.
107      * @param roleHierarchyResolver
108      *            The role hierachy resolver.
109      * @param groupHierarchyResolver
110      *            The group hierarchy resolver.
111      */
112     public UserManagerImpl(SecurityProvider securityProvider,
113             HierarchyResolver roleHierarchyResolver,
114             HierarchyResolver groupHierarchyResolver)
115     {
116         securityProvider.getSecurityMappingHandler().setRoleHierarchyResolver(
117                 roleHierarchyResolver);
118         securityProvider.getSecurityMappingHandler().setGroupHierarchyResolver(
119                 groupHierarchyResolver);
120         this.atnProviderProxy = securityProvider
121                 .getAuthenticationProviderProxy();
122         this.securityMappingHandler = securityProvider
123                 .getSecurityMappingHandler();
124     }
125 
126     /***
127      * @param securityProvider
128      *            The security provider.
129      * @param roleHierarchyResolver
130      *            The role hierachy resolver.
131      * @param groupHierarchyResolver
132      *            The group hierarchy resolver.
133      * @param anonymousUser
134      *            The anonymous user name
135      */
136     public UserManagerImpl(SecurityProvider securityProvider,
137             HierarchyResolver roleHierarchyResolver,
138             HierarchyResolver groupHierarchyResolver, String anonymousUser)
139     {
140         securityProvider.getSecurityMappingHandler().setRoleHierarchyResolver(
141                 roleHierarchyResolver);
142         securityProvider.getSecurityMappingHandler().setGroupHierarchyResolver(
143                 groupHierarchyResolver);
144         this.atnProviderProxy = securityProvider
145                 .getAuthenticationProviderProxy();
146         this.securityMappingHandler = securityProvider
147                 .getSecurityMappingHandler();
148         if (anonymousUser != null)
149         {
150             this.anonymousUser = anonymousUser;
151         }
152     }
153 
154     /*
155      * (non-Javadoc)
156      * 
157      * @see org.apache.jetspeed.security.UserManager#getAnonymousUser()
158      */
159     public String getAnonymousUser()
160     {
161         return this.anonymousUser;
162     }
163     
164     public void setRolesInheritableViaGroups(boolean rolesInheritableViaGroups)
165     {
166         this.rolesInheritableViaGroups = rolesInheritableViaGroups;
167     }
168     
169     /***
170      * @see org.apache.jetspeed.security.UserManager#authenticate(java.lang.String,
171      *      java.lang.String)
172      */
173     public boolean authenticate(String username, String password)
174     {
175         ArgUtil.notNull(new Object[]
176         { username, password}, new String[]
177         { "username", "password"},
178                 "authenticate(java.lang.String, java.lang.String)");
179 
180         boolean authenticated = false;
181         try
182         {
183             if (!getAnonymousUser().equals(username))
184             {
185                 authenticated = atnProviderProxy.authenticate(username,
186                         password);
187                 if (authenticated && log.isDebugEnabled())
188                 {
189                     log.debug("Authenticated user: " + username);
190                 }
191             }
192         } catch (SecurityException e)
193         {
194             // ignore: not authenticated
195         }
196         return authenticated;
197     }
198 
199     /***
200      * @see org.apache.jetspeed.security.UserManager#addUser(java.lang.String,
201      *      java.lang.String)
202      */
203     public void addUser(String username, String password)
204             throws SecurityException
205     {
206         ArgUtil.notNull(new Object[]
207         { username}, new String[]
208         { "username"}, "addUser(java.lang.String, java.lang.String)");
209 
210         createUser(username, password, atnProviderProxy
211                 .getDefaultAuthenticationProvider(),false);
212     }
213 
214     
215 
216     /***
217      * @see org.apache.jetspeed.security.UserManager#addUser(java.lang.String,
218      *      java.lang.String, java.lang.String)
219      */
220     public void addUser(String username, String password, String atnProviderName)
221             throws SecurityException
222     {
223         ArgUtil.notNull(new Object[]
224         { username}, new String[]
225         { "username"}, "addUser(java.lang.String, java.lang.String)");
226 
227         createUser(username, password, atnProviderName, false);
228     }
229 
230     /***
231      * @see org.apache.jetspeed.security.UserManager#importUser(java.lang.String,
232      *      java.lang.String, boolean)
233      */
234     public void importUser(String username, String password, boolean passThrough)
235             throws SecurityException
236     {
237         ArgUtil.notNull(new Object[]
238         { username}, new String[]
239         { "username"}, "addUser(java.lang.String, java.lang.String)");
240 
241         createUser(username, password, atnProviderProxy
242                 .getDefaultAuthenticationProvider(),passThrough);
243     }
244 
245     /***
246      * @see org.apache.jetspeed.security.UserManager#importUser(java.lang.String,
247      *      java.lang.String, java.lang.String, boolean)
248      */
249     public void importUser(String username, String password, String atnProviderName, boolean passThrough)
250             throws SecurityException
251     {
252         ArgUtil.notNull(new Object[]
253         { username}, new String[]
254         { "username"}, "addUser(java.lang.String, java.lang.String)");
255 
256         createUser(username, password, atnProviderName,passThrough);
257     }
258     /***
259      * @see org.apache.jetspeed.security.UserManager#addUser(java.lang.String,
260      *      java.lang.String, java.lang.String)
261      */
262     protected void createUser(String username, String password, String atnProviderName, boolean raw)
263             throws SecurityException
264     {
265         ArgUtil
266                 .notNull(new Object[]
267                 { username, atnProviderName}, new String[]
268                 { "username", "atnProviderName"},
269                         "addUser(java.lang.String, java.lang.String, java.lang.String)");
270 
271 //        if (getAnonymousUser().equals(username)) { throw new SecurityException(
272 //                SecurityException.ANONYMOUS_USER_PROTECTED.create(username)); }
273 
274         // Check if user already exists.
275         if (userExists(username)) { 
276             throw new SecurityException(SecurityException.USER_ALREADY_EXISTS.create(username));
277         }
278 
279         UserPrincipal userPrincipal = new UserPrincipalImpl(username);
280         String fullPath = userPrincipal.getFullPath();
281         // Add the preferences.
282         Preferences preferences = Preferences.userRoot().node(fullPath);
283         if (log.isDebugEnabled())
284         {
285             log.debug("Added user preferences node: " + fullPath);
286         }
287         try
288         {
289             if ((null != preferences)
290                     && preferences.absolutePath().equals(fullPath))
291             {
292                 // Add user principal.
293                 atnProviderProxy.addUserPrincipal(userPrincipal);
294                 if (password != null)
295                 {
296                     try
297                     {
298                         // Set private password credential
299                     	if (raw)
300                             atnProviderProxy.importPassword(username, password,atnProviderName);
301                     	else
302                     		atnProviderProxy.setPassword(username, null, password,atnProviderName);
303                     }
304                     catch (SecurityException se1)
305                     {
306                         try
307                         {
308                             // rollback created user
309                             atnProviderProxy.removeUserPrincipal(userPrincipal);
310                         }
311                         catch (SecurityException se2)
312                         {
313                             log.error("Failed to rollback created user after its password turned out to be invalid", se2);
314                         }
315                         throw se1;
316                     }
317                 }
318                 if (log.isDebugEnabled())
319                 {
320                     log.debug("Added user: " + fullPath);
321                 }
322             }
323         } catch (SecurityException se)
324         {
325             log.error(se.getMessage(), se);
326 
327             // Remove the preferences node.
328             try
329             {
330                 preferences.removeNode();
331             } catch (BackingStoreException bse)
332             {
333                 bse.printStackTrace();
334             }
335             throw se;
336         }
337     }
338 
339     
340     
341     /***
342      * @see org.apache.jetspeed.security.UserManager#removeUser(java.lang.String)
343      * 
344      * TODO Enforce that only administrators can do this.
345      */
346     public void removeUser(String username) throws SecurityException
347     {
348         ArgUtil.notNull(new Object[]
349         { username}, new String[]
350         { "username"}, "removeUser(java.lang.String)");
351 
352         if (getAnonymousUser().equals(username)) { throw new SecurityException(
353                 SecurityException.ANONYMOUS_USER_PROTECTED.create(username)); }
354         UserPrincipal userPrincipal = new UserPrincipalImpl(username);
355         String fullPath = userPrincipal.getFullPath();
356         atnProviderProxy.removeUserPrincipal(userPrincipal);
357         // Remove preferences
358         Preferences preferences = Preferences.userRoot().node(fullPath);
359         try
360         {
361             preferences.removeNode();
362         } catch (BackingStoreException bse)
363         {
364             bse.printStackTrace();
365         }
366     }
367 
368     /***
369      * @see org.apache.jetspeed.security.UserManager#userExists(java.lang.String)
370      */
371     public boolean userExists(String username)
372     {
373         ArgUtil.notNull(new Object[]
374         { username}, new String[]
375         { "username"}, "userExists(java.lang.String)");
376 
377         return atnProviderProxy.getUserPrincipal(username) != null;
378     }
379 
380     /***
381      * @see org.apache.jetspeed.security.UserManager#getUser(java.lang.String)
382      */
383     public User getUser(String username) throws SecurityException
384     {
385         ArgUtil.notNull(new Object[]
386         { username}, new String[]
387         { "username"}, "getUser(java.lang.String)");
388 
389         // optimize guest lookups as they can be excessive
390         if (guest != null && getAnonymousUser().equals(username))
391         {
392             // TODO: need to handle caching issues            
393             return guest;
394         }
395         
396         Set principals = new PrincipalsSet();
397         String fullPath = (new UserPrincipalImpl(username)).getFullPath();
398 
399         Principal userPrincipal = atnProviderProxy.getUserPrincipal(username);
400         if (null == userPrincipal) { 
401             throw new SecurityException(SecurityException.USER_DOES_NOT_EXIST.create(username));
402         }
403 
404         principals.add(userPrincipal);
405         principals.addAll(securityMappingHandler.getRolePrincipals(username));
406         Set groupPrincipals = securityMappingHandler.getGroupPrincipals(username);
407         principals.addAll(groupPrincipals);
408         
409         if (this.rolesInheritableViaGroups)
410         {
411             for (Iterator it = groupPrincipals.iterator(); it.hasNext(); )
412             {
413                 Principal groupPrincipal = (Principal) it.next();
414                 Set rolePrincipalsInGroup = securityMappingHandler.getRolePrincipalsInGroup(groupPrincipal.getName());
415                 principals.addAll(rolePrincipalsInGroup);
416             }
417         }
418 
419         Subject subject = null;
420         if (getAnonymousUser().equals(username))
421         {
422             subject = new Subject(true, principals, new HashSet(),
423                     new HashSet());
424         } else
425         {
426             subject = new Subject(true, principals, atnProviderProxy
427                     .getPublicCredentials(username), atnProviderProxy
428                     .getPrivateCredentials(username));
429         }
430         Preferences preferences = Preferences.userRoot().node(fullPath);
431         User user = new UserImpl(subject, preferences);
432         if (getAnonymousUser().equals(username))
433         {
434             guest = user;
435         }
436         return user;
437     }
438 
439     /***
440      * @see org.apache.jetspeed.security.UserManager#getUsers(java.lang.String)
441      */
442     public Iterator getUsers(String filter) throws SecurityException
443     {
444         List users = new LinkedList();
445         Iterator userPrincipals = atnProviderProxy.getUserPrincipals(filter)
446                 .iterator();
447         while (userPrincipals.hasNext())
448         {
449             String username = ((Principal) userPrincipals.next()).getName();
450             User user = getUser(username);
451             users.add(user);
452         }
453         return users.iterator();
454     }
455 
456     /***
457      * @see org.apache.jetspeed.security.UserManager#getUserNames(java.lang.String)
458      */
459     public Iterator getUserNames(String filter) throws SecurityException
460     {
461         List usernames = new LinkedList();
462         Iterator userPrincipals = atnProviderProxy.getUserPrincipals(filter).iterator();
463         while (userPrincipals.hasNext())
464         {
465             usernames.add(((Principal) userPrincipals.next()).getName());
466         }
467         return usernames.iterator();
468     }
469 
470     /***
471      * @see org.apache.jetspeed.security.UserManager#getUsersInRole(java.lang.String)
472      */
473     public Collection getUsersInRole(String roleFullPathName)
474             throws SecurityException
475     {
476         ArgUtil.notNull(new Object[]
477         { roleFullPathName}, new String[]
478         { "roleFullPathName"}, "getUsersInRole(java.lang.String)");
479 
480         Collection users = new ArrayList();
481 
482         Set userPrincipals = securityMappingHandler
483                 .getUserPrincipalsInRole(roleFullPathName);
484         Iterator userPrincipalsIter = userPrincipals.iterator();
485         while (userPrincipalsIter.hasNext())
486         {
487             Principal userPrincipal = (Principal) userPrincipalsIter.next();
488             users.add(getUser(userPrincipal.getName()));
489         }
490         return users;
491     }
492 
493     /***
494      * @see org.apache.jetspeed.security.UserManager#getUsersInGroup(java.lang.String)
495      */
496     public Collection getUsersInGroup(String groupFullPathName)
497             throws SecurityException
498     {
499         ArgUtil.notNull(new Object[]
500         { groupFullPathName}, new String[]
501         { "groupFullPathName"}, "getUsersInGroup(java.lang.String)");
502 
503         Collection users = new ArrayList();
504 
505         Set userPrincipals = securityMappingHandler
506                 .getUserPrincipalsInGroup(groupFullPathName);
507         Iterator userPrincipalsIter = userPrincipals.iterator();
508         while (userPrincipalsIter.hasNext())
509         {
510             Principal userPrincipal = (Principal) userPrincipalsIter.next();
511             users.add(getUser(userPrincipal.getName()));
512         }
513         return users;
514     }
515 
516     /***
517      * @see org.apache.jetspeed.security.UserManager#setPassword(java.lang.String,
518      *      java.lang.String, java.lang.String)
519      * 
520      * TODO Enforce that only administrators can do this.
521      */
522     public void setPassword(String username, String oldPassword,
523             String newPassword) throws SecurityException
524     {
525         ArgUtil
526                 .notNull(new Object[]
527                 { username, newPassword}, new String[]
528                 { "username", "newPassword"},
529                         "setPassword(java.lang.String, java.lang.String, java.lang.String)");
530 
531         if (getAnonymousUser().equals(username)) { throw new SecurityException(
532                 SecurityException.ANONYMOUS_USER_PROTECTED.create(username)); }
533         atnProviderProxy.setPassword(username, oldPassword, newPassword);
534     }
535 
536     /***
537      * @see org.apache.jetspeed.security.UserManager#setPasswordEnabled(java.lang.String,
538      *      boolean)
539      */
540     public void setPasswordEnabled(String userName, boolean enabled)
541             throws SecurityException
542     {
543         ArgUtil.notNull(new Object[]
544         { userName,}, new String[]
545         { "userName"}, "setPasswordEnabled(java.lang.String, boolean)");
546 
547         if (getAnonymousUser().equals(userName)) { throw new SecurityException(
548                 SecurityException.ANONYMOUS_USER_PROTECTED.create(userName)); }
549         atnProviderProxy.setPasswordEnabled(userName, enabled);
550     }
551 
552     /***
553      * @see org.apache.jetspeed.security.UserManager#setPasswordUpdateRequired(java.lang.String,
554      *      boolean)
555      */
556     public void setPasswordUpdateRequired(String userName,
557             boolean updateRequired) throws SecurityException
558     {
559         ArgUtil.notNull(new Object[]
560         { userName,}, new String[]
561         { "userName"}, "setPasswordUpdateRequired(java.lang.String, boolean)");
562 
563         if (getAnonymousUser().equals(userName)) { throw new SecurityException(
564                 SecurityException.ANONYMOUS_USER_PROTECTED.create(userName)); }
565         atnProviderProxy.setPasswordUpdateRequired(userName, updateRequired);
566     }
567     
568     
569     /***
570      * @see org.apache.jetspeed.security.UserManager#setUserEnabled(java.lang.String, boolean)
571      */
572     public void setUserEnabled(String userName, boolean enabled) throws SecurityException
573     {
574         ArgUtil.notNull(new Object[] { userName, }, new String[] { "userName" },
575                 "setUserEnabled(java.lang.String, boolean)");
576 
577         if (getAnonymousUser().equals(userName))
578         {
579             throw new SecurityException(SecurityException.ANONYMOUS_USER_PROTECTED.create(userName));
580         }
581 
582         UserPrincipalImpl userPrincipal = (UserPrincipalImpl)atnProviderProxy.getUserPrincipal(userName);
583         if (null == userPrincipal) 
584         { 
585             throw new SecurityException(SecurityException.USER_DOES_NOT_EXIST.create(userName));
586         }
587         if ( enabled != userPrincipal.isEnabled() )
588         {
589             userPrincipal.setEnabled(enabled);
590             atnProviderProxy.updateUserPrincipal(userPrincipal);
591         }
592     }
593 
594     /***
595      * @see org.apache.jetspeed.security.UserManager#setPasswordExpiration(java.lang.String, java.sql.Date)
596      */
597     public void setPasswordExpiration(String userName, Date expirationDate) throws SecurityException
598     {
599         ArgUtil.notNull(new Object[]
600         { userName,}, new String[]
601         { "userName"}, "setPasswordExpiration(java.lang.String, java.sql.Date)");
602 
603         if (getAnonymousUser().equals(userName)) 
604         { 
605             throw new SecurityException(SecurityException.ANONYMOUS_USER_PROTECTED.create(userName)); 
606         }
607         atnProviderProxy.setPasswordExpiration(userName, expirationDate);
608     }
609 }