From e56fd2d3e400fd2ede9cd2a5f4e1ee47891f3e96 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 4 Jul 2019 14:51:59 +0200 Subject: [PATCH] Merge pull request #4096 from jvz/JENKINS-56243 [JENKINS-56243] Ensure user seed saved to session (cherry picked from commit a0095dc1eee06dcb485406e0ee63c586060be53d) --- .../TokenBasedRememberMeServices2.java | 8 +++ .../TokenBasedRememberMeServices2Test.java | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java index 71ba57c692..9b7966b5d4 100644 --- a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java +++ b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java @@ -269,6 +269,14 @@ public class TokenBasedRememberMeServices2 extends TokenBasedRememberMeServices userDetails.getAuthorities()); auth.setDetails(authenticationDetailsSource.buildDetails(request)); + // Ensure this session is linked to the user's seed + if (!UserSeedProperty.DISABLE_USER_SEED) { + User user = User.get(auth); + UserSeedProperty userSeed = user.getProperty(UserSeedProperty.class); + String sessionSeed = userSeed.getSeed(); + request.getSession().setAttribute(UserSeedProperty.USER_SESSION_SEED, sessionSeed); + } + return auth; } diff --git a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java index e98eb4354a..8b711c899d 100644 --- a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java +++ b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java @@ -8,6 +8,7 @@ import java.util.Arrays; import static java.util.logging.Level.FINEST; import java.util.stream.Collectors; +import hudson.model.User; import jenkins.model.Jenkins; import jenkins.security.seed.UserSeedProperty; @@ -29,8 +30,11 @@ import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.LoggerRule; +import org.kohsuke.stapler.Stapler; import org.springframework.dao.DataAccessException; +import test.security.realm.InMemorySecurityRealm; +import javax.annotation.concurrent.GuardedBy; import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.is; @@ -289,6 +293,51 @@ public class TokenBasedRememberMeServices2Test { } } + @Test + @Issue("JENKINS-56243") + public void rememberMeToken_shouldLoadUserDetailsOnlyOnce() throws Exception { + j.jenkins.setDisableRememberMe(false); + LoadUserCountingSecurityRealm realm = new LoadUserCountingSecurityRealm(); + realm.createAccount("alice"); + j.jenkins.setSecurityRealm(realm); + User alice = User.getOrCreateByIdOrFullName("alice"); + realm.verifyInvocations(1); + + // first, start a session with a remember me token + Cookie cookie = getRememberMeCookie(j.createWebClient().login("alice", "alice", true)); + // next, start a new session with that token + JenkinsRule.WebClient wc = j.createWebClient(); + wc.getCookieManager().addCookie(cookie); + // trigger remember me + String sessionSeed = wc.executeOnServer(() -> Stapler.getCurrentRequest().getSession(false).getAttribute(UserSeedProperty.USER_SESSION_SEED).toString()); + realm.verifyInvocations(1); + String userSeed = alice.getProperty(UserSeedProperty.class).getSeed(); + + assertEquals(userSeed, sessionSeed); + + // finally, ensure that loadUserByUsername is not being called anymore + wc.goTo(""); + assertUserConnected(wc, "alice"); + realm.verifyInvocations(0); + } + + private static class LoadUserCountingSecurityRealm extends InMemorySecurityRealm { + // if this class wasn't serialized into config.xml, this could be replaced by @Spy from Mockito + @GuardedBy("this") + private int counter = 0; + + @Override + public synchronized UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { + ++counter; + return super.loadUserByUsername(username); + } + + synchronized void verifyInvocations(int count) { + assertEquals(count, counter); + counter = 0; + } + } + private Cookie createRememberMeCookie(TokenBasedRememberMeServices2 tokenService, long deltaDuration, hudson.model.User user) throws Exception { long tokenValiditySeconds = tokenService.getTokenValiditySeconds(); long expiryTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(tokenValiditySeconds);