#1255 Simplify MySQL data source extensions

- Mostly oving the logic of getting the ID from the DB to the extensions superclass
This commit is contained in:
ljacqu 2017-07-23 14:54:04 +02:00
parent cbc794ba20
commit 8eceaa8cbb
9 changed files with 190 additions and 188 deletions

View File

@ -85,6 +85,7 @@ public class MySQL implements DataSource {
* Retrieves various settings.
*
* @param settings the settings to read properties from
* @param extensionsFactory factory to create the MySQL extension
*/
private void setParameters(Settings settings, MySqlExtensionsFactory extensionsFactory) {
this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
@ -435,8 +436,8 @@ public class MySQL implements DataSource {
@Override
public boolean updateQuitLoc(PlayerAuth auth) {
String sql = "UPDATE " + tableName
+ " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?, "
+ col.LASTLOC_YAW + "=?, " + col.LASTLOC_PITCH + "=?"
+ " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, "
+ col.LASTLOC_WORLD + "=?, " + col.LASTLOC_YAW + "=?, " + col.LASTLOC_PITCH + "=?"
+ " WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setDouble(1, auth.getQuitLocX());

View File

@ -3,12 +3,10 @@ package fr.xephi.authme.datasource.mysqlextensions;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
@ -16,53 +14,42 @@ import java.sql.SQLException;
*/
class Ipb4Extension extends MySqlExtension {
private final Columns col;
private final String tableName;
private final String ipbPrefix;
private final int ipbGroup;
Ipb4Extension(Settings settings, Columns col) {
this.col = col;
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
super(settings, col);
this.ipbPrefix = settings.getProperty(HooksSettings.IPB_TABLE_PREFIX);
this.ipbGroup = settings.getProperty(HooksSettings.IPB_ACTIVATED_GROUP_ID);
}
@Override
public void saveAuth(PlayerAuth auth, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getNickname());
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
// Update player group in core_members
sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".member_group_id=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setInt(1, ipbGroup);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
// Get current time without ms
long time = System.currentTimeMillis() / 1000;
// update joined date
sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".joined=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setLong(1, time);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
// Update last_visit
sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setLong(1, time);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
}
}
// Update player group in core_members
String sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".member_group_id=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setInt(1, ipbGroup);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
// Get current time without ms
long time = System.currentTimeMillis() / 1000;
// update joined date
sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".joined=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setLong(1, time);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
// Update last_visit
sql = "UPDATE " + ipbPrefix + tableName
+ " SET " + tableName + ".last_visit=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
pst2.setLong(1, time);
pst2.setString(2, auth.getNickname());
pst2.executeUpdate();
}
}
}

View File

@ -1,10 +1,16 @@
package fr.xephi.authme.datasource.mysqlextensions;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.OptionalInt;
/**
* Extension for the MySQL data source for forums. For certain password hashes (e.g. phpBB), we want
@ -12,6 +18,14 @@ import java.sql.SQLException;
*/
public abstract class MySqlExtension {
protected final Columns col;
protected final String tableName;
MySqlExtension(Settings settings, Columns col) {
this.col = col;
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
}
/**
* Performs additional actions when a new player is saved.
*
@ -59,4 +73,24 @@ public abstract class MySqlExtension {
// extend for custom behavior
}
/**
* Fetches the database ID of the given name from the database.
*
* @param name the name to get the ID for
* @param con connection to the sql table
* @return id of the playerAuth, or empty OptionalInt if the name is not registered
* @throws SQLException .
*/
protected OptionalInt retrieveIdFromTable(String name, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, name);
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
return OptionalInt.of(rs.getInt(col.ID));
}
}
}
return OptionalInt.empty();
}
}

View File

@ -15,6 +15,12 @@ public class MySqlExtensionsFactory {
@Inject
private Settings settings;
/**
* Creates a new {@link MySqlExtension} object according to the configured hash algorithm.
*
* @param columnsConfig the columns configuration
* @return the extension the MySQL data source should use
*/
public MySqlExtension buildExtension(Columns columnsConfig) {
HashAlgorithm hash = settings.getProperty(SecuritySettings.PASSWORD_HASH);
switch (hash) {
@ -27,7 +33,7 @@ public class MySqlExtensionsFactory {
case XFBCRYPT:
return new XfBcryptExtension(settings, columnsConfig);
default:
return new NoOpExtension();
return new NoOpExtension(settings, columnsConfig);
}
}
}

View File

@ -1,7 +1,14 @@
package fr.xephi.authme.datasource.mysqlextensions;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.settings.Settings;
/**
* Extension implementation that does not do anything.
*/
class NoOpExtension extends MySqlExtension {
NoOpExtension(Settings settings, Columns col) {
super(settings, col);
}
}

View File

@ -3,42 +3,32 @@ package fr.xephi.authme.datasource.mysqlextensions;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.OptionalInt;
/**
* Extensions for phpBB when MySQL is used as data source.
*/
class PhpBbExtension extends MySqlExtension {
private final Columns col;
private final String tableName;
private final String phpBbPrefix;
private final int phpBbGroup;
PhpBbExtension(Settings settings, Columns col) {
this.col = col;
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
super(settings, col);
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
}
@Override
public void saveAuth(PlayerAuth auth, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getNickname());
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
int id = rs.getInt(col.ID);
updateSpecificsOnSave(id, auth.getNickname(), con);
}
}
OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con);
if (authId.isPresent()) {
updateSpecificsOnSave(authId.getAsInt(), auth.getNickname(), con);
}
}

