/*
- * Copyright (C) 2015 Roland Haeder
+ * Copyright (C) 2016 Roland Haeder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
package org.mxchange.jusercore.model.user;
-import org.mxchange.jcore.BaseFrameworkSystem;
+import java.io.Serializable;
+import java.security.SecureRandom;
+import java.text.MessageFormat;
+import java.util.Random;
+import org.apache.commons.codec.digest.Crypt;
+import org.mxchange.jusercore.container.login.LoginContainer;
/**
- * An utilities class for customers
+ * An utilities class for users
* <p>
- * @author Roland Haeder
+ * @author Roland Haeder<roland@mxchange.org>
*/
-public class UserUtils extends BaseFrameworkSystem {
+public class UserUtils implements Serializable {
+
+ /**
+ * Password alphabet
+ */
+ private static final String PASSWORD_ALPHABET = "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY0123456789-/?!_+#@"; //NOI18N
+
+ /**
+ * Minimum password length
+ */
+ private static final Integer PASSWORD_MINIMUM_LENGTH = 5;
+
+ /**
+ * Random number generator
+ */
+ private static final Random RANDOM_NUMBER_GENERATOR;
+
+ /**
+ * Serial number
+ */
+ private static final long serialVersionUID = 18_356_847_120_972L;
+
+ /**
+ * Static initializer
+ */
+ static {
+ // Init RNG
+ RANDOM_NUMBER_GENERATOR = new SecureRandom();
+ }
+
+ /**
+ * Creates a pseudo-random password with given length
+ * <p>
+ * @param length Length of the password
+ * <p>
+ * @return Pseudo-random password
+ */
+ public static String createRandomPassword (final Integer length) {
+ // Parameter should be valid
+ if (null == length) {
+ // Throw NPE
+ throw new NullPointerException("length is null"); //NOI18N
+ } else if (length < PASSWORD_MINIMUM_LENGTH) {
+ // To weak passwords
+ throw new IllegalArgumentException(MessageFormat.format("Password length {0} is to short, minimum: {1}", length, PASSWORD_MINIMUM_LENGTH)); //NOI18N
+ }
+
+ // Init variable
+ StringBuilder password = new StringBuilder(length);
+
+ // Start creating it
+ for (int i = 0; i < length; i++) {
+ // Generate random number
+ int pos = RANDOM_NUMBER_GENERATOR.nextInt(PASSWORD_ALPHABET.length());
+
+ // Get char at this position and add it to the final password
+ password.append(String.valueOf(PASSWORD_ALPHABET.charAt(pos)));
+ }
+
+ // Should have the wanted length
+ assert (password.length() == length) : MessageFormat.format("Password length {0} doesn't match requested: {1}", password.length(), length); //NOI18N
+
+ // Return it
+ return password.toString();
+ }
+
+ /**
+ * Hashes given user password and adds a salt to it
+ * <p>
+ * @param userPassword User password to be hashed
+ * <p>
+ * @return Hashed user password
+ */
+ public static String encryptPassword (final String userPassword) {
+ // Is it null or empty?
+ if (null == userPassword) {
+ // Throw NPE
+ throw new NullPointerException("userPassword is null"); //NOI18N
+ } else if (userPassword.isEmpty()) {
+ // Empty passwords are hardcoded not allowed due to security risks
+ throw new IllegalArgumentException("userPassword is empty"); //NOI18N
+ }
+
+ // Generate large number
+ String number = Long.toString(RANDOM_NUMBER_GENERATOR.nextLong() * 10_000_000_000L);
+
+ // Generate salt
+ String salt = Crypt.crypt(number);
+
+ // First encrypt password
+ String encryptedPassword = Crypt.crypt(userPassword, salt);
+
+ // Return it
+ return encryptedPassword;
+ }
+
+ /**
+ * Checks if password from container matches the updatedUser's password
+ * <p>
+ * @param container Container holding user instance and unencrypted password
+ * @param updatedUser Updated user instance from database
+ * <p>
+ * @return Whether the password matches
+ */
+ public static boolean ifPasswordMatches (final LoginContainer container, final User updatedUser) {
+ // Validate parameters
+ if (null == container) {
+ // Throw NPE
+ throw new NullPointerException("container is null"); //NOI18N
+ } else if (null == updatedUser) {
+ // And again NPE ...
+ throw new NullPointerException("updatedUser is null"); //NOI18N
+ } else if (container.getUser() == null) {
+ // NPE for user in container
+ throw new NullPointerException("container.user is null"); //NOI18N
+ } else if (container.getUserPassword() == null) {
+ // NPE for user password in container
+ throw new NullPointerException("container.userPassword is null"); //NOI18N
+ } else if (container.getUserPassword().isEmpty()) {
+ // Empty password in container
+ throw new IllegalArgumentException("container.userPassword is empty"); //NOI18N
+ }
+
+ // First encrypt password
+ String encryptedPassword = Crypt.crypt(container.getUserPassword(), updatedUser.getUserEncryptedPassword());
+
+ // Is it matching?
+ return encryptedPassword.equals(updatedUser.getUserEncryptedPassword());
+ }
+
+ /**
+ * Checks if password from container matches with from user instance.
+ * <p>
+ * @param container Container holding user instance and unencrypted password
+ * <p>
+ * @return Whether it maches
+ */
+ public static boolean ifPasswordMatches (final LoginContainer container) {
+ // Validate parameters
+ if (null == container) {
+ // Throw NPE
+ throw new NullPointerException("container is null"); //NOI18N
+ } else if (container.getUser() == null) {
+ // NPE for user in container
+ throw new NullPointerException("container.user is null"); //NOI18N
+ } else if (container.getUserPassword() == null) {
+ // NPE for user password in container
+ throw new NullPointerException("container.userPassword is null"); //NOI18N
+ } else if (container.getUserPassword().isEmpty()) {
+ // Empty password in container
+ throw new IllegalArgumentException("container.userPassword is empty"); //NOI18N
+ }
+
+ // First encrypt password
+ String encryptedPassword = Crypt.crypt(container.getUserPassword(), container.getUser().getUserEncryptedPassword());
+
+ // Is it matching?
+ return encryptedPassword.equals(container.getUser().getUserEncryptedPassword());
+ }
/**
* No instance from this class