Merge branch '427-register-with-pass-and-email' of https://github.com/AuthMe-Team/AuthMeReloaded

This commit is contained in:
ljacqu 2016-12-21 21:39:30 +01:00
commit 92f71d47c2
27 changed files with 1147 additions and 261 deletions

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Nov 13 13:34:49 CET 2016. See docs/config/config.tpl.md -->
<!-- File auto-generated on Thu Dec 15 22:27:25 CET 2016. See docs/config/config.tpl.md -->
## AuthMe Configuration
The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
@ -102,10 +102,14 @@ settings:
# Message language, available languages:
# https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md
messagesLanguage: 'en'
# Log level: INFO, FINE, DEBUG. Use INFO for general messages,
# FINE for some additional detailed ones (like password failed),
# and DEBUG for debugging
logLevel: 'FINE'
# By default we schedule async tasks when talking to the database. If you want
# typical communication with the database to happen synchronously, set this to false
useAsyncTasks: true
restrictions:
# Keeps collisions disabled for logged players
# Works only with MC 1.9
keepCollisionsDisabled: false
# Can not authenticated players chat?
# Keep in mind that this feature also blocks all commands not
# listed in the list below.
@ -158,7 +162,7 @@ settings:
# Should unregistered players be kicked immediately?
kickNonRegistered: false
# Should players be kicked on wrong password?
kickOnWrongPassword: false
kickOnWrongPassword: true
# Should not logged in players be teleported to the spawn?
# After the authentication they will be teleported back to
# their normal position.
@ -176,14 +180,10 @@ settings:
# How far can unregistered players walk?
# Set to 0 for unlimited radius
allowedMovementRadius: 100
# Enable double check of password when you register
# when it's true, registration requires that kind of command:
# /register <password> <confirmPassword>
enablePasswordConfirmation: true
# Should we protect the player inventory before logging in? Requires ProtocolLib.
ProtectInventoryBeforeLogIn: true
# Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.
DenyTabCompleteBeforeLogin: true
DenyTabCompleteBeforeLogin: false
# Should we display all other accounts from a player when he joins?
# permission: /authme.admin.accounts
displayOtherAccounts: true
@ -204,13 +204,6 @@ settings:
# Command to run when a user has more accounts than the configured threshold.
# Available variables: %playername%, %playerip%
otherAccountsCmd: 'say The player %playername% with ip %playerip% has multiple accounts!'
# Log level: INFO, FINE, DEBUG. Use INFO for general messages,
# FINE for some additional detailed ones (like password failed),
# and DEBUG for debugging
logLevel: 'FINE'
# By default we schedule async tasks when talking to the database. If you want
# typical communication with the database to happen synchronously, set this to false
useAsyncTasks: true
GameMode:
# Force survival gamemode when player joins?
ForceSurvivalMode: false
@ -240,9 +233,10 @@ settings:
# Otherwise your group will be wiped and the player will join in the default group []!
# Example unLoggedinGroup: NotLogged
unLoggedinGroup: 'unLoggedinGroup'
# Possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,
# MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,
# DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only)
# Possible values: SHA256, BCRYPT, BCRYPT2Y, PBKDF2, SALTEDSHA512, WHIRLPOOL,
# MYBB, IPB3, PHPBB, PHPFUSION, SMF, XENFORO, XAUTH, JOOMLA, WBB3, WBB4, MD5VB,
# PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only). See full list at
# https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/hash_algorithms.md
passwordHash: 'SHA256'
# Salt length for the SALTED2MD5 MD5(MD5(password)+salt)
doubleMD5SaltLength: 8
@ -252,6 +246,8 @@ settings:
# legacyHashes:
# - 'SHA1'
legacyHashes: []
# Number of rounds to use if passwordHash is set to PBKDF2. Default is 10000
pbkdf2Rounds: 10000
# Prevent unsafe passwords from being used; put them in lowercase!
# You should always set 'help' as unsafePassword due to possible conflicts.
# unsafePasswords:
@ -275,27 +271,14 @@ settings:
# Only registered and logged in players can play.
# See restrictions for exceptions
force: true
# Do we replace password registration by an email registration method?
enableEmailRegistrationSystem: false
# Enable double check of email when you register
# when it's true, registration requires that kind of command:
# /register <email> <confirmEmail>
doubleEmailCheck: false
# Type of registration: PASSWORD, PASSWORD_WITH_CONFIRMATION, EMAIL
# EMAIL_WITH_CONFIRMATION, PASSWORD_WITH_EMAIL
type: 'PASSWORD_WITH_CONFIRMATION'
# Do we force kick a player after a successful registration?
# Do not use with login feature below
forceKickAfterRegister: false
# Does AuthMe need to enforce a /login after a successful registration?
forceLoginAfterRegister: false
# Force these commands after /login, without any '/', use %p to replace with player name
forceCommands: []
# Force these commands after /login as service console, without any '/'.
# Use %p to replace with player name
forceCommandsAsConsole: []
# Force these commands after /register, without any '/', use %p to replace with player name
forceRegisterCommands: []
# Force these commands after /register as a server console, without any '/'.
# Use %p to replace with player name
forceRegisterCommandsAsConsole: []
# Enable to display the welcome message (welcome.txt) after a login
# You can use colors in this welcome.txt + some replaced strings:
# {PLAYER}: player name, {ONLINE}: display number of online players,
@ -318,7 +301,7 @@ settings:
applyBlindEffect: false
# Do we need to prevent people to login with another case?
# If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
preventOtherCase: false
preventOtherCase: true
permission:
# Take care with this option; if you want
# to use group switching of AuthMe
@ -363,7 +346,7 @@ Hooks:
# Send player to this BungeeCord server after register/login
sendPlayerTo: ''
# Do we need to disable Essentials SocialSpy on join?
disableSocialSpy: true
disableSocialSpy: false
# Do we need to force /motd Essentials command on join?
useEssentialsMotd: false
GroupOptions:
@ -464,4 +447,4 @@ To change settings on a running server, save your changes to config.yml and use
---
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Nov 13 13:34:49 CET 2016
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Thu Dec 15 22:27:25 CET 2016

View File