View File

@ -3,105 +3,100 @@ package fr.xephi.authme.datasource.mysqlextensions;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.OptionalInt;
/**
* MySQL extensions for Wordpress.
*/
class WordpressExtension extends MySqlExtension {
private final Columns col;
private final String tableName;
private final String wordpressPrefix;
WordpressExtension(Settings settings, Columns col) {
this.col = col;
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
super(settings, col);
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
}
@Override
public void saveAuth(PlayerAuth auth, Connection con) throws SQLException {
try (PreparedStatement pst = con.prepareStatement("SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;")) {
pst.setString(1, auth.getNickname());
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
int id = rs.getInt(col.ID);
String sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)";
try (PreparedStatement pst2 = con.prepareStatement(sql)) {
// First Name
pst2.setInt(1, id);
pst2.setString(2, "first_name");
pst2.setString(3, "");
pst2.addBatch();
// Last Name
pst2.setInt(1, id);
pst2.setString(2, "last_name");
pst2.setString(3, "");
pst2.addBatch();
// Nick Name
pst2.setInt(1, id);
pst2.setString(2, "nickname");
pst2.setString(3, auth.getNickname());
pst2.addBatch();
// Description
pst2.setInt(1, id);
pst2.setString(2, "description");
pst2.setString(3, "");
pst2.addBatch();
// Rich_Editing
pst2.setInt(1, id);
pst2.setString(2, "rich_editing");
pst2.setString(3, "true");
pst2.addBatch();
// Comments_Shortcuts
pst2.setInt(1, id);
pst2.setString(2, "comment_shortcuts");
pst2.setString(3, "false");
pst2.addBatch();
// admin_color
pst2.setInt(1, id);
pst2.setString(2, "admin_color");
pst2.setString(3, "fresh");
pst2.addBatch();
// use_ssl
pst2.setInt(1, id);
pst2.setString(2, "use_ssl");
pst2.setString(3, "0");
pst2.addBatch();
// show_admin_bar_front
pst2.setInt(1, id);
pst2.setString(2, "show_admin_bar_front");
pst2.setString(3, "true");
pst2.addBatch();
// wp_capabilities
pst2.setInt(1, id);
pst2.setString(2, wordpressPrefix + "capabilities");
pst2.setString(3, "a:1:{s:10:\"subscriber\";b:1;}");
pst2.addBatch();
// wp_user_level
pst2.setInt(1, id);
pst2.setString(2, wordpressPrefix + "user_level");
pst2.setString(3, "0");
pst2.addBatch();
// default_password_nag
pst2.setInt(1, id);
pst2.setString(2, "default_password_nag");
pst2.setString(3, "");
pst2.addBatch();
OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con);
if (authId.isPresent()) {
saveSpecifics(auth, authId.getAsInt(), con);
}
}
// Execute queries
pst2.executeBatch();
pst2.clearBatch();
}
}
}
private void saveSpecifics(PlayerAuth auth, int id, Connection con) throws SQLException {
String sql = "INSERT INTO " + wordpressPrefix + "usermeta (user_id, meta_key, meta_value) VALUES (?,?,?)";
try (PreparedStatement pst = con.prepareStatement(sql)) {
// First Name
pst.setInt(1, id);
pst.setString(2, "first_name");
pst.setString(3, "");
pst.addBatch();
// Last Name
pst.setInt(1, id);
pst.setString(2, "last_name");
pst.setString(3, "");
pst.addBatch();
// Nick Name
pst.setInt(1, id);
pst.setString(2, "nickname");
pst.setString(3, auth.getNickname());
pst.addBatch();
// Description
pst.setInt(1, id);
pst.setString(2, "description");
pst.setString(3, "");
pst.addBatch();
// Rich_Editing
pst.setInt(1, id);
pst.setString(2, "rich_editing");
pst.setString(3, "true");
pst.addBatch();
// Comments_Shortcuts
pst.setInt(1, id);
pst.setString(2, "comment_shortcuts");
pst.setString(3, "false");
pst.addBatch();
// admin_color
pst.setInt(1, id);
pst.setString(2, "admin_color");
pst.setString(3, "fresh");
pst.addBatch();
// use_ssl
pst.setInt(1, id);
pst.setString(2, "use_ssl");
pst.setString(3, "0");
pst.addBatch();
// show_admin_bar_front
pst.setInt(1, id);
pst.setString(2, "show_admin_bar_front");
pst.setString(3, "true");
pst.addBatch();
// wp_capabilities
pst.setInt(1, id);
pst.setString(2, wordpressPrefix + "capabilities");
pst.setString(3, "a:1:{s:10:\"subscriber\";b:1;}");
pst.addBatch();
// wp_user_level
pst.setInt(1, id);
pst.setString(2, wordpressPrefix + "user_level");
pst.setString(3, "0");
pst.addBatch();
// default_password_nag
pst.setInt(1, id);
pst.setString(2, "default_password_nag");
pst.setString(3, "");
pst.addBatch();
// Execute queries
pst.executeBatch();
pst.clearBatch();
}
}
}

