Merge branch 'master' of https://github.com/AuthMe-Team/AuthMeReloaded into 137-xenforo-support

Conflicts:
	src/main/java/fr/xephi/authme/datasource/DataSource.java
	src/main/java/fr/xephi/authme/datasource/SQLite.java
	src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java
This commit is contained in:
ljacqu 2016-01-02 00:52:08 +01:00
commit 561e21f5e2
41 changed files with 1519 additions and 971 deletions

1461
pom.xml

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,35 @@
package fr.xephi.authme;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.mcstats.Metrics;
import org.mcstats.Metrics.Graph;
import com.earth2me.essentials.Essentials;
import com.onarandombox.MultiverseCore.MultiverseCore;
import fr.xephi.authme.api.API;
import fr.xephi.authme.api.NewAPI;
import fr.xephi.authme.cache.auth.PlayerAuth;
@ -52,32 +80,6 @@ import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.Wrapper;
import net.minelink.ctplus.CombatTagPlus;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.mcstats.Metrics;
import org.mcstats.Metrics.Graph;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
/**
* The AuthMe main class.
@ -435,7 +437,7 @@ public class AuthMe extends JavaPlugin {
// Set up the API
api = new NewAPI(this);
// Setup the old deprecated API
// Set up the deprecated API
new API(this);
}
@ -983,6 +985,8 @@ public class AuthMe extends JavaPlugin {
/**
* Return the management instance.
*
* @return management The Management
*/
public Management getManagement() {
return management;

View File

@ -1,12 +1,5 @@
package fr.xephi.authme;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.io.File;
import java.util.List;
import java.util.concurrent.Callable;
@ -14,6 +7,14 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils;
/**
*/
public class DataManager {
@ -65,7 +66,7 @@ public class DataManager {
/**
* Method purgeAntiXray.
*
* @param cleared List<String>
* @param cleared List of String
*/
public synchronized void purgeAntiXray(List<String> cleared) {
int i = 0;
@ -90,7 +91,7 @@ public class DataManager {
/**
* Method purgeLimitedCreative.
*
* @param cleared List<String>
* @param cleared List of String
*/
public synchronized void purgeLimitedCreative(List<String> cleared) {
int i = 0;
@ -127,7 +128,7 @@ public class DataManager {
/**
* Method purgeDat.
*
* @param cleared List<String>
* @param cleared List of String
*/
public synchronized void purgeDat(List<String> cleared) {
int i = 0;
@ -160,7 +161,7 @@ public class DataManager {
/**
* Method purgeEssentials.
*
* @param cleared List<String>
* @param cleared List of String
*/
@SuppressWarnings("deprecation")
public void purgeEssentials(List<String> cleared) {

View File

@ -1,15 +1,16 @@
package fr.xephi.authme.api;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
/**
* The current API of AuthMe.
@ -76,7 +77,7 @@ public class NewAPI {
}
/**
* @param player
* @param player a Player
*
* @return true if player is a npc
*/
@ -85,7 +86,7 @@ public class NewAPI {
}
/**
* @param player
* @param player a Player
*
* @return true if the player is unrestricted
*/

View File

@ -1,11 +1,12 @@
package fr.xephi.authme.cache.auth;
import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.Location;
import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;
import org.bukkit.Location;
import fr.xephi.authme.security.crypts.HashedPassword;
/**
*/
@ -24,7 +25,7 @@ public class PlayerAuth {
private String realName;
/**
*
* @param serialized String
*/
public PlayerAuth(String serialized) {
this.deserialize(serialized);
@ -340,6 +341,8 @@ public class PlayerAuth {
/**
* Method to deserialize PlayerAuth
*
* @param str String
*/
public void deserialize(String str) {
String[] args = str.split(";");

View File

@ -12,12 +12,13 @@ import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
/**
* Command description - defines which labels ("names") will lead to a command and points to the
* Command description defines which labels ("names") will lead to a command and points to the
* {@link ExecutableCommand} implementation that executes the logic of the command.
*
* CommandDescription instances are built hierarchically and have one parent or {@code null} for base commands
* (main commands such as /authme) and may have multiple children extending the mapping of the parent: e.g. if
* /authme has a child whose label is "register", then "/authme register" is the command that the child defines.
* CommandDescription instances are built hierarchically: they have one parent, or {@code null} for base commands
* (main commands such as {@code /authme}), and may have multiple children extending the mapping of the parent: e.g. if
* {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that
* the child defines.
*/
public class CommandDescription {
@ -102,10 +103,11 @@ public class CommandDescription {
}
/**
* Get all relative labels of this command. For example, if this object describes "/authme register" and
* "/authme r", then "r" and "register" are the relative labels, whereas "authme" is the label of the parent.
* Return all relative labels of this command. For example, if this object describes {@code /authme register} and
* {@code /authme r}, then it will return a list with {@code register} and {@code r}. The parent label
* {@code authme} is not returned.
*
* @return All relative labels.
* @return All labels of the command description.
*/
public List<String> getLabels() {
return labels;

View File

@ -1,11 +1,12 @@
package fr.xephi.authme.command;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.command.CommandSender;
import fr.xephi.authme.util.StringUtils;
/**
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription}
* or to display help messages for unknown invocations.
@ -16,6 +17,8 @@ public class CommandHandler {
/**
* Create a command handler.
*
* @param commandService The CommandService instance
*/
public CommandHandler(CommandService commandService) {
this.commandService = commandService;
@ -45,6 +48,12 @@ public class CommandHandler {
return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus());
}
/**
* Execute the command for the given command sender.
*
* @param sender The sender which initiated the command
* @param result The mapped result
*/
private void executeCommand(CommandSender sender, FoundCommandResult result) {
ExecutableCommand executableCommand = result.getCommandDescription().getExecutableCommand();
List<String> arguments = result.getArguments();

View File

@ -1,5 +1,9 @@
package fr.xephi.authme.command;
import java.util.List;
import org.bukkit.command.CommandSender;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.datasource.DataSource;
@ -8,9 +12,6 @@ import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import org.bukkit.command.CommandSender;
import java.util.List;
/**
* Service for implementations of {@link ExecutableCommand} to execute some common tasks.
@ -31,6 +32,7 @@ public class CommandService {
* @param commandMapper Command mapper
* @param helpProvider Help provider
* @param messages Messages instance
* @param passwordSecurity The Password Security instance
*/
public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages,
PasswordSecurity passwordSecurity) {
@ -51,6 +53,13 @@ public class CommandService {
messages.send(sender, messageKey);
}
/**
* Send a message to a player.
*
* @param sender The command sender to send the message to
* @param messageKey The message key to send
* @param replacements The replacement arguments for the message key's tags
*/
public void send(CommandSender sender, MessageKey messageKey, String... replacements) {
messages.send(sender, messageKey, replacements);
}
@ -119,7 +128,7 @@ public class CommandService {
}
/**
* Returns the management instance of the plugin.
* Return the management instance of the plugin.
*
* @return The Management instance linked to the AuthMe instance
*/
@ -127,11 +136,22 @@ public class CommandService {
return authMe.getManagement();
}
/**
* Return the permissions manager.
*
* @return the permissions manager
*/
public PermissionsManager getPermissionsManager() {
// TODO ljacqu 20151226: Might be nicer to pass the perm manager via constructor
return authMe.getPermissionsManager();
}
/**
* Retrieve a message by its message key.
*
* @param key The message to retrieve
* @return The message
*/
public String[] retrieveMessage(MessageKey key) {
return messages.retrieve(key);
}

View File

@ -5,7 +5,7 @@ import java.util.List;
/**
* Result of a command mapping by {@link CommandHandler}. An object of this class represents a successful mapping
* as well as erroneous ones, as communicated with {@link FoundResultStatus}.
* <p />
* <p>
* Fields other than {@link FoundResultStatus} are available depending, among other factors, on the status:
* <ul>
* <li>{@link FoundResultStatus#SUCCESS} entails that mapping the input to a command was successful. Therefore,

View File

@ -1,10 +1,10 @@
package fr.xephi.authme.command;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
/**
* Common base type for player-only commands, handling the verification that the command sender is indeed a player.
*/
@ -35,7 +35,7 @@ public abstract class PlayerCommand implements ExecutableCommand {
/**
* Return an alternative command (textual representation) that is not restricted to players only.
* Example: "authme register &lt;playerName> &lt;password>"
* Example: {@code "authme register <playerName> <password>"}
*
* @return Alternative command not only for players, or null if not applicable
*/

View File

@ -1,5 +1,11 @@
package fr.xephi.authme.datasource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@ -7,16 +13,11 @@ import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalListeners;
import com.google.common.cache.RemovalNotification;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
*/
public class CacheDataSource implements DataSource {
@ -336,7 +337,7 @@ public class CacheDataSource implements DataSource {
/**
* Method purgeBanned.
*
* @param banned List<String>
* @param banned List of String
*
* @see fr.xephi.authme.datasource.DataSource#purgeBanned(List)
*/

View File

@ -79,7 +79,7 @@ public interface DataSource {
*
* @param until long
*
* @return List<String>
* @return List of String
*/
List<String> autoPurgeDatabase(long until);
@ -115,7 +115,7 @@ public interface DataSource {
*
* @param auth PlayerAuth
*
* @return List<String>
* @return List of String
*/
List<String> getAllAuthsByName(PlayerAuth auth);
@ -124,7 +124,7 @@ public interface DataSource {
*
* @param ip String
*
* @return List<String> * @throws Exception
* @return List of String * @throws Exception
*/
List<String> getAllAuthsByIp(String ip);
@ -133,7 +133,7 @@ public interface DataSource {
*
* @param email String
*
* @return List<String> * @throws Exception
* @return List of String * @throws Exception
*/
List<String> getAllAuthsByEmail(String email);
@ -153,7 +153,7 @@ public interface DataSource {
/**
* Method purgeBanned.
*
* @param banned List<String>
* @param banned List of String
*/
void purgeBanned(List<String> banned);
@ -207,14 +207,14 @@ public interface DataSource {
/**
* Method getAllAuths.
*
* @return List<PlayerAuth>
* @return List of PlayerAuth
*/
List<PlayerAuth> getAllAuths();
/**
* Method getLoggedPlayers.
*
* @return List<PlayerAuth>
* @return List of PlayerAuth
*/
List<PlayerAuth> getLoggedPlayers();

View File

@ -406,7 +406,7 @@ public class FlatFile implements DataSource {
*
* @param until long
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
* @return List of String * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
*/
@Override
public List<String> autoPurgeDatabase(long until) {
@ -622,7 +622,7 @@ public class FlatFile implements DataSource {
*
* @param auth PlayerAuth
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
* @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
*/
@Override
public List<String> getAllAuthsByName(PlayerAuth auth) {
@ -659,7 +659,7 @@ public class FlatFile implements DataSource {
*
* @param ip String
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
* @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
*/
@Override
public List<String> getAllAuthsByIp(String ip) {
@ -696,7 +696,7 @@ public class FlatFile implements DataSource {
*
* @param email String
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
* @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
*/
@Override
public List<String> getAllAuthsByEmail(String email) {
@ -731,7 +731,7 @@ public class FlatFile implements DataSource {
/**
* Method purgeBanned.
*
* @param banned List<String>
* @param banned List of String
*
* @see fr.xephi.authme.datasource.DataSource#purgeBanned(List)
*/
@ -876,7 +876,7 @@ public class FlatFile implements DataSource {
/**
* Method getAllAuths.
*
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getAllAuths()
* @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAllAuths()
*/
@Override
public List<PlayerAuth> getAllAuths() {
@ -928,7 +928,7 @@ public class FlatFile implements DataSource {
/**
* Method getLoggedPlayers.
*
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
* @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers()
*/
@Override
public List<PlayerAuth> getLoggedPlayers() {

View File

@ -1,11 +1,5 @@
package fr.xephi.authme.datasource;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
@ -15,6 +9,12 @@ import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
/**
*/
public class SQLite implements DataSource {
@ -40,7 +40,8 @@ public class SQLite implements DataSource {
/**
* Constructor for SQLite.
*
* @throws ClassNotFoundException * @throws SQLException
* @throws ClassNotFoundException Exception
* @throws SQLException Exception
*/
public SQLite() throws ClassNotFoundException, SQLException {
this.database = Settings.getMySQLDatabase;
@ -72,7 +73,8 @@ public class SQLite implements DataSource {
/**
* Method connect.
*
* @throws ClassNotFoundException * @throws SQLException
* @throws ClassNotFoundException
* @throws SQLException
*/
private synchronized void connect() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.JDBC");
@ -152,7 +154,8 @@ public class SQLite implements DataSource {
*
* @param user String
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String)
*/
@Override
public synchronized boolean isAuthAvailable(String user) {
@ -200,7 +203,8 @@ public class SQLite implements DataSource {
*
* @param user String
*
* @return PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAuth(String)
* @return PlayerAuth
* @see fr.xephi.authme.datasource.DataSource#getAuth(String)
*/
@Override
public synchronized PlayerAuth getAuth(String user) {
@ -229,7 +233,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth)
*/
@Override
public synchronized boolean saveAuth(PlayerAuth auth) {
@ -275,7 +280,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth)
*/
@Override
public synchronized boolean updatePassword(PlayerAuth auth) {
@ -314,7 +320,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth)
*/
@Override
public boolean updateSession(PlayerAuth auth) {
@ -340,7 +347,8 @@ public class SQLite implements DataSource {
*
* @param until long
*
* @return int * @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long)
* @return int
* @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long)
*/
@Override
public int purgeDatabase(long until) {
@ -363,7 +371,8 @@ public class SQLite implements DataSource {
*
* @param until long
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
* @return List of String
* @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long)
*/
@Override
public List<String> autoPurgeDatabase(long until) {
@ -392,7 +401,8 @@ public class SQLite implements DataSource {
*
* @param user String
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#removeAuth(String)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#removeAuth(String)
*/
@Override
public synchronized boolean removeAuth(String user) {
@ -415,7 +425,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth)
*/
@Override
public boolean updateQuitLoc(PlayerAuth auth) {
@ -442,7 +453,8 @@ public class SQLite implements DataSource {
*
* @param ip String
*
* @return int * @see fr.xephi.authme.datasource.DataSource#getIps(String)
* @return int
* @see fr.xephi.authme.datasource.DataSource#getIps(String)
*/
@Override
public int getIps(String ip) {
@ -472,7 +484,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth)
* @return boolean
* @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth)
*/
@Override
public boolean updateEmail(PlayerAuth auth) {
@ -549,7 +562,8 @@ public class SQLite implements DataSource {
*
* @param auth PlayerAuth
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
* @return List of String
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth)
*/
@Override
public List<String> getAllAuthsByName(PlayerAuth auth) {
@ -580,7 +594,8 @@ public class SQLite implements DataSource {
*
* @param ip String
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
* @return List of String
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String)
*/
@Override
public List<String> getAllAuthsByIp(String ip) {
@ -611,7 +626,8 @@ public class SQLite implements DataSource {
*
* @param email String
*
* @return List<String> * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
* @return List of String
* @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String)
*/
@Override
public List<String> getAllAuthsByEmail(String email) {
@ -656,7 +672,8 @@ public class SQLite implements DataSource {
/**
* Method getType.
*
* @return DataSourceType * @see fr.xephi.authme.datasource.DataSource#getType()
* @return DataSourceType
* @see fr.xephi.authme.datasource.DataSource#getType()
*/
@Override
public DataSourceType getType() {
@ -758,7 +775,8 @@ public class SQLite implements DataSource {
/**
* Method getAccountsRegistered.
*
* @return int * @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered()
* @return int
* @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered()
*/
@Override
public int getAccountsRegistered() {
@ -798,7 +816,7 @@ public class SQLite implements DataSource {
/**
* Method getAllAuths.
*
* @return List<PlayerAuth>
* @return List of PlayerAuth
*/
@Override
public List<PlayerAuth> getAllAuths() {
@ -824,7 +842,7 @@ public class SQLite implements DataSource {
/**
* Method getLoggedPlayers.
*
* @return List<PlayerAuth>
* @return List of PlayerAuth
*/
@Override
public List<PlayerAuth> getLoggedPlayers() {

View File

@ -25,7 +25,11 @@ public enum DefaultPermission {
this.title = title;
}
/** Return the textual representation. */
/**
* Return the textual representation.
*
* @return String
*/
public String getTitle() {
return title;
}

View File

@ -1,10 +1,11 @@
package fr.xephi.authme.permission;
import de.bananaco.bpermissions.api.ApiLayer;
import de.bananaco.bpermissions.api.CalculableType;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.util.CollectionUtils;
import net.milkbowl.vault.permission.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
import org.bukkit.Bukkit;
@ -17,24 +18,25 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import de.bananaco.bpermissions.api.ApiLayer;
import de.bananaco.bpermissions.api.CalculableType;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.util.CollectionUtils;
import net.milkbowl.vault.permission.Permission;
import ru.tehkode.permissions.PermissionManager;
import ru.tehkode.permissions.PermissionUser;
import ru.tehkode.permissions.bukkit.PermissionsEx;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* <p>
* PermissionsManager.
* <p/>
* </p><p>
* A permissions manager, to manage and use various permissions systems.
* This manager supports dynamic plugin hooking and various other features.
* <p/>
* </p><p>
* Written by Tim Visée.
*
* </p>
* @author Tim Visée, http://timvisee.com
* @version 0.2.1
*/

View File

@ -13,6 +13,9 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package fr.xephi.authme.security.crypts;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
@ -21,9 +24,6 @@ import fr.xephi.authme.security.crypts.description.Usage;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
/**
* <p>
* BCrypt implements OpenBSD-style Blowfish password hashing using the scheme
@ -64,7 +64,6 @@ import java.security.SecureRandom;
* is twice as much work. The default log_rounds is 10, and the valid range is 4
* to 31.
* </p>
*
* @author Damien Miller
* @version 0.2
*/

View File

@ -10,8 +10,6 @@ import fr.xephi.authme.security.crypts.description.HasSalt;
import java.nio.charset.Charset;
import java.security.MessageDigest;
@Recommendation(Usage.DO_NOT_USE)
@HasSalt(SaltType.USERNAME)
public class CRAZYCRYPT1 extends UsernameSaltMethod {
private static final char[] CRYPTCHARS =

View File

@ -8,7 +8,7 @@ import fr.xephi.authme.security.crypts.description.Usage;
import static fr.xephi.authme.security.HashUtils.md5;
@Recommendation(Usage.DO_NOT_USE)
@Recommendation(Usage.ACCEPTABLE)
@HasSalt(value = SaltType.TEXT, length = 5)
public class IPB3 extends SeparateSaltMethod {

View File

@ -1,9 +1,15 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
import static fr.xephi.authme.security.HashUtils.md5;
@Recommendation(Usage.ACCEPTABLE)
@HasSalt(value = SaltType.TEXT, length = 8)
public class MYBB extends SeparateSaltMethod {
@Override

View File

@ -1,9 +1,15 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
import static fr.xephi.authme.security.HashUtils.sha1;
@Recommendation(Usage.ACCEPTABLE)
@HasSalt(value = SaltType.TEXT, length = 40)
public class WBB3 extends SeparateSaltMethod {
@Override

View File

@ -241,8 +241,9 @@ public class WHIRLPOOL extends UnsaltedMethod {
*
* @param source plaintext data to hash.
* @param sourceBits how many bits of plaintext to process.
* <p/>
* This method maintains the invariant: bufferBits < 512
* <p>
* This method maintains the invariant: bufferBits &lt; 512
* </p>
*/
public void NESSIEadd(byte[] source, long sourceBits) {
/*
@ -322,10 +323,12 @@ public class WHIRLPOOL extends UnsaltedMethod {
}
/**
* <p>
* Get the hash value from the hashing state.
* <p/>
* This method uses the invariant: bufferBits < 512
*
* </p>
* <p>
* This method uses the invariant: bufferBits &lt; 512
* </p>
* @param digest byte[]
*/
public void NESSIEfinalize(byte[] digest) {
@ -367,7 +370,7 @@ public class WHIRLPOOL extends UnsaltedMethod {
* Delivers string input data to the hashing algorithm.
*
* @param source plaintext data to hash (ASCII text string).
* This method maintains the invariant: bufferBits < 512
* This method maintains the invariant: bufferBits &lt; 512
*/
public void NESSIEadd(String source) {
if (source.length() > 0) {

View File

@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Denotes an encryption algorithm that is restricted to the ASCII charset.
* Denotes a hashing algorithm that is restricted to the ASCII charset.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

View File

@ -13,10 +13,18 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface HasSalt {
/** The type of the salt. */
/**
* The type of the salt.
*
* @return The salt type
*/
SaltType value();
/** For text salts, the length of the salt. */
/**
* For text salts, the length of the salt.
*
* @return The length of the salt the algorithm uses, or 0 if not defined or not applicable.
*/
int length() default 0;
}

View File

@ -6,13 +6,19 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to mark a hash algorithm with the usage recommendation, see {@link Usage}.
* Annotation to mark a hash algorithm with the usage recommendation.
*
* @see Usage
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Recommendation {
/** The recommendation for using the hash algorithm. */
/**
* The recommendation for using the hash algorithm.
*
* @return The recommended usage
*/
Usage value();
}

View File

@ -8,7 +8,7 @@ public enum SaltType {
/** Random, newly generated text. */
TEXT,
/** Salt is based on the username, including variations and repetitions. */
/** Salt is based on the username, including variations and repetitions thereof. */
USERNAME,
/** No salt. */

View File

@ -2,6 +2,12 @@ package fr.xephi.authme.security.crypts.description;
/**
* Usage recommendation that can be provided for a hash algorithm.
* <p>
* Use the following rules of thumb:
* <ul>
* <li>Hashes using MD5 may be {@link #ACCEPTABLE} but never {@link #RECOMMENDED}.</li>
* <li>Hashes using no salt or one based on the username should be {@link #DO_NOT_USE}.</li>
* </ul>
*/
public enum Usage {

View File

@ -1,15 +1,16 @@
package fr.xephi.authme.security.pbkdf2;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* Default PRF implementation based on standard javax.crypt.Mac mechanisms.
* <p>
* <hr />
* Default PRF implementation based on standard javax.crypt.Mac mechanisms.
* </p>
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner

View File

@ -75,7 +75,7 @@ public interface PBKDF2 {
/**
* Allow setting of configured parameters.
*
* @param parameters
* @param parameters PBKDF2Parameters
*/
void setParameters(PBKDF2Parameters parameters);

View File

@ -8,20 +8,17 @@ import java.security.SecureRandom;
/**
* <p>
* Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification
* <p>
* </p><p>
* Version 2.0
* <p>
* </p>
* <p>
* PBKDF2 (P, S, c, dkLen)
* <p>
* <p>
* </p>
* Options:
* <ul>
* <li>PRF underlying pseudorandom function (hLen denotes the length in octets
* of the pseudorandom function output). PRF is pluggable.</li>
* </ul>
* <p>
* <p>
* Input:
* <ul>
* <li>P password, an octet string</li>
@ -30,15 +27,11 @@ import java.security.SecureRandom;
* <li>dkLen intended length in octets of the derived key, a positive integer,
* at most (2^32 - 1) * hLen</li>
* </ul>
* <p>
* <p>
* Output:
* <ul>
* <li>DK derived key, a dkLen-octet string</li>
* </ul>
* <p>
* <hr />
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>
@ -115,13 +108,14 @@ public class PBKDF2Engine implements PBKDF2 {
* ISO-8559-1 encoding. Output result as
* &quot;Salt:iteration-count:PBKDF2&quot; with binary data in hexadecimal
* encoding.
* <p/>
* <p>
* Example: Password &quot;password&quot; (without the quotes) leads to
* 48290A0B96C426C3:1000:973899B1D4AFEB3ED371060D0797E0EE0142BD04
*
* </p>
* @param args Supply the password as argument.
*
* @throws IOException * @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws IOException an ioexception occured
* @throws NoSuchAlgorithmException a NoSuchAlgorithmException occured
*/
public static void main(String[] args)
throws IOException, NoSuchAlgorithmException {
@ -266,8 +260,8 @@ public class PBKDF2Engine implements PBKDF2 {
/**
* Integer division with ceiling function.
*
* @param a
* @param b
* @param a Integer
* @param b Integer
*
* @return ceil(a/b) * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 2.</a>
@ -288,7 +282,7 @@ public class PBKDF2Engine implements PBKDF2 {
* @param prf Pseudo Random Function
* @param S Salt as array of bytes
* @param c Iteration count
* @param blockIndex
* @param blockIndex Integer
*
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 3.</a>
@ -314,8 +308,8 @@ public class PBKDF2Engine implements PBKDF2 {
* Block-Xor. Xor source bytes into destination byte buffer. Destination
* buffer must be same length or less than source buffer.
*
* @param dest
* @param src
* @param dest byte array
* @param src byte array
*/
protected void xor(byte[] dest, byte[] src) {
for (int i = 0; i < dest.length; i++) {
@ -326,9 +320,9 @@ public class PBKDF2Engine implements PBKDF2 {
/**
* Four-octet encoding of the integer i, most significant octet first.
*
* @param dest
* @param offset
* @param i
* @param dest byte array
* @param offset Integer
* @param i Integer
*
* @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step
* 3.</a>

View File

@ -5,8 +5,6 @@ package fr.xephi.authme.security.pbkdf2;
* Parameter data holder for PBKDF2 configuration.
* </p>
* <p>
* <hr />
* <p>
* A free Java implementation of Password Based Key Derivation Function 2 as
* defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
* </p>

View File

@ -1,13 +1,13 @@
package fr.xephi.authme.settings;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* @author Xephi59
* @version $Revision: 1.0 $
@ -88,7 +88,7 @@ public class OtherAccounts extends CustomConfiguration {
*
* @param uuid UUID
*
* @return List<String>
* @return StringList
*/
public List<String> getAllPlayersByUUID(UUID uuid) {
return this.getStringList(uuid.toString());

View File

@ -1,32 +1,27 @@
package fr.xephi.authme.settings;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.util.Wrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.bukkit.configuration.file.YamlConfiguration;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.util.Wrapper;
/**
*/
public final class Settings {
@ -122,7 +117,7 @@ public final class Settings {
/**
* Method reload.
*
* @throws Exception
* @throws Exception if something went wrong
*/
public static void reload() throws Exception {
plugin.getLogger().info("Loading Configuration File...");
@ -141,7 +136,6 @@ public final class Settings {
messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml");
}
public static void loadVariables() {
helpHeader = configFile.getString("settings.helpHeader", "AuthMeReloaded");
messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage", "en").toLowerCase());
@ -311,35 +305,22 @@ public final class Settings {
}
private static String loadEmailText() {
if (!EMAIL_FILE.exists())
saveDefaultEmailText();
StringBuilder str = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new FileReader(EMAIL_FILE));
String s;
while ((s = in.readLine()) != null)
str.append(s);
in.close();
} catch (IOException ignored) {
if (!EMAIL_FILE.exists()) {
plugin.saveResource("email.html", false);
}
return str.toString();
}
private static void saveDefaultEmailText() {
InputStream file = plugin.getResource("email.html");
StringBuilder str = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(file, Charset.forName("utf-8")));
String s;
while ((s = in.readLine()) != null)
str.append(s);
in.close();
Files.touch(EMAIL_FILE);
Files.write(str.toString(), EMAIL_FILE, Charsets.UTF_8);
} catch (Exception ignored) {
return Files.toString(EMAIL_FILE, Charsets.UTF_8);
} catch (IOException e) {
ConsoleLogger.showError(e.getMessage());
ConsoleLogger.writeStackTrace(e);
return "";
}
}
/**
* @param key the key to set
* @param value the value to set
*/
public static void setValue(String key, Object value) {
instance.set(key, value);
save();
@ -380,8 +361,9 @@ public final class Settings {
* return false if ip and name doesn't match with player that join the
* server, so player has a restricted access
*
* @param name String
* @param ip String
* @param name String
* @param ip String
* @param domain String
*
* @return boolean
*/
@ -396,14 +378,12 @@ public final class Settings {
String testIp = args[1];
if (testName.equalsIgnoreCase(name)) {
nameFound = true;
if (ip != null)
{
if (ip != null) {
if (testIp.equalsIgnoreCase(ip)) {
trueOnce = true;
}
}
if (domain != null)
{
if (domain != null) {
if (testIp.equalsIgnoreCase(domain)) {
trueOnce = true;
}
@ -737,10 +717,9 @@ public final class Settings {
changes = true;
}
if (!contains("settings.preventOtherCase"))
{
set("settings.preventOtherCase", false);
changes = true;
if (!contains("settings.preventOtherCase")) {
set("settings.preventOtherCase", false);
changes = true;
}
if (contains("Email.mailText")) {
@ -749,15 +728,14 @@ public final class Settings {
}
if (!contains("Security.stop.kickPlayersBeforeStopping")) {
set("Security.stop.kickPlayersBeforeStopping", true);
changes = true;
set("Security.stop.kickPlayersBeforeStopping", true);
changes = true;
}
if (!contains("Email.emailOauth2Token"))
set("Email.emailOauth2Token", "");
set("Email.emailOauth2Token", "");
if (!contains("Hook.sendPlayerTo"))
{
if (!contains("Hook.sendPlayerTo")) {
set("Hooks.sendPlayerTo", "");
changes = true;
}
@ -768,11 +746,21 @@ public final class Settings {
}
}
/**
* @param path
*
* @return
*/
private static boolean contains(String path) {
return configFile.contains(path);
}
// public because it's used in AuthMe at one place
/**
* @param path String
* @param value String
*/
public void set(String path, Object value) {
configFile.set(path, value);
}

View File

@ -15,6 +15,8 @@ public final class CollectionUtils {
/**
* Get a range from a list based on start and count parameters in a safe way.
*
* @param <T> element
* @param list The List
* @param start The start index
* @param count The number of elements to add
*
@ -34,6 +36,8 @@ public final class CollectionUtils {
/**
* Get all elements from a list starting from the given index.
*
* @param <T> element
* @param list The List
* @param start The start index
*
* @return The sublist of all elements from index {@code start} and on; empty list
@ -46,6 +50,11 @@ public final class CollectionUtils {
return getRange(list, start, list.size() - start);
}
/**
* @param <T> element
* @param coll Collection
* @return boolean Boolean
*/
public static <T> boolean isEmpty(Collection<T> coll) {
return coll == null || coll.isEmpty();
}

View File

@ -142,30 +142,44 @@ public abstract class AbstractEncryptionMethodTest {
return method.comparePassword(password, hashes.get(password), USERNAME);
}
// @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); }
// TODO #364: Remove this method
/**
* Generates a test class for a given encryption method. Simply create a test class and run the following code,
* replacing {@code XXX} with the actual class:
* <p>
* <code>@org.junit.Test public void generate() { AbstractEncryptionMethodTest.generateTest(new XXX()); }</code>
* <p>
* The output is the entire test class.
*
* @param method The method to create a test class for
*/
static void generateTest(EncryptionMethod method) {
String className = method.getClass().getSimpleName();
// Create javadoc and "public class extends" and the constructor call "super(new Class(),"
System.out.println("/**\n * Test for {@link " + className + "}.\n */");
System.out.println("public class " + className + "Test extends AbstractEncryptionMethodTest {");
System.out.println("\n\tpublic " + className + "Test() {");
System.out.println("\t\tsuper(new " + className + "(),");
// Iterate through the GIVEN_PASSWORDS and generate a hash so we can always check it later
String delim = ", ";
for (String password : GIVEN_PASSWORDS) {
if (password.equals(GIVEN_PASSWORDS[GIVEN_PASSWORDS.length - 1])) {
delim = "); ";
}
// Encr. method uses separate salt, so we need to call the constructor that takes HashedPassword instances
if (method.hasSeparateSalt()) {
HashedPassword hashedPassword = method.computeHash(password, USERNAME);
System.out.println(String.format("\t\tnew HashedPassword(\"%s\", \"%s\")%s// %s",
hashedPassword.getHash(), hashedPassword.getSalt(), delim, password));
} else {
// Encryption method doesn't have separate salt, so simply pass the generated hash to the constructor
System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash()
+ "\"" + delim + "// " + password);
}
}
// Close the constructor and class declarations
System.out.println("\t}");
System.out.println("\n}");
}

View File

@ -0,0 +1,78 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Thu Dec 31 13:41:44 CET 2015. See hashmethods/hash_algorithms.tpl.md -->
## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely.
Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate?
--------- | -------------- | ----------- | ----- | --- | --------- | ------ | ---------
BCRYPT | Recommended | 60 | | | Text | |
BCRYPT2Y | Recommended | 60 | | | Text | 22 |
CRAZYCRYPT1 | Do not use | 128 | | | Username | |
DOUBLEMD5 | Do not use | 32 | | | None | |
IPB3 | Acceptable | 32 | | | Text | 5 | Y
JOOMLA | Recommended | 65 | | | Text | 32 |
MD5 | Do not use | 32 | | | None | |
MD5VB | Acceptable | 56 | | | Text | 16 |
MYBB | Acceptable | 32 | | | Text | 8 | Y
PBKDF2 | Does not work | 330 | | | Text | 12 |
PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 |
PHPBB | Acceptable | 34 | | | Text | 16 |
PHPFUSION | Do not use | 64 | Y | | | | Y
ROYALAUTH | Do not use | 128 | | | None | |
SALTED2MD5 | Acceptable | 32 | | | Text | | Y
SALTEDSHA512 | Recommended | 128 | | | | | Y
SHA1 | Do not use | 40 | | | None | |
SHA256 | Recommended | 86 | | | Text | 16 |
SHA512 | Do not use | 128 | | | None | |
SMF | Do not use | 40 | | | Username | |
WBB3 | Acceptable | 40 | | | Text | 40 | Y
WBB4 | Does not work | 60 | | | Text | 8 |
WHIRLPOOL | Do not use | 128 | | | None | |
WORDPRESS | Do not use | 34 | | | Text | 9 |
XAUTH | Recommended | 140 | | | Text | 12 |
CUSTOM | | | | | | | |
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
### Columns
#### Algorithm
The algorithm is the hashing algorithm used to store passwords with. Default is SHA256 and is recommended.
You can change the hashing algorithm in the config.yml: under `security`, locate `passwordHash`.
#### Recommendation
The recommendation lists our usage recommendation in terms of how secure it is (not how _well_ the algorithm works!).
- Recommended: The hash algorithm appears to be cryptographically secure and is one we recommend.
- Acceptable: There are safer algorithms that can be chosen but using the algorithm is generally OK.
- Do not use: Hash algorithm isn't sufficiently secure. Use only if required to hook into another system.
- Does not work: The algorithm does not work properly; do not use.
#### Hash Length
The length of the hashes the algorithm produces. Note that the hash length is not (primarily) indicative of
whether an algorithm is secure or not.
#### ASCII
If denoted with a **y**, means that the algorithm is restricted to ASCII characters only, i.e. it will simply ignore
"special characters" such as `ÿ` or `Â`. Note that we do not recommend the use of "special characters" in passwords.
#### Salt Columns
Before hashing, a _salt_ may be appended to the password to make the hash more secure. The following columns describe
the salt the algorithm uses.
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
##### Salt Type
We do not recommend the usage
of any algorithm that doesn't use a randomly generated text as salt. This "salt type" column indicates what type of
salt the algorithm uses:
- Text: randomly generated text (see also the following column, "Length")
- Username: the salt is constructed from the username (bad)
- None: the algorithm uses no salt (bad)
##### Length
If applicable (salt type is "Text"), indicates the length of the generated salt. The longer the better.
If this column is empty when the salt type is "Text", it typically means the salt length can be defined in config.yml.
##### Separate
If denoted with a **y**, it means that the salt is stored in a separate column in the database. This is neither good
or bad.

View File

@ -0,0 +1,135 @@
package hashmethods;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HexSaltedMethod;
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Sets.newHashSet;
/**
* Gathers information on {@link fr.xephi.authme.security.crypts.EncryptionMethod} implementations based on
* the annotations in {@link fr.xephi.authme.security.crypts.description}.
*/
public class EncryptionMethodInfoGatherer {
@SuppressWarnings("unchecked")
private final static Set<Class<? extends Annotation>> RELEVANT_ANNOTATIONS =
newHashSet(HasSalt.class, Recommendation.class, AsciiRestricted.class);
private Map<HashAlgorithm, MethodDescription> descriptions;
public EncryptionMethodInfoGatherer() {
descriptions = new LinkedHashMap<>();
constructDescriptions();
}
public Map<HashAlgorithm, MethodDescription> getDescriptions() {
return descriptions;
}
private void constructDescriptions() {
for (HashAlgorithm algorithm : HashAlgorithm.values()) {
Class<? extends EncryptionMethod> methodClazz = algorithm.getClazz();
if (!HashAlgorithm.CUSTOM.equals(algorithm) && !methodClazz.isAnnotationPresent(Deprecated.class)) {
MethodDescription description = createDescription(methodClazz);
descriptions.put(algorithm, description);
}
}
}
private static MethodDescription createDescription(Class<? extends EncryptionMethod> clazz) {
EncryptionMethod method = instantiateMethod(clazz);
MethodDescription description = new MethodDescription(clazz);
description.setHashLength(method.computeHash("test", "user").getHash().length());
description.setHasSeparateSalt(method.hasSeparateSalt());
Map<Class<?>, Annotation> annotationMap = gatherAnnotations(clazz);
if (annotationMap.containsKey(HasSalt.class)) {
setSaltInformation(description, returnTyped(annotationMap, HasSalt.class), method);
}
if (annotationMap.containsKey(Recommendation.class)) {
description.setUsage(returnTyped(annotationMap, Recommendation.class).value());
}
if (annotationMap.containsKey(AsciiRestricted.class)) {
description.setAsciiRestricted(true);
}
return description;
}
private static Map<Class<?>, Annotation> gatherAnnotations(Class<?> methodClass) {
// Note ljacqu 20151231: The map could be Map<Class<? extends Annotation>, Annotation> and it has the constraint
// that for a key Class<T>, the value is of type T. We write a simple "Class<?>" for brevity.
Map<Class<?>, Annotation> collection = new HashMap<>();
Class<?> currentMethodClass = methodClass;
while (currentMethodClass != null) {
getRelevantAnnotations(currentMethodClass, collection);
currentMethodClass = getSuperClass(currentMethodClass);
}
return collection;
}
// Parameters could be Class<? extends EncryptionMethod>; Map<Class<? extends Annotation>, Annotation>
// but the constraint doesn't have any technical relevance, so just clutters the code
private static void getRelevantAnnotations(Class<?> methodClass, Map<Class<?>, Annotation> collection) {
for (Annotation annotation : methodClass.getAnnotations()) {
if (RELEVANT_ANNOTATIONS.contains(annotation.annotationType())
&& !collection.containsKey(annotation.annotationType())) {
collection.put(annotation.annotationType(), annotation);
}
}
}
/**
* Returns the super class of the given encryption method if it is also of EncryptionMethod type.
* (Anything beyond EncryptionMethod is not of interest.)
*/
private static Class<?> getSuperClass(Class<?> methodClass) {
Class<?> zuper = methodClass.getSuperclass();
if (EncryptionMethod.class.isAssignableFrom(zuper)) {
return zuper;
}
return null;
}
/**
* Set the salt information for the given encryption method and the found {@link HasSalt} annotation.
* Also gets the salt length from {@link HexSaltedMethod#getSaltLength()} for such instances.
*
* @param description The description to update
* @param hasSalt The associated HasSalt annotation
* @param method The encryption method
*/
private static void setSaltInformation(MethodDescription description, HasSalt hasSalt, EncryptionMethod method) {
description.setSaltType(hasSalt.value());
if (hasSalt.length() != 0) {
description.setSaltLength(hasSalt.length());
} else if (method instanceof HexSaltedMethod) {
int saltLength = ((HexSaltedMethod) method).getSaltLength();
description.setSaltLength(saltLength);
}
}
private static EncryptionMethod instantiateMethod(Class<? extends EncryptionMethod> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Could not instantiate " + clazz, e);
}
}
// Convenience method for retrieving an annotation in a typed fashion.
// We know implicitly that the key of the map always corresponds to the type of the value
private static <T> T returnTyped(Map<Class<?>, Annotation> map, Class<T> key) {
return key.cast(map.get(key));
}
}

View File

@ -0,0 +1,100 @@
package hashmethods;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.WrapperMock;
import utils.ANewMap;
import utils.FileUtils;
import utils.TagReplacer;
import utils.ToolTask;
import utils.ToolsConstants;
import java.util.Map;
import java.util.Scanner;
/**
* Task for generating the markdown page describing the AuthMe hash algorithms.
*
* @see {@link fr.xephi.authme.security.HashAlgorithm}
*/
public class HashAlgorithmsDescriptionTask implements ToolTask {
private static final String CUR_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "hashmethods/";
private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "hash_algorithms.md";
@Override
public void execute(Scanner scanner) {
// Unfortunately, we need the Wrapper to be around to work with Settings, and certain encryption methods
// directly read from the Settings file
WrapperMock.createInstance();
Settings.bCryptLog2Rounds = 8;
Settings.saltLength = 8;
// Gather info and construct a row for each method
EncryptionMethodInfoGatherer infoGatherer = new EncryptionMethodInfoGatherer();
Map<HashAlgorithm, MethodDescription> descriptions = infoGatherer.getDescriptions();
final String methodRows = constructMethodRows(descriptions);
// Write to the docs file
Map<String, String> tags = ANewMap.with("method_rows", methodRows).build();
FileUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags);
}
private static String constructMethodRows(Map<HashAlgorithm, MethodDescription> descriptions) {
final String rowTemplate = FileUtils.readFromFile(CUR_FOLDER + "hash_algorithms_row.tpl.md");
StringBuilder result = new StringBuilder();
for (Map.Entry<HashAlgorithm, MethodDescription> entry : descriptions.entrySet()) {
MethodDescription description = entry.getValue();
Map<String, String> tags = ANewMap
.with("name", asString(entry.getKey()))
.and("recommendation", asString(description.getUsage()))
.and("hash_length", asString(description.getHashLength()))
.and("ascii_restricted", asString(description.isAsciiRestricted()))
.and("salt_type", asString(description.getSaltType()))
.and("salt_length", asString(description.getSaltLength()))
.and("separate_salt", asString(description.hasSeparateSalt()))
.build();
result.append(TagReplacer.applyReplacements(rowTemplate, tags));
}
return result.toString();
}
@Override
public String getTaskName() {
return "describeHashAlgos";
}
// ----
// String representations
// ----
private static String asString(boolean value) {
return value ? "Y" : "";
}
private static String asString(int value) {
return String.valueOf(value);
}
private static String asString(Integer value) {
if (value == null) {
return "";
}
return String.valueOf(value);
}
private static String asString(HashAlgorithm value) {
return value.toString();
}
private static <E extends Enum<E>> String asString(E value) {
if (value == null) {
return "";
}
// Get the enum name and replace something like "DO_NOT_USE" to "Do not use"
String enumName = value.toString().replace("_", " ");
return enumName.length() > 2
? enumName.substring(0, 1) + enumName.substring(1).toLowerCase()
: enumName;
}
}

View File

@ -0,0 +1,85 @@
package hashmethods;
import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
/**
* Description of a {@link EncryptionMethod}.
*/
public class MethodDescription {
/** The implementation class the description belongs to. */
private final Class<? extends EncryptionMethod> method;
/** The type of the salt that is used. */
private SaltType saltType;
/** The length of the salt for SaltType.TEXT salts. */
private Integer saltLength;
/** The usage recommendation. */
private Usage usage;
/** Whether or not the encryption method is restricted to ASCII characters for proper functioning. */
private boolean asciiRestricted;
/** Whether or not the encryption method requires its salt stored separately. */
private boolean hasSeparateSalt;
/** The length of the hash output, based on a test hash (i.e. assumes same length for all hashes.) */
private int hashLength;
public MethodDescription(Class<? extends EncryptionMethod> method) {
this.method = method;
}
// Trivial getters and setters
public Class<? extends EncryptionMethod> getMethod() {
return method;
}
public SaltType getSaltType() {
return saltType;
}
public void setSaltType(SaltType saltType) {
this.saltType = saltType;
}
public Integer getSaltLength() {
return saltLength;
}
public void setSaltLength(int saltLength) {
this.saltLength = saltLength;
}
public Usage getUsage() {
return usage;
}
public void setUsage(Usage usage) {
this.usage = usage;
}
public boolean isAsciiRestricted() {
return asciiRestricted;
}
public void setAsciiRestricted(boolean asciiRestricted) {
this.asciiRestricted = asciiRestricted;
}
public boolean hasSeparateSalt() {
return hasSeparateSalt;
}
public void setHasSeparateSalt(boolean hasSeparateSalt) {
this.hasSeparateSalt = hasSeparateSalt;
}
public int getHashLength() {
return hashLength;
}
public void setHashLength(int hashLength) {
this.hashLength = hashLength;
}
}

View File

@ -0,0 +1,53 @@
<!-- {gen_warning} -->
<!-- File auto-generated on {gen_date}. See hashmethods/hash_algorithms.tpl.md -->
## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely.
Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate?
--------- | -------------- | ----------- | ----- | --- | --------- | ------ | ---------
{method_rows}CUSTOM | | | | | | | |
<!-- {gen_warning} -->
### Columns
#### Algorithm
The algorithm is the hashing algorithm used to store passwords with. Default is SHA256 and is recommended.
You can change the hashing algorithm in the config.yml: under `security`, locate `passwordHash`.
#### Recommendation
The recommendation lists our usage recommendation in terms of how secure it is (not how _well_ the algorithm works!).
- Recommended: The hash algorithm appears to be cryptographically secure and is one we recommend.
- Acceptable: There are safer algorithms that can be chosen but using the algorithm is generally OK.
- Do not use: Hash algorithm isn't sufficiently secure. Use only if required to hook into another system.
- Does not work: The algorithm does not work properly; do not use.
#### Hash Length
The length of the hashes the algorithm produces. Note that the hash length is not (primarily) indicative of
whether an algorithm is secure or not.
#### ASCII
If denoted with a **y**, means that the algorithm is restricted to ASCII characters only, i.e. it will simply ignore
"special characters" such as `ÿ` or `Â`. Note that we do not recommend the use of "special characters" in passwords.
#### Salt Columns
Before hashing, a _salt_ may be appended to the password to make the hash more secure. The following columns describe
the salt the algorithm uses.
<!-- {gen_warning} -->
##### Salt Type
We do not recommend the usage
of any algorithm that doesn't use a randomly generated text as salt. This "salt type" column indicates what type of
salt the algorithm uses:
- Text: randomly generated text (see also the following column, "Length")
- Username: the salt is constructed from the username (bad)
- None: the algorithm uses no salt (bad)
##### Length
If applicable (salt type is "Text"), indicates the length of the generated salt. The longer the better.
If this column is empty when the salt type is "Text", it typically means the salt length can be defined in config.yml.
##### Separate
If denoted with a **y**, it means that the salt is stored in a separate column in the database. This is neither good
or bad.

View File

@ -0,0 +1 @@
{name} | {recommendation} | {hash_length} | {ascii_restricted} | | {salt_type} | {salt_length} | {separate_salt}