From d56a26211ce829a0861d2225297444fd25ebc23e Mon Sep 17 00:00:00 2001 From: Mykhailo Alipa <6442572+strobil@users.noreply.github.com> Date: Wed, 23 Sep 2026 13:51:34 +0200 Subject: [PATCH 1/2] feat(sessions): add per-player session exclusion list Players listed in settings.sessions.excludedPlayers are never granted a session and never get one restored, so they always have to authenticate even if their IP hasn't changed. This prevents a player from entering another player's account when both share the same IP. --- .../xephi/authme/service/SessionService.java | 15 ++- .../settings/properties/PluginSettings.java | 15 +++ .../authme/service/SessionServiceTest.java | 93 ++++++++++++++++++- docs/config.md | 8 ++ 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java b/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java index 6f7cc435f4..bacc24ebb2 100644 --- a/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java +++ b/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java @@ -12,6 +12,8 @@ import org.bukkit.entity.Player; import javax.inject.Inject; +import java.util.Locale; +import java.util.Set; import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE; @@ -26,6 +28,7 @@ public class SessionService implements Reloadable { private final DataSource database; private boolean isEnabled; + private Set excludedPlayers; @Inject SessionService(CommonService service, BukkitService bukkitService, DataSource database) { @@ -46,6 +49,9 @@ public boolean canResumeSession(Player player) { if (isEnabled && database.hasSession(name)) { database.setUnlogged(name); database.revokeSession(name); + if (isExcluded(name)) { + return false; + } SessionState state = fetchSessionStatus(name, database.getAuth(name), PlayerUtils.getPlayerIp(player)); if (state.equals(SessionState.VALID)) { RestoreSessionEvent event = bukkitService.createAndCallEvent( @@ -67,7 +73,7 @@ public boolean canResumeSession(Player player) { * @return true if the player's session is currently valid, false otherwise */ public boolean hasValidSession(String playerName, String ipAddress) { - if (!isEnabled || ipAddress == null || !database.hasSession(playerName)) { + if (!isEnabled || ipAddress == null || isExcluded(playerName) || !database.hasSession(playerName)) { return false; } @@ -104,7 +110,7 @@ private SessionState fetchSessionStatus(String playerName, PlayerAuth auth, Stri } public void grantSession(String name) { - if (isEnabled) { + if (isEnabled && !isExcluded(name)) { database.grantSession(name); } } @@ -116,5 +122,10 @@ public void revokeSession(String name) { @Override public void reload() { this.isEnabled = service.getProperty(PluginSettings.SESSIONS_ENABLED); + this.excludedPlayers = service.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); + } + + private boolean isExcluded(String name) { + return excludedPlayers.contains(name.toLowerCase(Locale.ROOT)); } } diff --git a/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java index 884021ca48..307f89ebac 100644 --- a/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -5,6 +5,9 @@ import ch.jalu.configme.properties.Property; import fr.xephi.authme.output.LogLevel; +import java.util.Set; + +import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty; import static ch.jalu.configme.properties.PropertyInitializer.newProperty; public final class PluginSettings implements SettingsHolder { @@ -27,6 +30,18 @@ public final class PluginSettings implements SettingsHolder { public static final Property SESSIONS_TIMEOUT = newProperty("settings.sessions.timeout", 10); + @Comment({ + "Players listed here never get their session restored and must", + "always authenticate, even if their IP hasn't changed.", + "Useful when several players share the same IP address.", + "It is case-insensitive! Example:", + "excludedPlayers:", + "- 'playerOne'", + "- 'playerTwo'" + }) + public static final Property> SESSIONS_EXCLUDED_PLAYERS = + newLowercaseStringSetProperty("settings.sessions.excludedPlayers"); + @Comment({ "Message language, available languages:", "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md" diff --git a/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java b/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java index 01cd1e9cf7..0ffb1c6811 100644 --- a/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java +++ b/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java @@ -14,6 +14,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Set; import java.util.function.Function; import static org.hamcrest.MatcherAssert.assertThat; @@ -50,6 +51,7 @@ static void initLogger() { @BeforeEach void createSessionService() { given(commonService.getProperty(PluginSettings.SESSIONS_ENABLED)).willReturn(true); + given(commonService.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS)).willReturn(Set.of()); sessionService = new SessionService(commonService, bukkitService, dataSource); } @@ -81,7 +83,9 @@ void shouldCheckIfUserHasSession() { // then assertThat(result, equalTo(false)); - verify(commonService, only()).getProperty(PluginSettings.SESSIONS_ENABLED); + verify(commonService).getProperty(PluginSettings.SESSIONS_ENABLED); + verify(commonService).getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); + verifyNoMoreInteractions(commonService); verify(dataSource, only()).hasSession(name); } @@ -177,6 +181,7 @@ void shouldEmitEventForValidSession() { assertThat(result, equalTo(true)); verify(commonService).getProperty(PluginSettings.SESSIONS_ENABLED); verify(commonService).getProperty(PluginSettings.SESSIONS_TIMEOUT); + verify(commonService).getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); verifyNoMoreInteractions(commonService); verify(dataSource).setUnlogged(name); verify(dataSource).revokeSession(name); @@ -222,6 +227,92 @@ void shouldHandlePlayerAuthWithNullLastIp() { verify(dataSource).revokeSession(name); } + @Test + void shouldNotResumeSessionForExcludedPlayer() { + // given + excludePlayers("bobby"); + String name = "Bobby"; + Player player = mock(Player.class); + given(player.getName()).willReturn(name); + given(dataSource.hasSession(name)).willReturn(true); + + // when + boolean result = sessionService.canResumeSession(player); + + // then + assertThat(result, equalTo(false)); + verify(dataSource).hasSession(name); + verify(dataSource).setUnlogged(name); + verify(dataSource).revokeSession(name); + verifyNoMoreInteractions(dataSource); + verifyNoInteractions(bukkitService); + } + + @Test + void shouldResumeSessionForPlayerNotInExclusionList() { + // given + excludePlayers("alice"); + String name = "Bobby"; + String ip = "127.3.12.15"; + Player player = mockPlayerWithNameAndIp(name, ip); + given(commonService.getProperty(PluginSettings.SESSIONS_TIMEOUT)).willReturn(8); + given(dataSource.hasSession(name)).willReturn(true); + PlayerAuth auth = PlayerAuth.builder() + .name(name) + .lastLogin(System.currentTimeMillis() - 60 * 1000) + .lastIp(ip).build(); + given(dataSource.getAuth(name)).willReturn(auth); + given(bukkitService.createAndCallEvent(any(Function.class))).willReturn(new RestoreSessionEvent(player, false)); + + // when + boolean result = sessionService.canResumeSession(player); + + // then + assertThat(result, equalTo(true)); + } + + @Test + void shouldNotReportValidSessionForExcludedPlayer() { + // given + excludePlayers("bobby"); + + // when + boolean result = sessionService.hasValidSession("Bobby", "127.3.12.15"); + + // then + assertThat(result, equalTo(false)); + verifyNoInteractions(dataSource); + } + + @Test + void shouldNotGrantSessionToExcludedPlayer() { + // given + excludePlayers("bobby"); + + // when + sessionService.grantSession("Bobby"); + + // then + verifyNoInteractions(dataSource); + } + + @Test + void shouldGrantSessionToPlayerNotInExclusionList() { + // given + excludePlayers("alice"); + + // when + sessionService.grantSession("bobby"); + + // then + verify(dataSource, only()).grantSession("bobby"); + } + + private void excludePlayers(String... names) { + given(commonService.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS)).willReturn(Set.of(names)); + sessionService.reload(); + } + private static Player mockPlayerWithNameAndIp(String name, String ip) { Player player = mock(Player.class); given(player.getName()).willReturn(name); diff --git a/docs/config.md b/docs/config.md index 3018345f75..8881d0a62e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -123,6 +123,14 @@ settings: # After how many minutes should a session expire? # A player's session ends after the timeout or if his IP has changed timeout: 10 + # Players listed here never get their session restored and must + # always authenticate, even if their IP hasn't changed. + # Useful when several players share the same IP address. + # It is case-insensitive! Example: + # excludedPlayers: + # - 'playerOne' + # - 'playerTwo' + excludedPlayers: [] # Message language, available languages: # https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md messagesLanguage: en From af59e3eb5e1824eb1cb2d5a634e9a6cf3ad83785 Mon Sep 17 00:00:00 2001 From: Mykhailo Alipa <6442572+strobil@users.noreply.github.com> Date: Wed, 23 Sep 2026 23:26:38 +0200 Subject: [PATCH 2/2] feat(sessions): replace player exclusions with permission --- .../permission/PlayerStatePermission.java | 5 ++ .../process/login/AsynchronousLogin.java | 2 +- .../xephi/authme/service/SessionService.java | 27 ++++---- .../settings/properties/PluginSettings.java | 15 ----- authme-core/src/main/resources/plugin.yml | 4 ++ .../authme/service/SessionServiceTest.java | 64 ++++++++++++------- authme-core/src/test/resources/plugin.yml | 4 ++ authme-folia/src/main/resources/plugin.yml | 4 ++ authme-paper/src/main/resources/plugin.yml | 4 ++ .../src/main/resources/plugin.yml | 4 ++ .../src/main/resources/plugin.yml | 4 ++ docs/config.md | 12 +--- docs/permission_nodes.md | 6 +- 13 files changed, 89 insertions(+), 66 deletions(-) diff --git a/authme-core/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/authme-core/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java index b9fe17e763..c4fd484797 100644 --- a/authme-core/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java +++ b/authme-core/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java @@ -31,6 +31,11 @@ public enum PlayerStatePermission implements PermissionNode { */ ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY), + /** + * Disables sessions for the player, requiring authentication on every join. + */ + DISABLE_SESSION("authme.session.disable", DefaultPermission.NOT_ALLOWED), + /** * Permission to bypass the purging process. */ diff --git a/authme-core/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/authme-core/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 96e4a09687..a5ae22f3ff 100644 --- a/authme-core/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/authme-core/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -345,7 +345,7 @@ private void doPerformLogin(Player player, PlayerAuth auth, boolean proxyInitiat // makes player loggedin playerCache.updatePlayer(auth); dataSource.setLogged(name); - sessionService.grantSession(name); + sessionService.grantSession(player); if (bungeeSender.isEnabled()) { // As described at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ diff --git a/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java b/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java index bacc24ebb2..030aacb44f 100644 --- a/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java +++ b/authme-core/src/main/java/fr/xephi/authme/service/SessionService.java @@ -7,13 +7,13 @@ import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.output.ConsoleLoggerFactory; import fr.xephi.authme.message.MessageKey; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.util.PlayerUtils; import org.bukkit.entity.Player; import javax.inject.Inject; -import java.util.Locale; -import java.util.Set; import static fr.xephi.authme.util.Utils.MILLIS_PER_MINUTE; @@ -26,15 +26,17 @@ public class SessionService implements Reloadable { private final CommonService service; private final BukkitService bukkitService; private final DataSource database; + private final PermissionsManager permissionsManager; private boolean isEnabled; - private Set excludedPlayers; @Inject - SessionService(CommonService service, BukkitService bukkitService, DataSource database) { + SessionService(CommonService service, BukkitService bukkitService, DataSource database, + PermissionsManager permissionsManager) { this.service = service; this.bukkitService = bukkitService; this.database = database; + this.permissionsManager = permissionsManager; reload(); } @@ -49,7 +51,7 @@ public boolean canResumeSession(Player player) { if (isEnabled && database.hasSession(name)) { database.setUnlogged(name); database.revokeSession(name); - if (isExcluded(name)) { + if (permissionsManager.hasPermission(player, PlayerStatePermission.DISABLE_SESSION)) { return false; } SessionState state = fetchSessionStatus(name, database.getAuth(name), PlayerUtils.getPlayerIp(player)); @@ -67,13 +69,15 @@ public boolean canResumeSession(Player player) { /** * Returns whether the given player name has a valid resumable session for the supplied IP address. * This check is side-effect free and can be used before a Bukkit {@link Player} instance exists. + * The permission is checked again against the player in {@link #canResumeSession(Player)} before login. * * @param playerName the player name * @param ipAddress the player's IP address * @return true if the player's session is currently valid, false otherwise */ public boolean hasValidSession(String playerName, String ipAddress) { - if (!isEnabled || ipAddress == null || isExcluded(playerName) || !database.hasSession(playerName)) { + if (!isEnabled || ipAddress == null || !database.hasSession(playerName) + || permissionsManager.hasPermissionOffline(playerName, PlayerStatePermission.DISABLE_SESSION)) { return false; } @@ -109,9 +113,9 @@ private SessionState fetchSessionStatus(String playerName, PlayerAuth auth, Stri return SessionState.OUTDATED; } - public void grantSession(String name) { - if (isEnabled && !isExcluded(name)) { - database.grantSession(name); + public void grantSession(Player player) { + if (isEnabled && !permissionsManager.hasPermission(player, PlayerStatePermission.DISABLE_SESSION)) { + database.grantSession(player.getName()); } } @@ -122,10 +126,5 @@ public void revokeSession(String name) { @Override public void reload() { this.isEnabled = service.getProperty(PluginSettings.SESSIONS_ENABLED); - this.excludedPlayers = service.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); - } - - private boolean isExcluded(String name) { - return excludedPlayers.contains(name.toLowerCase(Locale.ROOT)); } } diff --git a/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java index 307f89ebac..884021ca48 100644 --- a/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/authme-core/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -5,9 +5,6 @@ import ch.jalu.configme.properties.Property; import fr.xephi.authme.output.LogLevel; -import java.util.Set; - -import static ch.jalu.configme.properties.PropertyInitializer.newLowercaseStringSetProperty; import static ch.jalu.configme.properties.PropertyInitializer.newProperty; public final class PluginSettings implements SettingsHolder { @@ -30,18 +27,6 @@ public final class PluginSettings implements SettingsHolder { public static final Property SESSIONS_TIMEOUT = newProperty("settings.sessions.timeout", 10); - @Comment({ - "Players listed here never get their session restored and must", - "always authenticate, even if their IP hasn't changed.", - "Useful when several players share the same IP address.", - "It is case-insensitive! Example:", - "excludedPlayers:", - "- 'playerOne'", - "- 'playerTwo'" - }) - public static final Property> SESSIONS_EXCLUDED_PLAYERS = - newLowercaseStringSetProperty("settings.sessions.excludedPlayers"); - @Comment({ "Message language, available languages:", "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md" diff --git a/authme-core/src/main/resources/plugin.yml b/authme-core/src/main/resources/plugin.yml index caa3a3b42c..82345257cc 100644 --- a/authme-core/src/main/resources/plugin.yml +++ b/authme-core/src/main/resources/plugin.yml @@ -358,6 +358,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java b/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java index 0ffb1c6811..d8689941ae 100644 --- a/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java +++ b/authme-core/src/test/java/fr/xephi/authme/service/SessionServiceTest.java @@ -5,6 +5,8 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.RestoreSessionEvent; import fr.xephi.authme.message.MessageKey; +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.settings.properties.PluginSettings; import org.bukkit.entity.Player; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +16,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Set; import java.util.function.Function; import static org.hamcrest.MatcherAssert.assertThat; @@ -42,6 +43,8 @@ class SessionServiceTest { private CommonService commonService; @Mock private BukkitService bukkitService; + @Mock + private PermissionsManager permissionsManager; @BeforeAll static void initLogger() { @@ -51,8 +54,7 @@ static void initLogger() { @BeforeEach void createSessionService() { given(commonService.getProperty(PluginSettings.SESSIONS_ENABLED)).willReturn(true); - given(commonService.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS)).willReturn(Set.of()); - sessionService = new SessionService(commonService, bukkitService, dataSource); + sessionService = new SessionService(commonService, bukkitService, dataSource, permissionsManager); } @Test @@ -84,7 +86,6 @@ void shouldCheckIfUserHasSession() { // then assertThat(result, equalTo(false)); verify(commonService).getProperty(PluginSettings.SESSIONS_ENABLED); - verify(commonService).getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); verifyNoMoreInteractions(commonService); verify(dataSource, only()).hasSession(name); } @@ -181,7 +182,6 @@ void shouldEmitEventForValidSession() { assertThat(result, equalTo(true)); verify(commonService).getProperty(PluginSettings.SESSIONS_ENABLED); verify(commonService).getProperty(PluginSettings.SESSIONS_TIMEOUT); - verify(commonService).getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS); verifyNoMoreInteractions(commonService); verify(dataSource).setUnlogged(name); verify(dataSource).revokeSession(name); @@ -228,13 +228,13 @@ void shouldHandlePlayerAuthWithNullLastIp() { } @Test - void shouldNotResumeSessionForExcludedPlayer() { + void shouldNotResumeSessionForPlayerWithDisabledSessionPermission() { // given - excludePlayers("bobby"); String name = "Bobby"; Player player = mock(Player.class); given(player.getName()).willReturn(name); given(dataSource.hasSession(name)).willReturn(true); + given(permissionsManager.hasPermission(player, PlayerStatePermission.DISABLE_SESSION)).willReturn(true); // when boolean result = sessionService.canResumeSession(player); @@ -249,9 +249,8 @@ void shouldNotResumeSessionForExcludedPlayer() { } @Test - void shouldResumeSessionForPlayerNotInExclusionList() { + void shouldResumeSessionForPlayerWithoutDisabledSessionPermission() { // given - excludePlayers("alice"); String name = "Bobby"; String ip = "127.3.12.15"; Player player = mockPlayerWithNameAndIp(name, ip); @@ -272,45 +271,64 @@ void shouldResumeSessionForPlayerNotInExclusionList() { } @Test - void shouldNotReportValidSessionForExcludedPlayer() { + void shouldNotReportValidSessionForPlayerWithDisabledSessionPermission() { // given - excludePlayers("bobby"); + given(dataSource.hasSession("Bobby")).willReturn(true); + given(permissionsManager.hasPermissionOffline("Bobby", PlayerStatePermission.DISABLE_SESSION)) + .willReturn(true); // when boolean result = sessionService.hasValidSession("Bobby", "127.3.12.15"); // then assertThat(result, equalTo(false)); - verifyNoInteractions(dataSource); + verify(dataSource, only()).hasSession("Bobby"); } @Test - void shouldNotGrantSessionToExcludedPlayer() { + void shouldReportValidSessionForPlayerWithoutDisabledSessionPermission() { // given - excludePlayers("bobby"); + String name = "Bobby"; + String ip = "127.3.12.15"; + given(dataSource.hasSession(name)).willReturn(true); + given(commonService.getProperty(PluginSettings.SESSIONS_TIMEOUT)).willReturn(8); + given(dataSource.getAuth(name)).willReturn(PlayerAuth.builder() + .name(name) + .lastLogin(System.currentTimeMillis() - 60 * 1000) + .lastIp(ip).build()); // when - sessionService.grantSession("Bobby"); + boolean result = sessionService.hasValidSession(name, ip); // then - verifyNoInteractions(dataSource); + assertThat(result, equalTo(true)); + verify(permissionsManager).hasPermissionOffline(name, PlayerStatePermission.DISABLE_SESSION); } @Test - void shouldGrantSessionToPlayerNotInExclusionList() { + void shouldNotGrantSessionToPlayerWithDisabledSessionPermission() { // given - excludePlayers("alice"); + Player player = mock(Player.class); + given(permissionsManager.hasPermission(player, PlayerStatePermission.DISABLE_SESSION)).willReturn(true); // when - sessionService.grantSession("bobby"); + sessionService.grantSession(player); // then - verify(dataSource, only()).grantSession("bobby"); + verifyNoInteractions(dataSource); } - private void excludePlayers(String... names) { - given(commonService.getProperty(PluginSettings.SESSIONS_EXCLUDED_PLAYERS)).willReturn(Set.of(names)); - sessionService.reload(); + @Test + void shouldGrantSessionToPlayerWithoutDisabledSessionPermission() { + // given + Player player = mock(Player.class); + given(player.getName()).willReturn("bobby"); + + // when + sessionService.grantSession(player); + + // then + verify(dataSource, only()).grantSession("bobby"); } private static Player mockPlayerWithNameAndIp(String name, String ip) { diff --git a/authme-core/src/test/resources/plugin.yml b/authme-core/src/test/resources/plugin.yml index 7fda08fbd2..985ee87ecc 100644 --- a/authme-core/src/test/resources/plugin.yml +++ b/authme-core/src/test/resources/plugin.yml @@ -342,6 +342,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/authme-folia/src/main/resources/plugin.yml b/authme-folia/src/main/resources/plugin.yml index e206119f6f..4ea3c62b59 100644 --- a/authme-folia/src/main/resources/plugin.yml +++ b/authme-folia/src/main/resources/plugin.yml @@ -359,6 +359,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/authme-paper/src/main/resources/plugin.yml b/authme-paper/src/main/resources/plugin.yml index a001d537f9..d23d91ce83 100644 --- a/authme-paper/src/main/resources/plugin.yml +++ b/authme-paper/src/main/resources/plugin.yml @@ -358,6 +358,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/authme-spigot-1.21/src/main/resources/plugin.yml b/authme-spigot-1.21/src/main/resources/plugin.yml index a001d537f9..d23d91ce83 100644 --- a/authme-spigot-1.21/src/main/resources/plugin.yml +++ b/authme-spigot-1.21/src/main/resources/plugin.yml @@ -358,6 +358,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/authme-spigot-legacy/src/main/resources/plugin.yml b/authme-spigot-legacy/src/main/resources/plugin.yml index a001d537f9..d23d91ce83 100644 --- a/authme-spigot-legacy/src/main/resources/plugin.yml +++ b/authme-spigot-legacy/src/main/resources/plugin.yml @@ -358,6 +358,10 @@ permissions: authme.player.unregister: description: Command permission to unregister. default: true + authme.session.disable: + description: Disables sessions for the player, requiring authentication on every + join. + default: false authme.vip: description: When the server is full and someone with this permission joins the server, someone will be kicked. diff --git a/docs/config.md b/docs/config.md index 8881d0a62e..150d31b52e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,5 +1,5 @@ - + ## AuthMe Configuration The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, @@ -123,14 +123,6 @@ settings: # After how many minutes should a session expire? # A player's session ends after the timeout or if his IP has changed timeout: 10 - # Players listed here never get their session restored and must - # always authenticate, even if their IP hasn't changed. - # Useful when several players share the same IP address. - # It is case-insensitive! Example: - # excludedPlayers: - # - 'playerOne' - # - 'playerTwo' - excludedPlayers: [] # Message language, available languages: # https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md messagesLanguage: en @@ -657,4 +649,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 Tue May 19 08:22:43 CEST 2026 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Wed Sep 23 23:23:54 CEST 2026 diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 02b47abd1a..3f61944006 100644 --- a/docs/permission_nodes.md +++ b/docs/permission_nodes.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. @@ -76,9 +76,9 @@ and Paper 1.21 builds. - **authme.player.totpadd** – Permission to enable two-factor authentication. - **authme.player.totpremove** – Permission to disable two-factor authentication. - **authme.player.unregister** – Command permission to unregister. +- **authme.session.disable** – Disables sessions for the player, requiring authentication on every join. - **authme.vip** – When the server is full and someone with this permission joins the server, someone will be kicked. - --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Wed May 06 10:21:25 CEST 2026 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Wed Sep 23 23:24:40 CEST 2026