View File

@ -5,7 +5,6 @@ import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.XfBCrypt;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.HooksSettings;
import java.sql.Blob;
@ -13,35 +12,27 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.OptionalInt;
/**
* Extension for XFBCRYPT.
*/
class XfBcryptExtension extends MySqlExtension {
private final Columns col;
private final String tableName;
private final String xfPrefix;
private final int xfGroup;
XfBcryptExtension(Settings settings, Columns col) {
this.col = col;
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
super(settings, col);
this.xfPrefix = settings.getProperty(HooksSettings.XF_TABLE_PREFIX);
this.xfGroup = settings.getProperty(HooksSettings.XF_ACTIVATED_GROUP_ID);
}
@Override
public void saveAuth(PlayerAuth auth, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getNickname());
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
int id = rs.getInt(col.ID);
updateXenforoTablesOnSave(auth, id, con);
}
}
OptionalInt authId = retrieveIdFromTable(auth.getNickname(), con);
if (authId.isPresent()) {
updateXenforoTablesOnSave(auth, authId.getAsInt(), con);
}
}
@ -110,50 +101,39 @@ class XfBcryptExtension extends MySqlExtension {
@Override
public void changePassword(String user, HashedPassword password, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user);
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
int id = rs.getInt(col.ID);
// Insert password in the correct table
// TODO #1255: Close these statements with try-catch
sql = "UPDATE " + xfPrefix + "user_authenticate SET data=? WHERE " + col.ID + "=?;";
PreparedStatement pst2 = con.prepareStatement(sql);
String serializedHash = XfBCrypt.serializeHash(password.getHash());
byte[] bytes = serializedHash.getBytes();
Blob blob = con.createBlob();
blob.setBytes(1, bytes);
pst2.setBlob(1, blob);
pst2.setInt(2, id);
pst2.executeUpdate();
pst2.close();
// ...
sql = "UPDATE " + xfPrefix + "user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;";
pst2 = con.prepareStatement(sql);
pst2.setString(1, XfBCrypt.SCHEME_CLASS);
pst2.setInt(2, id);
pst2.executeUpdate();
pst2.close();
}
OptionalInt authId = retrieveIdFromTable(user, con);
if (authId.isPresent()) {
final int id = authId.getAsInt();
// Insert password in the correct table
String sql = "UPDATE " + xfPrefix + "user_authenticate SET data=? WHERE " + col.ID + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
String serializedHash = XfBCrypt.serializeHash(password.getHash());
byte[] bytes = serializedHash.getBytes();
Blob blob = con.createBlob();
blob.setBytes(1, bytes);
pst.setBlob(1, blob);
pst.setInt(2, id);
pst.executeUpdate();
}
// ...
sql = "UPDATE " + xfPrefix + "user_authenticate SET scheme_class=? WHERE " + col.ID + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, XfBCrypt.SCHEME_CLASS);
pst.setInt(2, id);
pst.executeUpdate();
}
}
}
@Override
public void removeAuth(String user, Connection con) throws SQLException {
String sql = "SELECT " + col.ID + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
try (PreparedStatement xfSelect = con.prepareStatement(sql)) {
xfSelect.setString(1, user);
try (ResultSet rs = xfSelect.executeQuery()) {
if (rs.next()) {
int id = rs.getInt(col.ID);
sql = "DELETE FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;";
try (PreparedStatement xfDelete = con.prepareStatement(sql)) {
xfDelete.setInt(1, id);
xfDelete.executeUpdate();
}
}
OptionalInt authId = retrieveIdFromTable(user, con);
if (authId.isPresent()) {
String sql = "DELETE FROM " + xfPrefix + "user_authenticate WHERE " + col.ID + "=?;";
try (PreparedStatement xfDelete = con.prepareStatement(sql)) {
xfDelete.setInt(1, authId.getAsInt());
xfDelete.executeUpdate();
}
}
}

View File

@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import fr.xephi.authme.datasource.Columns;
import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension;
import fr.xephi.authme.initialization.HasCleanup;
import fr.xephi.authme.process.register.executors.RegistrationMethod;
import fr.xephi.authme.security.crypts.Whirlpool;
@ -55,6 +56,7 @@ public class ClassesConsistencyTest {
/** Classes excluded from the field visibility test. */
private static final Set<Class<?>> CLASSES_EXCLUDED_FROM_VISIBILITY_TEST = ImmutableSet.of(
Whirlpool.class, // not our implementation, so we don't touch it
MySqlExtension.class, // has immutable protected fields used by all children
Columns.class // uses non-static String constants, which is safe
);