@ -4,10 +4,11 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.service.PluginHookService;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.PluginHookService;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -33,13 +34,15 @@ public class NewAPI {
private final Management management;
private final ValidationService validationService;
private final PlayerCache playerCache;
private final RegistrationExecutorProvider registrationExecutorProvider;
/*
* Constructor for NewAPI.
*/
@Inject
NewAPI(AuthMe plugin, PluginHookService pluginHookService, DataSource dataSource, PasswordSecurity passwordSecurity,
Management management, ValidationService validationService, PlayerCache playerCache) {
Management management, ValidationService validationService, PlayerCache playerCache,
RegistrationExecutorProvider registrationExecutorProvider) {
this.plugin = plugin;
this.pluginHookService = pluginHookService;
this.dataSource = dataSource;
@ -47,6 +50,7 @@ public class NewAPI {
this.management = management;
this.validationService = validationService;
this.playerCache = playerCache;
this.registrationExecutorProvider = registrationExecutorProvider;
NewAPI.singleton = this;
}
@ -199,7 +203,8 @@ public class NewAPI {
* @param autoLogin Should the player be authenticated automatically after the registration?
*/
public void forceRegister(Player player, String password, boolean autoLogin) {
management.performRegister(player, password, null, autoLogin);
management.performRegister(player,
registrationExecutorProvider.getPasswordRegisterExecutor(player, password, autoLogin));
}
/**

View File

@ -5,21 +5,23 @@ import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import fr.xephi.authme.settings.properties.RegistrationArgumentType.Execution;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
import static fr.xephi.authme.settings.properties.RegistrationSettings.ENABLE_CONFIRM_EMAIL;
import static fr.xephi.authme.settings.properties.RegistrationSettings.USE_EMAIL_REGISTRATION;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION;
import static fr.xephi.authme.settings.properties.RegistrationArgumentType.EMAIL_WITH_CONFIRMATION;
import static fr.xephi.authme.settings.properties.RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION;
import static fr.xephi.authme.settings.properties.RegistrationArgumentType.PASSWORD_WITH_EMAIL;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REGISTRATION_TYPE;
/**
* Command for /register.
@ -38,22 +40,26 @@ public class RegisterCommand extends PlayerCommand {
@Inject
private ValidationService validationService;
@Inject
private RegistrationExecutorProvider registrationExecutorProvider;
@Override
public void runCommand(Player player, List<String> arguments) {
if (commonService.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
//for two factor auth we don't need to check the usage
management.performRegister(player, "", "", true);
management.performRegister(player,
registrationExecutorProvider.getTwoFactorRegisterExecutor(player));
return;
}
// Ensure that there is 1 argument, or 2 if confirmation is required
final boolean useConfirmation = isConfirmationRequired();
if (arguments.isEmpty() || useConfirmation && arguments.size() < 2) {
RegistrationArgumentType registerType = commonService.getProperty(REGISTRATION_TYPE);
if (registerType.getRequiredNumberOfArgs() > arguments.size()) {
commonService.send(player, MessageKey.USAGE_REGISTER);
return;
}
if (commonService.getProperty(USE_EMAIL_REGISTRATION)) {
if (registerType.getExecution() == Execution.EMAIL) {
handleEmailRegistration(player, arguments);
} else {
handlePasswordRegistration(player, arguments);
@ -66,10 +72,23 @@ public class RegisterCommand extends PlayerCommand {
}
private void handlePasswordRegistration(Player player, List<String> arguments) {
if (commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION) && !arguments.get(0).equals(arguments.get(1))) {
RegistrationArgumentType registrationType = commonService.getProperty(REGISTRATION_TYPE);
if (registrationType == PASSWORD_WITH_CONFIRMATION && !arguments.get(0).equals(arguments.get(1))) {
commonService.send(player, MessageKey.PASSWORD_MATCH_ERROR);
} else if (registrationType == PASSWORD_WITH_EMAIL) {
handlePasswordWithEmailRegistration(player, arguments);
} else {
management.performRegister(player, arguments.get(0), "", true);
management.performRegister(player, registrationExecutorProvider
.getPasswordRegisterExecutor(player, arguments.get(0)));
}
}
private void handlePasswordWithEmailRegistration(Player player, List<String> arguments) {
if (validationService.validateEmail(arguments.get(1))) {
management.performRegister(player, registrationExecutorProvider
.getPasswordRegisterExecutor(player, arguments.get(0), arguments.get(1)));
} else {
commonService.send(player, MessageKey.INVALID_EMAIL);
}
}
@ -84,22 +103,10 @@ public class RegisterCommand extends PlayerCommand {
final String email = arguments.get(0);
if (!validationService.validateEmail(email)) {
commonService.send(player, MessageKey.INVALID_EMAIL);
} else if (commonService.getProperty(ENABLE_CONFIRM_EMAIL) && !email.equals(arguments.get(1))) {
} else if (commonService.getProperty(REGISTRATION_TYPE) == EMAIL_WITH_CONFIRMATION && !email.equals(arguments.get(1))) {
commonService.send(player, MessageKey.USAGE_REGISTER);
} else {
String thePass = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
management.performRegister(player, thePass, email, true);
management.performRegister(player, registrationExecutorProvider.getEmailRegisterExecutor(player, email));
}
}
/**
* Return whether the password or email has to be confirmed.
*
* @return True if the confirmation is needed, false otherwise
*/
private boolean isConfirmationRequired() {
return commonService.getProperty(USE_EMAIL_REGISTRATION)
? commonService.getProperty(ENABLE_CONFIRM_EMAIL)
: commonService.getProperty(ENABLE_PASSWORD_CONFIRMATION);
}
}

View File

@ -8,6 +8,7 @@ import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.process.logout.AsynchronousLogout;
import fr.xephi.authme.process.quit.AsynchronousQuit;
import fr.xephi.authme.process.register.AsyncRegister;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
import fr.xephi.authme.service.BukkitService;
import org.bukkit.command.CommandSender;
@ -59,8 +60,8 @@ public class Management {
runTask(() -> asynchronousLogout.logout(player));
}
public void performRegister(Player player, String password, String email, boolean autoLogin) {
runTask(() -> asyncRegister.register(player, password, email, autoLogin));
public void performRegister(Player player, RegistrationExecutor registrationExecutor) {
runTask(() -> asyncRegister.register(player, registrationExecutor));
}
public void performUnregister(Player player, String password) {

View File

@ -9,6 +9,7 @@ import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType.Execution;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@ -63,7 +64,7 @@ public class AsyncAddEmail implements AsynchronousProcess {
private void sendUnloggedMessage(Player player) {
if (dataSource.isAuthAvailable(player.getName())) {
service.send(player, MessageKey.LOGIN_MESSAGE);
} else if (service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)) {
} else if (service.getProperty(RegistrationSettings.REGISTRATION_TYPE).getExecution() == Execution.EMAIL) {
service.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
} else {
service.send(player, MessageKey.REGISTER_MESSAGE);

View File

@ -8,6 +8,7 @@ import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType.Execution;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@ -66,7 +67,7 @@ public class AsyncChangeEmail implements AsynchronousProcess {
private void outputUnloggedMessage(Player player) {
if (dataSource.isAuthAvailable(player.getName())) {
service.send(player, MessageKey.LOGIN_MESSAGE);
} else if (service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)) {
} else if (service.getProperty(RegistrationSettings.REGISTRATION_TYPE).getExecution() == Execution.EMAIL) {
service.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
} else {
service.send(player, MessageKey.REGISTER_MESSAGE);

View File

@ -3,28 +3,14 @@ package fr.xephi.authme.process.register;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.TwoFactor;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@ -37,38 +23,31 @@ import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_AC
*/
public class AsyncRegister implements AsynchronousProcess {
/**
* Number of ticks to wait before running the login action when it is run synchronously.
* A small delay is necessary or the database won't return the newly saved PlayerAuth object
* and the login process thinks the user is not registered.
*/
private static final int SYNC_LOGIN_DELAY = 5;
@Inject
private DataSource database;
@Inject
private PlayerCache playerCache;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private CommonService service;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private PermissionsManager permissionsManager;
@Inject
private ValidationService validationService;
@Inject
private SendMailSSL sendMailSsl;
@Inject
private AsynchronousLogin asynchronousLogin;
@Inject
private BukkitService bukkitService;
AsyncRegister() {
}
private boolean preRegisterCheck(Player player, String password) {
/**
* Performs the registration process for the given player.
*
* @param player the player to register
* @param executor the registration executor to perform the registration with
*/
public void register(Player player, RegistrationExecutor executor) {
if (preRegisterCheck(player) && executor.isRegistrationAdmitted()) {
executeRegistration(player, executor);
}
}
private boolean preRegisterCheck(Player player) {
final String name = player.getName().toLowerCase();
if (playerCache.isAuthenticated(name)) {
service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
@ -76,23 +55,36 @@ public class AsyncRegister implements AsynchronousProcess {
} else if (!service.getProperty(RegistrationSettings.IS_ENABLED)) {
service.send(player, MessageKey.REGISTRATION_DISABLED);
return false;
}
//check the password safety only if it's not a automatically generated password
if (service.getProperty(SecuritySettings.PASSWORD_HASH) != HashAlgorithm.TWO_FACTOR) {
ValidationResult passwordValidation = validationService.validatePassword(password, player.getName());
if (passwordValidation.hasError()) {
service.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return false;
}
}
//check this in both possibilities so don't use 'else if'
if (database.isAuthAvailable(name)) {
} else if (database.isAuthAvailable(name)) {
service.send(player, MessageKey.NAME_ALREADY_REGISTERED);
return false;
}
return isPlayerIpAllowedToRegister(player);
}
/**
* Executes the registration.
*
* @param player the player to register
* @param executor the executor to perform the registration process with
*/
private void executeRegistration(Player player, RegistrationExecutor executor) {
PlayerAuth auth = executor.buildPlayerAuth();
if (database.saveAuth(auth)) {
executor.executePostPersistAction();
} else {
service.send(player, MessageKey.ERROR);
}
}
/**
* Checks whether the registration threshold has been exceeded for the given player's IP address.
*
* @param player the player to check
* @return true if registration may take place, false otherwise (IP check failed)
*/
private boolean isPlayerIpAllowedToRegister(Player player) {
final int maxRegPerIp = service.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP);
final String ip = PlayerUtils.getPlayerIp(player);
if (maxRegPerIp > 0
@ -108,84 +100,4 @@ public class AsyncRegister implements AsynchronousProcess {
}
return true;
}
public void register(Player player, String password, String email, boolean autoLogin) {
if (preRegisterCheck(player, password)) {
if (!StringUtils.isEmpty(email)) {
emailRegister(player, password, email);
} else {
passwordRegister(player, password, autoLogin);
}
}
}
private void emailRegister(Player player, String password, String email) {
final String name = player.getName().toLowerCase();
final int maxRegPerEmail = service.getProperty(EmailSettings.MAX_REG_PER_EMAIL);
if (maxRegPerEmail > 0 && !permissionsManager.hasPermission(player, ALLOW_MULTIPLE_ACCOUNTS)) {
int otherAccounts = database.countAuthsByEmail(email);
if (otherAccounts >= maxRegPerEmail) {
service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerEmail),
Integer.toString(otherAccounts), "@");
return;
}
}
final HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
final String ip = PlayerUtils.getPlayerIp(player);
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
.password(hashedPassword)
.ip(ip)
.location(player.getLocation())
.email(email)
.build();
if (!database.saveAuth(auth)) {
service.send(player, MessageKey.ERROR);
return;
}
database.updateEmail(auth);
database.updateSession(auth);
boolean couldSendMail = sendMailSsl.sendPasswordMail(name, email, password);
if (couldSendMail) {
syncProcessManager.processSyncEmailRegister(player);
} else {
service.send(player, MessageKey.EMAIL_SEND_FAILURE);
}
}
private void passwordRegister(final Player player, String password, boolean autoLogin) {
final String name = player.getName().toLowerCase();
final String ip = PlayerUtils.getPlayerIp(player);
final HashedPassword hashedPassword = passwordSecurity.computeHash(password, name);
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
.password(hashedPassword)
.ip(ip)
.location(player.getLocation())
.build();
if (!database.saveAuth(auth)) {
service.send(player, MessageKey.ERROR);
return;
}
if (!service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER) && autoLogin) {
if (service.getProperty(PluginSettings.USE_ASYNC_TASKS)) {
bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player));
} else {
bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY);
}
}
syncProcessManager.processSyncPasswordRegister(player);
//give the user the secret code to setup their app code generation
if (service.getProperty(SecuritySettings.PASSWORD_HASH) == HashAlgorithm.TWO_FACTOR) {
String qrCodeUrl = TwoFactor.getQRBarcodeURL(player.getName(), Bukkit.getIp(), hashedPassword.getHash());
service.send(player, MessageKey.TWO_FACTOR_CREATE, hashedPassword.getHash(), qrCodeUrl);
}
}
}

View File

@ -0,0 +1,91 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
/**
* Provides a registration executor for email registration.
*/
class EmailRegisterExecutorProvider {
@Inject
private PermissionsManager permissionsManager;
@Inject
private DataSource dataSource;
@Inject
private CommonService commonService;
@Inject
private SendMailSSL sendMailSsl;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private PasswordSecurity passwordSecurity;
EmailRegisterExecutorProvider() {
}
/** Registration executor implementation for email registration. */
class EmailRegisterExecutor implements RegistrationExecutor {
private final Player player;
private final String email;
private String password;
EmailRegisterExecutor(Player player, String email) {
this.player = player;
this.email = email;
}
@Override
public boolean isRegistrationAdmitted() {
final int maxRegPerEmail = commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL);
if (maxRegPerEmail > 0 && !permissionsManager.hasPermission(player, ALLOW_MULTIPLE_ACCOUNTS)) {
int otherAccounts = dataSource.countAuthsByEmail(email);
if (otherAccounts >= maxRegPerEmail) {
commonService.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerEmail),
Integer.toString(otherAccounts), "@");
return false;
}
}
return true;
}
@Override
public PlayerAuth buildPlayerAuth() {
password = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
HashedPassword hashedPassword = passwordSecurity.computeHash(password, player.getName());
return createPlayerAuth(player, hashedPassword, email);
}
@Override
public void executePostPersistAction() {
boolean couldSendMail = sendMailSsl.sendPasswordMail(player.getName(), email, password);
if (couldSendMail) {
syncProcessManager.processSyncEmailRegister(player);
} else {
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
}
}
}
}

View File

@ -0,0 +1,155 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.TwoFactor;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
/**
* Provides registration executors for password-based registration variants.
*/
class PasswordRegisterExecutorProvider {
/**
* Number of ticks to wait before running the login action when it is run synchronously.
* A small delay is necessary or the database won't return the newly saved PlayerAuth object
* and the login process thinks the user is not registered.
*/
private static final int SYNC_LOGIN_DELAY = 5;
@Inject
private ValidationService validationService;
@Inject
private CommonService commonService;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private BukkitService bukkitService;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private AsynchronousLogin asynchronousLogin;
PasswordRegisterExecutorProvider() {
}
/** Registration executor for password registration. */
class PasswordRegisterExecutor implements RegistrationExecutor {
protected final Player player;
private final String password;
private final String email;
protected HashedPassword hashedPassword;
/**
* Constructor.
*
* @param player the player to register
* @param password the password to register with
* @param email the email of the player (may be null)
*/
PasswordRegisterExecutor(Player player, String password, String email) {
this.player = player;
this.password = password;
this.email = email;
}
@Override
public boolean isRegistrationAdmitted() {
ValidationResult passwordValidation = validationService.validatePassword(password, player.getName());
if (passwordValidation.hasError()) {
commonService.send(player, passwordValidation.getMessageKey(), passwordValidation.getArgs());
return false;
}
return true;
}
@Override
public PlayerAuth buildPlayerAuth() {
hashedPassword = passwordSecurity.computeHash(password, player.getName().toLowerCase());
return createPlayerAuth(player, hashedPassword, email);
}
protected boolean performLoginAfterRegister() {
return !commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER);
}
@Override
public void executePostPersistAction() {
if (performLoginAfterRegister()) {
if (commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)) {
bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player));
} else {
bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY);
}
}
syncProcessManager.processSyncPasswordRegister(player);
}
}
/** Executor for password registration via API call. */
class ApiPasswordRegisterExecutor extends PasswordRegisterExecutor {
private final boolean loginAfterRegister;
/**
* Constructor.
*
* @param player the player to register
* @param password the password to register with
* @param loginAfterRegister whether the user should be automatically logged in after registration
*/
ApiPasswordRegisterExecutor(Player player, String password, boolean loginAfterRegister) {
super(player, password, null);
this.loginAfterRegister = loginAfterRegister;
}
@Override
protected boolean performLoginAfterRegister() {
return loginAfterRegister;
}
}
/** Executor for two factor registration. */
class TwoFactorRegisterExecutor extends PasswordRegisterExecutor {
TwoFactorRegisterExecutor(Player player) {
super(player, "", null);
}
@Override
public boolean isRegistrationAdmitted() {
// nothing to check
return true;
}
@Override
public void executePostPersistAction() {
super.executePostPersistAction();
String qrCodeUrl = TwoFactor.getQRBarcodeURL(player.getName(), Bukkit.getIp(), hashedPassword.getHash());
commonService.send(player, MessageKey.TWO_FACTOR_CREATE, hashedPassword.getHash(), qrCodeUrl);
}
}
}

