#1350 Add option to force using the sync PlayerLoginEvent

- Introduce new configuration (taken from @sgdc3)
- Create JoiningPlayer, based on a Player object or String name, determining how permissions will be checked
This commit is contained in:
ljacqu 2017-11-01 21:02:22 +01:00
parent a5542051f4
commit 44a7baff9a
9 changed files with 180 additions and 55 deletions

View File

@ -1,8 +1,8 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly --> <!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sat Oct 28 10:39:36 CEST 2017. See docs/config/config.tpl.md --> <!-- File auto-generated on Tue Oct 31 15:56:59 CET 2017. See docs/config/config.tpl.md -->
## AuthMe Configuration ## AuthMe Configuration
The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder,
with which you can configure various settings. This following is the initial contents of with which you can configure various settings. This following is the initial contents of
the generated config.yml file. the generated config.yml file.
@ -110,6 +110,8 @@ settings:
# Message language, available languages: # Message language, available languages:
# https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md # https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md
messagesLanguage: 'en' messagesLanguage: 'en'
# Forces authme to hook into Vault instead of a specific permission handler system.
forceVaultHook: false
# Log level: INFO, FINE, DEBUG. Use INFO for general messages, # Log level: INFO, FINE, DEBUG. Use INFO for general messages,
# FINE for some additional detailed ones (like password failed), # FINE for some additional detailed ones (like password failed),
# and DEBUG for debugging # and DEBUG for debugging
@ -117,6 +119,10 @@ settings:
# By default we schedule async tasks when talking to the database. If you want # 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 # typical communication with the database to happen synchronously, set this to false
useAsyncTasks: true useAsyncTasks: true
# By default we handle the AsyncPlayerPreLoginEvent which makes the plugin faster
# but it is incompatible with any permission plugin not included in our compatibility list.
# If you have issues with permission checks on player join please disable this option.
useAsyncPreLoginEvent: true
restrictions: restrictions:
# Can not authenticated players chat? # Can not authenticated players chat?
# Keep in mind that this feature also blocks all commands not # Keep in mind that this feature also blocks all commands not
@ -125,7 +131,7 @@ settings:
# Hide the chat log from players who are not authenticated? # Hide the chat log from players who are not authenticated?
hideChat: false hideChat: false
# Allowed commands for unauthenticated players # Allowed commands for unauthenticated players
allowCommands: allowCommands:
- '/login' - '/login'
- '/register' - '/register'
- '/l' - '/l'
@ -152,7 +158,7 @@ settings:
enabled: false enabled: false
# WorldNames where we need to force the spawn location # WorldNames where we need to force the spawn location
# Case-sensitive! # Case-sensitive!
worlds: worlds:
- 'world' - 'world'
- 'world_nether' - 'world_nether'
- 'world_the_end' - 'world_the_end'
@ -252,7 +258,7 @@ settings:
# - '123456' # - '123456'
# - 'password' # - 'password'
# - 'help' # - 'help'
unsafePasswords: unsafePasswords:
- '123456' - '123456'
- 'password' - 'password'
- 'qwerty' - 'qwerty'
@ -358,7 +364,7 @@ Email:
# Delay in minute for the recall scheduler # Delay in minute for the recall scheduler
delayRecall: 5 delayRecall: 5
# Blacklist these domains for emails # Blacklist these domains for emails
emailBlacklisted: emailBlacklisted:
- '10minutemail.com' - '10minutemail.com'
# Whitelist ONLY these domains for emails # Whitelist ONLY these domains for emails
emailWhitelisted: [] emailWhitelisted: []
@ -385,12 +391,12 @@ Protection:
# Countries allowed to join the server and register. For country codes, see # Countries allowed to join the server and register. For country codes, see
# http://dev.maxmind.com/geoip/legacy/codes/iso3166/ # http://dev.maxmind.com/geoip/legacy/codes/iso3166/
# PLEASE USE QUOTES! # PLEASE USE QUOTES!
countries: countries:
- 'US' - 'US'
- 'GB' - 'GB'
# Countries not allowed to join the server and register # Countries not allowed to join the server and register
# PLEASE USE QUOTES! # PLEASE USE QUOTES!
countriesBlacklist: countriesBlacklist:
- 'A1' - 'A1'
# Do we need to enable automatic antibot system? # Do we need to enable automatic antibot system?
enableAntiBot: true enableAntiBot: true
@ -549,9 +555,9 @@ Converter:
password: '' password: ''
``` ```
To change settings on a running server, save your changes to config.yml and use To change settings on a running server, save your changes to config.yml and use
`/authme reload`. `/authme reload`.
--- ---
This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Oct 28 10:39:36 CEST 2017 This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Tue Oct 31 15:56:59 CET 2017

