Skip to content

Commit 8b41f72

Browse files
committed
fix(paper): deny a pre-join connection whose name claim was taken over
1 parent 39eed4e commit 8b41f72

4 files changed

Lines changed: 58 additions & 4 deletions

File tree

‎authme-paper-common/src/main/java/fr/xephi/authme/listener/PaperLoginValidationListener.java‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public class PaperLoginValidationListener implements Listener {
2828

2929
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
3030

31-
/** Extra time a name stays claimed on top of the configured login / register timeout. */
32-
private static final long CLAIM_GRACE_MILLIS = TimeUnit.SECONDS.toMillis(10);
31+
/** Safety net for a connection that never reports itself as gone; not the release mechanism. */
32+
private static final long CLAIM_GRACE_MILLIS = TimeUnit.SECONDS.toMillis(60);
3333

3434
@Inject
3535
private OnJoinVerifier onJoinVerifier;
@@ -110,8 +110,18 @@ private void verifyConfigurationPhase(PlayerConnectionValidateLoginEvent event,
110110
PlayerConfigurationConnection connection) {
111111
PlayerProfile profile = connection.getProfile();
112112
String playerName = profile == null ? null : profile.getName();
113-
// No claim means an online player being reconfigured, which must not be checked against itself
114-
if (playerName == null || !pendingConnectionRegistry.holdsClaim(playerName, connection)) {
113+
if (playerName == null) {
114+
return;
115+
}
116+
117+
// This connection held the name to get here, so losing it means another one took it over
118+
if (pendingConnectionRegistry.isClaimedByOtherConnection(playerName, connection)) {
119+
denyConnection(event, playerName, MessageKey.USERNAME_ALREADY_ONLINE_ERROR);
120+
return;
121+
}
122+
123+
// No claim at all means an online player being reconfigured, never checked against itself
124+
if (!pendingConnectionRegistry.holdsClaim(playerName, connection)) {
115125
return;
116126
}
117127

‎authme-paper-common/src/main/java/fr/xephi/authme/service/PendingConnectionRegistry.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public boolean holdsClaim(String name, PlayerConnection connection) {
3333
return claim != null && !claim.isStale() && claim.isHeldBy(connectionKey(connection));
3434
}
3535

36+
public boolean isClaimedByOtherConnection(String name, PlayerConnection connection) {
37+
Claim claim = claims.get(normalize(name));
38+
return claim != null && !claim.isStale() && !claim.isHeldBy(connectionKey(connection));
39+
}
40+
3641
public void release(String name) {
3742
claims.remove(normalize(name));
3843
}

‎authme-paper-common/src/test/java/fr/xephi/authme/listener/PaperLoginValidationListenerTest.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,20 @@ public void shouldIgnoreReconfigurationOfPlayerWithoutClaim() {
115115
assertThat(event.isAllowed(), is(true));
116116
}
117117

118+
@Test
119+
public void shouldKickWhenClaimWasTakenOverDuringConfiguration() {
120+
PlayerConfigurationConnection connection = newConfigurationConnection("Bobby");
121+
given(pendingConnectionRegistry.isClaimedByOtherConnection("Bobby", connection)).willReturn(true);
122+
givenAlreadyOnlineMessage();
123+
PlayerConnectionValidateLoginEvent event = new PlayerConnectionValidateLoginEvent(connection, null);
124+
125+
listener.onPlayerConnectionValidateLogin(event);
126+
127+
assertThat(event.isAllowed(), is(false));
128+
assertThat(serialize(event.getKickMessage()), is("&cAlready online"));
129+
verifyNoInteractions(onJoinVerifier);
130+
}
131+
118132
@Test
119133
public void shouldVerifySingleSessionWhenFinishingConfiguration() throws FailedVerificationException {
120134
givenConfiguredTimeouts();

‎authme-paper-common/src/test/java/fr/xephi/authme/service/PendingConnectionRegistryTest.java‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,31 @@ public void shouldRefuseSecondLiveConnectionWithSameName() {
5353
assertThat(registry.holdsClaim("Bobby", first), is(true));
5454
}
5555

56+
@Test
57+
public void shouldReportNameClaimedByAnotherLiveConnection() {
58+
PlayerConnection holder = newConnection(50_000);
59+
PlayerConnection other = newConnection(50_001);
60+
registry.tryClaim("Bobby", holder, TTL);
61+
62+
assertThat(registry.isClaimedByOtherConnection("Bobby", other), is(true));
63+
assertThat(registry.isClaimedByOtherConnection("Bobby", holder), is(false));
64+
}
65+
66+
@Test
67+
public void shouldNotReportStaleOrMissingClaimAsHeldByAnotherConnection() {
68+
PlayerConnection other = newConnection(50_001);
69+
70+
assertThat(registry.isClaimedByOtherConnection("Bobby", other), is(false));
71+
72+
PlayerConnection gone = newConnection(50_000);
73+
registry.tryClaim("Bobby", gone, TTL);
74+
given(gone.isConnected()).willReturn(false);
75+
assertThat(registry.isClaimedByOtherConnection("Bobby", other), is(false));
76+
77+
registry.tryClaim("Alice", newConnection(50_002), -1L);
78+
assertThat(registry.isClaimedByOtherConnection("Alice", other), is(false));
79+
}
80+
5681
@Test
5782
public void shouldAllowSameConnectionToRenewItsClaim() {
5883
PlayerConnection connection = newConnection(50_000);

0 commit comments

Comments
 (0)