Password hashes are now class instances, not naked strings.

This commit is contained in:
Mark H. Wood
2012-07-11 14:24:04 -04:00
parent f3f9433bfe
commit 9b58faa601
4 changed files with 99 additions and 17 deletions

View File

@@ -32,6 +32,7 @@ import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.PasswordHash;
import org.jdom.Namespace; import org.jdom.Namespace;
@@ -70,6 +71,8 @@ public class RoleDisseminator implements PackageDisseminator
public static final String LAST_NAME = "LastName"; public static final String LAST_NAME = "LastName";
public static final String LANGUAGE = "Language"; public static final String LANGUAGE = "Language";
public static final String PASSWORD_HASH = "PasswordHash"; public static final String PASSWORD_HASH = "PasswordHash";
public static final String PASSWORD_DIGEST = "digest";
public static final String PASSWORD_SALT = "salt";
public static final String CAN_LOGIN = "CanLogin"; public static final String CAN_LOGIN = "CanLogin";
public static final String REQUIRE_CERTIFICATE = "RequireCertificate"; public static final String REQUIRE_CERTIFICATE = "RequireCertificate";
public static final String SELF_REGISTERED = "SelfRegistered"; public static final String SELF_REGISTERED = "SelfRegistered";
@@ -475,8 +478,19 @@ public class RoleDisseminator implements PackageDisseminator
if (emitPassword) if (emitPassword)
{ {
PasswordHash password = eperson.getPasswordHash();
writer.writeStartElement(PASSWORD_HASH); writer.writeStartElement(PASSWORD_HASH);
writer.writeCharacters(eperson.getPasswordHash());
String algorithm = password.getAlgorithm();
if (null != algorithm)
writer.writeAttribute(PASSWORD_DIGEST, algorithm);
String salt = password.getSaltString();
if (null != salt)
writer.writeAttribute(PASSWORD_SALT, salt);
writer.writeCharacters(password.getHashString());
writer.writeEndElement(); writer.writeEndElement();
} }

View File

@@ -16,6 +16,7 @@ import java.util.List;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.codec.DecoderException;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection; import org.dspace.content.Collection;
@@ -26,11 +27,10 @@ import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.PasswordHash;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document; import org.w3c.dom.*;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/** /**
@@ -171,7 +171,30 @@ public class RoleIngester implements PackageIngester
data = user.getElementsByTagName(RoleDisseminator.PASSWORD_HASH); data = user.getElementsByTagName(RoleDisseminator.PASSWORD_HASH);
if (data.getLength() > 0) if (data.getLength() > 0)
{ {
eperson.setPasswordHash(data.item(0).getTextContent()); Node element = data.item(0);
NamedNodeMap attributes = element.getAttributes();
Node algorithm = attributes.getNamedItem(RoleDisseminator.PASSWORD_DIGEST);
String algorithmText;
if (null != algorithm)
algorithmText = algorithm.getNodeValue();
else
algorithmText = null;
Node salt = attributes.getNamedItem(RoleDisseminator.PASSWORD_SALT);
String saltText;
if (null != salt)
saltText = salt.getNodeValue();
else
saltText = null;
PasswordHash password;
try {
password = new PasswordHash(algorithmText, saltText, element.getTextContent());
} catch (DecoderException ex) {
throw new PackageValidationException("Unable to decode hexadecimal password hash or salt", ex);
}
eperson.setPasswordHash(password);
} }
else else
{ {

View File

@@ -11,7 +11,6 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
@@ -869,26 +868,43 @@ public class EPerson extends DSpaceObject
/** /**
* Set the EPerson's password hash. * Set the EPerson's password hash.
* FIXME include the salt and algorithm
* *
* @param s * @param password
* hash of the password * hashed password, or null to set row data to NULL.
*/ */
public void setPasswordHash(String s) public void setPasswordHash(PasswordHash password)
{ {
myRow.setColumn("password", s); if (null == password)
{
myRow.setColumnNull("digest_algorithm");
myRow.setColumnNull("salt");
myRow.setColumnNull("password");
}
else
{
myRow.setColumn("digest_algorithm", password.getAlgorithm());
myRow.setColumn("salt", password.getSaltString());
myRow.setColumn("password", password.getHashString());
}
modified = true; modified = true;
} }
/** /**
* Return the EPerson's password hash. * Return the EPerson's password hash.
* FIXME return an actual PasswordHash
* *
* @return hash of the password * @return hash of the password
*/ */
public String getPasswordHash() public PasswordHash getPasswordHash()
{ {
return myRow.getStringColumn("password"); PasswordHash hash = null;
try {
hash = new PasswordHash(myRow.getStringColumn("digestAlgorithm"),
myRow.getStringColumn("salt"),
myRow.getStringColumn("password"));
} catch (DecoderException ex) {
log.error("Problem decoding stored salt or hash: " + ex.getMessage());
}
return hash;
} }
/** /**

View File

@@ -85,7 +85,10 @@ public class PasswordHash
else else
this.algorithm = algorithm; this.algorithm = algorithm;
this.salt = Hex.decodeHex(salt.toCharArray()); if (null == salt)
this.salt = null;
else
this.salt = Hex.decodeHex(salt.toCharArray());
this.hash = Hex.decodeHex(hash.toCharArray()); this.hash = Hex.decodeHex(hash.toCharArray());
} }
@@ -132,7 +135,7 @@ public class PasswordHash
} }
/** /**
* Get the value of hash * Get the hash.
* *
* @return the value of hash * @return the value of hash
*/ */
@@ -142,7 +145,20 @@ public class PasswordHash
} }
/** /**
* Get the value of salt * Get the hash, as a String.
*
* @return hash encoded as hexadecimal digits, or null if none.
*/
public String getHashString()
{
if (null != hash)
return new String(Hex.encodeHex(hash));
else
return null;
}
/**
* Get the salt.
* *
* @return the value of salt * @return the value of salt
*/ */
@@ -151,6 +167,19 @@ public class PasswordHash
return salt; return salt;
} }
/**
* Get the salt, as a String.
*
* @return salt encoded as hexadecimal digits, or null if none.
*/
public String getSaltString()
{
if (null != salt)
return new String(Hex.encodeHex(salt));
else
return null;
}
/** /**
* Get the value of algorithm * Get the value of algorithm
* *