View File

@ -0,0 +1,26 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.entity.Player;
/**
* Helper for constructing PlayerAuth objects.
*/
final class PlayerAuthBuilderHelper {
private PlayerAuthBuilderHelper() {
}
static PlayerAuth createPlayerAuth(Player player, HashedPassword hashedPassword, String email) {
return PlayerAuth.builder()
.name(player.getName().toLowerCase())
.realName(player.getName())
.password(hashedPassword)
.email(email)
.ip(PlayerUtils.getPlayerIp(player))
.location(player.getLocation())
.build();
}
}

View File

@ -0,0 +1,33 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
/**
* Performs the registration action.
*/
public interface RegistrationExecutor {
/**
* Returns whether the registration may take place. Use this method to execute
* checks specific to the registration method.
* <p>
* If this method returns {@code false}, it is expected that the executor inform
* the player about the error within this method call.
*
* @return true if registration may be performed, false otherwise
*/
boolean isRegistrationAdmitted();
/**
* Constructs the PlayerAuth object to persist into the database.
*
* @return the player auth to register in the data source
*/
PlayerAuth buildPlayerAuth();
/**
* Follow-up method called after the player auth could be added into the database.
*/
void executePostPersistAction();
}

View File

@ -0,0 +1,40 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Provides a {@link RegistrationExecutor} for various registration methods.
*/
public class RegistrationExecutorProvider {
@Inject
private PasswordRegisterExecutorProvider passwordRegisterExecutorProvider;
@Inject
private EmailRegisterExecutorProvider emailRegisterExecutorProvider;
RegistrationExecutorProvider() {
}
public RegistrationExecutor getPasswordRegisterExecutor(Player player, String password) {
return getPasswordRegisterExecutor(player, password, null);
}
public RegistrationExecutor getPasswordRegisterExecutor(Player player, String password, String email) {
return passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, password, email);
}
public RegistrationExecutor getPasswordRegisterExecutor(Player player, String password, boolean loginAfterRegister) {
return passwordRegisterExecutorProvider.new ApiPasswordRegisterExecutor(player, password, loginAfterRegister);
}
public RegistrationExecutor getTwoFactorRegisterExecutor(Player player) {
return passwordRegisterExecutorProvider.new TwoFactorRegisterExecutor(player);
}
public RegistrationExecutor getEmailRegisterExecutor(Player player, String email) {
return emailRegisterExecutorProvider.new EmailRegisterExecutor(player, email);
}
}

