business.security.SecureTokenGenerator.java Source code

Java tutorial

Introduction

Here is the source code for business.security.SecureTokenGenerator.java

Source

/**
 * Copyright (C) 2016  Stichting PALGA
 * This file is distributed under the GNU Affero General Public License
 * (see accompanying file <a href="{@docRoot}/LICENSE">LICENSE</a>).
 */
package business.security;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.UUID;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import business.validation.PasswordValidator;

public class SecureTokenGenerator {
    private static SecureRandom rng = new SecureRandom();

    public static String generateToken() {
        return new BigInteger(130, rng).toString(32);
    }

    private final static String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
            "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i",
            "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };

    private final static String[] specials = { "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+",
            "\\", "|", "{", "}", "[", "]", "/", "?", "<", ">", ",", ".", "`" };

    private static PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * Generates a password that is valid for the {@link PasswordValidator}.
     *
     * Rationale behind this function:
     * - Generate a long enough secure pseudo random string that contains at
     *   least a number, a letter and a 'special character'.
     * - The number, letter and special character are explicitely chosen
     *   (one letter, one special character and a random number between 0 and 1024).
     * - A long enough secure random string is generated by using the
     *   {@link SecureRandom} generator and {@link BigInteger} to generate a
     *   very large random number (in base 32 encoding). Because theoretically
     *   this could be not long enough (in number of characters), the
     *   {@link BCryptPasswordEncoder} is applied to that number as well.
     * - All these values are concatenated.
     *
     * Note: for the alphanumerical part, probably {@link UUID.randomUUID()}
     * would suffice as well.
     *
     * @return the password.
     */
    public static String generatePassword() {
        String special = specials[rng.nextInt(specials.length)];
        String letter = letters[rng.nextInt(letters.length)];
        String number = new BigInteger(10, rng).toString(10);
        String alphanumerical = passwordEncoder.encode(generateToken());
        return alphanumerical + special + letter + number;
    }
}