PasswordUtil.java

  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.util.password;

  35. import fr.paris.lutece.portal.service.admin.AdminUserService;
  36. import fr.paris.lutece.portal.service.util.AppPropertiesService;
  37. import fr.paris.lutece.util.date.DateUtil;

  38. import java.security.SecureRandom;
  39. import java.sql.Timestamp;

  40. import java.util.ArrayList;
  41. import java.util.Collections;
  42. import java.util.Random;

  43. /**
  44.  * Utility class used to generate random passwords
  45.  */
  46. public final class PasswordUtil
  47. {
  48.     public static final String PROPERTY_PASSWORD_SIZE = "randomPassword.size";
  49.     public static final int CONSTANT_DEFAULT_RANDOM_PASSWORD_SIZE = 16;
  50.     private static final int CONSTANT_NUMBER_LETTERS = 26;
  51.     private static final int CONSTANT_NUMBER_NUMBERS_BASE10 = 10;
  52.     private static final int CONSTANT_ASCII_CODE_A_UPPERCASE = 65;
  53.     private static final int CONSTANT_ASCII_CODE_A_LOWERCASE = 97;
  54.     private static final int CONSTANT_ASCII_CODE_ZERO = 48;
  55.     private static final char [ ] CONSTANT_SPECIAL_CHARACTERS = {
  56.             '!', ',', ':', '?', '$', '-', '@', '}', '{', '(', ')', '*', '+', '=', '[', ']', '%', '.',
  57.     };
  58.     private static final String CONSTANT_PASSWORD_BEGIN_REGEX = "^";
  59.     private static final String CONSTANT_PASSWORD_REGEX_NUM = "(?=.*[0-9])";
  60.     private static final String CONSTANT_PASSWORD_REGEX_SPECIAL = "(?=.*[^a-zA-Z0-9])";
  61.     private static final String CONSTANT_PASSWORD_REGEX_UPPER_LOWER = "(?=.*[a-z])(?=.*[A-Z])";
  62.     private static final String CONSTANT_PASSWORD_END_REGEX = "(.*)$";
  63.     private static final String PARAMETER_PASSWORD_MINIMUM_LENGTH = "password_minimum_length";

  64.     /** Private Constructor */
  65.     private PasswordUtil( )
  66.     {
  67.     }

  68.     /**
  69.      * Generate a new random password
  70.      *
  71.      * @return the new password
  72.      */
  73.     public static String makePassword( )
  74.     {
  75.         // reinitialize password
  76.         int nPasswordSize = AppPropertiesService.getPropertyInt( PROPERTY_PASSWORD_SIZE, CONSTANT_DEFAULT_RANDOM_PASSWORD_SIZE );
  77.         int nMinPasswordSize = AdminUserService.getIntegerSecurityParameter( PARAMETER_PASSWORD_MINIMUM_LENGTH );

  78.         if ( nMinPasswordSize > nPasswordSize )
  79.         {
  80.             nPasswordSize = nMinPasswordSize;
  81.         }

  82.         return makePassword( nPasswordSize, true, true, true );
  83.     }

  84.     /**
  85.      * Generate a new random password
  86.      *
  87.      * @param nPasswordSize
  88.      *            the password size
  89.      * @param bUpperAndLowerCase
  90.      *            true if the password must contain upper and lower case
  91.      * @param bNumbers
  92.      *            if the password must contain numbers
  93.      * @param bSpecialCaracters
  94.      *            if the password must contain special characters
  95.      *
  96.      * @return the new password
  97.      */
  98.     public static String makePassword( int nPasswordSize, boolean bUpperAndLowerCase, boolean bNumbers, boolean bSpecialCaracters )
  99.     {
  100.         // reinitialize password
  101.         Random r = new SecureRandom( );

  102.         ArrayList<Character> listCharacters = new ArrayList<>( nPasswordSize );

  103.         // No of Big letters
  104.         int nNumCapitalLetters = bUpperAndLowerCase ? ( r.nextInt( nPasswordSize - 3 ) + 1 ) : 0; // choose a number between 1 and CONSTANT_PASSWORD_SIZE -1

  105.         // no on special characters
  106.         int nNumSpecial = bSpecialCaracters ? ( r.nextInt( nPasswordSize - 2 - nNumCapitalLetters ) + 1 ) : 0; // choose a number beetwen 1 and
  107.                                                                                                                // CONSTANT_PASSWORD_SIZE - a1

  108.         // no of nos
  109.         int nNumNumbers = bNumbers ? ( r.nextInt( nPasswordSize - 1 - nNumCapitalLetters - nNumSpecial ) + 1 ) : 0; // choose a number to complete list of
  110.                                                                                                                     // CONSTANT_PASSWORD_SIZE characters

  111.         // no of small
  112.         int nNumSmallLetters = nPasswordSize - nNumCapitalLetters - nNumSpecial - nNumNumbers; // choose a number to complete list of CONSTANT_PASSWORD_SIZE
  113.                                                                                                // characters

  114.         for ( int j = 0; j < nNumCapitalLetters; j++ )
  115.         {
  116.             char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_LETTERS ) + CONSTANT_ASCII_CODE_A_UPPERCASE );
  117.             listCharacters.add( Character.valueOf( c1 ) );
  118.         }

  119.         for ( int j = 0; j < nNumSmallLetters; j++ )
  120.         {
  121.             char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_LETTERS ) + CONSTANT_ASCII_CODE_A_LOWERCASE );
  122.             listCharacters.add( Character.valueOf( c1 ) );
  123.         }

  124.         for ( int j = 0; j < nNumNumbers; j++ )
  125.         {
  126.             char c1 = (char) ( r.nextInt( CONSTANT_NUMBER_NUMBERS_BASE10 - 1 ) + CONSTANT_ASCII_CODE_ZERO );
  127.             listCharacters.add( Character.valueOf( c1 ) );
  128.         }

  129.         for ( int j = 0; j < nNumSpecial; j++ )
  130.         {
  131.             char c1 = CONSTANT_SPECIAL_CHARACTERS [r.nextInt( CONSTANT_SPECIAL_CHARACTERS.length )];
  132.             listCharacters.add( Character.valueOf( c1 ) );
  133.         }

  134.         Collections.shuffle( listCharacters, r );

  135.         StringBuilder sbPassword = new StringBuilder( listCharacters.size( ) );

  136.         for ( Character myChar : listCharacters )
  137.         {
  138.             sbPassword.append( myChar );
  139.         }

  140.         return sbPassword.toString( );
  141.     }

  142.     /**
  143.      * Check whether a password contains upper and lower case letters, special characters and numbers.
  144.      *
  145.      * @param strPassword
  146.      *            The password to check
  147.      * @return True if the password format is correct, false otherwise
  148.      */
  149.     public static boolean checkPasswordFormat( String strPassword )
  150.     {
  151.         return checkPasswordFormat( strPassword, true, true, true );
  152.     }

  153.     /**
  154.      * Check whether a password contains upper and lower case letters, special characters and numbers.
  155.      *
  156.      * @param strPassword
  157.      *            The password to check
  158.      * @param bUpperAndLowerCase
  159.      *            true if the password must contain upper and lower case
  160.      * @param bNumero
  161.      *            if the password must contain numero
  162.      * @param bSpecialCaracters
  163.      *            if the password must contain special characters
  164.      *
  165.      * @return True if the password format is correct, false otherwise
  166.      */
  167.     public static boolean checkPasswordFormat( String strPassword, boolean bUpperAndLowerCase, boolean bNumero, boolean bSpecialCaracters )
  168.     {
  169.         if ( ( strPassword == null ) || strPassword.isEmpty( ) )
  170.         {
  171.             return false;
  172.         }

  173.         StringBuilder sbRegex = new StringBuilder( CONSTANT_PASSWORD_BEGIN_REGEX );

  174.         if ( bUpperAndLowerCase )
  175.         {
  176.             sbRegex.append( CONSTANT_PASSWORD_REGEX_UPPER_LOWER );
  177.         }

  178.         if ( bNumero )
  179.         {
  180.             sbRegex.append( CONSTANT_PASSWORD_REGEX_NUM );
  181.         }

  182.         if ( bSpecialCaracters )
  183.         {
  184.             sbRegex.append( CONSTANT_PASSWORD_REGEX_SPECIAL );
  185.         }

  186.         sbRegex.append( CONSTANT_PASSWORD_END_REGEX );

  187.         return strPassword.matches( sbRegex.toString( ) );
  188.     }

  189.     /**
  190.      * Get the maximum valid date of a password starting from now with the given number of days.
  191.      *
  192.      * @param nNumberDay
  193.      *            The number of days the password is valid
  194.      * @return The maximum valid date of a password
  195.      */
  196.     public static Timestamp getPasswordMaxValidDate( int nNumberDay )
  197.     {
  198.         if ( nNumberDay <= 0 )
  199.         {
  200.             return null;
  201.         }

  202.         long nMilliSeconds = DateUtil.convertDaysInMiliseconds( nNumberDay );
  203.         return new Timestamp( new java.util.Date( ).getTime( ) + nMilliSeconds );
  204.     }
  205. }