View File

@ -9,6 +9,8 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import fr.xephi.authme.settings.properties.SecuritySettings;
import javax.inject.Inject;
@ -67,6 +69,7 @@ public class SettingsMigrationService extends PlainMigrationService {
| changeBooleanSettingToLogLevelProperty(resource)
| hasOldHelpHeaderProperty(resource)
| hasSupportOldPasswordProperty(resource)
| convertToRegistrationType(resource)
|| hasDeprecatedProperties(resource);
}
@ -224,6 +227,34 @@ public class SettingsMigrationService extends PlainMigrationService {
return false;
}
private static boolean convertToRegistrationType(PropertyResource resource) {
if (RegistrationSettings.REGISTRATION_TYPE.isPresent(resource)) {
return false;
}
boolean useEmail = newProperty("settings.registration.enableEmailRegistrationSystem", false).getValue(resource);
String useConfirmationPath = useEmail
? "settings.registration.doubleEmailCheck"
: "settings.restrictions.enablePasswordConfirmation";
boolean hasConfirmation = newProperty(useConfirmationPath, false).getValue(resource);
RegistrationArgumentType registerType;
if (useEmail) {
registerType = hasConfirmation
? RegistrationArgumentType.EMAIL_WITH_CONFIRMATION
: RegistrationArgumentType.EMAIL;
} else {
registerType = hasConfirmation
? RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION
: RegistrationArgumentType.PASSWORD;
}
ConsoleLogger.warning("Merging old registration settings into '"
+ RegistrationSettings.REGISTRATION_TYPE.getPath() + "'");
resource.setValue(RegistrationSettings.REGISTRATION_TYPE.getPath(), registerType);
return true;
}
/**
* Checks for an old property path and moves it to a new path if present.
*

View File

@ -0,0 +1,60 @@
package fr.xephi.authme.settings.properties;
/**
* Type of arguments used for the login command.
*/
public enum RegistrationArgumentType {
/** /register [password] */
PASSWORD(Execution.PASSWORD, 1),
/** /register [password] [password] */
PASSWORD_WITH_CONFIRMATION(Execution.PASSWORD, 2),
/** /register [email] */
EMAIL(Execution.EMAIL, 1),
/** /register [email] [email] */
EMAIL_WITH_CONFIRMATION(Execution.EMAIL, 2),
/** /register [password] [email] */
PASSWORD_WITH_EMAIL(Execution.PASSWORD, 2);
private final Execution execution;
private final int requiredNumberOfArgs;
/**
* Constructor.
*
* @param execution the registration process
* @param requiredNumberOfArgs the required number of arguments
*/
RegistrationArgumentType(Execution execution, int requiredNumberOfArgs) {
this.execution = execution;
this.requiredNumberOfArgs = requiredNumberOfArgs;
}
/**
* @return the registration execution that is used for this argument type
*/
public Execution getExecution() {
return execution;
}
/**
* @return number of arguments required to process the register command
*/
public int getRequiredNumberOfArgs() {
return requiredNumberOfArgs;
}
/**
* Registration execution (the type of registration).
*/
public enum Execution {
PASSWORD,
EMAIL
}
}

