##### Coverage Report - org.apache.turbine.services.security.BaseSecurityService

Classes in this File | Line Coverage | Branch Coverage | Complexity
BaseSecurityService |
26% | 52/193
11% | 6/52
| 2.391304347826087;2,391

1 |  |
     package org.apache.turbine.services.security;
2 |  |
3 |  |
4 |  |
     /*
5 |  |
      * Licensed to the Apache Software Foundation (ASF) under one
6 |  |
      * or more contributor license agreements.  See the NOTICE file
7 |  |
      * distributed with this work for additional information
8 |  |
      * regarding copyright ownership.  The ASF licenses this file
9 |  |
      * to you under the Apache License, Version 2.0 (the
10 |  |
      * "License"); you may not use this file except in compliance
11 |  |
      * with the License.  You may obtain a copy of the License at
12 |  |
      *
13 |  |
      *   http://www.apache.org/licenses/LICENSE-2.0
14 |  |
      *
15 |  |
      * Unless required by applicable law or agreed to in writing,
16 |  |
      * software distributed under the License is distributed on an
17 |  |
      * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 |  |
      * KIND, either express or implied.  See the License for the
19 |  |
      * specific language governing permissions and limitations
20 |  |
      * under the License.
21 |  |
      */
22 |  |
23 |  |
24 |  |
     import java.util.Map;
25 |  |
26 |  |
     import javax.servlet.ServletConfig;
27 |  |
28 |  |
     import org.apache.commons.configuration.Configuration;
29 |  |
     import org.apache.commons.lang.StringUtils;
30 |  |
     import org.apache.commons.logging.Log;
31 |  |
     import org.apache.commons.logging.LogFactory;
32 |  |
     import org.apache.fulcrum.crypto.CryptoAlgorithm;
33 |  |
     import org.apache.fulcrum.crypto.CryptoService;
34 |  |
     import org.apache.fulcrum.factory.FactoryService;
35 |  |
     import org.apache.turbine.om.security.Group;
36 |  |
     import org.apache.turbine.om.security.Permission;
37 |  |
     import org.apache.turbine.om.security.Role;
38 |  |
     import org.apache.turbine.om.security.User;
39 |  |
     import org.apache.turbine.services.InitializationException;
40 |  |
     import org.apache.turbine.services.ServiceManager;
41 |  |
     import org.apache.turbine.services.TurbineBaseService;
42 |  |
     import org.apache.turbine.services.TurbineServices;
43 |  |
     import org.apache.turbine.util.security.AccessControlList;
44 |  |
     import org.apache.turbine.util.security.DataBackendException;
45 |  |
     import org.apache.turbine.util.security.EntityExistsException;
46 |  |
     import org.apache.turbine.util.security.GroupSet;
47 |  |
     import org.apache.turbine.util.security.PasswordMismatchException;
48 |  |
     import org.apache.turbine.util.security.PermissionSet;
49 |  |
     import org.apache.turbine.util.security.RoleSet;
50 |  |
     import org.apache.turbine.util.security.UnknownEntityException;
51 |  |
52 |  |
     /**
53 |  |
      * This is a common subset of SecurityService implementation.
54 |  |
      *
55 |  |
      * Provided functionality includes:
56 |  |
      * <ul>
57 |  |
      * <li> methods for retrieving User objects, that delegates functionality
58 |  |
      *      to the pluggable implementations of the User interface.
59 |  |
      * <li> synchronization mechanism for methods reading/modifying the security
60 |  |
      *      information, that guarantees that multiple threads may read the
61 |  |
      *      information concurrently, but threads that modify the information
62 |  |
      *      acquires exclusive access.
63 |  |
      * <li> implementation of convenience methods for retrieving security entities
64 |  |
      *      that maintain in-memory caching of objects for fast access.
65 |  |
      * </ul>
66 |  |
      *
67 |  |
      * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
68 |  |
      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
69 |  |
      * @author <a href="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
70 |  |
      * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
71 |  |
      * @version $Id: BaseSecurityService.java 1096130 2011-04-23 10:37:19Z ludwig $
72 |  |
      */
73 | 20 |
     public abstract class BaseSecurityService
74 |  |
             extends TurbineBaseService
75 |  |
             implements SecurityService
