| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.ambari.server.security; |
| |
| import java.security.SecureRandom; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import com.google.inject.Singleton; |
| |
| @Singleton |
| public class SecurePasswordHelper { |
| |
| /** |
| * The default number of characters to generate for a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_LENGTH = 18; |
| /** |
| * The default minimum number of lowercase letters to include when generating a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_MIN_LOWERCASE_LETTERS = 1; |
| /** |
| * The default minimum number of uppercase letters to include when generating a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_MIN_UPPERCASE_LETTERS = 1; |
| /** |
| * The default minimum number of digits to include when generating a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_MIN_DIGITS = 1; |
| /** |
| * The default minimum number of punctuation characters to include when generating a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_MIN_PUNCTUATION = 1; |
| /** |
| * The default minimum number of whitespace characters to include when generating a secure password |
| */ |
| public final static int DEFAULT_SECURE_PASSWORD_MIN_WHITESPACE = 1; |
| |
| /** |
| * The set of available lowercase letters to use when generating a secure password |
| */ |
| protected final static char[] SECURE_PASSWORD_CHARACTER_CLASS_LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz".toCharArray(); |
| /** |
| * The set of available uppercase letters to use when generating a secure password |
| */ |
| protected final static char[] SECURE_PASSWORD_CHARACTER_CLASS_UPPERCASE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); |
| /** |
| * The set of available digits to use when generating a secure password |
| */ |
| protected final static char[] SECURE_PASSWORD_CHARACTER_CLASS_DIGITS = "0123456789".toCharArray(); |
| /** |
| * The set of available punctuation characters to use when generating a secure password |
| */ |
| protected final static char[] SECURE_PASSWORD_CHARACTER_CLASS_PUNCTUATION = "?.!$%^*()-_+=~".toCharArray(); |
| /** |
| * The set of available whitespace characters to use when generating a secure password |
| */ |
| protected final static char[] SECURE_PASSWORD_CHARACTER_CLASS_WHITESPACE = " ".toCharArray(); |
| /** |
| * The collection of available character classes |
| */ |
| private final static char[][] SECURE_PASSWORD_CHARACTER_CLASSES = { |
| SECURE_PASSWORD_CHARACTER_CLASS_LOWERCASE_LETTERS, |
| SECURE_PASSWORD_CHARACTER_CLASS_UPPERCASE_LETTERS, |
| SECURE_PASSWORD_CHARACTER_CLASS_DIGITS, |
| SECURE_PASSWORD_CHARACTER_CLASS_PUNCTUATION, |
| SECURE_PASSWORD_CHARACTER_CLASS_WHITESPACE |
| }; |
| |
| private final SecureRandom secureRandom = new SecureRandom(); |
| |
| /** |
| * Create a secure (random) password using a secure random number generator and a set of (reasonable) |
| * characters. |
| * <p/> |
| * The default rules are used to generate the password. See {@link #createSecurePassword(Integer, Integer, Integer, Integer, Integer, Integer)} |
| * |
| * @return a String containing the new password |
| * @see #createSecurePassword(Integer, Integer, Integer, Integer, Integer, Integer) |
| */ |
| public String createSecurePassword() { |
| return createSecurePassword(null, null, null, null, null, null); |
| } |
| |
| /** |
| * Create a secure (random) password using a secure random number generator, a set of (reasonable) |
| * characters, and meeting the specified rules. |
| * <p/> |
| * If any rule is <code>null</code>, it's default value will be used: |
| * <ul> |
| * <li>length: 18</li> |
| * <li>minimum lowercase letters (a-z): 1</li> |
| * <li>minimum uppercase letters (A-Z): 1</li> |
| * <li>minimum digits (0-9): 1</li> |
| * <li>minimum punctuation (?.!$%^*()-_+=~): 1</li> |
| * <li>minimum whitespace ( ): 0</li> |
| * </ul> |
| * |
| * @param length the required length of the generated password |
| * @param minLowercaseLetters the required minimum number of lowercase letters |
| * @param minUppercaseLetters the required minimum number of uppercase letters |
| * @param minDigits the required minimum number of digits |
| * @param minPunctuation the required minimum number of punctuation characters |
| * @param minWhitespace the required minimum number of space characters |
| * @return a String containing the new password |
| */ |
| public String createSecurePassword(Integer length, Integer minLowercaseLetters, Integer minUppercaseLetters, Integer minDigits, Integer minPunctuation, Integer minWhitespace) { |
| if ((length == null) || (length < 1)) { |
| length = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_LENGTH; |
| } |
| |
| if (minLowercaseLetters == null) { |
| minLowercaseLetters = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_MIN_LOWERCASE_LETTERS; |
| } |
| |
| if (minUppercaseLetters == null) { |
| minUppercaseLetters = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_MIN_UPPERCASE_LETTERS; |
| } |
| |
| if (minDigits == null) { |
| minDigits = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_MIN_DIGITS; |
| } |
| |
| if (minPunctuation == null) { |
| minPunctuation = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_MIN_PUNCTUATION; |
| } |
| |
| if (minWhitespace == null) { |
| minWhitespace = SecurePasswordHelper.DEFAULT_SECURE_PASSWORD_MIN_WHITESPACE; |
| } |
| |
| // Gather the set of characters that meet the specified requirements |
| List<Character> characters = new ArrayList<>(length); |
| |
| for (int i = 0; i < minLowercaseLetters; i++) { |
| characters.add(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_LOWERCASE_LETTERS[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_LOWERCASE_LETTERS.length)]); |
| } |
| |
| for (int i = 0; i < minUppercaseLetters; i++) { |
| characters.add(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_UPPERCASE_LETTERS[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_UPPERCASE_LETTERS.length)]); |
| } |
| |
| for (int i = 0; i < minDigits; i++) { |
| characters.add(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_DIGITS[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_DIGITS.length)]); |
| } |
| |
| for (int i = 0; i < minPunctuation; i++) { |
| characters.add(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_PUNCTUATION[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_PUNCTUATION.length)]); |
| } |
| |
| for (int i = 0; i < minWhitespace; i++) { |
| characters.add(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_WHITESPACE[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASS_WHITESPACE.length)]); |
| } |
| |
| // If we need to gather more characters, select randomly from the set of character classes |
| if (characters.size() < length) { |
| int difference = length - characters.size(); |
| for (int i = 0; i < difference; i++) { |
| char[] characterClass = SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASSES[secureRandom.nextInt(SecurePasswordHelper.SECURE_PASSWORD_CHARACTER_CLASSES.length - 1)]; |
| characters.add(characterClass[secureRandom.nextInt(characterClass.length)]); |
| } |
| } |
| |
| // Generate the password string by randomly selecting from the list of available characters |
| StringBuilder passwordBuilder = new StringBuilder(characters.size()); |
| |
| while (!characters.isEmpty()) { |
| passwordBuilder.append(characters.remove(secureRandom.nextInt(characters.size()))); |
| } |
| |
| return passwordBuilder.toString(); |
| } |
| |
| } |