--- /dev/null
+/*******************************************************************************
+ * Copyright � Igor Barma, Alexandre Desoubeaux, Christian Martel, Eric Brun, Mathieu Amblard, Gwenael Gevet, Pierre Guillot, 2012
+ * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Alexandre Lefevre, Marc Salvat 2014-2016
+ * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Marc Salvat, Marc Suarez, Harifetra Ramamonjy 2017
+ *
+ * This file is part of the work and learning management system Pentila Nero.
+ *
+ * Pentila Nero is free software. You can redistribute it and/or modify since
+ * you respect the terms of either (at least one of the both license) :
+ * - under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ * - the CeCILL-C as published by CeCILL-C; either version 1 of the
+ * License, or any later version
+ * - the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the license,
+ * or (at your option) any later version.
+ *
+ * There are special exceptions to the terms and conditions of the
+ * licenses as they are applied to this software. View the full text of
+ * the exception in file LICENSE-PROJECT.txt in the directory of this software
+ * distribution.
+ *
+ * Pentila Nero is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Licenses for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * and the CeCILL-C and the GNU Lesser General Public License along with
+ * Pentila Nero. If not, see :
+ * <http://www.gnu.org/licenses/> and
+ * <http://www.cecill.info/licences.fr.html>.
+ ******************************************************************************/
+/**
+ * @author Darron Schall
+ * @version 1.0
+ *
+ * Aug. 22, 2003
+ *
+ * PasswordGenerator for creating random passwords.
+ *
+ * Four password flags are available to dictate generation,
+ * or a template can be specificed to generate a string with
+ * a specified character type at each position.
+ *
+ * Revision History:
+ * Rev Date Who Description
+ * 1.0 8/22/03 darron Initial Draft
+ * --------------------------------------
+ * License For Use
+ * --------------------------------------
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+package com.liferay.portal.security.ldap;
+
+import java.util.ArrayList;
+import java.util.prefs.InvalidPreferencesFormatException;
+import java.text.ParseException;
+
+public class PasswordGenerator {
+
+ /** The length. */
+ private int length;
+
+ /** The lowercase included. */
+ private boolean lowercaseIncluded;
+
+ /** The numbers included. */
+ private boolean numbersIncluded;
+
+ /** The others included. */
+ private boolean othersIncluded;
+
+ /** The uppercase included. */
+ private boolean uppercaseIncluded;
+
+ /** The password. */
+ private String password;
+
+ /** The template. */
+ private String template;
+
+ /**
+ * Instantiates a new password generator.
+ */
+ public PasswordGenerator() {
+ // by default, include lowercase only
+ // in the password, and make it 8 characters long.
+ password = "";
+ template = "";
+ length = 8;
+ lowercaseIncluded = true;
+ uppercaseIncluded = true;
+ numbersIncluded = true;
+ othersIncluded = false;
+
+ // start the ball rolling by generating a password so that
+ // we keep our data integrity
+ // i.e. so length matches password.length());
+ generatePassword();
+ }
+
+ /**
+ * Flags ok.
+ *
+ * @return true if at least one of the password generation flags is true,
+ * otherwise returns false
+ */
+ private boolean flagsOK() {
+ return lowercaseIncluded || uppercaseIncluded || numbersIncluded
+ || othersIncluded;
+ }
+
+ /**
+ * Random lowercase.
+ *
+ * @return a random lowercase character from 'a' to 'z'
+ */
+ private static char randomLowercase() {
+ return (char) (97 + (int) (Math.random() * 26));
+ }
+
+ /**
+ * Random uppercase.
+ *
+ * @return a random uppercase character from 'A' to 'Z'
+ */
+ private static char randomUppercase() {
+ return (char) (65 + (int) (Math.random() * 26));
+ }
+
+ /**
+ * Random other.
+ *
+ * @return a random character in this list: !"#$%&'()*+,-./
+ */
+ private static char randomOther() {
+ return (char) (33 + (int) (Math.random() * 15));
+ }
+
+ /**
+ * Random number.
+ *
+ * @return a random character from '0' to '9'
+ */
+ private static char randomNumber() {
+ return (char) (48 + (int) (Math.random() * 10));
+ }
+
+ /**
+ * Generate password.
+ */
+ public void generatePassword() /*
+ * throws InvalidPreferencesFormatException,
+ * ParseException
+ */{
+ // clear password if necessary
+ if (password.length() != 0) {
+ password = "";
+ }
+
+ // check to make sure at least one "type" is included
+ // for password generation if template is not defined
+
+ // commented out because our setters/construcor should
+ // ensure data integrity
+ // if (!flagsOK() && template.length() == 0) {
+ // throw new
+ // java.util.prefs.InvalidPreferencesFormatException("At least one flag must be on to generate a password");
+ // }
+
+ // we know length >= 1 here because setLength
+ // doesn't allow invalid lengths and the constructor
+ // initializes length to 8
+
+ // a template being defined overrides all flags
+ if (template.length() > 0) {
+ length = template.length();
+ for (int i = 0; i < length; i++) {
+ switch (template.charAt(i)) {
+ case 'a':
+ password += randomLowercase();
+ break;
+
+ case 'A':
+ password += randomUppercase();
+ break;
+
+ case 'n':
+ case 'N':
+ password += randomNumber();
+ break;
+
+ case 'o':
+ case 'O':
+ password += randomOther();
+ break;
+
+ // commented out because our setters/constructor
+ // should ensure data integrity
+ // default :
+ // throw new
+ // ParseException("Password template contains an invalid character",
+ // i);
+ }
+ }
+ } else {
+ // In Java we can't create an array of function references
+ // so I've created 4 "wrapper" classes that inherit from the
+ // randomCharacter interface to provide the same
+ // type of functionality.
+
+ // create an ArrayList to store the functions that we're allowed
+ // to call to generate the password, based on what the flags
+ // are set to.
+ ArrayList flags = new ArrayList();
+ if (lowercaseIncluded) {
+ flags.add(new randomLowercase());
+ }
+ if (uppercaseIncluded) {
+ flags.add(new randomUppercase());
+ }
+ if (othersIncluded) {
+ flags.add(new randomOther());
+ }
+ if (numbersIncluded) {
+ flags.add(new randomNumber());
+ }
+
+ int flagLength = flags.size();
+
+ for (int i = 0; i < length; i++) {
+ // get a random wrapper class from the flags ArrayList
+ // and cast it to our interface so we can call the execute
+ // method
+ // which just calls the function and returns its value.
+ password += ((randomCharacter) flags
+ .get((int) (Math.random() * flagLength))).execute();
+ }
+ }
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length of the generated password
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Gets the password.
+ *
+ * @return the generated password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Gets the template.
+ *
+ * @return password template
+ */
+ public String getTemplate() {
+ return template;
+ }
+
+ /**
+ * Checks if is lowercase included.
+ *
+ * @return lowercaseIncluded
+ */
+ public boolean isLowercaseIncluded() {
+ return lowercaseIncluded;
+ }
+
+ /**
+ * Checks if is numbers included.
+ *
+ * @return numbersIncluded
+ */
+ public boolean isNumbersIncluded() {
+ return numbersIncluded;
+ }
+
+ /**
+ * Checks if is others included.
+ *
+ * @return othersIncluded
+ */
+ public boolean isOthersIncluded() {
+ return othersIncluded;
+ }
+
+ /**
+ * Checks if is uppercase included.
+ *
+ * @return uppercaseIncluded
+ */
+ public boolean isUppercaseIncluded() {
+ return uppercaseIncluded;
+ }
+
+ /**
+ * Sets the length.
+ *
+ * @param length , enforced to be a positive integer >= 3.
+ */
+ public void setLength(int length) {
+ this.length = (length < 3) ? 3 : length;
+ }
+
+ /**
+ * Sets the lowercase included.
+ *
+ * @param b the b
+ *
+ * @throws InvalidPreferencesFormatException the invalid preferences format exception
+ */
+ public void setLowercaseIncluded(boolean b)
+ throws InvalidPreferencesFormatException {
+ lowercaseIncluded = b;
+
+ // did we turn off the last flag? if so
+ // turn it back on and report error
+ if (b == false && !flagsOK()) {
+ lowercaseIncluded = true;
+ throw new InvalidPreferencesFormatException(
+ "At least one flag must be on to generate a password");
+ }
+ }
+
+ /**
+ * Sets the numbers included.
+ *
+ * @param b the b
+ *
+ * @throws InvalidPreferencesFormatException the invalid preferences format exception
+ */
+ public void setNumbersIncluded(boolean b)
+ throws InvalidPreferencesFormatException {
+ numbersIncluded = b;
+
+ // did we turn off the last flag? if so
+ // turn it back on and report error
+ if (b == false && !flagsOK()) {
+ numbersIncluded = true;
+ throw new InvalidPreferencesFormatException(
+ "At least one flag must be on to generate a password");
+ }
+ }
+
+ /**
+ * Sets the others included.
+ *
+ * @param b the b
+ *
+ * @throws InvalidPreferencesFormatException the invalid preferences format exception
+ */
+ public void setOthersIncluded(boolean b)
+ throws InvalidPreferencesFormatException {
+ othersIncluded = b;
+
+ // did we turn off the last flag? if so
+ // turn it back on and report error
+ if (b == false && !flagsOK()) {
+ othersIncluded = true;
+ throw new InvalidPreferencesFormatException(
+ "At least one flag must be on to generate a password");
+ }
+ }
+
+ /**
+ * Sets the template.
+ *
+ * @param template the template
+ *
+ * @throws ParseException the parse exception
+ */
+ public void setTemplate(String template) throws ParseException {
+ // make sure the template contains only legal characters
+ for (int i = 0; i < template.length(); i++) {
+ switch (template.charAt(i)) {
+ case 'a':
+ case 'A':
+ case 'n':
+ case 'N':
+ case 'o':
+ case 'O':
+ break;
+
+ default:
+ throw new ParseException(
+ "Password template contains an invalid character", i);
+ }
+ }
+ this.template = template;
+ }
+
+ /**
+ * Clears the password template,making generation rely on the flags.
+ */
+ public void clearTemplate() {
+ template = "";
+ }
+
+ /**
+ * Sets the uppercase included.
+ *
+ * @param b the b
+ *
+ * @throws InvalidPreferencesFormatException the invalid preferences format exception
+ */
+ public void setUppercaseIncluded(boolean b)
+ throws InvalidPreferencesFormatException {
+ uppercaseIncluded = b;
+
+ // did we turn off the last flag? if so
+ // turn it back on and report error
+ if (b == false && !flagsOK()) {
+ uppercaseIncluded = true;
+ throw new InvalidPreferencesFormatException(
+ "At least one flag must be on to generate a password");
+ }
+ }
+
+ /*--------------------------------------------------------
+ Wrapper classes and interface to mimic the array of
+ function references functionality required.
+ ----------------------------------------------------------*/
+ /**
+ * The Class randomLowercase.
+ */
+ private static class randomLowercase implements randomCharacter {
+
+ /* (non-Javadoc)
+ * @see com.pentila.sconet.util.PasswordGenerator.randomCharacter#execute()
+ */
+ public char execute() {
+ return PasswordGenerator.randomLowercase();
+ }
+ }
+
+ /**
+ * The Class randomUppercase.
+ */
+ private static class randomUppercase implements randomCharacter {
+
+ /* (non-Javadoc)
+ * @see com.pentila.sconet.util.PasswordGenerator.randomCharacter#execute()
+ */
+ public char execute() {
+ return PasswordGenerator.randomUppercase();
+ }
+ }
+
+ /**
+ * The Class randomOther.
+ */
+ private static class randomOther implements randomCharacter {
+
+ /* (non-Javadoc)
+ * @see com.pentila.sconet.util.PasswordGenerator.randomCharacter#execute()
+ */
+ public char execute() {
+ return PasswordGenerator.randomOther();
+ }
+ }
+
+ /**
+ * The Class randomNumber.
+ */
+ private static class randomNumber implements randomCharacter {
+
+ /* (non-Javadoc)
+ * @see com.pentila.sconet.util.PasswordGenerator.randomCharacter#execute()
+ */
+ public char execute() {
+ return PasswordGenerator.randomNumber();
+ }
+ }
+
+ /**
+ * The Interface randomCharacter.
+ */
+ private static interface randomCharacter {
+
+ /**
+ * Execute.
+ *
+ * @return the char
+ */
+ char execute();
+ }
+
+}
+