View File

@ -24,16 +24,12 @@ public class RegistrationSettings implements SettingsHolder {
public static final Property<Boolean> FORCE =
newProperty("settings.registration.force", true);
@Comment("Do we replace password registration by an email registration method?")
public static final Property<Boolean> USE_EMAIL_REGISTRATION =
newProperty("settings.registration.enableEmailRegistrationSystem", false);
@Comment({
"Enable double check of email when you register",
"when it's true, registration requires that kind of command:",
"/register <email> <confirmEmail>"})
public static final Property<Boolean> ENABLE_CONFIRM_EMAIL =
newProperty("settings.registration.doubleEmailCheck", false);
"Type of registration: PASSWORD, PASSWORD_WITH_CONFIRMATION, EMAIL",
"EMAIL_WITH_CONFIRMATION, PASSWORD_WITH_EMAIL"
})
public static final Property<RegistrationArgumentType> REGISTRATION_TYPE =
newProperty(RegistrationArgumentType.class, "settings.registration.type", RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION);
@Comment({
"Do we force kick a player after a successful registration?",

View File

@ -126,13 +126,6 @@ public class RestrictionSettings implements SettingsHolder {
public static final Property<Integer> ALLOWED_MOVEMENT_RADIUS =
newProperty("settings.restrictions.allowedMovementRadius", 100);
@Comment({
"Enable double check of password when you register",
"when it's true, registration requires that kind of command:",
"/register <password> <confirmPassword>"})
public static final Property<Boolean> ENABLE_PASSWORD_CONFIRMATION =
newProperty("settings.restrictions.enablePasswordConfirmation", true);
@Comment("Should we protect the player inventory before logging in? Requires ProtocolLib.")
public static final Property<Boolean> PROTECT_INVENTORY_BEFORE_LOGIN =
newProperty("settings.restrictions.ProtectInventoryBeforeLogIn", true);

View File

@ -6,10 +6,11 @@ import fr.xephi.authme.data.limbo.LimboCache;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType.Execution;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.service.BukkitService;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
@ -95,7 +96,7 @@ public class LimboPlayerTaskManager {
if (isRegistered) {
return MessageKey.LOGIN_MESSAGE;
} else {
return settings.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)
return settings.getProperty(RegistrationSettings.REGISTRATION_TYPE).getExecution() == Execution.EMAIL
? MessageKey.REGISTER_EMAIL_MESSAGE
: MessageKey.REGISTER_MESSAGE;
}

View File

@ -4,12 +4,13 @@ import fr.xephi.authme.TestHelper;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.process.register.executors.RegistrationExecutorProvider;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
@ -25,9 +26,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Collections;
import static fr.xephi.authme.AuthMeMatchers.stringWithLength;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -44,7 +43,7 @@ public class RegisterCommandTest {
private RegisterCommand command;
@Mock
private CommonService commandService;
private CommonService commonService;
@Mock
private Management management;
@ -55,6 +54,9 @@ public class RegisterCommandTest {
@Mock
private ValidationService validationService;
@Mock
private RegistrationExecutorProvider registrationExecutorProvider;
@BeforeClass
public static void setup() {
TestHelper.setupLogger();
@ -62,9 +64,8 @@ public class RegisterCommandTest {
@Before
public void linkMocksAndProvideSettingDefaults() {
given(commandService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.BCRYPT);
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false);
given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(false);
given(commonService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.BCRYPT);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.PASSWORD);
}
@Test
@ -83,14 +84,16 @@ public class RegisterCommandTest {
@Test
public void shouldForwardToManagementForTwoFactor() {
// given
given(commandService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.TWO_FACTOR);
given(commonService.getProperty(SecuritySettings.PASSWORD_HASH)).willReturn(HashAlgorithm.TWO_FACTOR);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getTwoFactorRegisterExecutor(player)).willReturn(executor);
// when
command.executeCommand(player, Collections.emptyList());
// then
verify(management).performRegister(player, "", "", true);
verify(management).performRegister(player, executor);
verifyZeroInteractions(sendMailSsl);
}
@ -103,44 +106,42 @@ public class RegisterCommandTest {
command.executeCommand(player, Collections.emptyList());
// then
verify(commandService).send(player, MessageKey.USAGE_REGISTER);
verify(commonService).send(player, MessageKey.USAGE_REGISTER);
verifyZeroInteractions(management, sendMailSsl);
}
@Test
public void shouldReturnErrorForMissingConfirmation() {
// given
given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION);
Player player = mock(Player.class);
// when
command.executeCommand(player, Collections.singletonList("arrrr"));
// then
verify(commandService).send(player, MessageKey.USAGE_REGISTER);
verify(commonService).send(player, MessageKey.USAGE_REGISTER);
verifyZeroInteractions(management, sendMailSsl);
}
@Test
public void shouldReturnErrorForMissingEmailConfirmation() {
// given
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
Player player = mock(Player.class);
// when
command.executeCommand(player, Collections.singletonList("test@example.org"));
// then
verify(commandService).send(player, MessageKey.USAGE_REGISTER);
verify(commonService).send(player, MessageKey.USAGE_REGISTER);
verifyZeroInteractions(management, sendMailSsl);
}
@Test
public void shouldThrowErrorForMissingEmailConfiguration() {
// given
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(false);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL);
given(sendMailSsl.hasAllInformation()).willReturn(false);
Player player = mock(Player.class);
@ -148,7 +149,7 @@ public class RegisterCommandTest {
command.executeCommand(player, Collections.singletonList("myMail@example.tld"));
// then
verify(commandService).send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
verify(commonService).send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
verify(sendMailSsl).hasAllInformation();
verifyZeroInteractions(management);
}
@ -158,9 +159,7 @@ public class RegisterCommandTest {
// given
String playerMail = "player@example.org";
given(validationService.validateEmail(playerMail)).willReturn(false);
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
given(sendMailSsl.hasAllInformation()).willReturn(true);
Player player = mock(Player.class);
@ -169,7 +168,7 @@ public class RegisterCommandTest {
// then
verify(validationService).validateEmail(playerMail);
verify(commandService).send(player, MessageKey.INVALID_EMAIL);
verify(commonService).send(player, MessageKey.INVALID_EMAIL);
verifyZeroInteractions(management);
}
@ -178,9 +177,7 @@ public class RegisterCommandTest {
// given
String playerMail = "bobber@bobby.org";
given(validationService.validateEmail(playerMail)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
given(sendMailSsl.hasAllInformation()).willReturn(true);
Player player = mock(Player.class);
@ -188,7 +185,7 @@ public class RegisterCommandTest {
command.executeCommand(player, Arrays.asList(playerMail, "invalid"));
// then
verify(commandService).send(player, MessageKey.USAGE_REGISTER);
verify(commonService).send(player, MessageKey.USAGE_REGISTER);
verify(sendMailSsl).hasAllInformation();
verifyZeroInteractions(management);
}
@ -198,13 +195,11 @@ public class RegisterCommandTest {
// given
String playerMail = "asfd@lakjgre.lds";
given(validationService.validateEmail(playerMail)).willReturn(true);
int passLength = 7;
given(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)).willReturn(passLength);
given(commandService.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(commandService.getProperty(RegistrationSettings.ENABLE_CONFIRM_EMAIL)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
given(sendMailSsl.hasAllInformation()).willReturn(true);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getEmailRegisterExecutor(player, playerMail)).willReturn(executor);
// when
command.executeCommand(player, Arrays.asList(playerMail, playerMail));
@ -212,20 +207,20 @@ public class RegisterCommandTest {
// then
verify(validationService).validateEmail(playerMail);
verify(sendMailSsl).hasAllInformation();
verify(management).performRegister(eq(player), argThat(stringWithLength(passLength)), eq(playerMail), eq(true));
verify(management).performRegister(player, executor);
}
@Test
public void shouldRejectInvalidPasswordConfirmation() {
// given
given(commandService.getProperty(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION)).willReturn(true);
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION);
Player player = mock(Player.class);
// when
command.executeCommand(player, Arrays.asList("myPass", "mypass"));
// then
verify(commandService).send(player, MessageKey.PASSWORD_MATCH_ERROR);
verify(commonService).send(player, MessageKey.PASSWORD_MATCH_ERROR);
verifyZeroInteractions(management, sendMailSsl);
}
@ -233,11 +228,65 @@ public class RegisterCommandTest {
public void shouldPerformPasswordValidation() {
// given
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getPasswordRegisterExecutor(player, "myPass")).willReturn(executor);
// when
command.executeCommand(player, Collections.singletonList("myPass"));
// then
verify(management).performRegister(player, "myPass", "", true);
verify(management).performRegister(player, executor);
}
@Test
public void shouldPerformMailValidationForPasswordWithEmail() {
// given
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE))
.willReturn(RegistrationArgumentType.PASSWORD_WITH_EMAIL);
String email = "email@example.org";
given(validationService.validateEmail(email)).willReturn(true);
Player player = mock(Player.class);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(registrationExecutorProvider.getPasswordRegisterExecutor(player, "myPass", email)).willReturn(executor);
// when
command.executeCommand(player, Arrays.asList("myPass", email));
// then
verify(validationService).validateEmail(email);
verify(management).performRegister(player, executor);
}
@Test
public void shouldStopForInvalidEmail() {
// given
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE))
.willReturn(RegistrationArgumentType.PASSWORD_WITH_EMAIL);
String email = "email@example.org";
given(validationService.validateEmail(email)).willReturn(false);
Player player = mock(Player.class);
// when
command.executeCommand(player, Arrays.asList("myPass", email));
// then
verify(validationService).validateEmail(email);
verify(commonService).send(player, MessageKey.INVALID_EMAIL);
verifyZeroInteractions(management);
}
@Test
public void shouldFailForInsufficientArguments() {
// given
given(commonService.getProperty(RegistrationSettings.REGISTRATION_TYPE))
.willReturn(RegistrationArgumentType.PASSWORD_WITH_EMAIL);
Player player = mock(Player.class);
// when
command.executeCommand(player, Collections.singletonList("myPass"));
// then
verify(commonService).send(player, MessageKey.USAGE_REGISTER);
verifyZeroInteractions(management);
}
}

View File

@ -8,6 +8,7 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import org.bukkit.entity.Player;
import org.junit.BeforeClass;
import org.junit.Test;
@ -172,7 +173,7 @@ public class AsyncAddEmailTest {
given(player.getName()).willReturn("user");
given(playerCache.isAuthenticated("user")).willReturn(false);
given(dataSource.isAuthAvailable("user")).willReturn(false);
given(service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(service.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL);
// when
asyncAddEmail.addEmail(player, "test@mail.com");
@ -188,7 +189,7 @@ public class AsyncAddEmailTest {
given(player.getName()).willReturn("user");
given(playerCache.isAuthenticated("user")).willReturn(false);
given(dataSource.isAuthAvailable("user")).willReturn(false);
given(service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false);
given(service.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.PASSWORD_WITH_CONFIRMATION);
// when
asyncAddEmail.addEmail(player, "test@mail.com");

View File

@ -7,6 +7,7 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import org.bukkit.entity.Player;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -184,7 +185,7 @@ public class AsyncChangeEmailTest {
given(player.getName()).willReturn("Bobby");
given(playerCache.isAuthenticated("bobby")).willReturn(false);
given(dataSource.isAuthAvailable("Bobby")).willReturn(false);
given(service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(service.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
// when
process.changeEmail(player, "old@mail.tld", "new@mail.tld");
@ -201,7 +202,7 @@ public class AsyncChangeEmailTest {
given(player.getName()).willReturn("Bobby");
given(playerCache.isAuthenticated("bobby")).willReturn(false);
given(dataSource.isAuthAvailable("Bobby")).willReturn(false);
given(service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(false);
given(service.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.PASSWORD);
// when
process.changeEmail(player, "old@mail.tld", "new@mail.tld");

View File

@ -0,0 +1,121 @@
package fr.xephi.authme.process.register;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link AsyncRegister}.
*/
@RunWith(MockitoJUnitRunner.class)
public class AsyncRegisterTest {
@InjectMocks
private AsyncRegister asyncRegister;
@Mock
private PlayerCache playerCache;
@Mock
private PermissionsManager permissionsManager;
@Mock
private CommonService commonService;
@Mock
private DataSource dataSource;
@Test
public void shouldDetectAlreadyLoggedInPlayer() {
// given
String name = "robert";
Player player = mockPlayerWithName(name);
given(playerCache.isAuthenticated(name)).willReturn(true);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
// when
asyncRegister.register(player, executor);
// then
verify(commonService).send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
verifyZeroInteractions(dataSource, executor);
}
@Test
public void shouldStopForDisabledRegistration() {
// given
String name = "albert";
Player player = mockPlayerWithName(name);
given(playerCache.isAuthenticated(name)).willReturn(false);
given(commonService.getProperty(RegistrationSettings.IS_ENABLED)).willReturn(false);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
// when
asyncRegister.register(player, executor);
// then
verify(commonService).send(player, MessageKey.REGISTRATION_DISABLED);
verifyZeroInteractions(dataSource, executor);
}
@Test
public void shouldStopForAlreadyRegisteredName() {
// given
String name = "dilbert";
Player player = mockPlayerWithName(name);
given(playerCache.isAuthenticated(name)).willReturn(false);
given(commonService.getProperty(RegistrationSettings.IS_ENABLED)).willReturn(true);
given(dataSource.isAuthAvailable(name)).willReturn(true);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
// when
asyncRegister.register(player, executor);
// then
verify(commonService).send(player, MessageKey.NAME_ALREADY_REGISTERED);
verify(dataSource, only()).isAuthAvailable(name);
verifyZeroInteractions(executor);
}
@Test
public void shouldStopForFailedExecutorCheck() {
// given
String name = "edbert";
Player player = mockPlayerWithName(name);
TestHelper.mockPlayerIp(player, "33.44.55.66");
given(playerCache.isAuthenticated(name)).willReturn(false);
given(commonService.getProperty(RegistrationSettings.IS_ENABLED)).willReturn(true);
given(commonService.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP)).willReturn(0);
given(dataSource.isAuthAvailable(name)).willReturn(false);
RegistrationExecutor executor = mock(RegistrationExecutor.class);
given(executor.isRegistrationAdmitted()).willReturn(false);
// when
asyncRegister.register(player, executor);
// then
verify(dataSource, only()).isAuthAvailable(name);
verify(executor, only()).isRegistrationAdmitted();
}
private static Player mockPlayerWithName(String name) {
Player player = mock(Player.class);
given(player.getName()).willReturn(name);
return player;
}
}

View File

@ -0,0 +1,173 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.properties.EmailSettings;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData;
import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation;
import static fr.xephi.authme.AuthMeMatchers.stringWithLength;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link EmailRegisterExecutorProvider}.
*/
@RunWith(MockitoJUnitRunner.class)
public class EmailRegisterExecutorProviderTest {
@InjectMocks
private EmailRegisterExecutorProvider emailRegisterExecutorProvider;
@Mock
private PermissionsManager permissionsManager;
@Mock
private DataSource dataSource;
@Mock
private CommonService commonService;
@Mock
private SendMailSSL sendMailSsl;
@Mock
private SyncProcessManager syncProcessManager;
@Mock
private PasswordSecurity passwordSecurity;
@Test
public void shouldNotPassEmailValidation() {
// given
given(commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(3);
String email = "test@example.com";
given(dataSource.countAuthsByEmail(email)).willReturn(4);
Player player = mock(Player.class);
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, email);
// when
boolean result = executor.isRegistrationAdmitted();
// then
assertThat(result, equalTo(false));
verify(dataSource).countAuthsByEmail(email);
verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS);
verify(commonService).send(player, MessageKey.MAX_REGISTER_EXCEEDED, "3", "4", "@");
}
@Test
public void shouldPassVerificationForPlayerWithPermission() {
// given
given(commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(3);
Player player = mock(Player.class);
given(permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)).willReturn(true);
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, "test@example.com");
// when
boolean result = executor.isRegistrationAdmitted();
// then
assertThat(result, equalTo(true));
verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS);
}
@Test
public void shouldPassVerificationForPreviouslyUnregisteredIp() {
// given
given(commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL)).willReturn(1);
String email = "test@example.com";
given(dataSource.countAuthsByEmail(email)).willReturn(0);
Player player = mock(Player.class);
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, "test@example.com");
// when
boolean result = executor.isRegistrationAdmitted();
// then
assertThat(result, equalTo(true));
verify(permissionsManager).hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS);
verify(dataSource).countAuthsByEmail(email);
}
@Test
public void shouldCreatePlayerAuth() {
// given
given(commonService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)).willReturn(12);
given(passwordSecurity.computeHash(anyString(), anyString())).willAnswer(
invocation -> new HashedPassword(invocation.getArgument(0)));
Player player = mock(Player.class);
TestHelper.mockPlayerIp(player, "123.45.67.89");
given(player.getName()).willReturn("Veronica");
World world = mock(World.class);
given(world.getName()).willReturn("someWorld");
given(player.getLocation()).willReturn(new Location(world, 48, 96, 144));
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, "test@example.com");
// when
PlayerAuth auth = executor.buildPlayerAuth();
// then
assertThat(auth, hasAuthBasicData("veronica", "Veronica", "test@example.com", "123.45.67.89"));
assertThat(auth, hasAuthLocation(48, 96, 144, "someWorld"));
assertThat(auth.getPassword().getHash(), stringWithLength(12));
}
@Test
@SuppressWarnings("unchecked")
public void shouldPerformActionAfterDataSourceSave() {
// given
given(sendMailSsl.sendPasswordMail(anyString(), anyString(), anyString())).willReturn(true);
Player player = mock(Player.class);
given(player.getName()).willReturn("Laleh");
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, "test@example.com");
String password = "A892C#@";
ReflectionTestUtils.setField((Class) executor.getClass(), executor, "password", password);
// when
executor.executePostPersistAction();
// then
verify(sendMailSsl).sendPasswordMail("Laleh", "test@example.com", password);
verify(syncProcessManager).processSyncEmailRegister(player);
}
@Test
@SuppressWarnings("unchecked")
public void shouldHandleEmailSendingFailure() {
// given
given(sendMailSsl.sendPasswordMail(anyString(), anyString(), anyString())).willReturn(false);
Player player = mock(Player.class);
given(player.getName()).willReturn("Laleh");
RegistrationExecutor executor = emailRegisterExecutorProvider.new EmailRegisterExecutor(player, "test@example.com");
String password = "A892C#@";
ReflectionTestUtils.setField((Class) executor.getClass(), executor, "password", password);
// when
executor.executePostPersistAction();
// then
verify(sendMailSsl).sendPasswordMail("Laleh", "test@example.com", password);
verify(commonService).send(player, MessageKey.EMAIL_SEND_FAILURE);
verifyZeroInteractions(syncProcessManager);
}
}