View File

@ -0,0 +1,66 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
/**
* Represents a player joining the server, which depending on the available
* information may be his name or the actual Player object.
*/
public final class JoiningPlayer {
private final String name;
private final BiFunction<PermissionsManager, PermissionNode, Boolean> permissionLookupFunction;
/**
* Hidden constructor.
*
* @param name the player's name
* @param permFunction the function to use for permission lookups
*/
private JoiningPlayer(String name, BiFunction<PermissionsManager, PermissionNode, Boolean> permFunction) {
this.name = name;
this.permissionLookupFunction = permFunction;
}
/**
* Creates a {@link JoiningPlayer} instance from the given name.
*
* @param name the player's name
* @return the created instance
*/
public static JoiningPlayer fromName(String name) {
return new JoiningPlayer(name, (manager, perm) -> manager.hasPermissionOffline(name, perm));
}
/**
* Creates a {@link JoiningPlayer} instance from the given Player object.
*
* @param player the player
* @return the created instance
*/
public static JoiningPlayer fromPlayerObject(Player player) {
return new JoiningPlayer(player.getName(), (manager, perm) -> manager.hasPermission(player, perm));
}
/**
* @return the player's name
*/
public String getName() {
return name;
}
/**
* Returns the function to use for permission lookups. Takes two arguments: the PermissionsManager instance,
* and the permission node to look up. The result is a boolean indicating whether or not this joining player
* has permission.
*
* @return the permissions lookup function to use
*/
public BiFunction<PermissionsManager, PermissionNode, Boolean> getPermissionLookupFunction() {
return permissionLookupFunction;
}
}

View File

@ -64,16 +64,16 @@ public class OnJoinVerifier implements Reloadable {
/** /**
* Checks if Antibot is enabled. * Checks if Antibot is enabled.
* *
* @param name the player name * @param joiningPlayer the joining player to check
* @param isAuthAvailable whether or not the player is registered * @param isAuthAvailable whether or not the player is registered
* @throws FailedVerificationException if the verification fails * @throws FailedVerificationException if the verification fails
*/ */
public void checkAntibot(String name, boolean isAuthAvailable) throws FailedVerificationException { public void checkAntibot(JoiningPlayer joiningPlayer, boolean isAuthAvailable) throws FailedVerificationException {
if (isAuthAvailable || permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)) { if (isAuthAvailable || permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT)) {
return; return;
} }
if (antiBotService.shouldKick()) { if (antiBotService.shouldKick()) {
antiBotService.addPlayerKick(name); antiBotService.addPlayerKick(joiningPlayer.getName());
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT); throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
} }
} }
@ -149,7 +149,7 @@ public class OnJoinVerifier implements Reloadable {
* Checks that the casing in the username corresponds to the one in the database, if so configured. * Checks that the casing in the username corresponds to the one in the database, if so configured.
* *
* @param connectingName the player name to verify * @param connectingName the player name to verify
* @param auth the auth object associated with the player * @param auth the auth object associated with the player
* @throws FailedVerificationException if the verification fails * @throws FailedVerificationException if the verification fails
*/ */
public void checkNameCasing(String connectingName, PlayerAuth auth) throws FailedVerificationException { public void checkNameCasing(String connectingName, PlayerAuth auth) throws FailedVerificationException {
@ -167,15 +167,16 @@ public class OnJoinVerifier implements Reloadable {
/** /**
* Checks that the player's country is admitted. * Checks that the player's country is admitted.
* *
* @param name the player name * @param joiningPlayer the joining player to verify
* @param address the player address * @param address the player address
* @param isAuthAvailable whether or not the user is registered * @param isAuthAvailable whether or not the user is registered
* @throws FailedVerificationException if the verification fails * @throws FailedVerificationException if the verification fails
*/ */
public void checkPlayerCountry(String name, String address, boolean isAuthAvailable) throws FailedVerificationException { public void checkPlayerCountry(JoiningPlayer joiningPlayer, String address,
boolean isAuthAvailable) throws FailedVerificationException {
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)) if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
&& settings.getProperty(ProtectionSettings.ENABLE_PROTECTION) && settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)
&& !permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_COUNTRY_CHECK) && !permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_COUNTRY_CHECK)
&& !validationService.isCountryAdmitted(address)) { && !validationService.isCountryAdmitted(address)) {
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR); throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
} }

