View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.security;
35  
36  import fr.paris.lutece.portal.service.datastore.DatastoreService;
37  import fr.paris.lutece.portal.service.init.LuteceInitException;
38  import fr.paris.lutece.portal.service.util.AppLogService;
39  import fr.paris.lutece.portal.service.util.AppPropertiesService;
40  import fr.paris.lutece.util.url.UrlItem;
41  
42  import java.security.Principal;
43  
44  import java.util.Collection;
45  import java.util.Enumeration;
46  
47  import javax.security.auth.login.LoginException;
48  
49  import javax.servlet.http.HttpServletRequest;
50  import javax.servlet.http.HttpSession;
51  
52  
53  /**
54   * This class provides a security service to register and check user
55   * authentication
56   */
57  public final class SecurityService
58  {
59      /**
60       * Session attribute that stores the LuteceUser object attached to the
61       * session
62       */
63      private static final String ATTRIBUTE_LUTECE_USER = "lutece_user";
64      private static final String PROPERTY_AUTHENTICATION_CLASS = "mylutece.authentication.class";
65      private static final String PROPERTY_AUTHENTICATION_ENABLE = "mylutece.authentication.enable";
66      private static final String PROPERTY_PORTAL_AUTHENTICATION_REQUIRED = "mylutece.portal.authentication.required";
67      private static final String URL_INTERROGATIVE = "?";
68      private static final String URL_AMPERSAND = "&";
69      private static final String URL_EQUAL = "=";
70      private static SecurityService _singleton = new SecurityService(  );
71      private static LuteceAuthentication _authenticationService;
72      private static boolean _bEnable;
73  
74      /**
75       * Private constructor
76       */
77      private SecurityService(  )
78      {
79      }
80  
81      /**
82       * Initialize service
83       * @throws LuteceInitException if an error occurs
84       */
85      public static synchronized void init(  ) throws LuteceInitException
86      {
87          _bEnable = false;
88  
89          String strEnable = AppPropertiesService.getProperty( PROPERTY_AUTHENTICATION_ENABLE, "false" );
90  
91          if ( strEnable.equalsIgnoreCase( "true" ) )
92          {
93              _authenticationService = getPortalAuthentication(  );
94  
95              if ( _authenticationService != null )
96              {
97                  _bEnable = true;
98              }
99          } else
100         {
101             // in case authentication is disabled after having been enabled
102             _authenticationService = null;
103         }
104     }
105 
106     /**
107      * Get the unique instance of the Security Service
108      * @return The instance
109      */
110     public static SecurityService getInstance(  )
111     {
112         return _singleton;
113     }
114 
115     /**
116      * Returns the authentication's activation : enable or disable
117      * @return true if the authentication is active, false otherwise
118      */
119     public static boolean isAuthenticationEnable(  )
120     {
121         return _bEnable;
122     }
123 
124     /**
125      * Gets the LuteceUser attached to the current Http session
126      * @param request The Http request
127      * @return A LuteceUser object if found
128      * @throws UserNotSignedException If there is no current user
129      */
130     public LuteceUser getRemoteUser( HttpServletRequest request )
131         throws UserNotSignedException
132     {
133         LuteceUser user = getRegisteredUser( request );
134 
135         if ( user == null )
136         {
137             // User is not registered by Lutece, but it may be authenticated by another system
138             if ( _authenticationService.isExternalAuthentication(  ) ||
139                     _authenticationService.isMultiAuthenticationSupported(  ) )
140             {
141                 user = _authenticationService.getHttpAuthenticatedUser( request );
142 
143                 if ( ( user == null ) && isPortalAuthenticationRequired(  ) )
144                 {
145                     throw new UserNotSignedException(  );
146                 }
147 
148                 registerUser( request, user );
149             }
150             else
151             {
152                 throw new UserNotSignedException(  );
153             }
154         }
155 
156         return user;
157     }
158 
159     /**
160      * Returns the user's principal
161      * @param request The HTTP request
162      * @return The user's principal
163      * @throws UserNotSignedException The UserNotSignedException
164      */
165     public Principal getUserPrincipal( HttpServletRequest request )
166         throws UserNotSignedException
167     {
168         return getRemoteUser( request );
169     }
170 
171     /**
172      * Checks if the user is associated to a given role
173      * @param request The Http request
174      * @param strRole The Role name
175      * @return Returns true if the user is associated to the given role
176      */
177     public boolean isUserInRole( HttpServletRequest request, String strRole )
178     {
179         LuteceUser user;
180 
181         try
182         {
183             user = getRemoteUser( request );
184         }
185         catch ( UserNotSignedException e )
186         {
187             return false;
188         }
189 
190         return _authenticationService.isUserInRole( user, request, strRole );
191     }
192 
193     /**
194      * get all roles for this user : - user's roles - user's groups roles
195      *
196      * @param user The user
197      * @return Array of roles
198      */
199     public String[] getRolesByUser( LuteceUser user )
200     {
201         return _authenticationService.getRolesByUser( user );
202     }
203 
204     /**
205      * Checks user's login with the Authentication service.
206      * @param request The Http request
207      * @param strUserName The user's login
208      * @param strPassword The user's password
209      * @throws LoginException The LoginException
210      * @throws LoginRedirectException if redirect exception
211      */
212     public void loginUser( HttpServletRequest request, final String strUserName, final String strPassword )
213         throws LoginException, LoginRedirectException
214     {
215         LuteceUser user = _authenticationService.login( strUserName, strPassword, request );
216         _authenticationService.updateDateLastLogin( user, request );
217 
218         if ( _authenticationService.findResetPassword( request, strUserName ) )
219         {
220             String redirect = _authenticationService.getResetPasswordPageUrl( request );
221             registerUser( request, user );
222             throw new LoginRedirectException( redirect );
223         }
224 
225         registerUser( request, user );
226     }
227 
228     /**
229      * Logout the user
230      * @param request The HTTP request
231      */
232     public void logoutUser( HttpServletRequest request )
233     {
234         LuteceUser user;
235 
236         try
237         {
238             user = getRemoteUser( request );
239         }
240         catch ( UserNotSignedException e )
241         {
242             return;
243         }
244 
245         _authenticationService.logout( user );
246         unregisterUser( request );
247     }
248 
249     /**
250      * Retrieves the portal authentication service configured in the
251      * config.properties
252      * @return A PortalAuthentication object
253      * @throws LuteceInitException If an error occurred
254      */
255     private static LuteceAuthentication getPortalAuthentication(  )
256         throws LuteceInitException
257     {
258         String strAuthenticationClass = AppPropertiesService.getProperty( PROPERTY_AUTHENTICATION_CLASS );
259         LuteceAuthentication authentication = null;
260 
261         if ( ( strAuthenticationClass != null ) && !strAuthenticationClass.equals( "" ) )
262         {
263             try
264             {
265                 authentication = (LuteceAuthentication) Class.forName( strAuthenticationClass ).newInstance(  );
266                 AppLogService.info( "Authentication service loaded : " + authentication.getAuthServiceName(  ) );
267             }
268             catch ( InstantiationException e )
269             {
270                 throw new LuteceInitException( "Error instantiating Authentication Class", e );
271             }
272             catch ( IllegalAccessException e )
273             {
274                 throw new LuteceInitException( "Error instantiating Authentication Class", e );
275             }
276             catch ( ClassNotFoundException e )
277             {
278                 throw new LuteceInitException( "Error instantiating Authentication Class", e );
279             }
280         }
281 
282         return authentication;
283     }
284 
285     /**
286      * Register the user in the Http session
287      * @param request The Http request
288      * @param user The current user
289      */
290     public void registerUser( HttpServletRequest request, LuteceUser user )
291     {
292         HttpSession session = request.getSession( true );
293         session.setAttribute( ATTRIBUTE_LUTECE_USER, user );
294     }
295 
296     /**
297      * Unregister the user in the Http session
298      * @param request The Http request
299      */
300     public void unregisterUser( HttpServletRequest request )
301     {
302         HttpSession session = request.getSession( true );
303         session.removeAttribute( ATTRIBUTE_LUTECE_USER );
304     }
305 
306     /**
307      * Gets the Lutece user registered in the Http session
308      * @param request The HTTP request
309      * @return The User registered or null if the user has not been registered
310      */
311     public LuteceUser getRegisteredUser( HttpServletRequest request )
312     {
313         HttpSession session = ( request != null ) ? request.getSession( false ) : null;
314 
315         if ( session != null )
316         {
317             return (LuteceUser) session.getAttribute( ATTRIBUTE_LUTECE_USER );
318         }
319 
320         return null;
321     }
322 
323     /**
324      * Returns the authentication type : External or Lutece portal based
325      * @return true if the user is already authenticated or false if it needs to
326      *         login.
327      */
328     public boolean isExternalAuthentication(  )
329     {
330         return _authenticationService.isExternalAuthentication(  );
331     }
332 
333     /**
334      * Returns the Login page URL of the Authentication Service
335      * @return The URL
336      */
337     public String getLoginPageUrl(  )
338     {
339         return _authenticationService.getLoginPageUrl(  );
340     }
341 
342     /**
343      * Returns the DoLogin URL of the Authentication Service
344      * @return The URL
345      */
346     public String getDoLoginUrl(  )
347     {
348         return _authenticationService.getDoLoginUrl(  );
349     }
350 
351     /**
352      * Returns the DoLogout URL of the Authentication Service
353      * @return The URL
354      */
355     public String getDoLogoutUrl(  )
356     {
357         return _authenticationService.getDoLogoutUrl(  );
358     }
359 
360     /**
361      * Returns the new account page URL of the Authentication Service
362      * @return The URL
363      */
364     public String getNewAccountPageUrl(  )
365     {
366         return _authenticationService.getNewAccountPageUrl(  );
367     }
368 
369     /**
370      * Returns the view account page URL of the Authentication Service
371      * @return The URL
372      */
373     public String getViewAccountPageUrl(  )
374     {
375         return _authenticationService.getViewAccountPageUrl(  );
376     }
377 
378     /**
379      * Returns the lost password URL of the Authentication Service
380      * @return The URL
381      */
382     public String getLostPasswordPageUrl(  )
383     {
384         return _authenticationService.getLostPasswordPageUrl(  );
385     }
386 
387     // Added in v1.3
388 
389     /**
390      * Returns the access denied template
391      * @return The template
392      */
393     public String getAccessDeniedTemplate(  )
394     {
395         return _authenticationService.getAccessDeniedTemplate(  );
396     }
397 
398     /**
399      * Returns the access controled template
400      * @return The template
401      */
402     public String getAccessControledTemplate(  )
403     {
404         return _authenticationService.getAccessControledTemplate(  );
405     }
406 
407     /**
408      * Returns whether or not the portal needs authentication
409      * @return true if the access needs authentication, otherwise
410      * @since 1.3.1
411      */
412     public boolean isPortalAuthenticationRequired(  )
413     {
414         String strAuthenticationRequired = DatastoreService.getDataValue( PROPERTY_PORTAL_AUTHENTICATION_REQUIRED,
415                 "false" );
416 
417         return strAuthenticationRequired.equals( "true" );
418     }
419 
420     /**
421      * Checks user's login with the Authentication service. Used during remote
422      * authentication validation We don't have to put user informations in
423      * session, since it is only used in external
424      * applications
425      * @param request the request
426      * @param strUserName The user's login
427      * @param strPassword The user's password
428      * @return user's informations
429      * @throws LoginException The LoginException
430      * @throws LoginRedirectException The redirect exception
431      */
432     public LuteceUser remoteLoginUser( final HttpServletRequest request, final String strUserName,
433         final String strPassword ) throws LoginException, LoginRedirectException
434     {
435         LuteceUser user = _authenticationService.login( strUserName, strPassword, request );
436 
437         return user;
438     }
439 
440     /**
441      * Return true if the requested url is equal to LoginUrl
442      * @param request The Http servlet request
443      * @return True if the requested url is equal to LoginUrl, false else.
444      */
445     public boolean isLoginUrl( HttpServletRequest request )
446     {
447         if ( ( getLoginPageUrl(  ) == null ) || ( request == null ) )
448         {
449             return false;
450         }
451 
452         String strRequestUrl = request.getRequestURI(  );
453         UrlItem url = new UrlItem( strRequestUrl );
454 
455         for ( String strParamValueLoginPageUrl : getLoginPageUrl(  )
456                                                      .substring( getLoginPageUrl(  ).indexOf( URL_INTERROGATIVE ) + 1 )
457                                                      .split( URL_AMPERSAND ) )
458         {
459             String[] arrayParamValueLoginPageUrl = strParamValueLoginPageUrl.split( URL_EQUAL );
460             Enumeration<String> enumParams = request.getParameterNames(  );
461 
462             while ( enumParams.hasMoreElements(  ) )
463             {
464                 String strRequestParameter = (String) enumParams.nextElement(  );
465 
466                 if ( arrayParamValueLoginPageUrl[0].equals( strRequestParameter ) &&
467                         arrayParamValueLoginPageUrl[1].equals( request.getParameter( strRequestParameter ) ) )
468                 {
469                     url.addParameter( strRequestParameter, request.getParameter( strRequestParameter ) );
470                 }
471             }
472         }
473 
474         if ( url.getUrl(  ).endsWith( getLoginPageUrl(  ) ) && !getLoginPageUrl(  ).equals( "" ) )
475         {
476             return true;
477         }
478 
479         return false;
480     }
481 
482     /**
483      * Tells whether or not the authentication service can provide a list of all
484      * its users
485      * @return true if the service can return a users list
486      */
487     boolean isUsersListAvailable(  )
488     {
489         return _authenticationService.isUsersListAvailable(  );
490     }
491 
492     /**
493      * Returns all users managed by the authentication service if this feature
494      * is available.
495      * @return A collection of Lutece users or null if the service doesn't
496      *         provide a users list
497      */
498     public Collection<LuteceUser> getUsers(  )
499     {
500         return _authenticationService.getUsers(  );
501     }
502 
503     /**
504      * Returns user managed by the authentication service if this feature is
505      * available.
506      * @param strUserLogin the user login
507      * @return A Lutece user or null if the service doesn't provide LuteceUser
508      */
509     public LuteceUser getUser( String strUserLogin )
510     {
511         return _authenticationService.getUser( strUserLogin );
512     }
513 
514     /**
515      * <b>true</b> when the service provides multi authentication support
516      * @return <code>true</code> if multi authentication is supported,
517      *         <code>false</code> otherwise.
518      */
519     public boolean isMultiAuthenticationSupported(  )
520     {
521         return _authenticationService.isMultiAuthenticationSupported(  );
522     }
523 
524     /**
525      * Gets the actual authentication implementation
526      * @return {@link LuteceAuthentication} implementation
527      */
528     public LuteceAuthentication getAuthenticationService(  )
529     {
530         return _authenticationService;
531     }
532 }