View File

@ -0,0 +1,152 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.ValidationService.ValidationResult;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static fr.xephi.authme.AuthMeMatchers.equalToHash;
import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData;
import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link PasswordRegisterExecutorProvider}.
*/
@RunWith(MockitoJUnitRunner.class)
public class PasswordRegisterExecutorProviderTest {
@InjectMocks
private PasswordRegisterExecutorProvider passwordRegisterExecutorProvider;
@Mock
private ValidationService validationService;
@Mock
private CommonService commonService;
@Mock
private PasswordSecurity passwordSecurity;
@Mock
private BukkitService bukkitService;
@Mock
private SyncProcessManager syncProcessManager;
@Mock
private AsynchronousLogin asynchronousLogin;
@Test
public void shouldCheckPasswordValidity() {
// given
String password = "myPass";
String name = "player040";
given(validationService.validatePassword(password, name)).willReturn(new ValidationResult());
Player player = mockPlayerWithName(name);
RegistrationExecutor executor = passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, password, null);
// when
boolean result = executor.isRegistrationAdmitted();
// then
assertThat(result, equalTo(true));
verify(validationService).validatePassword(password, name);
}
@Test
public void shouldDetectInvalidPasswordAndInformPlayer() {
// given
String password = "myPass";
String name = "player040";
given(validationService.validatePassword(password, name)).willReturn(
new ValidationResult(MessageKey.PASSWORD_CHARACTERS_ERROR, "[a-z]"));
Player player = mockPlayerWithName(name);
RegistrationExecutor executor = passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, password, null);
// when
boolean result = executor.isRegistrationAdmitted();
// then
assertThat(result, equalTo(false));
verify(validationService).validatePassword(password, name);
verify(commonService).send(player, MessageKey.PASSWORD_CHARACTERS_ERROR, "[a-z]");
}
@Test
public void shouldCreatePlayerAuth() {
// given
given(passwordSecurity.computeHash(anyString(), anyString())).willAnswer(
invocation -> new HashedPassword(invocation.getArgument(0)));
Player player = mockPlayerWithName("S1m0N");
TestHelper.mockPlayerIp(player, "123.45.67.89");
World world = mock(World.class);
given(world.getName()).willReturn("someWorld");
given(player.getLocation()).willReturn(new Location(world, 48, 96, 144));
RegistrationExecutor executor = passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, "pass", "mail@example.org");
// when
PlayerAuth auth = executor.buildPlayerAuth();
// then
assertThat(auth, hasAuthBasicData("s1m0n", "S1m0N", "mail@example.org", "123.45.67.89"));
assertThat(auth, hasAuthLocation(48, 96, 144, "someWorld"));
assertThat(auth.getPassword(), equalToHash("pass"));
}
@Test
public void shouldLogPlayerIn() {
// given
given(commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)).willReturn(false);
given(commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)).willReturn(false);
Player player = mock(Player.class);
RegistrationExecutor executor = passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, "pass", "mail@example.org");
// when
executor.executePostPersistAction();
// then
TestHelper.runSyncDelayedTaskWithDelay(bukkitService);
verify(asynchronousLogin).forceLogin(player);
verify(syncProcessManager).processSyncPasswordRegister(player);
}
@Test
public void shouldNotLogPlayerIn() {
// given
given(commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)).willReturn(true);
Player player = mock(Player.class);
RegistrationExecutor executor = passwordRegisterExecutorProvider.new PasswordRegisterExecutor(player, "pass", "mail@example.org");
// when
executor.executePostPersistAction();
// then
verifyZeroInteractions(bukkitService, asynchronousLogin);
verify(syncProcessManager).processSyncPasswordRegister(player);
}
private static Player mockPlayerWithName(String name) {
Player player = mock(Player.class);
given(player.getName()).willReturn(name);
return player;
}
}

