/* * Copyright 2013-2017 Simba Open Source * * Licensed 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.simbasecurity.core.util; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.regex.Pattern; public class RandomPasswordGenerator { private List<List<Character>> allowedCharsPerPattern = new ArrayList<List<Character>>(); private int minSizeOfPwd; private int maxSizeOfPwd; @SuppressWarnings("unused") private RandomPasswordGenerator(){ } public RandomPasswordGenerator(int minSizeOfPwd, int maxSizeOfPwd){ this.minSizeOfPwd = minSizeOfPwd; this.maxSizeOfPwd = maxSizeOfPwd; } /** * Add a regex pattern that will be used to generate the password. You call this method multiple times to add more regex to complicate your password. * @param regex Regex pattern to match. */ public void addPattern(String regex){ allowedCharsPerPattern.add(compileAllowedChars(regex)); } private List<Character> compileAllowedChars(String regex) { Pattern pattern = Pattern.compile(regex); List<Character> allowedChars = new ArrayList<Character>(); for (char c = ' '; c <= '~'; c++) { if (pattern.matcher(Character.valueOf(c).toString()).matches()) { allowedChars.add(c); } } return allowedChars; } public String generate(){ try { Random rnd = SecureRandom.getInstance("SHA1PRNG"); Collections.shuffle(allowedCharsPerPattern, rnd); int passwordSize = rnd.nextInt(maxSizeOfPwd - minSizeOfPwd) + minSizeOfPwd; int allowedCharsIdx = 0; StringBuilder result = new StringBuilder(passwordSize); for (int i = 0; i < passwordSize; i++) { List<Character> characters = allowedCharsPerPattern.get(allowedCharsIdx); int charIdx = rnd.nextInt(characters.size()); result.append(characters.get(charIdx)); allowedCharsIdx++; if (allowedCharsIdx >= allowedCharsPerPattern.size()) { allowedCharsIdx = 0; } } return result.toString(); } catch (Exception e) { throw new RuntimeException(e); } } }