X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fusermanager%2Fapi%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fusermanager%2FUserConfig.java;fp=opendaylight%2Fusermanager%2Fapi%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fusermanager%2FUserConfig.java;h=0000000000000000000000000000000000000000;hp=8298f5b76a730e1d39e74db1115bf55fc0196ca5;hb=42c32160bfd41de57189bb246fec5ffb48ed8e9e;hpb=edf5bfcee83c750853253ccfd991ba7000f5f65b diff --git a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java deleted file mode 100644 index 8298f5b76a..0000000000 --- a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.usermanager; - -import java.io.Serializable; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -import org.opendaylight.controller.configuration.ConfigurationObject; -import org.opendaylight.controller.sal.authorization.AuthResultEnum; -import org.opendaylight.controller.sal.packet.BitBufferHelper; -import org.opendaylight.controller.sal.utils.HexEncode; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.sal.utils.StatusCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Configuration Java Object which represents a Local AAA user configuration - * information for User Manager. - */ -@XmlRootElement -@XmlAccessorType(XmlAccessType.NONE) -public class UserConfig extends ConfigurationObject implements Serializable { - private static final long serialVersionUID = 1L; - private static Logger log = LoggerFactory.getLogger(UserConfig.class); - private static final boolean strongPasswordCheck = Boolean.getBoolean("enableStrongPasswordCheck"); - private static final String DIGEST_ALGORITHM = "SHA-384"; - private static final String BAD_PASSWORD = "Bad Password"; - private static final int USERNAME_MAXLENGTH = 32; - protected static final String PASSWORD_REGEX = "(?=.*[^a-zA-Z0-9])(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,256}$"; - private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)"); - private static MessageDigest oneWayFunction; - private static SecureRandom randomGenerator; - - static { - try { - UserConfig.oneWayFunction = MessageDigest.getInstance(DIGEST_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - log.error(String.format("Implementation of %s digest algorithm not found: %s", DIGEST_ALGORITHM, - e.getMessage())); - } - UserConfig.randomGenerator = new SecureRandom(BitBufferHelper.toByteArray(System.currentTimeMillis())); - } - - /** - * User Id - */ - @XmlElement - protected String user; - - /** - * List of roles a user can have - * example - * System-Admin - * Network-Admin - * Network-Operator - */ - @XmlElement - protected List roles; - - /** - * Password - * Should be 8 to 256 characters long, - * contain both upper and lower case letters, at least one number, - * and at least one non alphanumeric character. - */ - @XmlElement - private String password; - - private byte[] salt; - - - - public UserConfig() { - } - - /** - * Construct a UserConfig object and takes care of hashing the user password - * - * @param user - * the user name - * @param password - * the plain text password - * @param roles - * the list of roles - */ - public UserConfig(String user, String password, List roles) { - this.user = user; - - /* - * Password validation to be done on clear text password. If fails, mark - * the password with a well known label, so that object validation can - * report the proper error. Only if password is a valid one, generate - * salt, concatenate it with clear text password and hash the - * resulting string. Hash result is going to be our stored password. - */ - if (validateClearTextPassword(password).isSuccess()) { - this.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong()); - this.password = hash(salt, password); - } else { - this.salt = null; - this.password = BAD_PASSWORD; - } - - this.roles = (roles == null) ? Collections.emptyList() : new ArrayList(roles); - } - - public String getUser() { - return user; - } - - public String getPassword() { - return password; - } - - public List getRoles() { - return new ArrayList(roles); - } - - public byte[] getSalt() { - return (salt == null) ? null : salt.clone(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((password == null) ? 0 : password.hashCode()); - result = prime * result + ((roles == null) ? 0 : roles.hashCode()); - result = prime * result + ((user == null) ? 0 : user.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - UserConfig other = (UserConfig) obj; - if (password == null) { - if (other.password != null) { - return false; - } - } else if (!password.equals(other.password)) { - return false; - } - if (roles == null) { - if (other.roles != null) { - return false; - } - } else if (!roles.equals(other.roles)) { - return false; - } - if (user == null) { - if (other.user != null) { - return false; - } - } else if (!user.equals(other.user)) { - return false; - } - return true; - } - - @Override - public String toString() { - return "UserConfig[user=" + user + ", password=" + password + ", roles=" + roles +"]"; - } - - public Status validate() { - Status validCheck = validateUsername(); - if (validCheck.isSuccess()) { - // Password validation was run at object construction time - validCheck = (!password.equals(BAD_PASSWORD)) ? new Status(StatusCode.SUCCESS) : new Status( - StatusCode.BADREQUEST, - "Password should be 8 to 256 characters long, contain both upper and lower case letters, " - + "at least one number and at least one non alphanumeric character"); - } - if (validCheck.isSuccess()) { - validCheck = validateRoles(); - } - return validCheck; - } - - protected Status validateUsername() { - if (user == null || user.isEmpty()) { - return new Status(StatusCode.BADREQUEST, "Username cannot be empty"); - } - - Matcher mUser = UserConfig.INVALID_USERNAME_CHARACTERS.matcher(user); - if (user.length() > UserConfig.USERNAME_MAXLENGTH || mUser.find() == true) { - return new Status(StatusCode.BADREQUEST, - "Username can have 1-32 non-whitespace " - + "alphanumeric characters and any special " - + "characters except ./#%;?\\"); - } - - return new Status(StatusCode.SUCCESS); - } - - public static Status validateClearTextPassword(String password) { - if (password == null || password.isEmpty()) { - return new Status(StatusCode.BADREQUEST, "Password cannot be empty"); - } - - if (strongPasswordCheck && !password.matches(UserConfig.PASSWORD_REGEX)) { - return new Status(StatusCode.BADREQUEST, "Password should be 8 to 256 characters long, " - + "contain both upper and lower case letters, at least one number " - + "and at least one non alphanumeric character"); - } - return new Status(StatusCode.SUCCESS); - } - - protected Status validateRoles() { - if (roles == null || roles.isEmpty()) { - return new Status(StatusCode.BADREQUEST, "No role specified"); - } - return new Status(StatusCode.SUCCESS); - } - - public Status update(String currentPassword, String newPassword, List newRoles) { - - // To make any changes to a user configured profile, current password - // must always be provided - if (!isPasswordMatch(currentPassword)) { - return new Status(StatusCode.BADREQUEST, "Current password is incorrect"); - } - - // Create a new object with the proposed modifications - UserConfig proposed = new UserConfig(); - proposed.user = this.user; - proposed.password = (newPassword == null)? this.password : hash(this.salt, newPassword); - proposed.roles = (newRoles == null)? this.roles : newRoles; - - // Validate it - Status status = proposed.validate(); - if (!status.isSuccess()) { - return status; - } - - // Accept the modifications - this.user = proposed.user; - this.password = proposed.password; - this.roles = new ArrayList(proposed.roles); - - return status; - } - - public boolean isPasswordMatch(String otherPass) { - return this.password.equals(hash(this.salt, otherPass)); - } - - public AuthResponse authenticate(String clearTextPassword) { - AuthResponse locResponse = new AuthResponse(); - if (isPasswordMatch(clearTextPassword)) { - locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC); - locResponse.addData(getRolesString()); - } else { - locResponse.setStatus(AuthResultEnum.AUTH_REJECT_LOC); - } - return locResponse; - } - - protected String getRolesString() { - StringBuffer buffer = new StringBuffer(); - if (!roles.isEmpty()) { - Iterator iter = roles.iterator(); - buffer.append(iter.next()); - while (iter.hasNext()) { - buffer.append(" "); - buffer.append(iter.next()); - } - } - return buffer.toString(); - } - - private static byte[] concatenate(byte[] salt, String password) { - byte[] messageArray = password.getBytes(); - byte[] concatenation = new byte[salt.length + password.length()]; - System.arraycopy(salt, 0, concatenation, 0, salt.length); - System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length); - return concatenation; - } - - private static String hash(byte[] salt, String message) { - if (message == null) { - log.warn("Password hash requested but empty or no password provided"); - return message; - } - if (salt == null || salt.length == 0) { - log.warn("Password hash requested but empty or no salt provided"); - return message; - } - - // Concatenate salt and password - byte[] messageArray = message.getBytes(); - byte[] concatenation = new byte[salt.length + message.length()]; - System.arraycopy(salt, 0, concatenation, 0, salt.length); - System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length); - - UserConfig.oneWayFunction.reset(); - return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(concatenate(salt, message))); - } - - /** - * Returns UserConfig instance populated with the passed parameters. It does - * not run any checks on the passed parameters. - * - * @param userName - * the user name - * @param password - * the plain text password - * @param roles - * the list of roles - * @return the UserConfig object populated with the passed parameters. No - * validity check is run on the input parameters. - */ - public static UserConfig getUncheckedUserConfig(String userName, String password, List roles) { - UserConfig config = new UserConfig(); - config.user = userName; - config.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong()); - config.password = hash(config.salt, password); - config.roles = roles; - return config; - } -}