View File

@ -14,6 +14,7 @@ import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader; import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings; import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -83,7 +84,7 @@ public class PlayerListener implements Listener {
@Inject @Inject
private PermissionsManager permissionsManager; private PermissionsManager permissionsManager;
private static boolean isAsyncPlayerPreLoginEventCalled = false; private boolean isAsyncPlayerPreLoginEventCalled = false;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
@ -206,8 +207,9 @@ public class PlayerListener implements Listener {
teleportationService.teleportNewPlayerToFirstSpawn(player); teleportationService.teleportNewPlayerToFirstSpawn(player);
} }
private void runOnJoinChecks(String name, String ip) throws FailedVerificationException { private void runOnJoinChecks(JoiningPlayer joiningPlayer, String ip) throws FailedVerificationException {
// Fast stuff // Fast stuff
final String name = joiningPlayer.getName();
onJoinVerifier.checkSingleSession(name); onJoinVerifier.checkSingleSession(name);
onJoinVerifier.checkIsValidName(name); onJoinVerifier.checkIsValidName(name);
@ -216,9 +218,9 @@ public class PlayerListener implements Listener {
final PlayerAuth auth = dataSource.getAuth(name); final PlayerAuth auth = dataSource.getAuth(name);
final boolean isAuthAvailable = auth != null; final boolean isAuthAvailable = auth != null;
onJoinVerifier.checkKickNonRegistered(isAuthAvailable); onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
onJoinVerifier.checkNameCasing(name, auth); onJoinVerifier.checkNameCasing(name, auth);
onJoinVerifier.checkPlayerCountry(name, ip, isAuthAvailable); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, isAuthAvailable);
} }
// Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode // Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
@ -230,6 +232,9 @@ public class PlayerListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onAsyncPlayerPreLoginEvent(AsyncPlayerPreLoginEvent event) { public void onAsyncPlayerPreLoginEvent(AsyncPlayerPreLoginEvent event) {
isAsyncPlayerPreLoginEventCalled = true; isAsyncPlayerPreLoginEventCalled = true;
if (!settings.getProperty(PluginSettings.USE_ASYNC_PRE_LOGIN_EVENT)) {
return;
}
final String name = event.getName(); final String name = event.getName();
@ -245,7 +250,7 @@ public class PlayerListener implements Listener {
} }
try { try {
runOnJoinChecks(name, event.getAddress().getHostAddress()); runOnJoinChecks(JoiningPlayer.fromName(name), event.getAddress().getHostAddress());
} catch (FailedVerificationException e) { } catch (FailedVerificationException e) {
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs())); event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
@ -271,9 +276,9 @@ public class PlayerListener implements Listener {
return; return;
} }
if (!isAsyncPlayerPreLoginEventCalled) { if (!isAsyncPlayerPreLoginEventCalled || !settings.getProperty(PluginSettings.USE_ASYNC_PRE_LOGIN_EVENT)) {
try { try {
runOnJoinChecks(name, event.getAddress().getHostAddress()); runOnJoinChecks(JoiningPlayer.fromPlayerObject(player), event.getAddress().getHostAddress());
} catch (FailedVerificationException e) { } catch (FailedVerificationException e) {
event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs())); event.setKickMessage(m.retrieveSingle(e.getReason(), e.getArgs()));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER); event.setResult(PlayerLoginEvent.Result.KICK_OTHER);

View File

@ -2,6 +2,7 @@ package fr.xephi.authme.permission;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.listener.JoiningPlayer;
import fr.xephi.authme.permission.handlers.BPermissionsHandler; import fr.xephi.authme.permission.handlers.BPermissionsHandler;
import fr.xephi.authme.permission.handlers.LuckPermsHandler; import fr.xephi.authme.permission.handlers.LuckPermsHandler;
import fr.xephi.authme.permission.handlers.PermissionHandler; import fr.xephi.authme.permission.handlers.PermissionHandler;
@ -76,7 +77,7 @@ public class PermissionsManager implements Reloadable {
*/ */
@PostConstruct @PostConstruct
private void setup() { private void setup() {
if(settings.getProperty(PluginSettings.FORCE_VAULT_HOOK)) { if (settings.getProperty(PluginSettings.FORCE_VAULT_HOOK)) {
try { try {
PermissionHandler handler = createPermissionHandler(PermissionsSystemType.VAULT); PermissionHandler handler = createPermissionHandler(PermissionsSystemType.VAULT);
if (handler != null) { if (handler != null) {
@ -86,7 +87,7 @@ public class PermissionsManager implements Reloadable {
return; return;
} }
} catch (PermissionHandlerException e) { } catch (PermissionHandlerException e) {
e.printStackTrace(); ConsoleLogger.logException("Failed to create Vault hook (forced):", e);
} }
} else { } else {
// Loop through all the available permissions system types // Loop through all the available permissions system types
@ -229,6 +230,17 @@ public class PermissionsManager implements Reloadable {
return player.hasPermission(permissionNode.getNode()); return player.hasPermission(permissionNode.getNode());
} }
/**
* Check if the given player has permission for the given permission node.
*
* @param joiningPlayer The player to check
* @param permissionNode The permission node to verify
* @return true if the player has permission, false otherwise
*/
public boolean hasPermission(JoiningPlayer joiningPlayer, PermissionNode permissionNode) {
return joiningPlayer.getPermissionLookupFunction().apply(this, permissionNode);
}
/** /**
* Check if a player has permission for the given permission node. This is for offline player checks. * Check if a player has permission for the given permission node. This is for offline player checks.
* If no permissions system is used, then the player will not have permission. * If no permissions system is used, then the player will not have permission.

View File

@ -82,6 +82,14 @@ public final class PluginSettings implements SettingsHolder {
public static final Property<Boolean> USE_ASYNC_TASKS = public static final Property<Boolean> USE_ASYNC_TASKS =
newProperty("settings.useAsyncTasks", true); newProperty("settings.useAsyncTasks", true);
@Comment({
"By default we handle the AsyncPlayerPreLoginEvent which makes the plugin faster",
"but it is incompatible with any permission plugin not included in our compatibility list.",
"If you have issues with permission checks on player join please disable this option."
})
public static final Property<Boolean> USE_ASYNC_PRE_LOGIN_EVENT =
newProperty("settings.useAsyncPreLoginEvent", true);
private PluginSettings() { private PluginSettings() {
} }

View File

@ -29,7 +29,6 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.net.InetSocketAddress;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -376,27 +375,27 @@ public class OnJoinVerifierTest {
@Test @Test
public void shouldAllowUser() throws FailedVerificationException { public void shouldAllowUser() throws FailedVerificationException {
// given // given
String name = "Bobby"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("Bobby");
boolean isAuthAvailable = false; boolean isAuthAvailable = false;
given(permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(false); given(permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(false);
given(antiBotService.shouldKick()).willReturn(false); given(antiBotService.shouldKick()).willReturn(false);
// when // when
onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
// then // then
verify(permissionsManager).hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT); verify(permissionsManager).hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT);
verify(antiBotService).shouldKick(); verify(antiBotService).shouldKick();
} }
@Test @Test
public void shouldAllowUserWithAuth() throws FailedVerificationException { public void shouldAllowUserWithAuth() throws FailedVerificationException {
// given // given
String name = "Lacey"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("Lacey");
boolean isAuthAvailable = true; boolean isAuthAvailable = true;
// when // when
onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
// then // then
verifyZeroInteractions(permissionsManager, antiBotService); verifyZeroInteractions(permissionsManager, antiBotService);
@ -405,32 +404,32 @@ public class OnJoinVerifierTest {
@Test @Test
public void shouldAllowUserWithBypassPermission() throws FailedVerificationException { public void shouldAllowUserWithBypassPermission() throws FailedVerificationException {
// given // given
String name = "Steward"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("Steward");
boolean isAuthAvailable = false; boolean isAuthAvailable = false;
given(permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(true); given(permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(true);
// when // when
onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
// then // then
verify(permissionsManager).hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT); verify(permissionsManager).hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT);
verifyZeroInteractions(antiBotService); verifyZeroInteractions(antiBotService);
} }
@Test @Test
public void shouldKickUserForFailedAntibotCheck() throws FailedVerificationException { public void shouldKickUserForFailedAntibotCheck() throws FailedVerificationException {
// given // given
String name = "D3"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("D3");
boolean isAuthAvailable = false; boolean isAuthAvailable = false;
given(permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(false); given(permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT)).willReturn(false);
given(antiBotService.shouldKick()).willReturn(true); given(antiBotService.shouldKick()).willReturn(true);
// when / then // when / then
try { try {
onJoinVerifier.checkAntibot(name, isAuthAvailable); onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
fail("Expected exception to be thrown"); fail("Expected exception to be thrown");
} catch (FailedVerificationException e) { } catch (FailedVerificationException e) {
verify(permissionsManager).hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT); verify(permissionsManager).hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT);
verify(antiBotService).shouldKick(); verify(antiBotService).shouldKick();
} }
@ -441,18 +440,18 @@ public class OnJoinVerifierTest {
*/ */
@Test @Test
public void shouldNotCheckCountry() throws FailedVerificationException { public void shouldNotCheckCountry() throws FailedVerificationException {
String name = "david"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("david");
String ip = "127.0.0.1"; String ip = "127.0.0.1";
// protection setting disabled // protection setting disabled
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(false); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(false);
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(true); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(true);
onJoinVerifier.checkPlayerCountry(name, ip, false); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, false);
verifyZeroInteractions(validationService); verifyZeroInteractions(validationService);
// protection for registered players disabled // protection for registered players disabled
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(false); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(false);
onJoinVerifier.checkPlayerCountry(name, ip, true); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, true);
verifyZeroInteractions(validationService); verifyZeroInteractions(validationService);
} }
@ -460,12 +459,12 @@ public class OnJoinVerifierTest {
public void shouldCheckAndAcceptUnregisteredPlayerCountry() throws FailedVerificationException { public void shouldCheckAndAcceptUnregisteredPlayerCountry() throws FailedVerificationException {
// given // given
String ip = "192.168.0.1"; String ip = "192.168.0.1";
String name = "lucas"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("lucas");
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true);
given(validationService.isCountryAdmitted(ip)).willReturn(true); given(validationService.isCountryAdmitted(ip)).willReturn(true);
// when // when
onJoinVerifier.checkPlayerCountry(name, ip, false); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, false);
// then // then
verify(validationService).isCountryAdmitted(ip); verify(validationService).isCountryAdmitted(ip);
@ -475,13 +474,13 @@ public class OnJoinVerifierTest {
public void shouldCheckAndAcceptRegisteredPlayerCountry() throws FailedVerificationException { public void shouldCheckAndAcceptRegisteredPlayerCountry() throws FailedVerificationException {
// given // given
String ip = "192.168.10.24"; String ip = "192.168.10.24";
String name = "gabriel"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("gabriel");
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true);
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(true); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED)).willReturn(true);
given(validationService.isCountryAdmitted(ip)).willReturn(true); given(validationService.isCountryAdmitted(ip)).willReturn(true);
// when // when
onJoinVerifier.checkPlayerCountry(name, ip, true); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, true);
// then // then
verify(validationService).isCountryAdmitted(ip); verify(validationService).isCountryAdmitted(ip);
@ -491,7 +490,7 @@ public class OnJoinVerifierTest {
public void shouldThrowForBannedCountry() throws FailedVerificationException { public void shouldThrowForBannedCountry() throws FailedVerificationException {
// given // given
String ip = "192.168.40.0"; String ip = "192.168.40.0";
String name = "bob"; JoiningPlayer joiningPlayer = JoiningPlayer.fromName("bob");
given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true); given(settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)).willReturn(true);
given(validationService.isCountryAdmitted(ip)).willReturn(false); given(validationService.isCountryAdmitted(ip)).willReturn(false);
@ -499,7 +498,7 @@ public class OnJoinVerifierTest {
expectValidationExceptionWith(MessageKey.COUNTRY_BANNED_ERROR); expectValidationExceptionWith(MessageKey.COUNTRY_BANNED_ERROR);
// when // when
onJoinVerifier.checkPlayerCountry(name, ip, false); onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, false);
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })

View File

@ -48,7 +48,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -64,6 +63,7 @@ import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
@ -555,7 +555,7 @@ public class PlayerListenerTest {
} }
@Test @Test
public void shouldPerformAllJoinVerificationsSuccessfully() throws FailedVerificationException, UnknownHostException { public void shouldPerformAllJoinVerificationsSuccessfully() throws FailedVerificationException {
// given // given
String name = "someone"; String name = "someone";
Player player = mockPlayerWithName(name); Player player = mockPlayerWithName(name);
@ -575,10 +575,10 @@ public class PlayerListenerTest {
verify(onJoinVerifier).refusePlayerForFullServer(event); verify(onJoinVerifier).refusePlayerForFullServer(event);
verify(onJoinVerifier).checkSingleSession(name); verify(onJoinVerifier).checkSingleSession(name);
verify(onJoinVerifier).checkIsValidName(name); verify(onJoinVerifier).checkIsValidName(name);
verify(onJoinVerifier).checkAntibot(name, true); verify(onJoinVerifier).checkAntibot(any(JoiningPlayer.class), eq(true));
verify(onJoinVerifier).checkKickNonRegistered(true); verify(onJoinVerifier).checkKickNonRegistered(true);
verify(onJoinVerifier).checkNameCasing(name, auth); verify(onJoinVerifier).checkNameCasing(name, auth);
verify(onJoinVerifier).checkPlayerCountry(name, ip, true); verify(onJoinVerifier).checkPlayerCountry(any(JoiningPlayer.class), eq(ip), eq(true));
verifyNoModifyingCalls(event); verifyNoModifyingCalls(event);
} }

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.permission; package fr.xephi.authme.permission;
import fr.xephi.authme.listener.JoiningPlayer;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -12,8 +13,13 @@ import org.mockito.junit.MockitoJUnitRunner;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/** /**
* Test for {@link PermissionsManager}. * Test for {@link PermissionsManager}.
@ -148,4 +154,26 @@ public class PermissionsManagerTest {
// then // then
assertThat(result, equalTo(true)); assertThat(result, equalTo(true));
} }
@Test
public void shouldHandleJoiningPlayerPermissionChecksWithProperMethod() {
// given
Player player = mock(Player.class);
JoiningPlayer fromPlayer = JoiningPlayer.fromPlayerObject(player);
JoiningPlayer fromName = JoiningPlayer.fromName("Chris");
PermissionsManager permManagerSpy = spy(permissionsManager);
given(permManagerSpy.hasPermission(any(Player.class), eq(PlayerPermission.LOGIN))).willReturn(true);
given(permManagerSpy.hasPermissionOffline(anyString(), eq(PlayerPermission.UNREGISTER))).willReturn(true);
// when
boolean resultFromPlayer = permManagerSpy.hasPermission(fromPlayer, PlayerPermission.LOGIN);
boolean resultFromName = permManagerSpy.hasPermission(fromName, PlayerPermission.UNREGISTER);
// then
assertThat(resultFromPlayer, equalTo(true));
assertThat(resultFromName, equalTo(true));
verify(permManagerSpy).hasPermission(player, PlayerPermission.LOGIN);
verify(permManagerSpy).hasPermissionOffline(fromName.getName(), PlayerPermission.UNREGISTER);
}
} }