76 |  |
     {
77 |  |
         /** The number of threads concurrently reading security information */
78 | 20 |
         private int readerCount = 0;
79 |  |
80 |  |
         /** The instance of UserManager the SecurityService uses */
81 | 20 |
         private UserManager userManager = null;
82 |  |
83 |  |
         /** The class of User the SecurityService uses */
84 | 20 |
         private Class userClass = null;
85 |  |
86 |  |
         /** The class of Group the SecurityService uses */
87 | 20 |
         private Class groupClass = null;
88 |  |
89 |  |
         /** The class of Permission the SecurityService uses */
90 | 20 |
         private Class permissionClass = null;
91 |  |
92 |  |
         /** The class of Role the SecurityService uses */
93 | 20 |
         private Class roleClass = null;
94 |  |
95 |  |
         /** The class of ACL the SecurityService uses */
96 | 20 |
         private Class aclClass = null;
97 |  |
98 |  |
         /** A factory to construct ACL Objects */
99 | 20 |
         private FactoryService aclFactoryService = null;
100 |  |
101 |  |
         /**
102 |  |
          * The Group object that represents the <a href="#global">global group</a>.
103 |  |
          */
104 | 20 |
         private static Group globalGroup = null;
105 |  |
106 |  |
         /** Logging */
107 | 20 |
         private static Log log = LogFactory.getLog(BaseSecurityService.class);
108 |  |
109 |  |
         /**
110 |  |
          * This method provides client-side encryption of passwords.
111 |  |
          *
112 |  |
          * If <code>secure.passwords</code> are enabled in TurbineResources,
113 |  |
          * the password will be encrypted, if not, it will be returned unchanged.
114 |  |
          * The <code>secure.passwords.algorithm</code> property can be used
115 |  |
          * to chose which digest algorithm should be used for performing the
116 |  |
          * encryption. <code>SHA</code> is used by default.
117 |  |
          *
118 |  |
          * @param password the password to process
119 |  |
          * @return processed password
120 |  |
          */
121 |  |
         public String encryptPassword(String password)
122 |  |
         {
123 | 0 |
             return encryptPassword(password, null);
124 |  |
         }
125 |  |
126 |  |
         /**
127 |  |
          * This method provides client-side encryption of passwords.
128 |  |
          *
129 |  |
          * If <code>secure.passwords</code> are enabled in TurbineResources,
130 |  |
          * the password will be encrypted, if not, it will be returned unchanged.
131 |  |
          * The <code>secure.passwords.algorithm</code> property can be used
132 |  |
          * to chose which digest algorithm should be used for performing the
133 |  |
          * encryption. <code>SHA</code> is used by default.
134 |  |
          *
135 |  |
          * The used algorithms must be prepared to accept null as a
136 |  |
          * valid parameter for salt. All algorithms in the Fulcrum Cryptoservice
137 |  |
          * accept this.
138 |  |
          *
139 |  |
          * @param password the password to process
140 |  |
          * @param salt     algorithms that needs a salt can provide one here
141 |  |
          * @return processed password
142 |  |
          */
143 |  |
144 |  |
         public String encryptPassword(String password, String salt)
145 |  |
         {
146 | 0 |
             if (password == null)
147 |  |
             {
148 | 0 |
                 return null;
149 |  |
             }
150 | 0 |
             String secure = getConfiguration().getString(
151 |  |
                     SecurityService.SECURE_PASSWORDS_KEY,
152 |  |
                     SecurityService.SECURE_PASSWORDS_DEFAULT).toLowerCase();
153 |  |
154 | 0 |
             String algorithm = getConfiguration().getString(
155 |  |
                     SecurityService.SECURE_PASSWORDS_ALGORITHM_KEY,
156 |  |
                     SecurityService.SECURE_PASSWORDS_ALGORITHM_DEFAULT);
157 |  |
158 | 0 |
             CryptoService cs = null;
159 |  |
             try {
160 | 0 |
                 ServiceManager serviceManager = TurbineServices.getInstance();
161 | 0 |
                 cs = (CryptoService)serviceManager.getService(CryptoService.ROLE);
162 |  |
             }
163 | 0 |
             catch (Exception e){
164 | 0 |
                 throw new RuntimeException("Could not access Crypto Service",e);
165 | 0 |
             }
166 |  |
167 | 0 |
             if (cs != null && (secure.equals("true") || secure.equals("yes")))
168 |  |
             {
169 |  |
                 try
170 |  |
                 {
171 | 0 |
                     CryptoAlgorithm ca = cs.getCryptoAlgorithm(algorithm);
172 |  |
173 | 0 |
                     ca.setSeed(salt);
174 |  |
175 | 0 |
                     String result = ca.encrypt(password);
176 |  |
177 | 0 |
                     return result;
178 |  |
                 }
179 | 0 |
                 catch (Exception e)
180 |  |
                 {
181 | 0 |
                     log.error("Unable to encrypt password: ", e);
182 |  |
183 | 0 |
                     return null;
184 |  |
                 }
185 |  |
             }
186 |  |
             else
187 |  |
             {
188 | 0 |
                 return password;
189 |  |
             }
190 |  |
         }
191 |  |
192 |  |
         /**
193 |  |
          * Checks if a supplied password matches the encrypted password
194 |  |
          *
195 |  |
          * @param checkpw      The clear text password supplied by the user
196 |  |
          * @param encpw        The current, encrypted password
197 |  |
          *
198 |  |
          * @return true if the password matches, else false
199 |  |
          *
200 |  |
          */
201 |  |
202 |  |
         public boolean checkPassword(String checkpw, String encpw)
203 |  |
         {
204 | 0 |
             String result = encryptPassword(checkpw, encpw);
205 |  |
206 | 0 |
             return (result == null) ? false : result.equals(encpw);
207 |  |
         }
208 |  |
209 |  |
         /**
210 |  |
          * Initializes the SecurityService, locating the apropriate UserManager
211 |  |
          * This is a zero parameter variant which queries the Turbine Servlet
212 |  |
          * for its config.
213 |  |
          *
214 |  |
          * @throws InitializationException Something went wrong in the init stage
215 |  |
          */
216 |  |
         public void init()
217 |  |
                 throws InitializationException
218 |  |
         {
219 | 24 |
             Configuration conf = getConfiguration();
220 |  |
221 | 24 |
             String userManagerClassName = conf.getString(
222 |  |
                     SecurityService.USER_MANAGER_KEY,
223 |  |
                     SecurityService.USER_MANAGER_DEFAULT);
224 |  |
225 | 24 |
             String userClassName = conf.getString(
226 |  |
                     SecurityService.USER_CLASS_KEY,
227 |  |
                     SecurityService.USER_CLASS_DEFAULT);
228 |  |
229 | 24 |
             String groupClassName = conf.getString(
230 |  |
                     SecurityService.GROUP_CLASS_KEY,
231 |  |
                     SecurityService.GROUP_CLASS_DEFAULT);
232 |  |
233 | 24 |
             String permissionClassName = conf.getString(
234 |  |
                     SecurityService.PERMISSION_CLASS_KEY,
235 |  |
                     SecurityService.PERMISSION_CLASS_DEFAULT);
236 |  |
237 | 24 |
             String roleClassName = conf.getString(
238 |  |
                     SecurityService.ROLE_CLASS_KEY,
239 |  |
                     SecurityService.ROLE_CLASS_DEFAULT);
240 |  |
241 | 24 |
             String aclClassName = conf.getString(
242 |  |
                     SecurityService.ACL_CLASS_KEY,
243 |  |
                     SecurityService.ACL_CLASS_DEFAULT);
244 |  |
245 |  |
             try
246 |  |
             {
247 | 24 |
                 userClass = Class.forName(userClassName);
248 | 24 |
                 groupClass = Class.forName(groupClassName);
249 | 24 |
                 permissionClass = Class.forName(permissionClassName);
250 | 24 |
                 roleClass = Class.forName(roleClassName);
251 | 24 |
                 aclClass = Class.forName(aclClassName);
252 |  |
             }
253 | 0 |
             catch (Exception e)
254 |  |
             {
255 | 0 |
                 if (userClass == null)
256 |  |
                 {
257 | 0 |
                     throw new InitializationException(
258 |  |
                             "Failed to create a Class object for User implementation", e);
259 |  |
                 }
260 | 0 |
                 if (groupClass == null)
261 |  |
                 {
262 | 0 |
                     throw new InitializationException(
263 |  |
                             "Failed to create a Class object for Group implementation", e);
264 |  |
                 }
265 | 0 |
                 if (permissionClass == null)
266 |  |
                 {
267 | 0 |
                     throw new InitializationException(
268 |  |
                             "Failed to create a Class object for Permission implementation", e);
269 |  |
                 }
270 | 0 |
                 if (roleClass == null)
271 |  |
                 {
272 | 0 |
                     throw new InitializationException(
273 |  |
                             "Failed to create a Class object for Role implementation", e);
274 |  |
                 }
275 | 0 |
                 if (aclClass == null)
276 |  |
                 {
277 | 0 |
                     throw new InitializationException(
278 |  |
                             "Failed to create a Class object for ACL implementation", e);
279 |  |
                 }
280 | 24 |
             }
281 |  |
282 |  |
             try
283 |  |
             {
284 | 24 |
                 UserManager userManager =
285 |  |
                         (UserManager) Class.forName(userManagerClassName).newInstance();
286 |  |
287 | 24 |
                 userManager.init(conf);
288 |  |
289 | 24 |
                 setUserManager(userManager);
290 |  |
             }
291 | 0 |
             catch (Exception e)
292 |  |
             {
293 | 0 |
                 throw new InitializationException("Failed to instantiate UserManager", e);
294 | 24 |
             }
295 |  |
296 |  |
             try
297 |  |
             {
298 | 24 |
                 aclFactoryService = (FactoryService)TurbineServices.getInstance().getService(FactoryService.ROLE);
299 |  |
             }
300 | 0 |
             catch (Exception e)
301 |  |
             {
302 | 0 |
                 throw new InitializationException(
303 |  |
                         "BaseSecurityService.init: Failed to get the Factory Service object", e);
304 | 24 |
             }
305 |  |
306 | 24 |
             setInit(true);
307 | 24 |
         }
308 |  |
309 |  |
         /**
310 |  |
          * Return a Class object representing the system's chosen implementation of
311 |  |
          * of User interface.
312 |  |
          *
313 |  |
          * @return systems's chosen implementation of User interface.
314 |  |
          * @throws UnknownEntityException if the implementation of User interface
315 |  |
          *         could not be determined, or does not exist.
316 |  |
          */
317 |  |
         public Class getUserClass()
318 |  |
                 throws UnknownEntityException
319 |  |
         {
320 | 4 |
             if (userClass == null)
321 |  |
             {
322 | 0 |
                 throw new UnknownEntityException(
323 |  |
                         "Failed to create a Class object for User implementation");
324 |  |
             }
325 | 4 |
             return userClass;
326 |  |
         }
327 |  |
328 |  |
         /**
329 |  |
          * Construct a blank User object.
330 |  |
          *
331 |  |
          * This method calls getUserClass, and then creates a new object using
332 |  |
          * the default constructor.
333 |  |
          *
334 |  |
          * @return an object implementing User interface.
335 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
336 |  |
          */
337 |  |
         public User getUserInstance()
338 |  |
                 throws UnknownEntityException
339 |  |
         {
340 |  |
             User user;
341 |  |
             try
342 |  |
             {
343 | 4 |
                 user = (User) getUserClass().newInstance();
344 |  |
             }
345 | 0 |
             catch (Exception e)
346 |  |
             {
347 | 0 |
                 throw new UnknownEntityException(
348 |  |
                         "Failed instantiate an User implementation object", e);
349 | 4 |
             }
350 | 4 |
             return user;
351 |  |
         }
352 |  |
353 |  |
         /**
354 |  |
          * Construct a blank User object.
355 |  |
          *
356 |  |
          * This method calls getUserClass, and then creates a new object using
357 |  |
          * the default constructor.
358 |  |
          *
359 |  |
          * @param userName The name of the user.
360 |  |
          *
361 |  |
          * @return an object implementing User interface.
362 |  |
          *
363 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
364 |  |
          */
365 |  |
         public User getUserInstance(String userName)
366 |  |
                 throws UnknownEntityException
367 |  |
         {
368 | 0 |
             User user = getUserInstance();
369 | 0 |
             user.setName(userName);
370 | 0 |
             return user;
371 |  |
         }
372 |  |
373 |  |
         /**
374 |  |
          * Return a Class object representing the system's chosen implementation of
375 |  |
          * of Group interface.
376 |  |
          *
377 |  |
          * @return systems's chosen implementation of Group interface.
378 |  |
          * @throws UnknownEntityException if the implementation of Group interface
379 |  |
          *         could not be determined, or does not exist.
380 |  |
          */
381 |  |
         public Class getGroupClass()
382 |  |
                 throws UnknownEntityException
383 |  |
         {
384 | 0 |
             if (groupClass == null)
385 |  |
             {
386 | 0 |
                 throw new UnknownEntityException(
387 |  |
                         "Failed to create a Class object for Group implementation");
388 |  |
             }
389 | 0 |
             return groupClass;
390 |  |
         }
391 |  |
392 |  |
         /**
393 |  |
          * Construct a blank Group object.
394 |  |
          *
395 |  |
          * This method calls getGroupClass, and then creates a new object using
396 |  |
          * the default constructor.
397 |  |
          *
398 |  |
          * @return an object implementing Group interface.
399 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
400 |  |
          */
401 |  |
         public Group getGroupInstance()
402 |  |
                 throws UnknownEntityException
403 |  |
         {
404 |  |
             Group group;
405 |  |
             try
406 |  |
             {
407 | 0 |
                 group = (Group) getGroupClass().newInstance();
408 |  |
             }
409 | 0 |
             catch (Exception e)
410 |  |
             {
411 | 0 |
                 throw new UnknownEntityException("Failed to instantiate a Group implementation object", e);
412 | 0 |
             }
413 | 0 |
             return group;
414 |  |
         }
415 |  |
416 |  |
         /**
417 |  |
          * Construct a blank Group object.
418 |  |
          *
419 |  |
          * This method calls getGroupClass, and then creates a new object using
420 |  |
          * the default constructor.
421 |  |
          *
422 |  |
          * @param groupName The name of the Group
423 |  |
          *
424 |  |
          * @return an object implementing Group interface.
425 |  |
          *
426 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
427 |  |
          */
428 |  |
         public Group getGroupInstance(String groupName)
429 |  |
                 throws UnknownEntityException
430 |  |
         {
431 | 0 |
             Group group = getGroupInstance();
432 | 0 |
             group.setName(groupName);
433 | 0 |
             return group;
434 |  |
         }
435 |  |
436 |  |
         /**
437 |  |
          * Return a Class object representing the system's chosen implementation of
438 |  |
          * of Permission interface.
439 |  |
          *
440 |  |
          * @return systems's chosen implementation of Permission interface.
441 |  |
          * @throws UnknownEntityException if the implementation of Permission interface
442 |  |
          *         could not be determined, or does not exist.
443 |  |
          */
444 |  |
         public Class getPermissionClass()
445 |  |
                 throws UnknownEntityException
446 |  |
         {
447 | 0 |
             if (permissionClass == null)
448 |  |
             {
449 | 0 |
                 throw new UnknownEntityException(
450 |  |
                         "Failed to create a Class object for Permission implementation");
451 |  |
             }
452 | 0 |
             return permissionClass;
453 |  |
         }
454 |  |
455 |  |
         /**
456 |  |
          * Construct a blank Permission object.
457 |  |
          *
458 |  |
          * This method calls getPermissionClass, and then creates a new object using
459 |  |
          * the default constructor.
460 |  |
          *
461 |  |
          * @return an object implementing Permission interface.
462 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
463 |  |
          */
464 |  |
         public Permission getPermissionInstance()
465 |  |
                 throws UnknownEntityException
466 |  |
         {
467 |  |
             Permission permission;
468 |  |
             try
469 |  |
             {
470 | 0 |
                 permission = (Permission) getPermissionClass().newInstance();
471 |  |
             }
472 | 0 |
             catch (Exception e)
473 |  |
             {
474 | 0 |
                 throw new UnknownEntityException("Failed to instantiate a Permission implementation object", e);
475 | 0 |
             }
476 | 0 |
             return permission;
477 |  |
         }
478 |  |
479 |  |
         /**
480 |  |
          * Construct a blank Permission object.
481 |  |
          *
482 |  |
          * This method calls getPermissionClass, and then creates a new object using
483 |  |
          * the default constructor.
484 |  |
          *
485 |  |
          * @param permName The name of the permission.
486 |  |
          *
487 |  |
          * @return an object implementing Permission interface.
488 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
489 |  |
          */
490 |  |
         public Permission getPermissionInstance(String permName)
491 |  |
                 throws UnknownEntityException
492 |  |
         {
493 | 0 |
             Permission perm = getPermissionInstance();
494 | 0 |
             perm.setName(permName);
495 | 0 |
             return perm;
496 |  |
         }
497 |  |
498 |  |
         /**
499 |  |
          * Return a Class object representing the system's chosen implementation of
500 |  |
          * of Role interface.
501 |  |
          *
502 |  |
          * @return systems's chosen implementation of Role interface.
503 |  |
          * @throws UnknownEntityException if the implementation of Role interface
504 |  |
          *         could not be determined, or does not exist.
505 |  |
          */
506 |  |
         public Class getRoleClass()
507 |  |
                 throws UnknownEntityException
508 |  |
         {
509 | 0 |
             if (roleClass == null)
510 |  |
             {
511 | 0 |
                 throw new UnknownEntityException(
512 |  |
                         "Failed to create a Class object for Role implementation");
513 |  |
             }
514 | 0 |
             return roleClass;
515 |  |
         }
516 |  |
517 |  |
         /**
518 |  |
          * Construct a blank Role object.
519 |  |
          *
520 |  |
          * This method calls getRoleClass, and then creates a new object using
521 |  |
          * the default constructor.
522 |  |
          *
523 |  |
          * @return an object implementing Role interface.
524 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
525 |  |
          */
526 |  |
         public Role getRoleInstance()
527 |  |
                 throws UnknownEntityException
528 |  |
         {
529 |  |
             Role role;
530 |  |
531 |  |
             try
532 |  |
             {
533 | 0 |
                 role = (Role) getRoleClass().newInstance();
534 |  |
             }
535 | 0 |
             catch (Exception e)
536 |  |
             {
537 | 0 |
                 throw new UnknownEntityException("Failed to instantiate a Role implementation object", e);
538 | 0 |
             }
539 | 0 |
             return role;
540 |  |
         }
541 |  |
542 |  |
         /**
543 |  |
          * Construct a blank Role object.
544 |  |
          *
545 |  |
          * This method calls getRoleClass, and then creates a new object using
546 |  |
          * the default constructor.
547 |  |
          *
548 |  |
          * @param roleName The name of the role.
549 |  |
          *
550 |  |
          * @return an object implementing Role interface.
551 |  |
          *
552 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
553 |  |
          */
554 |  |
         public Role getRoleInstance(String roleName)
555 |  |
                 throws UnknownEntityException
556 |  |
         {
557 | 0 |
             Role role = getRoleInstance();
558 | 0 |
             role.setName(roleName);
559 | 0 |
             return role;
560 |  |
         }
561 |  |
562 |  |
         /**
563 |  |
          * Return a Class object representing the system's chosen implementation of
564 |  |
          * of ACL interface.
565 |  |
          *
566 |  |
          * @return systems's chosen implementation of ACL interface.
567 |  |
          * @throws UnknownEntityException if the implementation of ACL interface
568 |  |
          *         could not be determined, or does not exist.
569 |  |
          */
570 |  |
         public Class getAclClass()
571 |  |
                 throws UnknownEntityException
572 |  |
         {
573 | 2 |
             if (aclClass == null)
574 |  |
             {
575 | 0 |
                 throw new UnknownEntityException(
576 |  |
                         "Failed to create a Class object for ACL implementation");
577 |  |
             }
578 | 2 |
             return aclClass;
579 |  |
         }
580 |  |
581 |  |
         /**
582 |  |
          * Construct a new ACL object.
583 |  |
          *
584 |  |
          * This constructs a new ACL object from the configured class and
585 |  |
          * initializes it with the supplied roles and permissions.
586 |  |
          *
587 |  |
          * @param roles The roles that this ACL should contain
588 |  |
          * @param permissions The permissions for this ACL
589 |  |
          *
590 |  |
          * @return an object implementing ACL interface.
591 |  |
          * @throws UnknownEntityException if the object could not be instantiated.
592 |  |
          */
593 |  |
         public AccessControlList getAclInstance(Map roles, Map permissions)
594 |  |
                 throws UnknownEntityException
595 |  |
         {
596 | 4 |
             Object[] objects = {roles, permissions};
597 | 4 |
             String[] signatures = {Map.class.getName(), Map.class.getName()};
598 |  |
             AccessControlList accessControlList;
599 |  |
600 |  |
             try
601 |  |
             {
602 | 4 |
                 accessControlList =
603 |  |
                         (AccessControlList) aclFactoryService.getInstance(aclClass.getName(),
604 |  |
                                 objects,
605 |  |
                                 signatures);
606 |  |
             }
607 | 0 |
             catch (Exception e)
608 |  |
             {
609 | 0 |
                 throw new UnknownEntityException(
610 |  |
                         "Failed to instantiate an ACL implementation object", e);
611 | 4 |
             }
612 |  |
613 | 4 |
             return accessControlList;
614 |  |
         }
615 |  |
616 |  |
         /**
617 |  |
          * Returns the configured UserManager.
618 |  |
          *
619 |  |
          * @return An UserManager object
620 |  |
          */
621 |  |
         public UserManager getUserManager()
622 |  |
         {
623 | 2 |
             return userManager;
624 |  |
         }
625 |  |
626 |  |
         /**
627 |  |
          * Configure a new user Manager.
628 |  |
          *
629 |  |
          * @param userManager An UserManager object
630 |  |
          */
631 |  |
         public void setUserManager(UserManager userManager)
632 |  |
         {
633 | 24 |
             this.userManager = userManager;
634 | 24 |
         }
635 |  |
636 |  |
         /**
637 |  |
          * Check whether a specified user's account exists.
638 |  |
          *
639 |  |
          * The login name is used for looking up the account.
640 |  |
          *
641 |  |
          * @param user The user to be checked.
642 |  |
          * @return true if the specified account exists
643 |  |
          * @throws DataBackendException if there was an error accessing the data
644 |  |
          *         backend.
645 |  |
          */
646 |  |
         public boolean accountExists(User user)
647 |  |
                 throws DataBackendException
648 |  |
         {
649 | 0 |
             return getUserManager().accountExists(user);
650 |  |
         }
651 |  |
652 |  |
         /**
653 |  |
          * Check whether a specified user's account exists.
654 |  |
          *
655 |  |
          * The login name is used for looking up the account.
656 |  |
          *
657 |  |
          * @param userName The name of the user to be checked.
658 |  |
          * @return true if the specified account exists
659 |  |
          * @throws DataBackendException if there was an error accessing the data
660 |  |
          *         backend.
661 |  |
          */
662 |  |
         public boolean accountExists(String userName)
663 |  |
                 throws DataBackendException
664 |  |
         {
665 | 0 |
             return getUserManager().accountExists(userName);
666 |  |
         }
667 |  |
668 |  |
         /**
669 |  |
          * Authenticates an user, and constructs an User object to represent
670 |  |
          * him/her.
671 |  |
          *
672 |  |
          * @param username The user name.
673 |  |
          * @param password The user password.
674 |  |
          * @return An authenticated Turbine User.
675 |  |
          * @throws PasswordMismatchException if the supplied password was incorrect.
676 |  |
          * @throws UnknownEntityException if the user's account does not
677 |  |
          *            exist in the database.
678 |  |
          * @throws DataBackendException if there is a problem accessing the storage.
679 |  |
          */
680 |  |
         public User getAuthenticatedUser(String username, String password)
681 |  |
                 throws DataBackendException, UnknownEntityException,
682 |  |
                        PasswordMismatchException
683 |  |
         {
684 | 2 |
             return getUserManager().retrieve(username, password);
685 |  |
         }
686 |  |
687 |  |
         /**
688 |  |
          * Constructs an User object to represent a registered user of the
689 |  |
          * application.
690 |  |
          *
691 |  |
          * @param username The user name.
692 |  |
          * @return A Turbine User.
693 |  |
          * @throws UnknownEntityException if the user's account does not exist
694 |  |
          * @throws DataBackendException if there is a problem accessing the storage.
695 |  |
          */
696 |  |
         public User getUser(String username)
697 |  |
                 throws DataBackendException, UnknownEntityException
698 |  |
         {
699 | 0 |
             return getUserManager().retrieve(username);
700 |  |
         }
701 |  |
702 |  |
703 |  |
         /**
704 |  |
          * Constructs an User object to represent an anonymous user of the
705 |  |
          * application.
706 |  |
          *
707 |  |
          * @return An anonymous Turbine User.
708 |  |
          * @throws UnknownEntityException if the implementation of User interface
709 |  |
          *         could not be determined, or does not exist.
710 |  |
          */
711 |  |
         public User getAnonymousUser()
712 |  |
                 throws UnknownEntityException
713 |  |
         {
714 | 4 |
             User user = getUserInstance();
715 | 4 |
             user.setName("");
716 | 4 |
             return user;
717 |  |
         }
718 |  |
719 |  |
         /**
720 |  |
          * Checks whether a passed user object matches the anonymous user pattern
721 |  |
          * according to the configured user manager
722 |  |
          *
723 |  |
          * @param user An user object
724 |  |
          *
725 |  |
          * @return True if this is an anonymous user
726 |  |
          *
727 |  |
          */
728 |  |
         public boolean isAnonymousUser(User user)
729 |  |
         {
730 |  |
             // Either just null, the name is null or the name is the empty string
731 | 20 |
             return (user == null) || StringUtils.isEmpty(user.getName());
732 |  |
         }
733 |  |
734 |  |
         /**
735 |  |
          * Saves User's data in the permanent storage. The user account is required
736 |  |
          * to exist in the storage.
737 |  |
          *
738 |  |
          * @param user the User object to save
739 |  |
          * @throws UnknownEntityException if the user's account does not
740 |  |
          *         exist in the database.
741 |  |
          * @throws DataBackendException if there is a problem accessing the storage.
742 |  |
          */
743 |  |
         public void saveUser(User user)
744 |  |
                 throws UnknownEntityException, DataBackendException
745 |  |
         {
746 | 0 |
             getUserManager().store(user);
747 | 0 |
         }
748 |  |
749 |  |
         /**
750 |  |
          * Saves User data when the session is unbound. The user account is required
751 |  |
          * to exist in the storage.
752 |  |
          *
753 |  |
          * LastLogin, AccessCounter, persistent pull tools, and any data stored
754 |  |
          * in the permData hashtable that is not mapped to a column will be saved.
755 |  |
          *
756 |  |
          * @exception UnknownEntityException if the user's account does not
757 |  |
          *            exist in the database.
758 |  |
          * @exception DataBackendException if there is a problem accessing the
759 |  |
          *            storage.
760 |  |
          */
761 |  |
         public void saveOnSessionUnbind(User user)
762 |  |
                 throws UnknownEntityException, DataBackendException
763 |  |
         {
764 | 0 |
             userManager.saveOnSessionUnbind(user);
765 | 0 |
         }
766 |  |
767 |  |
         /**
768 |  |
          * Creates new user account with specified attributes.
769 |  |
          *
770 |  |
          * @param user the object describing account to be created.
771 |  |
          * @param password The password to use for the account.
772 |  |
          *
773 |  |
          * @throws DataBackendException if there was an error accessing the
774 |  |
          *         data backend.
775 |  |
          * @throws EntityExistsException if the user account already exists.
776 |  |
          */
777 |  |
         public void addUser(User user, String password)
778 |  |
                 throws DataBackendException, EntityExistsException
779 |  |
         {
780 | 0 |
             getUserManager().createAccount(user, password);
781 | 0 |
         }
782 |  |
783 |  |
         /**
784 |  |
          * Removes an user account from the system.
785 |  |
          *
786 |  |
          * @param user the object describing the account to be removed.
787 |  |
          * @throws DataBackendException if there was an error accessing the data
788 |  |
          *         backend.
789 |  |
          * @throws UnknownEntityException if the user account is not present.
790 |  |
          */
791 |  |
         public void removeUser(User user)
792 |  |
                 throws DataBackendException, UnknownEntityException
793 |  |
         {
794 |  |
             // revoke all roles form the user
795 | 0 |
             revokeAll(user);
796 |  |
797 | 0 |
             getUserManager().removeAccount(user);
798 | 0 |
         }
799 |  |
800 |  |
         /**
801 |  |
          * Change the password for an User.
802 |  |
          *
803 |  |
          * @param user an User to change password for.
804 |  |
          * @param oldPassword the current password supplied by the user.
805 |  |
          * @param newPassword the current password requested by the user.
806 |  |
          * @throws PasswordMismatchException if the supplied password was incorrect.
807 |  |
          * @throws UnknownEntityException if the user's record does not
808 |  |
          *            exist in the database.
809 |  |
          * @throws DataBackendException if there is a problem accessing the storage.
810 |  |
          */
811 |  |
         public void changePassword(User user, String oldPassword,
812 |  |
                 String newPassword)
813 |  |
                 throws PasswordMismatchException, UnknownEntityException,
814 |  |
                        DataBackendException
815 |  |
         {
816 | 0 |
             getUserManager().changePassword(user, oldPassword, newPassword);
817 | 0 |
         }
818 |  |
819 |  |
         /**
820 |  |
          * Forcibly sets new password for an User.
821 |  |
          *
822 |  |
          * This is supposed by the administrator to change the forgotten or
823 |  |
          * compromised passwords. Certain implementatations of this feature
824 |  |
          * would require administrative level access to the authenticating
825 |  |
          * server / program.
826 |  |
          *
827 |  |
          * @param user an User to change password for.
828 |  |
          * @param password the new password.
829 |  |
          * @throws UnknownEntityException if the user's record does not
830 |  |
          *            exist in the database.
831 |  |
          * @throws DataBackendException if there is a problem accessing the storage.
832 |  |
          */
833 |  |
         public void forcePassword(User user, String password)
834 |  |
                 throws UnknownEntityException, DataBackendException
835 |  |
         {
836 | 0 |
             getUserManager().forcePassword(user, password);
837 | 0 |
         }
838 |  |
839 |  |
         /**
840 |  |
          * Acquire a shared lock on the security information repository.
841 |  |
          *
842 |  |
          * Methods that read security information need to invoke this
843 |  |
          * method at the beginning of their body.
844 |  |
          */
845 |  |
         protected synchronized void lockShared()
846 |  |
         {
847 | 0 |
             readerCount++;
848 | 0 |
         }
849 |  |
850 |  |
         /**
851 |  |
          * Release a shared lock on the security information repository.
852 |  |
          *
853 |  |
          * Methods that read security information need to invoke this
854 |  |
          * method at the end of their body.
855 |  |
          */
856 |  |
         protected synchronized void unlockShared()
857 |  |
         {
858 | 0 |
             readerCount--;
859 | 0 |
             this.notify();
860 | 0 |
         }
861 |  |
862 |  |
         /**
863 |  |
          * Acquire an exclusive lock on the security information repository.
864 |  |
          *
865 |  |
          * Methods that modify security information need to invoke this
866 |  |
          * method at the beginning of their body. Note! Those methods must
867 |  |
          * be <code>synchronized</code> themselves!
868 |  |
          */
869 |  |
         protected void lockExclusive()
870 |  |
         {
871 | 0 |
             while (readerCount > 0)
872 |  |
             {
873 |  |
                 try
874 |  |
                 {
875 | 0 |
                     this.wait();
876 |  |
                 }
877 | 0 |
                 catch (InterruptedException e)
878 |  |
                 {
879 | 0 |
                 }
880 |  |
             }
881 | 0 |
         }
882 |  |
883 |  |
         /**
884 |  |
          * Release an exclusive lock on the security information repository.
885 |  |
          *
886 |  |
          * This method is provided only for completeness. It does not really
887 |  |
          * do anything. Note! Methods that modify security information
888 |  |
          * must be <code>synchronized</code>!
889 |  |
          */
890 |  |
         protected void unlockExclusive()
891 |  |
         {
892 |  |
             // do nothing
893 | 0 |
         }
894 |  |
895 |  |
         /**
896 |  |
          * Provides a reference to the Group object that represents the
897 |  |
          * <a href="#global">global group</a>.
898 |  |
          *
899 |  |
          * @return a Group object that represents the global group.
900 |  |
          */
901 |  |
         public Group getGlobalGroup()
902 |  |
         {
903 | 0 |
             if (globalGroup == null)
904 |  |
             {
905 | 0 |
                 synchronized (BaseSecurityService.class)
906 |  |
                 {
907 | 0 |
                     if (globalGroup == null)
908 |  |
                     {
909 |  |
                         try
910 |  |
                         {
911 | 0 |
                             globalGroup = getAllGroups()
912 |  |
                                     .getGroupByName(Group.GLOBAL_GROUP_NAME);
913 |  |
                         }
914 | 0 |
                         catch (DataBackendException e)
915 |  |
                         {
916 | 0 |
                             log.error("Failed to retrieve global group object: ", e);
917 | 0 |
                         }
918 |  |
                     }
919 | 0 |
                 }
920 |  |
             }
921 | 0 |
             return globalGroup;
922 |  |
         }
923 |  |
924 |  |
         /**
925 |  |
          * Retrieve a Group object with specified name.
926 |  |
          *
927 |  |
          * @param name the name of the Group.
928 |  |
          * @return an object representing the Group with specified name.
929 |  |
          * @throws DataBackendException if there was an error accessing the
930 |  |
          *         data backend.
931 |  |
          * @throws UnknownEntityException if the group does not exist.
932 |  |
          */
933 |  |
         public Group getGroupByName(String name)
934 |  |
                 throws DataBackendException, UnknownEntityException
935 |  |
         {
936 | 0 |
             Group group = getAllGroups().getGroupByName(name);
937 | 0 |
             if (group == null)
938 |  |
             {
939 | 0 |
                 throw new UnknownEntityException(
940 |  |
                         "The specified group does not exist");
941 |  |
             }
942 | 0 |
             return group;
943 |  |
         }
944 |  |
945 |  |
         /**
946 |  |
          * Retrieve a Group object with specified Id.
947 |  |
          *
948 |  |
          * @param id the id of the Group.
949 |  |
          * @return an object representing the Group with specified name.
950 |  |
          * @throws UnknownEntityException if the permission does not
951 |  |
          *            exist in the database.
952 |  |
          * @throws DataBackendException if there is a problem accessing the
953 |  |
          *            storage.
954 |  |
          */
955 |  |
         public Group getGroupById(int id)
956 |  |
                 throws DataBackendException, UnknownEntityException
957 |  |
         {
958 | 0 |
             Group group = getAllGroups().getGroupById(id);
959 | 0 |
             if (group == null)
960 |  |
             {
961 | 0 |
                 throw new UnknownEntityException(
962 |  |
                         "The specified group does not exist");
963 |  |
             }
964 | 0 |
             return group;
965 |  |
         }
966 |  |
967 |  |
         /**
968 |  |
          * Retrieve a Role object with specified name.
969 |  |
          *
970 |  |
          * @param name the name of the Role.
971 |  |
          * @return an object representing the Role with specified name.
972 |  |
          * @throws DataBackendException if there was an error accessing the
973 |  |
          *         data backend.
974 |  |
          * @throws UnknownEntityException if the role does not exist.
975 |  |
          */
976 |  |
         public Role getRoleByName(String name)
977 |  |
                 throws DataBackendException, UnknownEntityException
978 |  |
         {
979 | 0 |
             Role role = getAllRoles().getRoleByName(name);
980 | 0 |
             if (role == null)
981 |  |
             {
982 | 0 |
                 throw new UnknownEntityException(
983 |  |
                         "The specified role does not exist");
984 |  |
             }
985 | 0 |
             role.setPermissions(getPermissions(role));
986 | 0 |
             return role;
987 |  |
         }
988 |  |
989 |  |
         /**
990 |  |
          * Retrieve a Role object with specified Id.
991 |  |
          * @param id the id of the Role.
992 |  |
          * @return an object representing the Role with specified name.
993 |  |
          * @throws UnknownEntityException if the permission does not
994 |  |
          *            exist in the database.
995 |  |
          * @throws DataBackendException if there is a problem accessing the
996 |  |
          *            storage.
997 |  |
          */
998 |  |
         public Role getRoleById(int id)
999 |  |
                 throws DataBackendException,
1000 |  |
                        UnknownEntityException
1001 |  |
         {
1002 | 0 |
             Role role = getAllRoles().getRoleById(id);
1003 | 0 |
             if (role == null)
1004 |  |
             {
1005 | 0 |
                 throw new UnknownEntityException(
1006 |  |
                         "The specified role does not exist");
1007 |  |
             }
1008 | 0 |
             role.setPermissions(getPermissions(role));
1009 | 0 |
             return role;
1010 |  |
         }
1011 |  |
1012 |  |
         /**
1013 |  |
          * Retrieve a Permission object with specified name.
1014 |  |
          *
1015 |  |
          * @param name the name of the Permission.
1016 |  |
          * @return an object representing the Permission with specified name.
1017 |  |
          * @throws DataBackendException if there was an error accessing the
1018 |  |
          *         data backend.
1019 |  |
          * @throws UnknownEntityException if the permission does not exist.
1020 |  |
          */
1021 |  |
         public Permission getPermissionByName(String name)
1022 |  |
                 throws DataBackendException, UnknownEntityException
1023 |  |
         {
1024 | 0 |
             Permission permission = getAllPermissions().getPermissionByName(name);
1025 | 0 |
             if (permission == null)
1026 |  |
             {
1027 | 0 |
                 throw new UnknownEntityException(
1028 |  |
                         "The specified permission does not exist");
1029 |  |
             }
1030 | 0 |
             return permission;
1031 |  |
         }
1032 |  |
1033 |  |
         /**
1034 |  |
          * Retrieve a Permission object with specified Id.
1035 |  |
          *
1036 |  |
          * @param id the id of the Permission.
1037 |  |
          * @return an object representing the Permission with specified name.
1038 |  |
          * @throws UnknownEntityException if the permission does not
1039 |  |
          *            exist in the database.
1040 |  |
          * @throws DataBackendException if there is a problem accessing the
1041 |  |
          *            storage.
1042 |  |
          */
1043 |  |
         public Permission getPermissionById(int id)
1044 |  |
                 throws DataBackendException,
1045 |  |
                        UnknownEntityException
1046 |  |
         {
1047 | 0 |
             Permission permission = getAllPermissions().getPermissionById(id);
1048 | 0 |
             if (permission == null)
1049 |  |
             {
1050 | 0 |
                 throw new UnknownEntityException(
1051 |  |
                         "The specified permission does not exist");
1052 |  |
             }
1053 | 0 |
             return permission;
1054 |  |
         }
1055 |  |
1056 |  |
         /**
1057 |  |
          * Retrieves all groups defined in the system.
1058 |  |
          *
1059 |  |
          * @return the names of all groups defined in the system.
1060 |  |
          * @throws DataBackendException if there was an error accessing the
1061 |  |
          *         data backend.
1062 |  |
          */
1063 |  |
         public abstract GroupSet getAllGroups()
1064 |  |
                 throws DataBackendException;
1065 |  |
1066 |  |
         /**
1067 |  |
          * Retrieves all roles defined in the system.
1068 |  |
          *
1069 |  |
          * @return the names of all roles defined in the system.
1070 |  |
          * @throws DataBackendException if there was an error accessing the
1071 |  |
          *         data backend.
1072 |  |
          */
1073 |  |
         public abstract RoleSet getAllRoles()
1074 |  |
                 throws DataBackendException;
1075 |  |
1076 |  |
         /**
1077 |  |
          * Retrieves all permissions defined in the system.
1078 |  |
          *
1079 |  |
          * @return the names of all roles defined in the system.
1080 |  |
          * @throws DataBackendException if there was an error accessing the
1081 |  |
          *         data backend.
1082 |  |
          */
1083 |  |
         public abstract PermissionSet getAllPermissions()
1084 |  |
                 throws DataBackendException;
1085 |  |
     }