View Javadoc

1   /*
2    * <cvs:source>$Source: /devel/astrogrid/community/server/src/java/org/astrogrid/community/server/security/service/SecurityServiceImpl.java,v $</cvs:source>
3    * <cvs:author>$Author: dave $</cvs:author>
4    * <cvs:date>$Date: 2004/09/16 23:18:08 $</cvs:date>
5    * <cvs:version>$Revision: 1.12 $</cvs:version>
6    *
7    * <cvs:log>
8    *   $Log: SecurityServiceImpl.java,v $
9    *   Revision 1.12  2004/09/16 23:18:08  dave
10   *   Replaced debug logging in Community.
11   *   Added stream close() to FileStore.
12   *
13   *   Revision 1.11.82.1  2004/09/16 09:58:48  dave
14   *   Replaced debug with commons logging ....
15   *
16   *   Revision 1.11  2004/06/18 13:45:20  dave
17   *   Merged development branch, dave-dev-200406081614, into HEAD
18   *
19   *   Revision 1.10.18.2  2004/06/17 15:24:31  dave
20   *   Removed unused imports (PMD report).
21   *
22   *   Revision 1.10.18.1  2004/06/17 13:38:59  dave
23   *   Tidied up old CVS log entries
24   *
25   * </cvs:log>
26   *
27   */
28  package org.astrogrid.community.server.security.service ;
29  
30  import org.apache.commons.logging.Log ;
31  import org.apache.commons.logging.LogFactory ;
32  
33  import java.util.Vector ;
34  
35  import java.rmi.server.UID ;
36  
37  import org.exolab.castor.jdo.Database;
38  import org.exolab.castor.jdo.ObjectNotFoundException ;
39  
40  import org.astrogrid.store.Ivorn ;
41  
42  import org.astrogrid.community.server.security.data.PasswordData ;
43  import org.astrogrid.community.common.security.data.SecurityToken ;
44  import org.astrogrid.community.common.security.service.SecurityService ;
45  
46  import org.astrogrid.community.common.ivorn.CommunityIvornParser ;
47  import org.astrogrid.community.common.ivorn.CommunityAccountIvornFactory ;
48  
49  import org.astrogrid.community.server.service.CommunityServiceImpl ;
50  import org.astrogrid.community.server.database.configuration.DatabaseConfiguration ;
51  
52  import org.astrogrid.community.common.exception.CommunityServiceException  ;
53  import org.astrogrid.community.common.exception.CommunitySecurityException ;
54  import org.astrogrid.community.common.exception.CommunityIdentifierException  ;
55  
56  /***
57   * Implementation of our SecurityService service.
58   *
59   */
60  public class SecurityServiceImpl
61      extends CommunityServiceImpl
62      implements SecurityService
63      {
64      /***
65       * Our debug logger.
66       *
67       */
68      private static Log log = LogFactory.getLog(SecurityServiceImpl.class);
69  
70      /***
71       * Public constructor, using default database configuration.
72       *
73       */
74      public SecurityServiceImpl()
75          {
76          super() ;
77          }
78  
79      /***
80       * Public constructor, using specific database configuration.
81       *
82       */
83      public SecurityServiceImpl(DatabaseConfiguration config)
84          {
85          super(config) ;
86          }
87  
88      /***
89       * Public constructor, using a parent service.
90       *
91       */
92      public SecurityServiceImpl(CommunityServiceImpl parent)
93          {
94          super(parent) ;
95          }
96  
97      /***
98       * Generate a new token for an account.
99       * @param account The Account ident.
100      * @throws CommunityIdentifierException If the identifiers are not valid.
101      * @throws CommunityServiceException If the local Community identifier is not set.
102      *
103      */
104     protected SecurityToken createToken(CommunityIvornParser account)
105         throws CommunityServiceException, CommunityIdentifierException
106         {
107         log.debug("") ;
108         log.debug("----\"----") ;
109         log.debug("SecurityServiceImpl.createToken()") ;
110         //
111         // Create a new UID.
112         UID uid = new UID() ;
113         //
114         // Create an Ivorn for the token.
115         Ivorn ivorn = CommunityAccountIvornFactory.createLocal(
116             uid.toString()
117             ) ;
118         //
119         // Issue a new Security token to the account.
120         SecurityToken token = new SecurityToken(
121             account.getAccountIdent(),
122             ivorn.toString()
123             ) ;
124         //
125         // Mark the token as valid.
126         token.setStatus(SecurityToken.VALID_TOKEN) ;
127         //
128         // Return the new token.
129         log.debug("  Token : " + token) ;
130         return token ;
131         }
132 
133     /***
134      * Check an Account password.
135      * @param account  The account ident.
136      * @param password The account password.
137      * @return A valid SecurityToken if the ident and password are valid.
138      * @throws CommunitySecurityException If the security check fails.
139      * @throws CommunityServiceException If there is an internal error in service.
140      * @throws CommunityIdentifierException If the account identifier is invalid.
141      * @todo Check Account is local.
142      *
143      */
144     public SecurityToken checkPassword(String account, String password)
145         throws CommunityServiceException, CommunitySecurityException, CommunityIdentifierException
146         {
147         log.debug("") ;
148         log.debug("----\"----") ;
149         log.debug("SecurityServiceImpl.checkPassword()") ;
150         log.debug("  Ident : " + account) ;
151         log.debug("  Pass  : " + password) ;
152         //
153         // Check for null account.
154         if (null == account)
155             {
156             throw new CommunityIdentifierException(
157                 "Null account"
158                 ) ;
159             }
160         //
161         // Check for null password.
162         if (null == password)
163             {
164             throw new CommunityIdentifierException(
165                 "Null password"
166                 ) ;
167             }
168         //
169         // Get the Account ident.
170         CommunityIvornParser ident = new CommunityIvornParser(
171             account
172             ) ;
173         //
174         // Try searching the database.
175         SecurityToken token = null ;
176         Database database = null ;
177         try {
178             //
179             // Open our database connection.
180             database = this.getDatabase() ;
181             //
182             // Begin a new database transaction.
183             database.begin();
184             //
185             // Try to load a matching PasswordData.
186             PasswordData match = (PasswordData) database.load(PasswordData.class, ident.getAccountIdent()) ;
187             log.debug("  PASS : Got password data") ;
188             log.debug("    Account  : " + match.getAccount()) ;
189             log.debug("    Password : " + match.getPassword()) ;
190             //
191             // Check if the password matches.
192             if (password.equals(match.getPassword()))
193                 {
194                 log.debug("  PASS : Password matches") ;
195                 //
196                 // Create our new SecurityToken.
197                 token = this.createToken(ident) ;
198                 database.create(token);
199                 log.debug("  PASS : Got new token") ;
200                 //
201                 // Commit the database transaction.
202                 database.commit() ;
203                 }
204             //
205             // If the password don't match.
206             else {
207                 //
208                 // Throw a new Exception.
209                 throw new CommunitySecurityException(
210                     "Password invalid",
211                     ident.getAccountIdent()
212                     ) ;
213                 }
214             }
215         //
216         // If the password check failed.
217         catch (CommunitySecurityException ouch)
218             {
219             //
220             // Cancel the database transaction.
221             rollbackTransaction(database) ;
222             //
223             // Throw the Exception.
224             throw ouch ;
225             }
226         //
227         // If we couldn't find the object.
228         catch (ObjectNotFoundException ouch)
229             {
230             //
231             // Cancel the database transaction.
232             rollbackTransaction(database) ;
233             //
234             // Throw a new Exception.
235             throw new CommunitySecurityException(
236                 "Account password not found",
237                 ident.toString()
238                 ) ;
239             }
240         //
241         // If anything else went bang.
242         catch (Exception ouch)
243             {
244             //
245             // Log the exception.
246             logException(
247                 ouch,
248                 "SecurityServiceImpl.checkPassword()"
249                 ) ;
250             //
251             // Cancel the database transaction.
252             rollbackTransaction(database) ;
253             //
254             // Throw a new Exception.
255             throw new CommunityServiceException(
256                 "Database transaction failed",
257                 ident.toString(),
258                 ouch
259                 ) ;
260             }
261         //
262         // Close our database connection.
263         finally
264             {
265             closeConnection(database) ;
266             }
267         //
268         // Return the new token.
269         return token ;
270         }
271 
272     /***
273      * Validate a SecurityToken.
274      * Validates a token, and creates a new tokens issued to the same account.
275      * @param token The token to validate.
276      * @return A new SecurityToken if the original was valid.
277      * @throws CommunitySecurityException If the security check fails.
278      * @throws CommunityServiceException If there is an internal error in service.
279      * @throws CommunityIdentifierException If the token is invalid.
280      * @todo Refactor to call split and unpack ?
281      * @todo Check Token is local.
282      *
283      */
284     public SecurityToken checkToken(SecurityToken original)
285         throws CommunityServiceException, CommunitySecurityException, CommunityIdentifierException
286         {
287         log.debug("") ;
288         log.debug("----\"----") ;
289         log.debug("SecurityServiceImpl.checkToken()") ;
290         log.debug("  Token : " + original) ;
291         //
292         // Check for null token.
293         if (null == original)
294             {
295             throw new CommunityIdentifierException(
296                 "Null token"
297                 ) ;
298             }
299         //
300         // Mark the original as invalid.
301         original.setStatus(SecurityToken.INVALID_TOKEN) ;
302         //
303         // Get the token value.
304         CommunityIvornParser token = new CommunityIvornParser(
305             original.getToken()
306             ) ;
307         log.debug("  Token   : " + token) ;
308         //
309         // Get the Account ident.
310         CommunityIvornParser account = new CommunityIvornParser(
311             original.getAccount()
312             ) ;
313         log.debug("  Account : " + account) ;
314 
315         SecurityToken result = null ;
316         Database database = null ;
317         try {
318             //
319             // Open our database connection.
320             database = this.getDatabase() ;
321             //
322             // Begin a new database transaction.
323             database.begin();
324             //
325             // Try loading the original token from our database.
326             SecurityToken match = (SecurityToken) database.load(SecurityToken.class, original.getToken()) ;
327             log.debug("  PASS : Got matching token") ;
328             log.debug("  Token : " + match) ;
329             //
330             // If the match is still valid.
331             if (match.isValid())
332                 {
333                 log.debug("  PASS : Original is valid") ;
334                 //
335                 // Update the original token.
336 // Mark as used not invalid.
337                 match.setStatus(SecurityToken.INVALID_TOKEN) ;
338                 //
339                 // Create a new token.
340                 result = this.createToken(account) ;
341                 database.create(result) ;
342                 //
343                 // Commit the database transaction.
344                 database.commit() ;
345                 //
346                 // Return the new token.
347                 return result ;
348                 }
349             //
350             // If the original is no longer valied.
351             else {
352                 log.debug("  FAIL : Original is not valid") ;
353                 //
354                 // Throw a new Exception.
355                 throw new CommunitySecurityException(
356                     "Token invalid",
357                     original.getToken()
358                     ) ;
359                 }
360             }
361         //
362         // If the password check failed.
363         catch (CommunitySecurityException ouch)
364             {
365             //
366             // Cancel the database transaction.
367             rollbackTransaction(database) ;
368             //
369             // Throw the Exception.
370             throw ouch ;
371             }
372         //
373         // If we couldn't find the object.
374         catch (ObjectNotFoundException ouch)
375             {
376             //
377             // Cancel the database transaction.
378             rollbackTransaction(database) ;
379             //
380             // Throw a new Exception.
381             throw new CommunitySecurityException(
382                 "Token not found",
383                 original.getToken()
384                 ) ;
385             }
386         //
387         // If anything else went bang.
388         catch (Exception ouch)
389             {
390             //
391             // Log the exception.
392             logException(
393                 ouch,
394                 "SecurityServiceImpl.checkToken()"
395                 ) ;
396             //
397             // Cancel the database transaction.
398             rollbackTransaction(database) ;
399             //
400             // Throw a new Exception.
401             throw new CommunityServiceException(
402                 "Database transaction failed",
403                 original.getToken(),
404                 ouch
405                 ) ;
406             }
407         //
408         // Close our database connection.
409         finally
410             {
411             closeConnection(database) ;
412             }
413         }
414 
415     /***
416      * Split a SecurityToken.
417      * Validates a token, and then creates a new set of tokens issued to the same account.
418      * @throws CommunitySecurityException If the security check fails.
419      * @throws CommunityServiceException If there is an internal error in service.
420      * @throws CommunityIdentifierException If the token is invalid.
421      * @todo Check Token is local.
422      *
423      */
424     public Object[] splitToken(SecurityToken original, int count)
425         throws CommunityServiceException, CommunitySecurityException, CommunityIdentifierException
426         {
427         log.debug("") ;
428         log.debug("----\"----") ;
429         log.debug("SecurityServiceImpl.checkToken()") ;
430         log.debug("  Token : " + original) ;
431         //
432         // Check for null token.
433         if (null == original)
434             {
435             throw new CommunityIdentifierException(
436                 "Null token"
437                 ) ;
438             }
439         //
440         // Mark the original as invalid.
441         original.setStatus(SecurityToken.INVALID_TOKEN) ;
442         //
443         // Get the token value.
444         CommunityIvornParser token = new CommunityIvornParser(
445             original.getToken()
446             ) ;
447         log.debug("  Token   : " + token) ;
448         //
449         // Get the Account ident.
450         CommunityIvornParser account = new CommunityIvornParser(
451             original.getAccount()
452             ) ;
453         log.debug("  Account : " + account) ;
454 
455         Vector vector = new Vector() ;
456         Database database = null ;
457         try {
458             //
459             // Open our database connection.
460             database = this.getDatabase() ;
461             //
462             // Begin a new database transaction.
463             database.begin();
464             //
465             // Try loading the original token from our database.
466             SecurityToken match = (SecurityToken) database.load(SecurityToken.class, original.getToken()) ;
467             log.debug("  PASS : Got matching token") ;
468             log.debug("  Token : " + match) ;
469             //
470             // If the match is still valid.
471             if (match.isValid())
472                 {
473                 log.debug("  PASS : Original is valid") ;
474                 //
475                 // Update the original token.
476 // Mark as used not invalid.
477                 match.setStatus(SecurityToken.INVALID_TOKEN) ;
478                 //
479                 // Create our new tokens.
480                 for (int i = 0 ; i < count ; i++)
481                     {
482                     SecurityToken result = this.createToken(account) ;
483                     database.create(result) ;
484                     vector.add(result) ;
485                     }
486                 //
487                 // Commit the database transaction.
488                 database.commit() ;
489                 }
490             //
491             // If the original is no longer valied.
492             else {
493                 log.debug("  FAIL : Original is not valid") ;
494                 //
495                 // Throw a new Exception.
496                 throw new CommunitySecurityException(
497                     "Token invalid",
498                     original.getToken()
499                     ) ;
500                 }
501             }
502         //
503         // If the password check failed.
504         catch (CommunitySecurityException ouch)
505             {
506             //
507             // Cancel the database transaction.
508             rollbackTransaction(database) ;
509             //
510             // Throw the Exception.
511             throw ouch ;
512             }
513         //
514         // If we couldn't find the object.
515         catch (ObjectNotFoundException ouch)
516             {
517             //
518             // Cancel the database transaction.
519             rollbackTransaction(database) ;
520             //
521             // Throw a new Exception.
522             throw new CommunitySecurityException(
523                 "Token not found",
524                 original.getToken()
525                 ) ;
526             }
527         //
528         // If anything else went bang.
529         catch (Exception ouch)
530             {
531             //
532             // Log the exception.
533             logException(
534                 ouch,
535                 "SecurityServiceImpl.checkToken()"
536                 ) ;
537             //
538             // Cancel the database transaction.
539             rollbackTransaction(database) ;
540             //
541             // Throw a new Exception.
542             throw new CommunityServiceException(
543                 "Database transaction failed",
544                 original.getToken(),
545                 ouch
546                 ) ;
547             }
548         //
549         // Close our database connection.
550         finally
551             {
552             closeConnection(database) ;
553             }
554         //
555         // Return the new token.
556         return vector.toArray() ;
557         }
558     }