View Javadoc
1   /*
2    * Copyright (c) 2002-2022, 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.portal.service.admin;
35  
36  import java.sql.Timestamp;
37  import java.text.DateFormat;
38  import java.text.SimpleDateFormat;
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Calendar;
42  import java.util.Collection;
43  import java.util.Date;
44  import java.util.GregorianCalendar;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Locale;
48  import java.util.Map;
49  import java.util.Map.Entry;
50  import java.util.Optional;
51  import java.util.Set;
52  import java.util.stream.Collectors;
53  
54  import javax.servlet.http.HttpServletRequest;
55  
56  import org.apache.commons.lang3.StringUtils;
57  import org.apache.commons.lang3.ArrayUtils;
58  
59  import fr.paris.lutece.portal.business.rbac.RBACRole;
60  import fr.paris.lutece.portal.business.rbac.RBAC;
61  import fr.paris.lutece.portal.business.regularexpression.RegularExpression;
62  import fr.paris.lutece.portal.business.right.Level;
63  import fr.paris.lutece.portal.business.right.LevelHome;
64  import fr.paris.lutece.portal.business.right.Right;
65  import fr.paris.lutece.portal.business.user.AdminUser;
66  import fr.paris.lutece.portal.business.user.AdminUserFilter;
67  import fr.paris.lutece.portal.business.user.AdminUserHome;
68  import fr.paris.lutece.portal.business.user.attribute.AdminUserField;
69  import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldFilter;
70  import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldHome;
71  import fr.paris.lutece.portal.business.user.attribute.IAttribute;
72  import fr.paris.lutece.portal.business.user.parameter.DefaultUserParameterHome;
73  import fr.paris.lutece.portal.business.workgroup.AdminWorkgroupHome;
74  import fr.paris.lutece.portal.service.datastore.DatastoreService;
75  import fr.paris.lutece.portal.service.i18n.I18nService;
76  import fr.paris.lutece.portal.service.mail.MailService;
77  import fr.paris.lutece.portal.service.message.AdminMessage;
78  import fr.paris.lutece.portal.service.message.AdminMessageService;
79  import fr.paris.lutece.portal.service.plugin.PluginService;
80  import fr.paris.lutece.portal.service.portal.PortalService;
81  import fr.paris.lutece.portal.service.rbac.RBACService;
82  import fr.paris.lutece.portal.service.regularexpression.RegularExpressionService;
83  import fr.paris.lutece.portal.service.spring.SpringContextService;
84  import fr.paris.lutece.portal.service.template.AppTemplateService;
85  import fr.paris.lutece.portal.service.template.DatabaseTemplateService;
86  import fr.paris.lutece.portal.service.user.AdminUserResourceIdService;
87  import fr.paris.lutece.portal.service.user.attribute.AdminUserFieldService;
88  import fr.paris.lutece.portal.service.user.attribute.AttributeService;
89  import fr.paris.lutece.portal.service.util.AppPropertiesService;
90  import fr.paris.lutece.portal.service.util.CryptoService;
91  import fr.paris.lutece.portal.web.l10n.LocaleService;
92  import fr.paris.lutece.util.ReferenceList;
93  import fr.paris.lutece.util.date.DateUtil;
94  import fr.paris.lutece.util.html.HtmlTemplate;
95  import fr.paris.lutece.util.password.IPassword;
96  import fr.paris.lutece.util.password.IPasswordFactory;
97  import fr.paris.lutece.util.password.PasswordUtil;
98  import fr.paris.lutece.util.url.UrlItem;
99  import fr.paris.lutece.util.xml.XmlUtil;
100 
101 /**
102  * This service provides features concerning the administration users
103  */
104 public final class AdminUserService
105 {
106     // DataStore keys
107     public static final String DSKEY_ACCOUNT_REACTIVATED_MAIL_SENDER = "core.advanced_parameters.account_reactivated_mail_sender";
108     public static final String DSKEY_ACCOUNT_REACTIVATED_MAIL_SUBJECT = "core.advanced_parameters.account_reactivated_mail_subject";
109     public static final String DSKEY_ACCOUNT_REACTIVATED_MAIL_BODY = "core_account_reactivated_mail";
110     public static final String DSKEY_PASSWORD_DURATION = "core.advanced_parameters.password_duration";
111     public static final String DSKEY_MAXIMUM_NUMBER_PASSWORD_CHANGE = "core.advanced_parameters.maximum_number_password_change";
112     public static final String DSKEY_PASSWORD_HISTORY_SIZE = "core.advanced_parameters.password_history_size";
113     public static final String DSKEY_TSW_SIZE_PASSWORD_CHANGE = "core.advanced_parameters.tsw_size_password_change";
114     public static final String DSKEY_NOTIFY_USER_PASSWORD_EXPIRED = "core.advanced_parameters.notify_user_password_expired";
115     public static final String DSKEY_BANNED_DOMAIN_NAMES = "banned_domain_names";
116     public static final String DSKEY_ACCOUNT_LIFE_TIME = "core.advanced_parameters.account_life_time";
117     public static final String DSKEY_TIME_BEFORE_ALERT_ACCOUNT = "core.advanced_parameters.time_before_alert_account";
118     public static final String DSKEY_NB_ALERT_ACCOUNT = "core.advanced_parameters.nb_alert_account";
119     public static final String DSKEY_TIME_BETWEEN_ALERTS_ACCOUNT = "core.advanced_parameters.time_between_alerts_account";
120     public static final String DSKEY_ACCES_FAILURES_MAX = "core.advanced_parameters.access_failures_max";
121     public static final String DSKEY_ACCES_FAILURES_INTERVAL = "core.advanced_parameters.access_failures_interval";
122     public static final String DSKEY_EMAIL_PATTERN = "core.advanced_parameters.email_pattern";
123     public static final String DSKEY_EMAIL_PATTERN_VERIFY_BY = "core.advanced_parameters.email_pattern_verify_by";
124     public static final String DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS = "core.advanced_parameters.password_format_special_characters";
125     public static final String DSKEY_PASSWORD_FORMAT_NUMERO = "core.advanced_parameters.password_format_numero";
126     public static final String DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE = "core.advanced_parameters.password_format_upper_lower_case";
127     public static final String DSKEY_FORCE_CHANGE_PASSWORD_REINIT = "core.advanced_parameters.force_change_password_reinit";
128     public static final String DSKEY_PASSWORD_MINIMUM_LENGTH = "core.advanced_parameters.password_minimum_length";
129     public static final String DSKEY_DEFAULT_USER_STATUS = "core.advanced_parameters.default_user_status";
130     public static final String DSKEY_DEFAULT_USER_LANGUAGE = "core.advanced_parameters.default_user_language";
131     public static final String DSKEY_DEFAULT_USER_NOTIFICATION = "core.advanced_parameters.default_user_notification";
132     public static final String DSKEY_DEFAULT_USER_LEVEL = "core.advanced_parameters.default_user_level";
133     public static final String DSKEY_USE_ADVANCED_SECURITY_PARAMETERS = "core.advanced_parameters.use_advanced_security_parameters";
134     public static final String DSKEY_RESET_TOKEN_VALIDITY = "core.advanced_parameters.reset_token_validity";
135     public static final String DSKEY_LOCK_RESET_TOKEN_TO_SESSION = "core.advanced_parameters.lock_reset_token_to_session";
136 
137     // Parameter
138     private static final String PARAMETER_ACCESS_CODE = "access_code";
139     private static final String PARAMETER_LAST_NAME = "last_name";
140     private static final String PARAMETER_FIRST_NAME = "first_name";
141     private static final String PARAMETER_EMAIL = "email";
142 
143     // Markers
144     private static final String MARK_DEFAULT_USER_LEVEL = "default_user_level";
145     private static final String MARK_DEFAULT_USER_NOTIFICATION = "default_user_notification";
146     private static final String MARK_DEFAULT_USER_LANGUAGE = "default_user_language";
147     private static final String MARK_DEFAULT_USER_STATUS = "default_user_status";
148     private static final String MARK_LANGUAGES_LIST = "languages_list";
149     private static final String MARK_USER_LEVELS_LIST = "user_levels";
150     private static final String MARK_SEARCH_IS_SEARCH = "search_is_search";
151     private static final String MARK_SEARCH_ADMIN_USER_FILTER = "search_admin_user_filter";
152     private static final String MARK_SEARCH_ADMIN_USER_FIELD_FILTER = "search_admin_user_field_filter";
153     private static final String MARK_ATTRIBUTES_LIST = "attributes_list";
154     private static final String MARK_LOCALE = "locale";
155     private static final String MARK_SORT_SEARCH_ATTRIBUTE = "sort_search_attribute";
156     private static final String MARK_MAP_ID_USER_LIST_USER_FIELDS = "map_id_user_list_user_fields";
157     private static final String MARK_EMAIL_PATTERN = "email_pattern";
158     private static final String MARK_AVAILABLE_REGULAREXPRESSIONS = "available_regularexpressions";
159     private static final String MARK_SELECTED_REGULAREXPRESSIONS = "selected_regularexpressions";
160     private static final String MARK_IS_EMAIL_PATTERN_SET_MANUALLY = "is_email_pattern_set_manually";
161     private static final String MARK_PLUGIN_REGULAREXPRESSION = "plugin_regularexpression";
162     private static final String MARK_FORCE_CHANGE_PASSWORD_REINIT = "force_change_password_reinit";
163     private static final String MARK_PASSWORD = "password";
164     private static final String MARK_PASSWORD_MINIMUM_LENGTH = "password_minimum_length";
165     private static final String MARK_PASSWORD_FORMAT_UPPER_LOWER_CASE = "password_format_upper_lower_case";
166     private static final String MARK_PASSWORD_FORMAT_NUMERO = "password_format_numero";
167     private static final String MARK_PASSWORD_FORMAT_SPECIAL_CHARACTERS = "password_format_special_characters";
168     private static final String MARK_PASSWORD_DURATION = "password_duration";
169     private static final String MARK_PASSWORD_HISTORY_SIZE = "password_history_size";
170     private static final String MARK_MAXIMUM_NUMBER_PASSWORD_CHANGE = "maximum_number_password_change";
171     private static final String MARK_TSW_SIZE_PASSWORD_CHANGE = "tsw_size_password_change";
172     private static final String MARK_USE_ADVANCED_SECURITY_PARAMETERS = "use_advanced_security_parameters";
173     private static final String MARK_ACCOUNT_LIFE_TIME = "account_life_time";
174     private static final String MARK_TIME_BEFORE_ALERT_ACCOUNT = "time_before_alert_account";
175     private static final String MARK_NB_ALERT_ACCOUNT = "nb_alert_account";
176     private static final String MARK_TIME_BETWEEN_ALERTS_ACCOUNT = "time_between_alerts_account";
177     private static final String MARK_ACCES_FAILURES_MAX = "access_failures_max";
178     private static final String MARK_ACCES_FAILURES_INTERVAL = "access_failures_interval";
179     private static final String MARK_NAME = "name";
180     private static final String MARK_FIRST_NAME = "first_name";
181     private static final String MARK_DATE_VALID = "date_valid";
182     private static final String MARK_BANNED_DOMAIN_NAMES = "banned_domain_names";
183     private static final String MARK_NOTIFY_USER_PASSWORD_EXPIRED = "notify_user_password_expired";
184     private static final String MARK_SITE_NAME = "site_name";
185     private static final String MARK_USER = "user";
186     private static final String MARK_SITE_LINK = "site_link";
187     private static final String MARK_LOGIN_URL = "login_url";
188     private static final String MARK_RESET_TOKEN_VALIDITY = "reset_token_validity";
189     private static final String MARK_LOCK_RESET_TOKEN_TO_SESSION = "lock_reset_token_to_session";
190 
191     // Properties
192     private static final String PROPERTY_EMAIL_PATTERN = "lutece.email.pattern";
193     private static final String PROPERTY_MESSAGE_EMAIL_FORMAT = "portal.users.message.user.emailFormat";
194     private static final String PROPERTY_MESSAGE_EMAIL_FORMAT_BANNED_DOMAIN_NAME = "portal.users.message.user.emailFormatBannedDomainNames";
195     private static final String PROPERTY_MESSAGE_MINIMUM_PASSWORD_LENGTH = "portal.users.message.password.minimumPasswordLength";
196     private static final String PROPERTY_MESSAGE_PASSWORD_FORMAT = "portal.users.message.password.format";
197     private static final String PROPERTY_MESSAGE_PASSWORD_FORMAT_UPPER_LOWER_CASE = "portal.users.message.password.formatUpperLowerCase";
198     private static final String PROPERTY_MESSAGE_PASSWORD_FORMAT_NUMERO = "portal.users.message.password.formatNumero";
199     private static final String PROPERTY_MESSAGE_PASSWORD_FORMAT_SPECIAL_CHARACTERS = "portal.users.message.password.formatSpecialCharacters";
200     private static final String PROPERTY_MESSAGE_PASSWORD_ALREADY_USED = "portal.users.message.password.passwordAlreadyUsed";
201     private static final String PROPERTY_MESSAGE_MAX_PASSWORD_CHANGE = "portal.users.message.password.maxPasswordChange";
202     private static final String PROPERTY_ANONYMIZATION_ENCRYPT_ALGO = "security.anonymization.encryptAlgo";
203     private static final String PROPERTY_DEFAULT_PASSWORD_MINIMAL_LENGTH = "security.defaultValues.passwordMinimalLength";
204     private static final String PROPERTY_DEFAULT_MAXIMUM_NUMBER_PASSWORD_CHANGE = "security.defaultValues.maximumPasswordChange";
205     private static final String PROPERTY_DEFAULT_TSW_SIZE_PASSWORD_CHANGE = "security.defaultValues.maximumPasswordChangeTSWSize";
206     private static final String PROPERTY_DEFAULT_HISTORY_SIZE = "security.defaultValues.passwordHistorySize";
207     private static final String PROPERTY_DEFAULT_PASSWORD_DURATION = "security.defaultValues.passwordDuration";
208 
209     // CONSTANTS
210     private static final String CONSTANT_DEFAULT_ENCRYPT_ALGO = "SHA-256";
211     private static final String COMMA = ",";
212     private static final String SEMICOLON = ";";
213     private static final String ZERO = "0";
214     private static final String CONSTANT_AT = "@";
215     private static final String CONSTANT_UNDERSCORE = "_";
216     private static final String CONSTANT_XML_USER = "user";
217     private static final String CONSTANT_XML_ACCESS_CODE = "access_code";
218     private static final String CONSTANT_XML_LAST_NAME = "last_name";
219     private static final String CONSTANT_XML_FIRST_NAME = "first_name";
220     private static final String CONSTANT_XML_EMAIL = "email";
221     private static final String CONSTANT_XML_STATUS = "status";
222     private static final String CONSTANT_XML_LOCALE = "locale";
223     private static final String CONSTANT_XML_LEVEL = "level";
224     private static final String CONSTANT_XML_MUST_CHANGE_PASSWORD = "must_change_password";
225     private static final String CONSTANT_XML_ACCESSIBILITY_MODE = "accessibility_mode";
226     private static final String CONSTANT_XML_PASSWORD_MAX_VALID_DATE = "password_max_valid_date";
227     private static final String CONSTANT_XML_ACCOUNT_MAX_VALID_DATE = "account_max_valid_date";
228     private static final String CONSTANT_XML_DATE_LAST_LOGIN = "date_last_login";
229     private static final String CONSTANT_XML_ROLES = "roles";
230     private static final String CONSTANT_XML_RIGHTS = "rights";
231     private static final String CONSTANT_XML_WORKGROUPS = "workgroups";
232     private static final String CONSTANT_XML_ROLE = "role";
233     private static final String CONSTANT_XML_RIGHT = "right";
234     private static final String CONSTANT_XML_WORKGROUP = "workgroup";
235     private static final String CONSTANT_XML_ATTRIBUTES = "attributes";
236     private static final String CONSTANT_XML_ATTRIBUTE = "attribute";
237     private static final String CONSTANT_XML_ATTRIBUTE_ID = "attribute-id";
238     private static final String CONSTANT_XML_ATTRIBUTE_FIELD_ID = "attribute-field-id";
239     private static final String CONSTANT_XML_ATTRIBUTE_VALUE = "attribute-value";
240 
241     /** Private constructor */
242     private AdminUserService( )
243     {
244     }
245 
246     /**
247      * Init
248      */
249     public static void init( )
250     {
251         AdminUser.init( );
252     }
253 
254     /**
255      * Get the user in session
256      * 
257      * @param request
258      *            The HTTP request
259      * @return the user in session
260      */
261     public static AdminUser getAdminUser( HttpServletRequest request )
262     {
263         return AdminAuthenticationService.getInstance( ).getRegisteredUser( request );
264     }
265 
266     /**
267      * Get the locale for the current request
268      * 
269      * @param request
270      *            The HTTP request
271      * @return the locale to use with this request
272      */
273     public static Locale getLocale( HttpServletRequest request )
274     {
275         Locale locale;
276         AdminUser user = getAdminUser( request );
277 
278         if ( user != null )
279         {
280             // Take the locale of the current user if exists
281             locale = user.getLocale( );
282         }
283         else
284         {
285             // TODO : Add cookie search
286 
287             // Take the locale of the browser
288             locale = request.getLocale( );
289         }
290 
291         return locale;
292     }
293 
294     /**
295      * Get the filtered list of admin users
296      * 
297      * @param listUsers
298      *            the initial list of users
299      * @param request
300      *            HttpServletRequest
301      * @param model
302      *            map
303      * @param url
304      *            URL of the current interface
305      * @return The filtered list of admin users
306      */
307     public static List<AdminUser> getFilteredUsersInterface( Collection<AdminUser> listUsers, HttpServletRequest request, Map<String, Object> model,
308             UrlItem url )
309     {
310         AdminUser currentUser = getAdminUser( request );
311 
312         // FILTER
313         AdminUserFilterser/AdminUserFilter.html#AdminUserFilter">AdminUserFilter auFilter = new AdminUserFilter( );
314         List<AdminUser> listFilteredUsers = new ArrayList<>( );
315         boolean bIsSearch = auFilter.setAdminUserFilter( request );
316         boolean bIsFiltered;
317 
318         for ( AdminUser filteredUser : AdminUserHome.findUserByFilter( auFilter ) )
319         {
320             bIsFiltered = false;
321 
322             for ( AdminUser user : listUsers )
323             {
324                 if ( user.getUserId( ) == filteredUser.getUserId( ) )
325                 {
326                     bIsFiltered = true;
327 
328                     break;
329                 }
330             }
331 
332             if ( bIsFiltered && ( currentUser.isParent( filteredUser ) || ( currentUser.isAdmin( ) ) ) )
333             {
334                 listFilteredUsers.add( filteredUser );
335             }
336         }
337 
338         List<AdminUser> filteredUsers = new ArrayList<>( );
339 
340         AdminUserFieldFilterute/AdminUserFieldFilter.html#AdminUserFieldFilter">AdminUserFieldFilter auFieldFilter = new AdminUserFieldFilter( );
341         auFieldFilter.setAdminUserFieldFilter( request, currentUser.getLocale( ) );
342 
343         List<AdminUser> listFilteredUsersByUserFields = AdminUserFieldHome.findUsersByFilter( auFieldFilter );
344 
345         if ( listFilteredUsersByUserFields != null )
346         {
347             Set<Integer> listFilteredUsersByUserFieldsId = listFilteredUsersByUserFields.stream( ).map( AdminUser::getUserId ).collect( Collectors.toSet( ) );
348             filteredUsers.addAll( listFilteredUsers.stream( ).filter( user -> listFilteredUsersByUserFieldsId.contains( user.getUserId( ) ) )
349                     .collect( Collectors.toList( ) ) );
350         }
351         else
352         {
353             filteredUsers = listFilteredUsers;
354         }
355 
356         Map<String, List<AdminUserField>> map = new HashMap<>( );
357 
358         for ( AdminUser user : filteredUsers )
359         {
360             auFieldFilter.setIdUser( user.getUserId( ) );
361 
362             List<AdminUserField> listAdminUserFields = AdminUserFieldHome.findByFilter( auFieldFilter );
363             map.put( String.valueOf( user.getUserId( ) ), listAdminUserFields );
364         }
365 
366         List<IAttribute> listAttributes = AttributeService.getInstance( ).getAllAttributesWithFields( currentUser.getLocale( ) );
367 
368         String strSortSearchAttribute = StringUtils.EMPTY;
369 
370         if ( bIsSearch )
371         {
372             auFilter.setUrlAttributes( url );
373             auFieldFilter.setUrlAttributes( url );
374             strSortSearchAttribute = auFieldFilter.getUrlAttributes( );
375         }
376 
377         model.put( MARK_SEARCH_ADMIN_USER_FILTER, auFilter );
378         model.put( MARK_SEARCH_IS_SEARCH, bIsSearch );
379         model.put( MARK_SEARCH_ADMIN_USER_FIELD_FILTER, auFieldFilter );
380         model.put( MARK_LOCALE, currentUser.getLocale( ) );
381         model.put( MARK_ATTRIBUTES_LIST, listAttributes );
382         model.put( MARK_SORT_SEARCH_ATTRIBUTE, strSortSearchAttribute );
383         model.put( MARK_MAP_ID_USER_LIST_USER_FIELDS, map );
384 
385         return filteredUsers;
386     }
387 
388     /**
389      * Build the advanced parameters management
390      * 
391      * @param user
392      *            The AdminUser object
393      * @return The model for the advanced parameters
394      */
395     public static Map<String, Object> getManageAdvancedParameters( AdminUser user )
396     {
397         Map<String, Object> model = new HashMap<>( );
398 
399         boolean bPermissionManageAdvancedParameters = RBACService.isAuthorized( AdminUser.RESOURCE_TYPE, RBAC.WILDCARD_RESOURCES_ID,
400                 AdminUserResourceIdService.PERMISSION_MANAGE_ADVANCED_PARAMETERS, user );
401 
402         if ( bPermissionManageAdvancedParameters )
403         {
404             // USER LEVEL
405             String strDefaultLevel = DefaultUserParameterHome.findByKey( DSKEY_DEFAULT_USER_LEVEL );
406             Level defaultLevel = LevelHome.findByPrimaryKey( Integer.parseInt( strDefaultLevel ) );
407 
408             // USER NOTIFICATION
409             int nDefaultUserNotification = Integer.parseInt( DefaultUserParameterHome.findByKey( DSKEY_DEFAULT_USER_NOTIFICATION ) );
410 
411             // USER LANGUAGE
412             ReferenceList listLanguages = I18nService.getAdminLocales( user.getLocale( ) );
413             String strDefaultUserLanguage = DefaultUserParameterHome.findByKey( DSKEY_DEFAULT_USER_LANGUAGE );
414 
415             // USER STATUS
416             int nDefaultUserStatus = Integer.parseInt( DefaultUserParameterHome.findByKey( DSKEY_DEFAULT_USER_STATUS ) );
417 
418             model.put( MARK_USER_LEVELS_LIST, LevelHome.getLevelsList( ) );
419             model.put( MARK_DEFAULT_USER_LEVEL, defaultLevel );
420             model.put( MARK_DEFAULT_USER_NOTIFICATION, nDefaultUserNotification );
421             model.put( MARK_LANGUAGES_LIST, listLanguages );
422             model.put( MARK_DEFAULT_USER_LANGUAGE, strDefaultUserLanguage );
423             model.put( MARK_DEFAULT_USER_STATUS, nDefaultUserStatus );
424 
425             // EMAIL PATTERN
426             model.put( MARK_PLUGIN_REGULAREXPRESSION, RegularExpressionService.getInstance( ).isAvailable( ) );
427             model.put( MARK_IS_EMAIL_PATTERN_SET_MANUALLY, isEmailPatternSetManually( ) );
428             model.put( MARK_EMAIL_PATTERN, getEmailPattern( ) );
429             model.put( MARK_AVAILABLE_REGULAREXPRESSIONS, getAvailableRegularExpressions( ) );
430             model.put( MARK_SELECTED_REGULAREXPRESSIONS, getSelectedRegularExpressions( ) );
431 
432             boolean bUseAdvancesSecurityParameters = getBooleanSecurityParameter( DSKEY_USE_ADVANCED_SECURITY_PARAMETERS );
433 
434             model.put( MARK_USE_ADVANCED_SECURITY_PARAMETERS, bUseAdvancesSecurityParameters );
435 
436             model.put( MARK_FORCE_CHANGE_PASSWORD_REINIT, getBooleanSecurityParameter( DSKEY_FORCE_CHANGE_PASSWORD_REINIT ) );
437             model.put( MARK_PASSWORD_MINIMUM_LENGTH, getIntegerSecurityParameter( DSKEY_PASSWORD_MINIMUM_LENGTH ) );
438 
439             model.put( MARK_RESET_TOKEN_VALIDITY, getIntegerSecurityParameter( DSKEY_RESET_TOKEN_VALIDITY ) );
440             model.put( MARK_LOCK_RESET_TOKEN_TO_SESSION, getBooleanSecurityParameter( DSKEY_LOCK_RESET_TOKEN_TO_SESSION ) );
441 
442             if ( bUseAdvancesSecurityParameters )
443             {
444                 // SECURITY PARAMETERS
445                 model.put( MARK_PASSWORD_FORMAT_UPPER_LOWER_CASE, getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE ) );
446                 model.put( MARK_PASSWORD_FORMAT_NUMERO, getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_NUMERO ) );
447                 model.put( MARK_PASSWORD_FORMAT_SPECIAL_CHARACTERS, getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS ) );
448                 model.put( MARK_PASSWORD_DURATION, getIntegerSecurityParameter( DSKEY_PASSWORD_DURATION ) );
449                 model.put( MARK_PASSWORD_HISTORY_SIZE, getIntegerSecurityParameter( DSKEY_PASSWORD_HISTORY_SIZE ) );
450                 model.put( MARK_MAXIMUM_NUMBER_PASSWORD_CHANGE, getIntegerSecurityParameter( DSKEY_MAXIMUM_NUMBER_PASSWORD_CHANGE ) );
451                 model.put( MARK_TSW_SIZE_PASSWORD_CHANGE, getIntegerSecurityParameter( DSKEY_TSW_SIZE_PASSWORD_CHANGE ) );
452                 model.put( MARK_NOTIFY_USER_PASSWORD_EXPIRED, getBooleanSecurityParameter( DSKEY_NOTIFY_USER_PASSWORD_EXPIRED ) );
453             }
454 
455             model.put( MARK_BANNED_DOMAIN_NAMES, getLargeSecurityParameter( DSKEY_BANNED_DOMAIN_NAMES ) );
456             model.put( MARK_ACCOUNT_LIFE_TIME, getIntegerSecurityParameter( DSKEY_ACCOUNT_LIFE_TIME ) );
457             model.put( MARK_TIME_BEFORE_ALERT_ACCOUNT, getIntegerSecurityParameter( DSKEY_TIME_BEFORE_ALERT_ACCOUNT ) );
458             model.put( MARK_NB_ALERT_ACCOUNT, getIntegerSecurityParameter( DSKEY_NB_ALERT_ACCOUNT ) );
459             model.put( MARK_TIME_BETWEEN_ALERTS_ACCOUNT, getIntegerSecurityParameter( DSKEY_TIME_BETWEEN_ALERTS_ACCOUNT ) );
460             model.put( MARK_ACCES_FAILURES_MAX, getIntegerSecurityParameter( DSKEY_ACCES_FAILURES_MAX ) );
461             model.put( MARK_ACCES_FAILURES_INTERVAL, getIntegerSecurityParameter( DSKEY_ACCES_FAILURES_INTERVAL ) );
462         }
463 
464         return model;
465     }
466 
467     /**
468      * Check if the given email is valid or not. <br>
469      * The given email is compared to the value of the parameter <i>'core_user_parameter.email_pattern'</i>.
470      *
471      * @param strEmail
472      *            the str email
473      * @return true, if successful
474      */
475     public static boolean checkEmail( String strEmail )
476     {
477         boolean bIsValid = true;
478 
479         if ( isEmailPatternSetManually( ) )
480         {
481             if ( StringUtils.isBlank( strEmail ) || !strEmail.matches( getEmailPattern( ) ) )
482             {
483                 bIsValid = false;
484             }
485         }
486         else
487         {
488             for ( RegularExpression regularExpression : getSelectedRegularExpressions( ) )
489             {
490                 if ( !RegularExpressionService.getInstance( ).isMatches( strEmail, regularExpression ) )
491                 {
492                     bIsValid = false;
493 
494                     break;
495                 }
496             }
497         }
498 
499         if ( !bIsValid )
500         {
501             return false;
502         }
503 
504         String strBannedDomainNames = AdminUserService.getSecurityParameter( DSKEY_BANNED_DOMAIN_NAMES );
505 
506         if ( StringUtils.isEmpty( strBannedDomainNames ) )
507         {
508             return bIsValid;
509         }
510 
511         String [ ] strListBannedDomainNames = strBannedDomainNames.split( SEMICOLON );
512         String strDomainName = strEmail.substring( strEmail.indexOf( CONSTANT_AT ) + 1 );
513 
514         if ( strDomainName != null && ArrayUtils.isNotEmpty( strListBannedDomainNames ) && Arrays.asList( strListBannedDomainNames ).contains( strDomainName ) )
515         {
516             bIsValid = false;
517         }
518         return bIsValid;
519     }
520 
521     /**
522      * Do modify the email pattern
523      * 
524      * @param strEmailPattern
525      *            the email pattern
526      * @param bIsSetManually
527      *            true if it is know set manually, false otherwise
528      */
529     public static void doModifyEmailPattern( String strEmailPattern, boolean bIsSetManually )
530     {
531         if ( bIsSetManually )
532         {
533             DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN, strEmailPattern );
534             DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN_VERIFY_BY, StringUtils.EMPTY );
535         }
536         else
537         {
538             if ( isEmailPatternSetManually( ) )
539             {
540                 // If the previous email pattern is set manually, then the parameter
541                 // email_pattern_verify_by is set at 0
542                 // This way, the interface know the email pattern is not set manually
543                 // Indeed, the control is set on the content of the parameter
544                 // 'email_pattern_verify_by'
545                 DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN_VERIFY_BY, ZERO );
546             }
547         }
548     }
549 
550     /**
551      * Reset the email pattern by putting the default email pattern that is set in the <b>lutece.properties</b>.
552      */
553     public static void doResetEmailPattern( )
554     {
555         DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN, getDefaultEmailPattern( ) );
556     }
557 
558     /**
559      * Get the email error message url.
560      *
561      * @param request
562      *            the request
563      * @return the error message
564      */
565     public static String getEmailErrorMessageUrl( HttpServletRequest request )
566     {
567         String strMessage;
568 
569         if ( isEmailPatternSetManually( ) )
570         {
571             strMessage = getEmailPattern( );
572         }
573         else
574         {
575             StringBuilder sbMessage = new StringBuilder( );
576             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
577             String [ ] regularExpressionIds = emailPatternVerifyBy.split( COMMA );
578 
579             for ( String strRegularExpressionId : regularExpressionIds )
580             {
581                 String trimedId = strRegularExpressionId.trim( );
582 
583                 if ( StringUtils.isNotBlank( trimedId ) && StringUtils.isNumeric( trimedId ) )
584                 {
585                     int nRegularExpressionId = Integer.parseInt( trimedId );
586                     RegularExpression regularExpression = RegularExpressionService.getInstance( ).getRegularExpressionByKey( nRegularExpressionId );
587 
588                     if ( regularExpression != null )
589                     {
590                         sbMessage.append( regularExpression.getValidExemple( ) );
591                         sbMessage.append( COMMA );
592                     }
593                 }
594             }
595 
596             // Get all message except the last character which is a comma
597             strMessage = sbMessage.toString( ).substring( 0, sbMessage.length( ) - 1 );
598         }
599 
600         String strBannedDomainNames = getSecurityParameter( DSKEY_BANNED_DOMAIN_NAMES );
601         String strMessageProperty;
602 
603         if ( !StringUtils.isEmpty( strBannedDomainNames ) )
604         {
605             strMessageProperty = PROPERTY_MESSAGE_EMAIL_FORMAT_BANNED_DOMAIN_NAME;
606         }
607         else
608         {
609             strMessageProperty = PROPERTY_MESSAGE_EMAIL_FORMAT;
610         }
611 
612         Object [ ] param = {
613                 strMessage, strBannedDomainNames
614         };
615 
616         return AdminMessageService.getMessageUrl( request, strMessageProperty, param, AdminMessage.TYPE_STOP );
617     }
618 
619     /**
620      * Do insert a regular expression
621      * 
622      * @param nRegularExpressionId
623      *            the ID of the regular expression
624      */
625     public static void doInsertRegularExpression( int nRegularExpressionId )
626     {
627         if ( !isEmailPatternSetManually( ) )
628         {
629             // Retrieve the rules from the database
630             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
631             String [ ] regularExpressionIds = emailPatternVerifyBy.split( COMMA );
632 
633             // Check if the ID is already inserted
634             boolean bIsAlreadyInserted = false;
635 
636             for ( String strRegularExpressionId : regularExpressionIds )
637             {
638                 String trimedId = strRegularExpressionId.trim( );
639 
640                 if ( StringUtils.isNotBlank( trimedId ) && StringUtils.isNumeric( trimedId ) )
641                 {
642                     int nRegexId = Integer.parseInt( trimedId );
643 
644                     if ( nRegexId == nRegularExpressionId )
645                     {
646                         bIsAlreadyInserted = true;
647 
648                         break;
649                     }
650                 }
651             }
652 
653             if ( !bIsAlreadyInserted )
654             {
655                 // If it is not inserted, then it is concatened to the list of regularExpression
656                 String strRegularExpressionIds = emailPatternVerifyBy + COMMA + nRegularExpressionId;
657                 emailPatternVerifyBy = strRegularExpressionIds;
658                 DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN_VERIFY_BY, emailPatternVerifyBy );
659             }
660         }
661     }
662 
663     /**
664      * Do remove a regular expression
665      * 
666      * @param nRegularExpressionId
667      *            the ID of the regularexpresion
668      */
669     public static void doRemoveRegularExpression( int nRegularExpressionId )
670     {
671         if ( !isEmailPatternSetManually( ) )
672         {
673             List<Integer> listRegularExpressionIds = new ArrayList<>( );
674 
675             // Retrieve the rules from the database
676             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
677             String [ ] regularExpressionIds = emailPatternVerifyBy.split( COMMA );
678 
679             // Build the list of regular expression without the regular expression id to
680             // delete
681             for ( String strRegularExpressionId : regularExpressionIds )
682             {
683                 String trimedId = strRegularExpressionId.trim( );
684 
685                 if ( StringUtils.isNotBlank( trimedId ) && StringUtils.isNumeric( trimedId ) )
686                 {
687                     int nRegexId = Integer.parseInt( trimedId );
688 
689                     if ( nRegexId != nRegularExpressionId )
690                     {
691                         listRegularExpressionIds.add( nRegexId );
692                     }
693                 }
694             }
695 
696             DefaultUserParameterHome.update( DSKEY_EMAIL_PATTERN_VERIFY_BY,
697                     listRegularExpressionIds.stream( ).map( String::valueOf ).collect( Collectors.joining( COMMA ) ) );
698         }
699     }
700 
701     /**
702      * Get the default email pattern defined in the <b>lutece.properties</b>.
703      * 
704      * @return the default email pattern
705      */
706     private static String getDefaultEmailPattern( )
707     {
708         return AppPropertiesService.getProperty( PROPERTY_EMAIL_PATTERN );
709     }
710 
711     /**
712      * Get the AdminUser email pattern that is stored in <b>'core_user_parameter.email_pattern'</b>. <br>
713      * If it does not exist, then it will retrieve the value in the <b>lutece.properties</b> file (parameter <b>email.pattern</b>)
714      * 
715      * @return the AdminUser email pattern
716      */
717     private static String getEmailPattern( )
718     {
719         String strEmailPattern = getDefaultEmailPattern( );
720         String emailPattern = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN );
721 
722         if ( emailPattern != null )
723         {
724             strEmailPattern = emailPattern;
725         }
726 
727         return strEmailPattern;
728     }
729 
730     /**
731      * Get the available rugalar expressions
732      * 
733      * @return a list of {@link ReferenceList}
734      */
735     public static ReferenceList getAvailableRegularExpressions( )
736     {
737         ReferenceListenceList">ReferenceList regularExpressionsList = new ReferenceList( );
738 
739         if ( !isEmailPatternSetManually( ) )
740         {
741             List<Integer> listRegularExpressionIds = new ArrayList<>( );
742 
743             // Retrieve the rules from the database
744             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
745             String [ ] regularExpressionIds = emailPatternVerifyBy.split( COMMA );
746 
747             for ( String strRegularExpressionId : regularExpressionIds )
748             {
749                 String trimedId = strRegularExpressionId.trim( );
750 
751                 if ( StringUtils.isNotBlank( trimedId ) && StringUtils.isNumeric( trimedId ) )
752                 {
753                     int nRegexId = Integer.parseInt( trimedId );
754                     listRegularExpressionIds.add( nRegexId );
755                 }
756             }
757 
758             // Fetch all regular expressions
759             List<RegularExpression> listRegularExpression = RegularExpressionService.getInstance( ).getAllRegularExpression( );
760 
761             // Get only the expressions that are not already selected
762             for ( RegularExpression regularExpression : listRegularExpression )
763             {
764                 if ( !listRegularExpressionIds.contains( regularExpression.getIdExpression( ) ) )
765                 {
766                     regularExpressionsList.addItem( regularExpression.getIdExpression( ), regularExpression.getTitle( ) );
767                 }
768             }
769         }
770 
771         return regularExpressionsList;
772     }
773 
774     /**
775      * Get the list of selected regular expression
776      * 
777      * @return a list of {@link RegularExpression}
778      */
779     public static List<RegularExpression> getSelectedRegularExpressions( )
780     {
781         List<RegularExpression> listRegularExpressions = new ArrayList<>( );
782 
783         if ( !isEmailPatternSetManually( ) )
784         {
785             // Retrieve the rules from the database
786             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
787             String [ ] regularExpressionIds = emailPatternVerifyBy.split( COMMA );
788 
789             for ( String strRegularExpressionId : regularExpressionIds )
790             {
791                 String trimedId = strRegularExpressionId.trim( );
792 
793                 if ( StringUtils.isNotBlank( trimedId ) && StringUtils.isNumeric( trimedId ) )
794                 {
795                     int nRegularExpressionId = Integer.parseInt( trimedId );
796                     RegularExpression expression = RegularExpressionService.getInstance( ).getRegularExpressionByKey( nRegularExpressionId );
797 
798                     if ( expression != null )
799                     {
800                         listRegularExpressions.add( expression );
801                     }
802                 }
803             }
804         }
805 
806         return listRegularExpressions;
807     }
808 
809     /**
810      * Check whether the email pattern is set manually or by a set of rules from the plugin-regularexpression.
811      * 
812      * @return true if it is set manually, false otherwise
813      */
814     private static boolean isEmailPatternSetManually( )
815     {
816         boolean bIsSetManually = true;
817 
818         if ( RegularExpressionService.getInstance( ).isAvailable( ) )
819         {
820             String emailPatternVerifyBy = DefaultUserParameterHome.findByKey( DSKEY_EMAIL_PATTERN_VERIFY_BY );
821 
822             if ( StringUtils.isNotBlank( emailPatternVerifyBy ) )
823             {
824                 bIsSetManually = false;
825             }
826         }
827 
828         return bIsSetManually;
829     }
830 
831     /**
832      * Get an integer user parameter from its key.
833      * 
834      * @param strParameterkey
835      *            Key of the parameter
836      * @return The value of the user parameter, or 0 if there is no value or an non integer value.
837      */
838     public static int getIntegerSecurityParameter( String strParameterkey )
839     {
840         String defaultUserParameter = DefaultUserParameterHome.findByKey( strParameterkey );
841 
842         if ( StringUtils.isBlank( defaultUserParameter ) )
843         {
844             return 0;
845         }
846 
847         try
848         {
849             return Integer.parseInt( defaultUserParameter );
850         }
851         catch( NumberFormatException e )
852         {
853             return 0;
854         }
855     }
856 
857     /**
858      * Get a boolean user parameter from its key.
859      * 
860      * @param strParameterkey
861      *            Key of the parameter
862      * @return The value of the user parameter, or false if there is no value or an non boolean value.
863      */
864     public static boolean getBooleanSecurityParameter( String strParameterkey )
865     {
866         String defaultUserParameter = DefaultUserParameterHome.findByKey( strParameterkey );
867 
868         return defaultUserParameter != null && Boolean.parseBoolean( defaultUserParameter );
869     }
870 
871     /**
872      * Get a user parameter from its key.
873      * 
874      * @param strParameterkey
875      *            Key of the parameter
876      * @return The value of the user parameter.
877      */
878     public static String getSecurityParameter( String strParameterkey )
879     {
880         return DefaultUserParameterHome.findByKey( strParameterkey );
881     }
882 
883     /**
884      * Get a user parameter from its key.
885      * 
886      * @param strParameterKey
887      *            Key of the parameter
888      * @return The value of the user parameter.
889      */
890     public static String getLargeSecurityParameter( String strParameterKey )
891     {
892         return DatastoreService.getDataValue( PluginService.getCore( ).getName( ) + CONSTANT_UNDERSCORE + strParameterKey, StringUtils.EMPTY );
893     }
894 
895     /**
896      * Update a security parameter value.
897      * 
898      * @param strParameterKey
899      *            The key of the parameter
900      * @param strValue
901      *            The new value
902      */
903     public static void updateSecurityParameter( String strParameterKey, String strValue )
904     {
905         String strValueTmp = StringUtils.isNotBlank( strValue ) ? strValue : StringUtils.EMPTY;
906         DefaultUserParameterHome.update( strParameterKey, strValueTmp );
907     }
908 
909     /**
910      * Update a security parameter value.
911      * 
912      * @param strParameterKey
913      *            The key of the parameter
914      * @param strValue
915      *            The new value
916      */
917     public static void updateLargeSecurityParameter( String strParameterKey, String strValue )
918     {
919         DatastoreService.setDataValue( PluginService.getCore( ).getName( ) + CONSTANT_UNDERSCORE + strParameterKey, strValue );
920     }
921 
922     /**
923      * Check that the password respect user parameters
924      * 
925      * @param request
926      *            The request
927      * @param strPassword
928      *            The password to check
929      * @param nUserId
930      *            The id of the modified user
931      * @return Null if the password is correct, or the url of an admin message describing the error
932      */
933     public static String checkPassword( HttpServletRequest request, String strPassword, int nUserId )
934     {
935         return checkPassword( request, strPassword, nUserId, Boolean.FALSE );
936     }
937 
938     /**
939      * Check that the password respect user parameters
940      * 
941      * @param request
942      *            The request
943      * @param strPassword
944      *            The password to check
945      * @param nUserId
946      *            The id of the modified user
947      * @param bSkipHistoryCheck
948      *            Indicates if the password history should be checked or not.
949      * @return Null if the password is correct, or the url of an admin message describing the error
950      */
951     public static String checkPassword( HttpServletRequest request, String strPassword, int nUserId, boolean bSkipHistoryCheck )
952     {
953         // Minimum password length
954         int nMinimumLength = AdminUserService.getIntegerSecurityParameter( DSKEY_PASSWORD_MINIMUM_LENGTH );
955 
956         if ( ( nMinimumLength > 0 ) && ( strPassword.length( ) < nMinimumLength ) )
957         {
958             Object [ ] param = {
959                     nMinimumLength
960             };
961 
962             return AdminMessageService.getMessageUrl( request, PROPERTY_MESSAGE_MINIMUM_PASSWORD_LENGTH, param, AdminMessage.TYPE_STOP );
963         }
964 
965         // Password format
966         String message = checkPasswordFormat( request, strPassword );
967         if ( message != null )
968         {
969             return message;
970         }
971 
972         // Check password history
973         if ( nUserId <= 0 || bSkipHistoryCheck )
974         {
975             return null;
976         }
977         return checkPasswordHistory( request, strPassword, nUserId );
978     }
979 
980     private static String checkPasswordHistory( HttpServletRequest request, String strPassword, int nUserId )
981     {
982         int nPasswordHistorySize = AdminUserService.getIntegerSecurityParameter( DSKEY_PASSWORD_HISTORY_SIZE );
983 
984         if ( nPasswordHistorySize > 0 )
985         {
986             List<IPassword> passwordHistory = AdminUserHome.selectUserPasswordHistory( nUserId );
987 
988             if ( nPasswordHistorySize < passwordHistory.size( ) )
989             {
990                 passwordHistory = passwordHistory.subList( 0, nPasswordHistorySize );
991             }
992 
993             for ( IPassword password : passwordHistory )
994             {
995                 if ( password.check( strPassword ) )
996                 {
997                     return AdminMessageService.getMessageUrl( request, PROPERTY_MESSAGE_PASSWORD_ALREADY_USED, AdminMessage.TYPE_STOP );
998                 }
999             }
1000         }
1001 
1002         int nTSWSizePasswordChange = AdminUserService.getIntegerSecurityParameter( DSKEY_TSW_SIZE_PASSWORD_CHANGE );
1003         int nMaximumNumberPasswordChange = AdminUserService.getIntegerSecurityParameter( DSKEY_MAXIMUM_NUMBER_PASSWORD_CHANGE );
1004 
1005         if ( nMaximumNumberPasswordChange > 0 )
1006         {
1007             Timestamp minDate;
1008 
1009             if ( nTSWSizePasswordChange > 0 )
1010             {
1011                 minDate = new Timestamp( new java.util.Date( ).getTime( ) - DateUtil.convertDaysInMiliseconds( nTSWSizePasswordChange ) );
1012             }
1013             else
1014             {
1015                 minDate = new Timestamp( 0 );
1016             }
1017 
1018             if ( AdminUserHome.countUserPasswordHistoryFromDate( minDate, nUserId ) >= nMaximumNumberPasswordChange )
1019             {
1020                 return AdminMessageService.getMessageUrl( request, PROPERTY_MESSAGE_MAX_PASSWORD_CHANGE, AdminMessage.TYPE_STOP );
1021             }
1022         }
1023 
1024         return null;
1025     }
1026 
1027     private static String checkPasswordFormat( HttpServletRequest request, String strPassword )
1028     {
1029         boolean bUserPasswordFormatUpperLowerCase = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE );
1030         boolean bUserPasswordFormatNumero = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_NUMERO );
1031         boolean bUserPasswordFormatSpecialCaracters = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS );
1032 
1033         if ( ( bUserPasswordFormatUpperLowerCase || bUserPasswordFormatNumero || bUserPasswordFormatSpecialCaracters ) && !PasswordUtil
1034                 .checkPasswordFormat( strPassword, bUserPasswordFormatUpperLowerCase, bUserPasswordFormatNumero, bUserPasswordFormatSpecialCaracters ) )
1035         {
1036             List<String> messageList = new ArrayList<>( );
1037 
1038             // Add Message Upper Lower Case
1039             if ( bUserPasswordFormatUpperLowerCase )
1040             {
1041                 messageList.add( I18nService.getLocalizedString( PROPERTY_MESSAGE_PASSWORD_FORMAT_UPPER_LOWER_CASE, request.getLocale( ) ) );
1042             }
1043 
1044             // Add Message Numero
1045             if ( bUserPasswordFormatNumero )
1046             {
1047                 messageList.add( I18nService.getLocalizedString( PROPERTY_MESSAGE_PASSWORD_FORMAT_NUMERO, request.getLocale( ) ) );
1048             }
1049 
1050             // Add Message Special Characters
1051             if ( bUserPasswordFormatSpecialCaracters )
1052             {
1053                 messageList.add( I18nService.getLocalizedString( PROPERTY_MESSAGE_PASSWORD_FORMAT_SPECIAL_CHARACTERS, request.getLocale( ) ) );
1054             }
1055 
1056             String strParam = messageList.stream( ).collect( Collectors.joining( ", " ) );
1057 
1058             Object [ ] param = {
1059                     strParam
1060             };
1061 
1062             return AdminMessageService.getMessageUrl( request, PROPERTY_MESSAGE_PASSWORD_FORMAT, param, AdminMessage.TYPE_STOP );
1063         }
1064         return null;
1065     }
1066 
1067     /**
1068      * Generate a new random password
1069      * 
1070      * @return the new password
1071      */
1072     public static String makePassword( )
1073     {
1074         // Password format
1075         boolean bUserPasswordFormatUpperLowerCase = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE );
1076         boolean bUserPasswordFormatNumero = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_NUMERO );
1077         boolean bUserPasswordFormatSpecialCaracters = AdminUserService.getBooleanSecurityParameter( DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS );
1078         int nMinPasswordSize = AdminUserService.getIntegerSecurityParameter( DSKEY_PASSWORD_MINIMUM_LENGTH );
1079 
1080         return PasswordUtil.makePassword( nMinPasswordSize, bUserPasswordFormatUpperLowerCase, bUserPasswordFormatNumero, bUserPasswordFormatSpecialCaracters );
1081     }
1082 
1083     /**
1084      * Encrypt a password
1085      * 
1086      * @param strPassword
1087      *            The password to encrypt
1088      * @return The given password encrypted
1089      */
1090     public static IPassword encryptPassword( String strPassword )
1091     {
1092         IPasswordFactory passwordFactory = SpringContextService.getBean( IPasswordFactory.BEAN_NAME );
1093 
1094         return passwordFactory.getPasswordFromCleartext( strPassword );
1095     }
1096 
1097     /**
1098      * Enable advanced security parameters
1099      */
1100     public static void useAdvancedSecurityParameters( )
1101     {
1102         updateSecurityParameter( DSKEY_USE_ADVANCED_SECURITY_PARAMETERS, Boolean.TRUE.toString( ) );
1103         updateSecurityParameter( DSKEY_FORCE_CHANGE_PASSWORD_REINIT, Boolean.TRUE.toString( ) );
1104         updateSecurityParameter( DSKEY_MAXIMUM_NUMBER_PASSWORD_CHANGE, AppPropertiesService.getProperty( PROPERTY_DEFAULT_MAXIMUM_NUMBER_PASSWORD_CHANGE ) );
1105         updateSecurityParameter( DSKEY_PASSWORD_DURATION, AppPropertiesService.getProperty( PROPERTY_DEFAULT_PASSWORD_DURATION ) );
1106         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE, Boolean.TRUE.toString( ) );
1107         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_NUMERO, Boolean.TRUE.toString( ) );
1108         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS, Boolean.TRUE.toString( ) );
1109         updateSecurityParameter( DSKEY_PASSWORD_HISTORY_SIZE, AppPropertiesService.getProperty( PROPERTY_DEFAULT_HISTORY_SIZE ) );
1110         updateSecurityParameter( DSKEY_TSW_SIZE_PASSWORD_CHANGE, AppPropertiesService.getProperty( PROPERTY_DEFAULT_TSW_SIZE_PASSWORD_CHANGE ) );
1111 
1112         int nMinPwdLength = getIntegerSecurityParameter( DSKEY_PASSWORD_MINIMUM_LENGTH );
1113 
1114         if ( nMinPwdLength <= 0 )
1115         {
1116             updateSecurityParameter( DSKEY_PASSWORD_MINIMUM_LENGTH, AppPropertiesService.getProperty( PROPERTY_DEFAULT_PASSWORD_MINIMAL_LENGTH ) );
1117         }
1118 
1119         updateSecurityParameter( DSKEY_NOTIFY_USER_PASSWORD_EXPIRED, Boolean.TRUE.toString( ) );
1120     }
1121 
1122     /**
1123      * Disable advances security parameters
1124      */
1125     public static void removeAdvancedSecurityParameters( )
1126     {
1127         updateSecurityParameter( DSKEY_USE_ADVANCED_SECURITY_PARAMETERS, StringUtils.EMPTY );
1128         updateSecurityParameter( DSKEY_MAXIMUM_NUMBER_PASSWORD_CHANGE, StringUtils.EMPTY );
1129         updateSecurityParameter( DSKEY_PASSWORD_DURATION, StringUtils.EMPTY );
1130         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_UPPER_LOWER_CASE, StringUtils.EMPTY );
1131         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_NUMERO, StringUtils.EMPTY );
1132         updateSecurityParameter( DSKEY_PASSWORD_FORMAT_SPECIAL_CHARACTERS, StringUtils.EMPTY );
1133         updateSecurityParameter( DSKEY_PASSWORD_HISTORY_SIZE, StringUtils.EMPTY );
1134         updateSecurityParameter( DSKEY_TSW_SIZE_PASSWORD_CHANGE, StringUtils.EMPTY );
1135         updateSecurityParameter( DSKEY_NOTIFY_USER_PASSWORD_EXPIRED, StringUtils.EMPTY );
1136     }
1137 
1138     /**
1139      * Compute the maximum valid date of a password with the current time and the parameters in the database.
1140      * 
1141      * @return The maximum valid date of a password
1142      */
1143     public static Timestamp getPasswordMaxValidDate( )
1144     {
1145         int nbDayPasswordValid = getIntegerSecurityParameter( DSKEY_PASSWORD_DURATION );
1146 
1147         if ( nbDayPasswordValid <= 0 )
1148         {
1149             return null;
1150         }
1151 
1152         return PasswordUtil.getPasswordMaxValidDate( nbDayPasswordValid );
1153     }
1154 
1155     /**
1156      * Compute the maximum valid date of an account with the current time and the parameters in the database.
1157      * 
1158      * @return The maximum valid date of an account
1159      */
1160     public static Timestamp getAccountMaxValidDate( )
1161     {
1162         int nbMonthsAccountValid = getIntegerSecurityParameter( DSKEY_ACCOUNT_LIFE_TIME );
1163 
1164         if ( nbMonthsAccountValid <= 0 )
1165         {
1166             return null;
1167         }
1168 
1169         Calendar calendar = new GregorianCalendar( LocaleService.getDefault( ) );
1170         calendar.add( Calendar.MONTH, nbMonthsAccountValid );
1171 
1172         return new Timestamp( calendar.getTimeInMillis( ) );
1173     }
1174 
1175     /**
1176      * Anonymize user data from his id. His rights, roles and his passwords history are also deleted.
1177      * 
1178      * @param nAdminUserId
1179      *            Id of the user to anonymize
1180      * @param locale
1181      *            The locale
1182      */
1183     public static void anonymizeUser( int nAdminUserId, Locale locale )
1184     {
1185         AdminUser user = AdminUserHome.findByPrimaryKey( nAdminUserId );
1186 
1187         String strEncryptionAlgorithme = AppPropertiesService.getProperty( PROPERTY_ANONYMIZATION_ENCRYPT_ALGO, CONSTANT_DEFAULT_ENCRYPT_ALGO );
1188 
1189         Map<String, Boolean> anonymizationStatus = AdminUserHome.getAnonymizationStatusUserStaticField( );
1190 
1191         if ( Boolean.TRUE.equals( anonymizationStatus.get( PARAMETER_ACCESS_CODE ) ) )
1192         {
1193             user.setAccessCode( CryptoService.encrypt( user.getAccessCode( ), strEncryptionAlgorithme ) );
1194         }
1195 
1196         if ( Boolean.TRUE.equals( anonymizationStatus.get( PARAMETER_FIRST_NAME ) ) )
1197         {
1198             user.setFirstName( CryptoService.encrypt( user.getFirstName( ), strEncryptionAlgorithme ) );
1199         }
1200 
1201         if ( Boolean.TRUE.equals( anonymizationStatus.get( PARAMETER_LAST_NAME ) ) )
1202         {
1203             user.setLastName( CryptoService.encrypt( user.getLastName( ), strEncryptionAlgorithme ) );
1204         }
1205 
1206         if ( Boolean.TRUE.equals( anonymizationStatus.get( PARAMETER_EMAIL ) ) )
1207         {
1208             user.setEmail( CryptoService.encrypt( user.getEmail( ), strEncryptionAlgorithme ) );
1209         }
1210 
1211         user.setStatus( AdminUser.ANONYMIZED_CODE );
1212         AdminUserHome.removeAllRightsForUser( nAdminUserId );
1213         AdminUserHome.removeAllRolesForUser( nAdminUserId );
1214         AdminUserHome.removeAllPasswordHistoryForUser( nAdminUserId );
1215         AdminUserHome.update( user );
1216 
1217         AttributeService attributeService = AttributeService.getInstance( );
1218         List<IAttribute> listAllAttributes = attributeService.getAllAttributesWithoutFields( locale );
1219         List<IAttribute> listAttributesText = new ArrayList<>( );
1220 
1221         for ( IAttribute attribut : listAllAttributes )
1222         {
1223             if ( attribut.isAnonymizable( ) )
1224             {
1225                 listAttributesText.add( attribut );
1226             }
1227         }
1228 
1229         for ( IAttribute attribute : listAttributesText )
1230         {
1231             List<AdminUserField> listAdminUserField = AdminUserFieldHome.selectUserFieldsByIdUserIdAttribute( nAdminUserId, attribute.getIdAttribute( ) );
1232 
1233             for ( AdminUserField adminUserField : listAdminUserField )
1234             {
1235                 adminUserField.setValue( CryptoService.encrypt( adminUserField.getValue( ), strEncryptionAlgorithme ) );
1236                 AdminUserFieldHome.update( adminUserField );
1237             }
1238         }
1239     }
1240 
1241     /**
1242      * Get the list of id of expired users
1243      * 
1244      * @return the list of id of expired users
1245      */
1246     public static List<Integer> getExpiredUserIdList( )
1247     {
1248         return AdminUserHome.findAllExpiredUserId( );
1249     }
1250 
1251     /**
1252      * Update the user expiration date with new values, and notify him with an email if his account was close to expire.
1253      * 
1254      * @param user
1255      *            The user to update
1256      */
1257     public static void updateUserExpirationDate( AdminUser user )
1258     {
1259         if ( user == null )
1260         {
1261             return;
1262         }
1263 
1264         Timestamp newExpirationDate = getAccountMaxValidDate( );
1265         Timestamp maxValidDate = user.getAccountMaxValidDate( );
1266         // We update the user account
1267         AdminUserHome.updateUserExpirationDate( user.getUserId( ), newExpirationDate );
1268 
1269         // We notify the user
1270         String strUserMail = user.getEmail( );
1271         int nbDaysBeforeFirstAlert = AdminUserService.getIntegerSecurityParameter( DSKEY_TIME_BEFORE_ALERT_ACCOUNT );
1272 
1273         if ( maxValidDate != null )
1274         {
1275             Timestamp firstAlertMaxDate = new Timestamp( maxValidDate.getTime( ) - DateUtil.convertDaysInMiliseconds( nbDaysBeforeFirstAlert ) );
1276             Timestamp currentTimestamp = new Timestamp( new java.util.Date( ).getTime( ) );
1277 
1278             if ( ( currentTimestamp.getTime( ) > firstAlertMaxDate.getTime( ) ) && StringUtils.isNotBlank( strUserMail ) )
1279             {
1280                 AdminUser completeUser = AdminUserHome.findByPrimaryKey( user.getUserId( ) );
1281                 String strBody = DatabaseTemplateService.getTemplateFromKey( DSKEY_ACCOUNT_REACTIVATED_MAIL_BODY );
1282 
1283                 String defaultUserParameter = DefaultUserParameterHome.findByKey( DSKEY_ACCOUNT_REACTIVATED_MAIL_SENDER );
1284                 String strSender = ( defaultUserParameter == null ) ? StringUtils.EMPTY : defaultUserParameter;
1285 
1286                 defaultUserParameter = DefaultUserParameterHome.findByKey( DSKEY_ACCOUNT_REACTIVATED_MAIL_SUBJECT );
1287 
1288                 String strSubject = ( defaultUserParameter == null ) ? StringUtils.EMPTY : defaultUserParameter;
1289 
1290                 Map<String, String> model = new HashMap<>( );
1291 
1292                 DateFormat dateFormat = DateFormat.getDateInstance( DateFormat.SHORT, LocaleService.getDefault( ) );
1293 
1294                 if ( newExpirationDate != null )
1295                 {
1296                     String accountMaxValidDate = dateFormat.format( new Date( newExpirationDate.getTime( ) ) );
1297                     model.put( MARK_DATE_VALID, accountMaxValidDate );
1298                 }
1299                 model.put( MARK_NAME, completeUser.getLastName( ) );
1300                 model.put( MARK_FIRST_NAME, completeUser.getFirstName( ) );
1301 
1302                 HtmlTemplate template = AppTemplateService.getTemplateFromStringFtl( strBody, LocaleService.getDefault( ), model );
1303                 MailService.sendMailHtml( strUserMail, strSender, strSender, strSubject, template.getHtml( ) );
1304             }
1305         }
1306     }
1307 
1308     /**
1309      * Update the date of last login of an admin user
1310      * 
1311      * @param nIdUser
1312      *            Id of the user to update
1313      */
1314     public static void updateDateLastLogin( int nIdUser )
1315     {
1316         AdminUserHome.updateDateLastLogin( nIdUser, new Timestamp( new Date( ).getTime( ) ) );
1317     }
1318 
1319     /**
1320      * Notify an user by email
1321      * 
1322      * @param strBaseUrl
1323      *            The base URL of the webapp
1324      * @param user
1325      *            The admin user to notify
1326      * @param strPropertyEmailSubject
1327      *            the property of the subject email
1328      * @param strTemplate
1329      *            the URL of the HTML Template
1330      */
1331     public static void notifyUser( String strBaseUrl, AdminUser user, String strPropertyEmailSubject, String strTemplate )
1332     {
1333         notifyUser( strBaseUrl, user, null, strPropertyEmailSubject, strTemplate );
1334     }
1335 
1336     /**
1337      * Notify an user by email
1338      * 
1339      * @param strBaseUrl
1340      *            The base URL of the webapp
1341      * @param user
1342      *            The admin user to notify
1343      * @param strPassword
1344      *            the user password in cleartext
1345      * @param strPropertyEmailSubject
1346      *            the property of the subject email
1347      * @param strTemplate
1348      *            the URL of the HTML Template
1349      */
1350     public static void notifyUser( String strBaseUrl, AdminUser user, String strPassword, String strPropertyEmailSubject, String strTemplate )
1351     {
1352         String strSenderEmail = MailService.getNoReplyEmail( );
1353         String strSiteName = PortalService.getSiteName( );
1354         Locale locale = user.getLocale( );
1355         String strEmailSubject = I18nService.getLocalizedString( strPropertyEmailSubject, new String [ ] {
1356                 strSiteName
1357         }, locale );
1358         Map<String, Object> model = new HashMap<>( );
1359         model.put( MARK_USER, user );
1360         model.put( MARK_PASSWORD, strPassword );
1361         model.put( MARK_SITE_NAME, strSiteName );
1362         model.put( MARK_LOGIN_URL, strBaseUrl + AdminAuthenticationService.getInstance( ).getLoginPageUrl( ) );
1363         model.put( MARK_SITE_LINK, MailService.getSiteLink( strBaseUrl, false ) );
1364 
1365         HtmlTemplate template = AppTemplateService.getTemplate( strTemplate, locale, model );
1366 
1367         MailService.sendMailHtml( user.getEmail( ), strSenderEmail, strSenderEmail, strEmailSubject, template.getHtml( ) );
1368     }
1369 
1370     /**
1371      * Get a XML string describing a user.<br>
1372      * The XML is constructed as follow :<br>
1373      * <b>&lt;user&gt;</b><br>
1374      * &nbsp;&nbsp;<b>&lt;access_code&gt;</b>value<b>&lt;/value&gt;</b><br>
1375      * &nbsp;&nbsp;<b>&lt;last_name&gt;</b>value<b>&gt;/user&gt;</b><br>
1376      * &nbsp;&nbsp;<b>&lt;first_name&gt;</b>value<b>&lt;/value&gt;</b><br>
1377      * &nbsp;&nbsp;<b>&lt;email&gt;</b>value<b>&lt;/email&gt;</b><br>
1378      * &nbsp;&nbsp;<b>&lt;status&gt;</b>value<b>&lt;/status&gt;</b><br>
1379      * &nbsp;&nbsp;<b>&lt;locale&gt;</b>value<b>&lt;/locale&gt;</b><br>
1380      * &nbsp;&nbsp;<b>&lt;level&gt;</b>value<b>&lt;/level&gt;</b><br>
1381      * &nbsp;&nbsp;<b>&lt;must_change_password&gt;</b>value<b>&lt; must_change_password&gt;</b><br>
1382      * &nbsp;&nbsp;<b>&lt;accessibility_mode&gt;</b>value<b>&lt; accessibility_mode&gt;</b><br>
1383      * &nbsp;&nbsp;<b>&lt;password_max_valid_date&gt;</b>value<b>&lt; password_max_valid_date&gt;</b><br>
1384      * &nbsp;&nbsp;<b>&lt;account_max_valid_date&gt;</b>value<b>&lt; account_max_valid_date&gt;</b><br>
1385      * &nbsp;&nbsp;<b>&lt;date_last_login&gt;</b>value<b>&lt;/date_last_login&gt;</b><br>
1386      * &nbsp;&nbsp;<b>&lt;roles&gt;</b><br>
1387      * &nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;role&gt;</b>value<b>&lt;/role&gt;</b><br>
1388      * &nbsp;&nbsp;&nbsp;&nbsp;...<br>
1389      * &nbsp;&nbsp;<b>&lt;/roles&gt;</b><br>
1390      * &nbsp;&nbsp;<b>&lt;rights&gt;</b><br>
1391      * &nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;right&gt;</b>value<b>&lt;/right&gt;</b><br>
1392      * &nbsp;&nbsp;&nbsp;&nbsp;...<br>
1393      * &nbsp;&nbsp;<b>&lt;/rights&gt;</b><br>
1394      * &nbsp;&nbsp;<b>&lt;workspaces&gt;</b><br>
1395      * &nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;workspace&gt;</b>value<b>&lt;/workspace&gt;</b><br>
1396      * &nbsp;&nbsp;&nbsp;&nbsp;...<br>
1397      * &nbsp;&nbsp;<b>&lt;/workspaces&gt;</b><br>
1398      * &nbsp;&nbsp;<b>&lt;attributes&gt;</b><br>
1399      * &nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;attribute&gt;</b><br>
1400      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;attribute-id&gt;</b>value<b>&lt;/attribute-id&gt;</b><br>
1401      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;attribute-field-id&gt;</b> value<b>&lt;/attribute-id&gt;</b><br>
1402      * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;attribute-value&gt;</b>value<b >&lt;/attribute-value&gt;</b><br>
1403      * &nbsp;&nbsp;&nbsp;&nbsp;<b>&lt;/attribute&gt;</b><br>
1404      * &nbsp;&nbsp;&nbsp;&nbsp;...<br>
1405      * &nbsp;&nbsp;<b>&lt;/attributes&gt;</b><br>
1406      * <b>&lt;/user&gt;</b><br>
1407      * <br>
1408      * Sections <b>roles</b>, <b>rights</b>, <b>workspaces</b> and <b>attributes</b> are not included if data are not imported
1409      * 
1410      * @param user
1411      *            The user to get the XML description of.
1412      * @param bIncludeRoles
1413      *            True to include roles of the user in the XML, false otherwise.
1414      * @param bIncludeRights
1415      *            True to include rights of the user in the XML, false otherwise.
1416      * @param bIncludeWorkgroups
1417      *            True to include workgroups of the user in the XML, false otherwise.
1418      * @param bIncludeAttributes
1419      *            True to include attributes of the user in the XML, false otherwise.
1420      * @param listAttributes
1421      *            The list of attributes to include in the XML if attributes are included.
1422      * @return A string of XML describing the user.
1423      */
1424     public static String getXmlFromUser( AdminUser user, boolean bIncludeRoles, boolean bIncludeRights, boolean bIncludeWorkgroups, boolean bIncludeAttributes,
1425             List<IAttribute> listAttributes )
1426     {
1427         StringBuffer sbXml = new StringBuffer( );
1428         DateFormat dateFormat = new SimpleDateFormat( );
1429 
1430         XmlUtil.beginElement( sbXml, CONSTANT_XML_USER );
1431         XmlUtil.addElement( sbXml, CONSTANT_XML_ACCESS_CODE, user.getAccessCode( ) );
1432         XmlUtil.addElement( sbXml, CONSTANT_XML_LAST_NAME, user.getLastName( ) );
1433         XmlUtil.addElement( sbXml, CONSTANT_XML_FIRST_NAME, user.getFirstName( ) );
1434         XmlUtil.addElement( sbXml, CONSTANT_XML_EMAIL, user.getEmail( ) );
1435         XmlUtil.addElement( sbXml, CONSTANT_XML_STATUS, Integer.toString( user.getRealStatus( ) ) );
1436         XmlUtil.addElement( sbXml, CONSTANT_XML_LOCALE, user.getLocale( ).toString( ) );
1437         XmlUtil.addElement( sbXml, CONSTANT_XML_LEVEL, Integer.toString( user.getUserLevel( ) ) );
1438         XmlUtil.addElement( sbXml, CONSTANT_XML_MUST_CHANGE_PASSWORD, Boolean.toString( user.isPasswordReset( ) ) );
1439         XmlUtil.addElement( sbXml, CONSTANT_XML_ACCESSIBILITY_MODE, Boolean.toString( user.getAccessibilityMode( ) ) );
1440 
1441         String strPasswordMaxValidDate = Optional.ofNullable( user.getPasswordMaxValidDate( ) ).map( dateFormat::format ).orElse( StringUtils.EMPTY );
1442         XmlUtil.addElement( sbXml, CONSTANT_XML_PASSWORD_MAX_VALID_DATE, strPasswordMaxValidDate );
1443 
1444         String strAccountMaxValidDate = Optional.ofNullable( user.getAccountMaxValidDate( ) ).map( dateFormat::format ).orElse( StringUtils.EMPTY );
1445         XmlUtil.addElement( sbXml, CONSTANT_XML_ACCOUNT_MAX_VALID_DATE, strAccountMaxValidDate );
1446 
1447         String strDateLastLogin = Optional.ofNullable( user.getDateLastLogin( ) ).map( dateFormat::format ).orElse( StringUtils.EMPTY );
1448         XmlUtil.addElement( sbXml, CONSTANT_XML_DATE_LAST_LOGIN, strDateLastLogin );
1449 
1450         if ( bIncludeRoles )
1451         {
1452             Map<String, RBACRole> mapRoles = AdminUserHome.getRolesListForUser( user.getUserId( ) );
1453             XmlUtil.beginElement( sbXml, CONSTANT_XML_ROLES );
1454             mapRoles.keySet( ).forEach( s -> XmlUtil.addElement( sbXml, CONSTANT_XML_ROLE, s ) );
1455             XmlUtil.endElement( sbXml, CONSTANT_XML_ROLES );
1456         }
1457 
1458         if ( bIncludeRights )
1459         {
1460             Map<String, Right> mapRights = AdminUserHome.getRightsListForUser( user.getUserId( ) );
1461             XmlUtil.beginElement( sbXml, CONSTANT_XML_RIGHTS );
1462             mapRights.keySet( ).forEach( s -> XmlUtil.addElement( sbXml, CONSTANT_XML_RIGHT, s ) );
1463             XmlUtil.endElement( sbXml, CONSTANT_XML_RIGHTS );
1464         }
1465 
1466         if ( bIncludeWorkgroups )
1467         {
1468             ReferenceList refListWorkgroups = AdminWorkgroupHome.getUserWorkgroups( user );
1469             XmlUtil.beginElement( sbXml, CONSTANT_XML_WORKGROUPS );
1470             refListWorkgroups.forEach( ri -> XmlUtil.addElement( sbXml, CONSTANT_XML_WORKGROUP, ri.getCode( ) ) );
1471             XmlUtil.endElement( sbXml, CONSTANT_XML_WORKGROUPS );
1472         }
1473 
1474         if ( bIncludeAttributes )
1475         {
1476             Map<String, Object> mapAttributes = AdminUserFieldService.getAdminUserFields( listAttributes, user.getUserId( ), LocaleService.getDefault( ) );
1477             XmlUtil.beginElement( sbXml, CONSTANT_XML_ATTRIBUTES );
1478 
1479             for ( Entry<String, Object> entry : mapAttributes.entrySet( ) )
1480             {
1481                 String strAttributeKey = entry.getKey( );
1482                 Object value = entry.getValue( );
1483 
1484                 if ( value instanceof List<?> )
1485                 {
1486                     List<AdminUserField> listFields = (List<AdminUserField>) value;
1487                     listFields = listFields.stream( ).filter( auf -> auf.getIdUserField( ) > 0 ).collect( Collectors.toList( ) );
1488 
1489                     for ( AdminUserField adminUserFields : listFields )
1490                     {
1491                         XmlUtil.beginElement( sbXml, CONSTANT_XML_ATTRIBUTE );
1492                         XmlUtil.addElement( sbXml, CONSTANT_XML_ATTRIBUTE_ID, strAttributeKey );
1493                         XmlUtil.addElement( sbXml, CONSTANT_XML_ATTRIBUTE_FIELD_ID, adminUserFields.getAttributeField( ).getIdField( ) );
1494                         XmlUtil.addElement( sbXml, CONSTANT_XML_ATTRIBUTE_VALUE, adminUserFields.getValue( ) );
1495                         XmlUtil.endElement( sbXml, CONSTANT_XML_ATTRIBUTE );
1496                     }
1497                 }
1498             }
1499 
1500             XmlUtil.endElement( sbXml, CONSTANT_XML_ATTRIBUTES );
1501         }
1502 
1503         XmlUtil.endElement( sbXml, CONSTANT_XML_USER );
1504 
1505         return sbXml.toString( );
1506     }
1507 
1508     /**
1509      * Get a user reset password token
1510      * 
1511      * @param user
1512      *            the user
1513      * @param timestamp
1514      *            the timestamp of the token
1515      * @param request
1516      *            he request
1517      * @return the reset password token
1518      */
1519     public static String getUserPasswordResetToken( AdminUser user, Date timestamp, HttpServletRequest request )
1520     {
1521         String strSessionId = null;
1522         if ( getBooleanSecurityParameter( DSKEY_LOCK_RESET_TOKEN_TO_SESSION ) )
1523         {
1524             strSessionId = request.getSession( ).getId( );
1525         }
1526         return AdminUserHome.getUserPasswordResetToken( user.getUserId( ), timestamp, strSessionId );
1527     }
1528 
1529 }