View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *  
17   */
18  
19  package org.caleigo.security;
20  
21  import java.util.HashMap;
22  
23  import org.caleigo.service.*;
24  import org.caleigo.toolkit.log.*;
25  import org.caleigo.toolkit.tunnel.*;
26  
27  /***
28   *
29   * @author  Mattias Hagstrand
30   * @version 1.00
31   *
32   *//*
33    *
34    * WHEN        WHO               WHY & WHAT
35    * -----------------------------------------------------------------------------
36    * 2002-10-18  Mattias Hagstrand    Creation
37    */
38  public class LoginService implements ILoginService
39  {
40      // Data members ------------------------------------------------------------
41  //    protected transient ILoginHandler mLoginHandler;
42      protected Object mServiceIdentity;
43      protected transient IMessageConsumer mMessageConsumer;
44  
45      protected ILoginInfoProvider mLoginInfoProvider;
46      protected transient HashMap mLoginHandlers = new HashMap();
47      
48      // Constructors ------------------------------------------------------------
49      public LoginService(Object serviceIdentity)
50      {
51          mServiceIdentity = serviceIdentity;
52          mMessageConsumer = new LoginServiceMessageConsumer();
53      }
54          
55      // ILoginService implementation --------------------------------------------
56  
57      public void setLoginInfoProvider(ILoginInfoProvider provider)
58      {
59          mLoginInfoProvider = provider;
60      }
61      
62      public void addLoginHandler(Class loginInfoClass, ILoginHandler loginHandler)
63      {
64          mLoginHandlers.put(loginInfoClass, loginHandler);
65      }
66      
67      public void removeLoginHandler(Class loginInfoClass)
68      {
69          mLoginHandlers.remove(loginInfoClass);
70      }
71      
72  
73      /*** Tries to log in a user without supplying any login information. This
74       * method preferably uses descendants of <I>ILoginInfoProvider</I> to
75       * figure out the login information for the user. Returns <code>null</code>
76       * if the login was canceled.
77       */
78      public UserInfo login()
79      {
80          ILoginHandler loginHandler = (ILoginHandler) mLoginHandlers.get(UserLoginInfo.class);
81          if (loginHandler == null)
82              throw new SecurityException("No login handler found for: " + UserLoginInfo.class);
83   
84          if (mLoginInfoProvider == null)
85              throw new SecurityException("No login info provider found");
86          
87          Object loginInfo = mLoginInfoProvider.getUserLoginInformation();
88          
89          UserInfo userInfo = loginHandler.login(loginInfo);
90          
91          if (userInfo == null)
92              return null;
93          
94          SessionHandler.getInstance().createSession(userInfo);
95          return userInfo;
96      }
97      
98      /*** This method takes login information supplied in the <I>loginInfo</I> 
99       * object. There should be a corresponding <I>ILoginHandler</I> that 
100      * is registered to handle the specific <I>loginInfo</I> class. Returns <code>null</code>
101      * if the login was canceled.
102      */
103     public UserInfo login(Object loginInfo)
104     {
105         Log.print(this, "Login in on a LoginService containing " + mLoginHandlers.size() + " login handlers ");
106         
107         ILoginHandler loginHandler = (ILoginHandler) mLoginHandlers.get(loginInfo.getClass());
108         if (loginHandler == null)
109         {
110             String s = loginInfo.getClass().toString();
111             Log.printError(this, "No login handler found for: " + s);
112             Log.print(this, "You can choose between:");
113             java.util.Iterator results = mLoginHandlers.keySet().iterator();
114             while (results.hasNext() )
115             {
116                 Log.print(this, results.toString());
117             }
118             throw new SecurityException("No login handler found for: " + s);
119         }
120 
121         UserInfo userInfo = loginHandler.login(loginInfo);
122 
123         if (userInfo == null)
124             return null;
125         
126         SessionHandler.getInstance().createSession(userInfo);
127         return userInfo;
128     }
129     
130     /*** This is a helper method that logs in a user based on the supplied 
131      * username-password pair. Returns <code>null</code>
132      * if the login was canceled.
133      */
134     public UserInfo login(String username, String password)
135     {
136         UserLoginInfo userLoginInfo = new UserLoginInfo(username, password);
137         ILoginHandler loginHandler = (ILoginHandler) mLoginHandlers.get(userLoginInfo.getClass());
138         if (loginHandler == null)
139             throw new SecurityException("No login handler found for: " + userLoginInfo.getClass());
140        
141         UserInfo userInfo = loginHandler.login(userLoginInfo);
142         
143         if (userInfo == null)
144             return null;
145         
146         SessionHandler.getInstance().createSession(userInfo);
147         return userInfo;
148     }
149     
150     public boolean logout(UserInfo userInfo)
151     {
152         if (SessionHandler.getInstance().isValidSession(userInfo, userInfo.getSessionID()))
153         {
154             SessionHandler.getInstance().destroySession(userInfo.getSessionID());
155             return true;
156         }
157         return false;
158         
159     }
160     
161     /*** Updates an UserInfo object that represents an allready logged in user with
162      * relevante user information.
163      */
164     public void updateUserInfo(UserInfo userInfo)
165     {
166         // TODO !
167     }
168     
169     public void handleError(String message)
170     {
171         mLoginInfoProvider.handleError(message);
172     }
173     
174     /*** Returns the maximum number of times a user is allowed to try to login
175      * before the application exits.
176      */
177     public int getMaximumNumberOfLoginTries()
178     {
179         return mLoginInfoProvider.getMaximumNumberOfLoginTries();
180     }
181     
182     // IService implementation -------------------------------------------------
183     
184     /*** This method is always called by the ServiceManager before any other 
185      * method in the service is called. 
186      */ 
187     public void initializeService()
188     {
189     }
190     
191     /*** This method is always called by the ServiceManager before the service
192      * is released. No other method calls will then be performed on this
193      * instance of the service. 
194      */ 
195     public void finalizeService()
196     {
197     }
198     
199     /*** Should return true if the service is online and reponding to calls.
200      * Note that initializeService() must be called prior to this method.
201      */ 
202     public boolean ping()
203     {
204         // TEMPORARY SOLUTION !
205         return (mLoginInfoProvider != null);
206     }
207     
208     /*** Returns the service object that this service provides. This object
209      * should always implement the interface defined by the service interface 
210      * class.
211      */
212     public Object getServiceInterface()
213     {
214         return this;
215     }
216     
217     /*** Returns the class object the defines the service interface that all 
218      * services with the same type provides.
219      */
220     public Class getServiceInterfaceClass()
221     {
222         return ILoginService.class;
223     }
224     
225     /*** Returns a URI that defines the type of this service. Note that
226      * there can be multiple services implementing the same service type but 
227      * implementations of a given type must implement the same service
228      * interface. 
229      */
230     public Object getServiceType()
231     {
232         return ILoginService.class;
233     }
234     
235     /*** Returns the URI defining the a unique individual service. 
236      */ 
237     public Object getServiceIdentity()
238     {
239         return mServiceIdentity;
240     }
241     
242     /*** If this method returns true then the method getCustomProxyService must
243      * not return <code>null</code>.
244      */
245     public boolean hasCustomProxyService()
246     {
247         return true;
248     }
249     
250     /*** Returns an IProxyService that is responsible for handling remote invokations
251      * of this service.
252      */
253     public IProxyService getCustomProxyService(org.caleigo.toolkit.tunnel.ITunnel tunnel)
254     {
255         LoginProxyService proxyService = new LoginProxyService(mServiceIdentity, tunnel);
256         proxyService.setLoginInfoProvider(mLoginInfoProvider);
257         tunnel.addMessageConsumer(mMessageConsumer);
258         return proxyService;
259     }
260     
261     // Nested classes ----------------------------------------------------------
262     protected static class LoginProxyService extends LoginService implements IProxyService
263     {
264         // Data members --------------------------------------------------------
265         protected transient ITunnel mTunnel;
266         
267         // Constructors --------------------------------------------------------
268         public LoginProxyService(Object serviceIdentity, ITunnel tunnel)
269         {
270             super(serviceIdentity);
271             mTunnel = tunnel;
272         }
273         
274         // Superclass overrides ------------------------------------------------
275         
276         /*** Tries to log in a user without supplying any login information. This
277          * method preferably uses descendants of <I>ILoginInfoProvider</I> to
278          * figure out the login information for the user. 
279          */
280         public UserInfo login()
281         {
282 //            ILoginHandler loginHandler = (ILoginHandler) mLoginHandlers.get(UserLoginInfo.class);
283 //            if (loginHandler == null)
284 //                throw new SecurityException("No login handler found for: " + UserLoginInfo.class);
285 //            if (mLoginInfoProvider == null)
286 //                throw new SecurityException("No login info provider found");
287 
288             Object loginInfo = mLoginInfoProvider.getUserLoginInformation();
289             if (loginInfo == null)
290                 return null;
291             
292             if (!(loginInfo instanceof UserLoginInfo))
293                throw new SecurityException("The login information has to be of type org.caleigo.security.ILoginService.UserLoginInfo");
294                  
295             UserLoginInfo userLoginInfo = (UserLoginInfo) loginInfo;
296             
297             LoginServiceReturnMessage returnMessage = null;
298             try
299             {
300                 returnMessage = (LoginServiceReturnMessage) mTunnel.ask(
301                     new LoginMessage(userLoginInfo.getUsername(), userLoginInfo.getPassword()));
302             }
303             catch (TunnelException te)
304             {
305                 Log.printError(this, "Received exception from tunnel", te);
306                 throw new SecurityException("Received exception from tunnel: " + te.getMessage());
307             }
308             
309             if (returnMessage.getException() != null)
310             {
311                 if (returnMessage.getException() instanceof SecurityException)
312                     throw (SecurityException) returnMessage.getException();
313                 else
314                 {
315                     Log.printError(this, "Unknown exception from login service", returnMessage.getException());
316                     return null;
317                 }
318             }
319 
320             UserInfo userInfo = new UserInfo.DefaultUserInfo();
321             userInfo.copyFrom(returnMessage.getUserInfo());
322             return userInfo;
323         }
324         
325         public boolean logout(UserInfo userInfo) throws SecurityException
326         {
327             LoginServiceReturnMessage returnMessage = null;
328             try
329             {
330                 returnMessage = (LoginServiceReturnMessage) mTunnel.ask(new LogoutMessage(userInfo, userInfo.getSessionID()));
331             }
332             catch (TunnelException te)
333             {
334                 Log.printError(this, "Received exception from tunnel", te);
335                 throw new SecurityException("Received exception from tunnel: " + te.getMessage());
336             }
337             
338             if (returnMessage.getException() != null)
339                 if (returnMessage.getException() instanceof SecurityException)
340                     throw (SecurityException) returnMessage.getException();
341                 else
342                 {
343                     Log.printError(this, "Unknown exception from login service", returnMessage.getException());
344                     return false;
345                 }
346             
347             return returnMessage.getResult();
348         }
349         
350         public void handleError(String message)
351         {
352             mLoginInfoProvider.handleError(message);
353         }
354         
355         // IProxyService implementation ----------------------------------------
356         
357         /*** Returns <code>true</code> if this IProxyService can be reconnected to
358          * an IService.
359          */
360         public boolean isReconnectable()
361         {
362             return false;
363         }
364 
365         /*** Tries to reconnect to the provided service. If the reconnection fails
366          * or if this IProxyService doesn't support reconnection an exception is
367          * thrown.
368          */
369         public void reconnect(org.caleigo.toolkit.tunnel.ITunnel tunnel) throws ServiceException
370         {
371             throw new ServiceException("Operation not supported");
372         }
373 
374         /*** Sets the ITunnel that should be used by this IProxyService.
375          */
376         public void setServiceTunnel(org.caleigo.toolkit.tunnel.ITunnel tunnel)
377         {
378             mTunnel = tunnel;
379         }
380     }
381     
382     protected class LoginServiceMessageConsumer implements IMessageConsumer
383     {
384         // Constructors --------------------------------------------------------
385         public LoginServiceMessageConsumer()
386         {
387         }
388         
389         // IMessageConsumer implementation -------------------------------------
390         
391         /***
392          * Returns <code>true</code> if this IMessageConsumer accepts the message.
393          * This method is allways called before <code>consumeMessage</code> for any
394          * given message.
395          */
396         public boolean acceptsMessage(Object message)
397         {
398             return (message instanceof LoginMessage || message instanceof LogoutMessage);
399         }
400 
401         /***
402          * Tells the IMessageConsumer to consume a message.
403          */
404         public void consumeMessage(Object message)
405         {
406         }
407 
408         /***
409          * Tells the IMessageConsumer to consume a message and returns a new message
410          * that will be delivered to the sender of the originial message.
411          */
412         public Object answerMessage(Object message)
413         {
414             try
415             {
416                 if (message instanceof LoginMessage)
417                 {
418                     UserInfo userInfo = login(((LoginMessage) message).getUserID(),
419                                               ((LoginMessage) message).getPassword());
420                     return new LoginServiceReturnMessage(userInfo, (userInfo != null), null);
421                 }
422                 else
423                 {
424                     // TODO: handle logging out
425                 }
426             }
427             catch (Throwable t)
428             {
429                 return new LoginServiceReturnMessage(null, false, t);
430             }
431             
432             return null;
433         }
434     }
435 }