View Javadoc
1   /*
2    * Copyright (c) 2002-2021, City of 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.plugins.mylutece.modules.oauth2.service;
35  
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.Map;
42  import java.util.Map.Entry;
43  
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletResponse;
46  
47  import org.apache.commons.lang3.StringUtils;
48  import org.apache.log4j.Logger;
49  
50  import fr.paris.lutece.plugins.mylutece.authentication.MultiLuteceAuthentication;
51  import fr.paris.lutece.plugins.mylutece.business.LuteceUserAttributeDescription;
52  import fr.paris.lutece.plugins.mylutece.modules.oauth2.authentication.Oauth2Authentication;
53  import fr.paris.lutece.plugins.mylutece.modules.oauth2.authentication.Oauth2User;
54  import fr.paris.lutece.plugins.mylutece.service.MyLuteceUserService;
55  import fr.paris.lutece.plugins.mylutece.web.MyLuteceApp;
56  import fr.paris.lutece.plugins.oauth2.business.Token;
57  import fr.paris.lutece.portal.service.security.LuteceUser;
58  import fr.paris.lutece.portal.service.security.SecurityService;
59  import fr.paris.lutece.portal.service.spring.SpringContextService;
60  import fr.paris.lutece.portal.service.util.AppLogService;
61  import fr.paris.lutece.portal.service.util.AppPropertiesService;
62  import fr.paris.lutece.portal.web.PortalJspBean;
63  
64  // TODO: Auto-generated Javadoc
65  /**
66   * France Connect Service.
67   */
68  public final class Oauth2Service
69  {
70  
71      /** The Constant _authService. */
72      private static  Oauth2Authentication _authService ;
73  
74      /** The logger. */
75      private static Logger _logger = Logger.getLogger( "lutece.oauth2" );
76  
77      /** The Constant AUTHENTICATION_BEAN_NAME. */
78      private static final String AUTHENTICATION_BEAN_NAME = "mylutece-oauth2.authentication";
79      
80      /** The Constant PROPERTY_USER_KEY_NAME. */
81      private static final String PROPERTY_USER_KEY_NAME = "mylutece-oauth2.attributeKeyUsername";
82  
83      /** The Constant PROPERTY_USER_MAPPING_ATTRIBUTES. */
84      private static final String PROPERTY_USER_MAPPING_ATTRIBUTES = "mylutece-oauth2.userMappingAttributes";
85  
86      /** The Constant PROPERTY_IDENTITY_ATTRIBUTE_KEY. */
87      private static final String PROPERTY_IDENTITY_ATTRIBUTE_KEY = "mylutece-oauth2.attributeIdentityKey";
88  
89      /** The Constant TOKEN_SUBJECT. */
90      private static final String TOKEN_SUBJECT = "sub";
91  
92      /** The Constant CONSTANT_LUTECE_USER_PROPERTIES_PATH. */
93      private static final String CONSTANT_LUTECE_USER_PROPERTIES_PATH = "mylutece-oauth2.attribute";
94  
95      /** The attribute user mapping. */
96      private static Map<String, List<String>> ATTRIBUTE_USER_MAPPING;
97  
98      /** The attribute user key name. */
99      private static String [ ] ATTRIBUTE_USER_KEY_NAME;
100 
101     /** The Constant SEPARATOR. */
102     private static final String SEPARATOR = ",";
103 
104     /** The singleton. */
105     private static Oauth2Service _singleton;
106 
107     /**
108      * private constructor.
109      */
110     private Oauth2Service( )
111     {
112     }
113 
114     /**
115      * Gets the instance.
116      *
117      * @return the instance
118      */
119     public static Oauth2Service getInstance( )
120     {
121         if ( _singleton == null )
122         {
123 
124             _singleton = new Oauth2Service( );
125             String strTabUserKey = AppPropertiesService.getProperty( PROPERTY_USER_KEY_NAME );
126             if ( StringUtils.isNotBlank( strTabUserKey ) )
127             {
128                 ATTRIBUTE_USER_KEY_NAME = strTabUserKey.split( SEPARATOR );
129             }
130             String strUserMappingAttributes = AppPropertiesService.getProperty( PROPERTY_USER_MAPPING_ATTRIBUTES );
131             ATTRIBUTE_USER_MAPPING = new HashMap<String, List<String>>( );
132 
133             if ( StringUtils.isNotBlank( strUserMappingAttributes ) )
134             {
135                 String [ ] tabUserProperties = strUserMappingAttributes.split( SEPARATOR );
136                 String [ ] tabPropertiesValues;
137                 String userProperties;
138 
139                 for ( int i = 0; i < tabUserProperties.length; i++ )
140                 {
141                     userProperties = AppPropertiesService.getProperty( CONSTANT_LUTECE_USER_PROPERTIES_PATH + "." + tabUserProperties [i] );
142 
143                     if ( StringUtils.isNotBlank( userProperties ) )
144                     {
145 
146                         if ( userProperties.contains( SEPARATOR ) )
147                         {
148                             tabPropertiesValues = userProperties.split( SEPARATOR );
149 
150                             for ( int n = 0; i < tabPropertiesValues.length; n++ )
151                             {
152                                 if ( !ATTRIBUTE_USER_MAPPING.containsKey( tabPropertiesValues [n] ) )
153                                 {
154                                     ATTRIBUTE_USER_MAPPING.put( tabPropertiesValues [n], new ArrayList<String>( ) );
155                                 }
156                                 ATTRIBUTE_USER_MAPPING.get( tabPropertiesValues [n] ).add( tabUserProperties [i] );
157                             }
158 
159                         }
160                         else
161                         {
162 
163                             if ( !ATTRIBUTE_USER_MAPPING.containsKey( userProperties ) )
164                             {
165                                 ATTRIBUTE_USER_MAPPING.put( userProperties, new ArrayList<String>( ) );
166                             }
167                             ATTRIBUTE_USER_MAPPING.get( userProperties ).add( tabUserProperties [i] );
168                         }
169 
170                     }
171                 }
172             }
173         }
174 
175         return _singleton;
176     }
177 
178     /**
179      * Process the authentication.
180      *
181      * @param request
182      *            The HTTP request
183      * @param mapUserInfo
184      *            the map user info
185      * @param token
186      *            the token
187      * @return the oauth 2 user
188      */
189     public Oauth2User processAuthentication( HttpServletRequest request, Map<String, Object> mapUserInfo, Token token )
190     {
191 
192         // subject in user map
193         if ( token.getIdToken( ) != null && token.getIdToken( ).getSubject( ) != null )
194         {
195             mapUserInfo.put( TOKEN_SUBJECT, token.getIdToken( ).getSubject( ) );
196 
197         }
198         Oauth2User user = null;
199         for ( int i = 0; i < ATTRIBUTE_USER_KEY_NAME.length; i++ )
200         {
201 
202             if ( mapUserInfo.containsKey( ATTRIBUTE_USER_KEY_NAME [i] ) )
203             {
204                 user = new Oauth2User( (String) mapUserInfo.get( ATTRIBUTE_USER_KEY_NAME [i] ), token, _authService );
205             }
206         }
207 
208         if ( user != null )
209         {
210 
211             for ( Entry<String, Object> entry : mapUserInfo.entrySet( ) )
212             {
213                 if ( ATTRIBUTE_USER_MAPPING.containsKey( entry.getKey( ) ) )
214                 {
215                     for ( String strUserInfo : ATTRIBUTE_USER_MAPPING.get( entry.getKey( ) ) )
216                     {
217 
218                         Object val = entry.getValue( );
219                         if ( val instanceof ArrayList<?> )
220                         {
221 
222                             StringBuffer strBufVal = new StringBuffer( );
223                             for ( String tabVal : (ArrayList<String>) val )
224                             {
225                                 strBufVal.append( tabVal );
226                                 strBufVal.append( SEPARATOR );
227                             }
228                             if ( strBufVal.length( ) > 0 )
229                             {
230                                 user.setUserInfo( strUserInfo, strBufVal.substring( 0, strBufVal.length( ) - 1 ) );
231                             }
232 
233                             user.setUserInfo( strUserInfo, strBufVal.toString( ) );
234 
235                         }
236                         else
237                         {
238                             user.setUserInfo( strUserInfo, (String) val );
239 
240                         }
241                     }
242                 }
243                 // set Email in lutece User
244                 if ( !StringUtils.isEmpty( user.getUserInfo( LuteceUser.HOME_INFO_ONLINE_EMAIL ) ) )
245                 {
246                     user.setEmail( user.getUserInfo( LuteceUser.HOME_INFO_ONLINE_EMAIL ) );
247 
248                 }
249                 else
250                     if ( !StringUtils.isEmpty( user.getUserInfo( LuteceUser.BUSINESS_INFO_ONLINE_EMAIL ) ) )
251                     {
252                         user.setEmail( user.getUserInfo( LuteceUser.BUSINESS_INFO_ONLINE_EMAIL ) );
253 
254                     }
255 
256             }
257 
258             // add Identities Informations
259             // get Identity key the default key is the value of lutece user name
260             String strIdentityKey = user.getName( );
261             String strIdentityKeyAttribute = AppPropertiesService.getProperty( PROPERTY_IDENTITY_ATTRIBUTE_KEY );
262             if ( strIdentityKeyAttribute != null && mapUserInfo.containsKey( strIdentityKeyAttribute ) )
263             {
264                 strIdentityKey = mapUserInfo.get( strIdentityKeyAttribute ).toString( );
265             }
266 
267             user.setName( strIdentityKey );
268             MyLuteceUserService.provideUserExternalInfos( user );
269 
270             // add Oauth2LuteceUserSessionService session
271             Oauth2LuteceUserSessionService.getInstance( ).addLuteceUserSession( user.getName( ), request.getSession( true ).getId( ) );
272 
273         }
274 
275         SecurityService.getInstance( ).registerUser( request, user );
276 
277         return user;
278     }
279     
280     /**
281      * Inits the service
282      */
283     public void init()
284     {
285     	
286      	//register Authentication
287      	 _authService = SpringContextService.getBean( AUTHENTICATION_BEAN_NAME );
288 
289          if ( _authService != null )
290          {
291              MultiLuteceAuthentication.registerAuthentication( _authService );
292          }
293          else
294          {
295              AppLogService.error( "Mylutece  Ouath2 Authentication not found, please check your mylutece-oauth2_context.xml configuration" );
296          }
297     	
298     }
299     
300     /**
301      * 
302      * @return the Lutece user Attribute provided by the authentication module
303      */
304     public List<LuteceUserAttributeDescription> getLuteceUserAttributesProvided(Locale locale)
305     {
306     	
307     	List<LuteceUserAttributeDescription> listUserDescription=  new ArrayList<LuteceUserAttributeDescription>();
308     
309     	
310     	String strUserMappingAttributes = AppPropertiesService.getProperty( PROPERTY_USER_MAPPING_ATTRIBUTES );
311         ATTRIBUTE_USER_MAPPING = new HashMap<String, List<String>>( );
312 
313         if ( StringUtils.isNotBlank( strUserMappingAttributes ) )
314         {
315             String [ ] tabUserProperties = strUserMappingAttributes.split( SEPARATOR );
316             
317             for ( int i = 0; i < tabUserProperties.length; i++ )
318             {
319                  
320                   listUserDescription.add(new LuteceUserAttributeDescription( tabUserProperties [i],  AppPropertiesService.getProperty( CONSTANT_LUTECE_USER_PROPERTIES_PATH + "." + tabUserProperties [i] ) , ""));
321             }
322         }
323     	
324          	
325         return listUserDescription;
326     }
327 
328     /**
329      * Process the logout.
330      *
331      * @param request
332      *            The HTTP request
333      */
334     public static void processLogout( HttpServletRequest request )
335     {
336         _logger.debug( "Process logout" );
337         SecurityService.getInstance( ).logoutUser( request );
338     }
339 
340     /**
341      * redirect after login or logout.
342      *
343      * @param request
344      *            The HTTP request
345      * @param response
346      *            The HTTP response
347      * @throws IOException
348      *             if an error occurs
349      */
350     public static void redirect( HttpServletRequest request, HttpServletResponse response ) throws IOException
351     {
352         String strNextURL = PortalJspBean.getLoginNextUrl( request );
353         _logger.info( "Next URL : " + strNextURL );
354 
355         if ( strNextURL == null )
356         {
357             strNextURL = MyLuteceApp.getDefaultRedirectUrl( );
358         }
359 
360         strNextURL = response.encodeRedirectURL( strNextURL );
361 
362         response.sendRedirect( strNextURL );
363     }
364     
365    
366     
367     
368     
369 
370 }