#358 Handle hash + salt as one "unit"

- Rename HashResult to EncryptedPassword to reflect its broader use
- Use EncryptedPassword in methods that require the hash and the salt, instead of passing them as strings separately
- Store EncryptedPassword as field in PlayerAuth; updatePassword() thus processes the entire data in the EncryptedPassword object
This commit is contained in:
ljacqu
2015-12-30 17:56:22 +01:00
parent 9c4a578bec
commit a3402d573f
46 changed files with 328 additions and 564 deletions
@@ -270,24 +270,6 @@ public class CacheDataSource implements DataSource {
return result;
}
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*
* @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public synchronized boolean updateSalt(final PlayerAuth auth) {
boolean result = source.updateSalt(auth);
if (result) {
cachedAuths.refresh(auth.getNickname());
}
return result;
}
/**
* Method getAllAuthsByName.
*
@@ -134,15 +134,6 @@ public interface DataSource {
*/
boolean updateEmail(PlayerAuth auth);
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*/
boolean updateSalt(PlayerAuth auth);
void close();
void reload();
@@ -102,7 +102,7 @@ public class FlatFile implements DataSource {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(source, true));
bw.write(auth.getNickname() + ":" + auth.getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
bw.write(auth.getNickname() + ":" + auth.getPassword() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
} catch (IOException ex) {
ConsoleLogger.showError(ex.getMessage());
return false;
@@ -137,25 +137,26 @@ public class FlatFile implements DataSource {
while ((line = br.readLine()) != null) {
String[] args = line.split(":");
if (args[0].equals(auth.getNickname())) {
// Note ljacqu 20151230: This does not persist the salt; it is not supported in flat file.
switch (args.length) {
case 4: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]);
newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]);
break;
}
case 7: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]);
newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]);
break;
}
case 8: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]);
newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]);
break;
}
case 9: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]);
newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]);
break;
}
default: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]);
newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]);
break;
}
}
@@ -600,18 +601,6 @@ public class FlatFile implements DataSource {
return true;
}
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public boolean updateSalt(PlayerAuth auth) {
return false;
}
/**
* Method getAllAuthsByName.
*
@@ -6,7 +6,9 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import java.sql.*;
import java.util.ArrayList;
@@ -284,13 +286,14 @@ public class MySQL implements DataSource {
if (!rs.next()) {
return null;
}
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : "";
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
String hash = rs.getString(columnPassword);
int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
int id = rs.getInt(columnID);
pAuth = PlayerAuth.builder()
.name(rs.getString(columnName))
.realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword))
.hash(new EncryptedPassword(hash, salt))
.lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld))
@@ -298,7 +301,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail))
.salt(salt)
.groupId(group)
.build();
rs.close();
@@ -328,7 +330,7 @@ public class MySQL implements DataSource {
ResultSet rs;
String sql;
boolean useSalt = !columnSalt.isEmpty() || !auth.getSalt().isEmpty();
boolean useSalt = !columnSalt.isEmpty() || !StringUtils.isEmpty(auth.getPassword().getSalt());
sql = "INSERT INTO " + tableName + "("
+ columnName + "," + columnPassword + "," + columnIp + ","
+ columnLastLogin + "," + columnRealName
@@ -336,12 +338,12 @@ public class MySQL implements DataSource {
+ ") VALUES (?,?,?,?,?" + (useSalt ? ",?" : "") + ");";
pst = con.prepareStatement(sql);
pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash());
pst.setString(2, auth.getPassword().getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
if (useSalt) {
pst.setString(6, auth.getSalt());
pst.setString(6, auth.getPassword().getSalt());
}
pst.executeUpdate();
pst.close();
@@ -513,10 +515,22 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean updatePassword(PlayerAuth auth) {
try (Connection con = getConnection()) {
String sql = "UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;";
PreparedStatement pst = con.prepareStatement(sql);
pst.setString(1, auth.getHash());
pst.setString(2, auth.getNickname());
boolean useSalt = !columnSalt.isEmpty();
PreparedStatement pst;
if (useSalt) {
String sql = String.format("UPDATE %s SET %s = ?, %s = ? WHERE %s = ?;",
tableName, columnPassword, columnSalt, columnName);
pst = con.prepareStatement(sql);
pst.setString(1, auth.getPassword().getHash());
pst.setString(2, auth.getPassword().getSalt());
pst.setString(3, auth.getNickname());
} else {
String sql = String.format("UPDATE %s SET %s = ? WHERE %s = ?;",
tableName, columnPassword, columnName);
pst = con.prepareStatement(sql);
pst.setString(1, auth.getPassword().getHash());
pst.setString(2, auth.getNickname());
}
pst.executeUpdate();
pst.close();
return true;
@@ -719,35 +733,6 @@ public class MySQL implements DataSource {
return false;
}
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*
* @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public synchronized boolean updateSalt(PlayerAuth auth) {
if (columnSalt.isEmpty()) {
return false;
}
try (Connection con = getConnection()) {
String sql = "UPDATE " + tableName + " SET " + columnSalt + " =? WHERE " + columnName + "=?;";
PreparedStatement pst = con.prepareStatement(sql);
pst.setString(1, auth.getSalt());
pst.setString(2, auth.getNickname());
pst.executeUpdate();
pst.close();
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
}
return false;
}
/**
* Method reload.
*
@@ -1045,12 +1030,12 @@ public class MySQL implements DataSource {
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName);
PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;");
while (rs.next()) {
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : "";
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
PlayerAuth pAuth = PlayerAuth.builder()
.name(rs.getString(columnName))
.realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword))
.hash(new EncryptedPassword(rs.getString(columnPassword), salt))
.lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld))
@@ -1058,7 +1043,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail))
.salt(salt)
.groupId(group)
.build();
@@ -1089,12 +1073,12 @@ public class MySQL implements DataSource {
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;");
PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;");
while (rs.next()) {
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : "";
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
PlayerAuth pAuth = PlayerAuth.builder()
.name(rs.getString(columnName))
.realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword))
.hash(new EncryptedPassword(rs.getString(columnPassword), salt))
.lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld))
@@ -1102,7 +1086,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail))
.salt(salt)
.groupId(group)
.build();
@@ -2,6 +2,7 @@ package fr.xephi.authme.datasource;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings;
import java.sql.*;
@@ -174,15 +175,7 @@ public class SQLite implements DataSource {
pst.setString(1, user);
rs = pst.executeQuery();
if (rs.next()) {
if (rs.getString(columnIp).isEmpty()) {
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "192.168.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
return buildAuthFromResultSet(rs);
} else {
return null;
}
@@ -206,21 +199,25 @@ public class SQLite implements DataSource {
public synchronized boolean saveAuth(PlayerAuth auth) {
PreparedStatement pst = null;
try {
if (columnSalt.isEmpty() && auth.getSalt().isEmpty()) {
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);");
EncryptedPassword password = auth.getPassword();
if (columnSalt.isEmpty() && password.getSalt().isEmpty()) {
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword +
"," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);");
pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash());
pst.setString(2, password.getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
pst.executeUpdate();
} else {
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName + ") VALUES (?,?,?,?,?,?);");
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + ","
+ columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName
+ ") VALUES (?,?,?,?,?,?);");
pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash());
pst.setString(2, password.getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getSalt());
pst.setString(5, password.getSalt());
pst.setString(6, auth.getRealName());
pst.executeUpdate();
}
@@ -244,9 +241,19 @@ public class SQLite implements DataSource {
public synchronized boolean updatePassword(PlayerAuth auth) {
PreparedStatement pst = null;
try {
pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;");
pst.setString(1, auth.getHash());
pst.setString(2, auth.getNickname());
EncryptedPassword password = auth.getPassword();
boolean useSalt = !columnSalt.isEmpty();
String sql = "UPDATE " + tableName + " SET " + columnPassword + " = ?"
+ (useSalt ? ", " + columnSalt + " = ?" : "")
+ " WHERE " + columnName + " = ?";
pst = con.prepareStatement(sql);
pst.setString(1, password.getHash());
if (useSalt) {
pst.setString(2, password.getSalt());
pst.setString(3, auth.getNickname());
} else {
pst.setString(2, auth.getNickname());
}
pst.executeUpdate();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
@@ -398,6 +405,7 @@ public class SQLite implements DataSource {
ResultSet rs = null;
int countIp = 0;
try {
// TODO ljacqu 20151230: Simply fetch COUNT(1) and return that
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;");
pst.setString(1, ip);
rs = pst.executeQuery();
@@ -438,33 +446,6 @@ public class SQLite implements DataSource {
return true;
}
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public boolean updateSalt(PlayerAuth auth) {
if (columnSalt.isEmpty()) {
return false;
}
PreparedStatement pst = null;
try {
pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnSalt + "=? WHERE " + columnName + "=?;");
pst.setString(1, auth.getSalt());
pst.setString(2, auth.getNickname());
pst.executeUpdate();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
return false;
} finally {
close(pst);
}
return true;
}
/**
* Method close.
*
@@ -761,14 +742,6 @@ public class SQLite implements DataSource {
return result;
}
/**
* Method updateName.
*
* @param oldOne String
* @param newOne String
*
* @see fr.xephi.authme.datasource.DataSource#updateName(String, String)
*/
@Override
public void updateName(String oldOne, String newOne) {
PreparedStatement pst = null;
@@ -787,7 +760,7 @@ public class SQLite implements DataSource {
/**
* Method getAllAuths.
*
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getAllAuths()
* @return List<PlayerAuth>
*/
@Override
public List<PlayerAuth> getAllAuths() {
@@ -798,17 +771,8 @@ public class SQLite implements DataSource {
pst = con.prepareStatement("SELECT * FROM " + tableName + ";");
rs = pst.executeQuery();
while (rs.next()) {
PlayerAuth pAuth;
if (rs.getString(columnIp).isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
auths.add(pAuth);
PlayerAuth auth = buildAuthFromResultSet(rs);
auths.add(auth);
}
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
@@ -822,7 +786,7 @@ public class SQLite implements DataSource {
/**
* Method getLoggedPlayers.
*
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
* @return List<PlayerAuth>
*/
@Override
public List<PlayerAuth> getLoggedPlayers() {
@@ -833,17 +797,8 @@ public class SQLite implements DataSource {
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;");
rs = pst.executeQuery();
while (rs.next()) {
PlayerAuth pAuth;
if (rs.getString(columnIp).isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
auths.add(pAuth);
PlayerAuth auth = buildAuthFromResultSet(rs);
auths.add(auth);
}
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
@@ -853,4 +808,25 @@ public class SQLite implements DataSource {
}
return auths;
}
private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException {
String salt = !columnSalt.isEmpty() ? row.getString(columnSalt) : null;
PlayerAuth.Builder authBuilder = PlayerAuth.builder()
.name(row.getString(columnName))
.email(row.getString(columnEmail))
.realName(row.getString(columnRealName))
.hash(row.getString(columnPassword), salt)
.lastLogin(row.getLong(columnLastLogin))
.locX(row.getDouble(lastlocX))
.locY(row.getDouble(lastlocY))
.locZ(row.getDouble(lastlocZ))
.locWorld(row.getString(lastlocWorld));
String ip = row.getString(columnIp);
if (!ip.isEmpty()) {
authBuilder.ip(ip);
}
return authBuilder.build();
}
}