/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.db;
import java.security.MessageDigest;
import java.util.Arrays;
import com.slamd.asn1.ASN1Boolean;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1OctetString;
import com.slamd.asn1.ASN1Sequence;
/**
* This class defines a set of information about a user defined in the SLAMD
* database, including the username and hashed password, the default folder,
* and the set of groups in which the user is a member.
*
*
* @author Neil A. Wilson
*/
public class SLAMDUser
{
/**
* The name of the encoded element that holds the name of the default folder
* for this user.
*/
public static final String ELEMENT_DEFAULT_FOLDER = "folder";
/**
* The name of the encoded element that holds the groups names associated with
* this user.
*/
public static final String ELEMENT_GROUPS = "groups";
/**
* The name of the encoded element that holds the hashed password for this
* user.
*/
public static final String ELEMENT_HASHED_PASSWORD = "password";
/**
* The name of the encoded element that indicates whether this user is an
* administrator.
*/
public static final String ELEMENT_IS_ADMIN = "isadmin";
/**
* The name of the encoded element that holds the user name for this user.
*/
public static final String ELEMENT_USER_NAME = "username";
// The SHA-1 digest used to hash passwords.
static MessageDigest shaDigest;
// Indicates whether this user is an administrator.
boolean isAdmin;
// The hashed password for this user.
byte[] hashedPassword;
// The default folder for this user.
String defaultFolder;
// The username for this user.
String userName;
// The set of groups in which this user is a member.
String[] groupNames;
static
{
try
{
shaDigest = MessageDigest.getInstance("SHA");
} catch (Exception e) {}
}
/**
* Creates a new user with the provided information.
*
* @param userName The user name for this user.
* @param hashedPassword The SHA-1 hash of the password for this user.
* @param groupNames The names of the groups in which this user is a
* member.
* @param isAdmin Indicates whether this user is an administrator.
* @param defaultFolder The default folder for this user.
*/
public SLAMDUser(String userName, byte[] hashedPassword, String[] groupNames,
boolean isAdmin, String defaultFolder)
{
this.userName = userName;
this.hashedPassword = hashedPassword;
this.isAdmin = isAdmin;
this.defaultFolder = defaultFolder;
if (groupNames == null)
{
this.groupNames = new String[0];
}
else
{
this.groupNames = groupNames;
}
}
/**
* Retrieves the user name for this user.
*
* @return The user name for this user.
*/
public String getUserName()
{
return userName;
}
/**
* Determines whether the provided clear-text password is the correct password
* for this user.
*
* @param password The clear-text password to validate for this user.
*
* @return <CODE>true</CODE> if the provided password is correct, or
* <CODE>false</CODE> if not.
*/
public boolean checkPassword(String password)
{
byte[] pwHash = shaDigest.digest(ASN1Element.getBytes(password));
if (pwHash.length != hashedPassword.length)
{
return false;
}
for (int i=0; i < pwHash.length; i++)
{
if (pwHash[i] != hashedPassword[i])
{
return false;
}
}
return true;
}
/**
* Specifies the password to use for the user.
*
* @param password The password to use for the user.
*/
public void setPassword(String password)
{
hashedPassword = shaDigest.digest(ASN1Element.getBytes(password));
}
/**
* Retrieves the names of the groups in which this user is a member.
*
* @return The names of the groups in which this user is a member.
*/
public String[] getGroupNames()
{
return groupNames;
}
/**
* Determines whether this user is a member of the specified group.
*
* @param groupName The name of the group for which to make the
* determination.
*
* @return <CODE>true</CODE> if this user is a member of the specified group,
* or <CODE>false</CODE> if not.
*/
public boolean memberOf(String groupName)
{
for (int i=0; i < groupNames.length; i++)
{
if (groupNames[i].equals(groupName))
{
return true;
}
}
return false;
}
/**
* Specifies the names of the groups in which this user is a member.
*
* @param groupNames The names of the groups in which this user is a member.
*/
public void setGroupNames(String[] groupNames)
{
if (groupNames == null)
{
groupNames = new String[0];
}
Arrays.sort(groupNames);
this.groupNames = groupNames;
}
/**
* Adds the provided group name to the set of groups associated with this
* user.
*
* @param groupName The name of the group to add to the set of groups for
* this user.
*/
public void addGroupName(String groupName)
{
String[] newGroups = new String[groupNames.length+1];
for (int i=0; i < groupNames.length; i++)
{
if (groupNames[i].equals(groupName))
{
return;
}
else
{
newGroups[i] = groupNames[i];
}
}
newGroups[groupNames.length] = groupName;
Arrays.sort(newGroups);
groupNames = newGroups;
}
/**
* Removes the provided group name from the set of groups associated with this
* user.
*
* @param groupName The name of the group to remove from the set of groups
* for this user.
*/
public void removeGroupName(String groupName)
{
int pos = -1;
for (int i=0; i < groupNames.length; i++)
{
if (groupNames[i].equals(groupName))
{
pos = i;
break;
}
}
if (pos == -1)
{
return;
}
String[] newGroupNames = new String[groupNames.length-1];
System.arraycopy(groupNames, 0, newGroupNames, 0, pos);
System.arraycopy(groupNames, pos+1, newGroupNames, pos,
(newGroupNames.length - pos));
groupNames = newGroupNames;
}
/**
* Indicates whether this user is an administrator with full rights.
*
* @return <CODE>true</CODE> if this user is an administrator, or
* <CODE>false</CODE> if not.
*/
public boolean isAdmin()
{
return isAdmin;
}
/**
* Specifies whether this user is an administrator.
*
* @param isAdmin Specifies whether this user is an administrator.
*/
public void setAdmin(boolean isAdmin)
{
this.isAdmin = isAdmin;
}
/**
* Retrieves the name of the default folder for this user.
*
* @return The name of the default folder for this user.
*/
public String getDefaultFolder()
{
return defaultFolder;
}
/**
* Specifies the name of the default folder for this user.
*
* @param defaultFolder The name of the default folder for this user.
*/
public void setDefaultFolder(String defaultFolder)
{
this.defaultFolder = defaultFolder;
}
/**
* Encodes the information for this user into a byte array.
*
* @return The byte array containing the encoded user information.
*/
public byte[] encode()
{
ASN1Element[] groupElements = new ASN1Element[groupNames.length];
for (int i=0; i < groupNames.length; i++)
{
groupElements[i] = new ASN1OctetString(groupNames[i]);
}
ASN1Element[] userElements = new ASN1Element[]
{
new ASN1OctetString(ELEMENT_USER_NAME),
new ASN1OctetString(userName),
new ASN1OctetString(ELEMENT_HASHED_PASSWORD),
new ASN1OctetString(hashedPassword),
new ASN1OctetString(ELEMENT_GROUPS),
new ASN1Sequence(groupElements),
new ASN1OctetString(ELEMENT_IS_ADMIN),
new ASN1Boolean(isAdmin),
new ASN1OctetString(ELEMENT_DEFAULT_FOLDER),
new ASN1OctetString(defaultFolder)
};
return new ASN1Sequence(userElements).encode();
}
/**
* Decodes the provided byte array as information about a user.
*
* @param encodedUser The byte array containing the encoded user
* information.
*
* @return The user decoded from the provided byte array.
*
* @throws DecodeException If a problem occurs while trying to decode the
* provided byte array.
*/
public static SLAMDUser decode(byte[] encodedUser)
throws DecodeException
{
try
{
boolean isAdmin = false;
byte[] hashedPassword = null;
String defaultFolder = null;
String userName = null;
String[] groupNames = new String[0];
ASN1Element element = ASN1Element.decode(encodedUser);
ASN1Element[] elements = element.decodeAsSequence().getElements();
for (int i=0; i < elements.length; i += 2)
{
String elementName = elements[i].decodeAsOctetString().getStringValue();
if (elementName.equals(ELEMENT_USER_NAME))
{
userName = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_HASHED_PASSWORD))
{
hashedPassword = elements[i+1].decodeAsOctetString().getValue();
}
else if (elementName.equals(ELEMENT_GROUPS))
{
ASN1Element[] groupElements =
elements[i+1].decodeAsSequence().getElements();
groupNames = new String[groupElements.length];
for (int j=0; j < groupNames.length; j++)
{
groupNames[j] =
groupElements[j].decodeAsOctetString().getStringValue();
}
}
else if (elementName.equals(ELEMENT_IS_ADMIN))
{
isAdmin = elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_DEFAULT_FOLDER))
{
defaultFolder = elements[i+1].decodeAsOctetString().getStringValue();
}
}
return new SLAMDUser(userName, hashedPassword, groupNames, isAdmin,
defaultFolder);
}
catch (Exception e)
{
throw new DecodeException("Unable to decode user information: " + e, e);
}
}
}