View File

@ -0,0 +1,49 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.junit.Test;
import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData;
import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Test for {@link PlayerAuthBuilderHelper}.
*/
public class PlayerAuthBuilderHelperTest {
@Test
public void shouldConstructPlayerAuth() {
// given
Player player = mock(Player.class);
given(player.getName()).willReturn("Noah");
String ip = "192.168.34.47";
TestHelper.mockPlayerIp(player, ip);
World world = mock(World.class);
given(world.getName()).willReturn("worldName");
Location location = new Location(world, 123, 80, -99);
given(player.getLocation()).willReturn(location);
HashedPassword hashedPassword = new HashedPassword("myHash0001");
String email = "test@example.org";
// when
PlayerAuth auth = PlayerAuthBuilderHelper.createPlayerAuth(player, hashedPassword, email);
// then
assertThat(auth, hasAuthBasicData("noah", "Noah", email, ip));
assertThat(auth, hasAuthLocation(123, 80, -99, "worldName"));
}
@Test
public void shouldHaveHiddenConstructor() {
TestHelper.validateHasOnlyPrivateEmptyConstructor(PlayerAuthBuilderHelper.class);
}
}

View File

@ -6,6 +6,7 @@ import com.google.common.io.Files;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@ -18,6 +19,7 @@ import java.nio.charset.StandardCharsets;
import static fr.xephi.authme.TestHelper.getJarFile;
import static fr.xephi.authme.settings.properties.PluginSettings.LOG_LEVEL;
import static fr.xephi.authme.settings.properties.RegistrationSettings.DELAY_JOIN_MESSAGE;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REGISTRATION_TYPE;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS;
import static fr.xephi.authme.settings.properties.RestrictionSettings.FORCE_SPAWN_LOCATION_AFTER_LOGIN;
import static fr.xephi.authme.settings.properties.RestrictionSettings.FORCE_SPAWN_ON_WORLDS;
@ -59,6 +61,7 @@ public class SettingsMigrationServiceTest {
assertThat(settings.getProperty(FORCE_SPAWN_LOCATION_AFTER_LOGIN), equalTo(true));
assertThat(settings.getProperty(FORCE_SPAWN_ON_WORLDS), contains("survival", "survival_nether", "creative"));
assertThat(settings.getProperty(LOG_LEVEL), equalTo(LogLevel.INFO));
assertThat(settings.getProperty(REGISTRATION_TYPE), equalTo(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION));
// Check migration of old setting to email.html
assertThat(Files.readLines(new File(dataFolder, "email.html"), StandardCharsets.UTF_8),

View File

@ -9,6 +9,7 @@ import fr.xephi.authme.message.Messages;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RegistrationArgumentType;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
@ -67,7 +68,7 @@ public class LimboPlayerTaskManagerTest {
given(messages.retrieve(key)).willReturn(new String[]{"Please register!"});
int interval = 12;
given(settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL)).willReturn(interval);
given(settings.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(settings.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL_WITH_CONFIRMATION);
// when
limboPlayerTaskManager.registerMessageTask(name, false);
@ -123,7 +124,7 @@ public class LimboPlayerTaskManagerTest {
.willReturn(new String[]{"Please register", "Use /register"});
given(settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL)).willReturn(8);
given(settings.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION)).willReturn(true);
given(settings.getProperty(RegistrationSettings.REGISTRATION_TYPE)).willReturn(RegistrationArgumentType.EMAIL);
// when
limboPlayerTaskManager.registerMessageTask(name, false);

View File

@ -218,11 +218,11 @@ settings:
# See restrictions for exceptions
force: true
# Does we replace password registration by an Email registration method ?
enableEmailRegistrationSystem: false
enableEmailRegistrationSystem: true
# Enable double check of email when you register
# when it's true, registration require that kind of command:
# /register <email> <confirmEmail>
doubleEmailCheck: false
doubleEmailCheck: true
# Do we force kicking player after a successful registration ?
# Do not use with login feature below
forceKickAfterRegister: false