From 9dafa6a67326e37371c4583b187de3fbc7216074 Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Tue, 3 Sep 2024 08:54:28 -0400 Subject: [PATCH 1/8] all support for "traditional api token access" --- .../plugins/oic/OicSecurityRealm.java | 34 ++++++++ .../plugins/oic/OicSecurityRealm/config.jelly | 3 + .../oic/OicSecurityRealm/config.properties | 3 +- ...help-traditionalApiTokenAccessEnabled.html | 7 ++ .../org/jenkinsci/plugins/oic/PluginTest.java | 80 +++++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html diff --git a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java index 3cdf9cb4..fb4bca65 100644 --- a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java +++ b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java @@ -83,6 +83,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -102,6 +103,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import jenkins.model.Jenkins; +import jenkins.security.ApiTokenProperty; import jenkins.security.SecurityListener; import org.apache.commons.lang.StringUtils; import org.kohsuke.accmod.Restricted; @@ -218,6 +220,10 @@ public static enum TokenAuthMethod { */ private boolean tokenExpirationCheckDisabled = false; + /** Flag to enable traditional Jenkins API token based access (no OicSession needed) + */ + private boolean traditionalApiTokenAccessEnabled = false; + /** Additional number of seconds to add to token expiration */ private Long allowedTokenExpirationClockSkewSeconds = 60L; @@ -539,6 +545,10 @@ public boolean isTokenExpirationCheckDisabled() { return tokenExpirationCheckDisabled; } + public boolean isTraditionalApiTokenAccessEnabled() { + return traditionalApiTokenAccessEnabled; + } + public Long getAllowedTokenExpirationClockSkewSeconds() { return allowedTokenExpirationClockSkewSeconds; } @@ -807,6 +817,11 @@ public void setTokenExpirationCheckDisabled(boolean tokenExpirationCheckDisabled this.tokenExpirationCheckDisabled = tokenExpirationCheckDisabled; } + @DataBoundSetter + public void setTraditionalApiTokenAccessEnabled(boolean traditionalApiTokenAccessEnabled) { + this.traditionalApiTokenAccessEnabled = traditionalApiTokenAccessEnabled; + } + @DataBoundSetter public void setAllowedTokenExpirationClockSkewSeconds(Long allowedTokenExpirationClockSkewSeconds) { this.allowedTokenExpirationClockSkewSeconds = allowedTokenExpirationClockSkewSeconds; @@ -1394,6 +1409,25 @@ public boolean handleTokenExpiration(HttpServletRequest httpRequest, HttpServlet User user = User.get2(authentication); + if (isTraditionalApiTokenAccessEnabled()) { + // check if this is a valid api token based request + if (httpRequest.getHeader("Authorization") != null) { + String token = new String( + Base64.getDecoder() + .decode(httpRequest + .getHeader("Authorization") + .substring(6)), + StandardCharsets.UTF_8) + .split(":")[1]; + + if (user.getProperty(ApiTokenProperty.class).matchesPassword(token)) { + // this was a valid jenkins token being used, exit this filter and let + // the rest of chain be processed + return true; + } // else do nothing and continue evaluating this request + } + } + if (user == null) { return true; } diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly index 0f807044..c868db01 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly @@ -113,6 +113,9 @@ + + + diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties index cbf370fd..fb3da34e 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties @@ -38,4 +38,5 @@ UsernameFieldName=User name field name WellknownConfigurationEndpoint=Well-known configuration endpoint UseRefreshTokens=Enable Token Refresh using Refresh Tokens DisableTokenExpirationCheck=Disable Token Expiration Check -AllowedTokenExpirationClockSkewSeconds=Token Expiry Expiration Clock Skew \ No newline at end of file +AllowedTokenExpirationClockSkewSeconds=Token Expiry Expiration Clock Skew +EnableTraditionalApiTokenAccess=Enable Tradition Jenkins API token access \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html new file mode 100644 index 00000000..e55d942a --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html @@ -0,0 +1,7 @@ +
+ Enabling this functionality allows Jenkins API token based access even if the associated user has + completly logged out from Jenkins and the OIC Provider. + + The default behavior is to require any Jenkins API token based access to have an valid OIC session user + session associated with it. +
\ No newline at end of file diff --git a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java index 7a164f0d..db9d9ec1 100644 --- a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java +++ b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java @@ -20,6 +20,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; @@ -37,6 +38,7 @@ import java.util.regex.Pattern; import javax.servlet.http.HttpSession; import jenkins.model.Jenkins; +import jenkins.security.ApiTokenProperty; import jenkins.security.LastGrantedAuthoritiesProperty; import org.hamcrest.MatcherAssert; import org.junit.Before; @@ -65,6 +67,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static com.google.gson.JsonParser.parseString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.jenkinsci.plugins.oic.TestRealm.AUTO_CONFIG_FIELD; @@ -365,6 +368,37 @@ private HttpResponse getPageWithGet(String url) throws IOException, Inte HttpResponse.BodyHandlers.ofString()); } + /** + * performs a GET request using a basic authorization header + * @param user - The user id + * @param token - the password api token to user + * @param url - the url to request + * @return HttpResponse + * @throws IOException + * @throws InterruptedException + */ + private HttpResponse getPageWithGet(String user, String token, String url) + throws IOException, InterruptedException { + // fix up the url, if needed + if (url.startsWith("/")) { + url = url.substring(1); + } + + HttpClient c = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.ALWAYS) + .build(); + return c.send( + HttpRequest.newBuilder(URI.create(jenkinsRule.getURL() + url)) + .header( + "Authorization", + "Basic " + + Base64.getEncoder() + .encodeToString((user + ":" + token).getBytes(StandardCharsets.UTF_8))) + .GET() + .build(), + HttpResponse.BodyHandlers.ofString()); + } + @Test public void testRefreshTokenAndTokenExpiration_withoutRefreshToken() throws Exception { mockAuthorizationRedirectsToFinishLogin(); @@ -943,6 +977,52 @@ public void loginWithCheckTokenFailure() throws Exception { assertAnonymous(); } + @Test + public void testAccessUsingJenkinsApiTokens() throws Exception { + mockAuthorizationRedirectsToFinishLogin(); + configureWellKnown(null, null, "authorization_code"); + jenkins.setSecurityRealm(new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, AUTO_CONFIG_FIELD)); + // login and assert normal auth is working + mockTokenReturnsIdTokenWithGroup(PluginTest::withoutRefreshToken); + mockUserInfoWithTestGroups(); + browseLoginPage(); + assertTestUser(); + + // create a jenkins api token for the test user + String token = User.getById(TEST_USER_USERNAME, false) + .getProperty(ApiTokenProperty.class) + .generateNewToken("foo") + .plainValue; + + // validate that the token can be used + HttpResponse rsp = getPageWithGet(TEST_USER_USERNAME, token, "/whoAmI/api/xml"); + MatcherAssert.assertThat("response should have been 200\n" + rsp.body(), rsp.statusCode(), is(200)); + + MatcherAssert.assertThat( + "response should have been 200\n" + rsp.body(), + rsp.body(), + containsString("true")); + + // expired oic session tokens, do not refreshed + expire(); + + // verify that jenkins api token is not authorized + rsp = getPageWithGet(TEST_USER_USERNAME, token, "/whoAmI/api/xml"); + MatcherAssert.assertThat("response should have been 401\n" + rsp.body(), rsp.statusCode(), is(401)); + + // enable "traditional api token access" + TestRealm tr = (TestRealm) jenkins.getSecurityRealm(); + tr.setTraditionalApiTokenAccessEnabled(true); + + // verify that jenkins api token is now working again + rsp = getPageWithGet(TEST_USER_USERNAME, token, "/whoAmI/api/xml"); + MatcherAssert.assertThat("response should have been 200\n" + rsp.body(), rsp.statusCode(), is(200)); + MatcherAssert.assertThat( + "response should have been 200\n" + rsp.body(), + rsp.body(), + containsString("true")); + } + private static @NonNull Consumer belongsToGroup(String groupName) { return sc -> { sc.setTokenFieldToCheckKey("contains(groups, '" + groupName + "')"); From bbc62956e6d90aca3a95ac95e2d90585e0eccb04 Mon Sep 17 00:00:00 2001 From: michael cirioli Date: Tue, 3 Sep 2024 09:53:44 -0400 Subject: [PATCH 2/8] Update src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties Co-authored-by: Antonio Muniz --- .../jenkinsci/plugins/oic/OicSecurityRealm/config.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties index fb3da34e..4b846b6b 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties @@ -39,4 +39,4 @@ WellknownConfigurationEndpoint=Well-known configuration endpoint UseRefreshTokens=Enable Token Refresh using Refresh Tokens DisableTokenExpirationCheck=Disable Token Expiration Check AllowedTokenExpirationClockSkewSeconds=Token Expiry Expiration Clock Skew -EnableTraditionalApiTokenAccess=Enable Tradition Jenkins API token access \ No newline at end of file +EnableTraditionalApiTokenAccess=Enable Traditional Jenkins API token access \ No newline at end of file From dde5121ed75f63834524a3c884cd193c71ead1e1 Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Tue, 3 Sep 2024 16:07:43 -0400 Subject: [PATCH 3/8] make help more detailed --- .../help-traditionalApiTokenAccessEnabled.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html index e55d942a..86f5fcbb 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html @@ -3,5 +3,6 @@ completly logged out from Jenkins and the OIC Provider. The default behavior is to require any Jenkins API token based access to have an valid OIC session user - session associated with it. + session associated with it. This means that the user associated with the Jenkins API token
    must
+ be logged in via the UI in order to use an API token for Jenkins CLI access. \ No newline at end of file From 31561d393b2c64505889f70e90a4a3bca599e8cf Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Tue, 3 Sep 2024 16:21:13 -0400 Subject: [PATCH 4/8] nits --- src/test/java/org/jenkinsci/plugins/oic/PluginTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java index db9d9ec1..62379377 100644 --- a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java +++ b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java @@ -1006,7 +1006,8 @@ public void testAccessUsingJenkinsApiTokens() throws Exception { // expired oic session tokens, do not refreshed expire(); - // verify that jenkins api token is not authorized + // the default behavior expects there to be a valid oic session, so token based + // access should now fail (unauthorized) rsp = getPageWithGet(TEST_USER_USERNAME, token, "/whoAmI/api/xml"); MatcherAssert.assertThat("response should have been 401\n" + rsp.body(), rsp.statusCode(), is(401)); From b5932fc582b26c7068ea8884ba1f1e8c040086f7 Mon Sep 17 00:00:00 2001 From: michael cirioli Date: Wed, 4 Sep 2024 09:02:28 -0400 Subject: [PATCH 5/8] better checking of auth header Co-authored-by: Vincent Latombe --- .../java/org/jenkinsci/plugins/oic/OicSecurityRealm.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java index fb4bca65..5b0f00af 100644 --- a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java +++ b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java @@ -1411,11 +1411,11 @@ public boolean handleTokenExpiration(HttpServletRequest httpRequest, HttpServlet if (isTraditionalApiTokenAccessEnabled()) { // check if this is a valid api token based request - if (httpRequest.getHeader("Authorization") != null) { + String authHeader = httpRequest.getHeader("Authorization"); + if (authHeader != null && authHeader.startsWith("Basic ")) { String token = new String( Base64.getDecoder() - .decode(httpRequest - .getHeader("Authorization") + .decode(authHeader .substring(6)), StandardCharsets.UTF_8) .split(":")[1]; From 8facd12857eae9a22999b7da3a5373f636326436 Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Wed, 4 Sep 2024 09:42:19 -0400 Subject: [PATCH 6/8] rename the flag --- .../plugins/oic/OicSecurityRealm.java | 18 +++++++----------- .../plugins/oic/OicSecurityRealm/config.jelly | 2 +- .../oic/OicSecurityRealm/config.properties | 2 +- ...elp-allowTokenAccessWithoutOicSession.html} | 0 4 files changed, 9 insertions(+), 13 deletions(-) rename src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/{help-traditionalApiTokenAccessEnabled.html => help-allowTokenAccessWithoutOicSession.html} (100%) diff --git a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java index 5b0f00af..8d922da2 100644 --- a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java +++ b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java @@ -222,7 +222,7 @@ public static enum TokenAuthMethod { /** Flag to enable traditional Jenkins API token based access (no OicSession needed) */ - private boolean traditionalApiTokenAccessEnabled = false; + private boolean allowTokenAccessWithoutOicSession = false; /** Additional number of seconds to add to token expiration */ @@ -545,8 +545,8 @@ public boolean isTokenExpirationCheckDisabled() { return tokenExpirationCheckDisabled; } - public boolean isTraditionalApiTokenAccessEnabled() { - return traditionalApiTokenAccessEnabled; + public boolean isAllowTokenAccessWithoutOicSession() { + return allowTokenAccessWithoutOicSession; } public Long getAllowedTokenExpirationClockSkewSeconds() { @@ -818,8 +818,8 @@ public void setTokenExpirationCheckDisabled(boolean tokenExpirationCheckDisabled } @DataBoundSetter - public void setTraditionalApiTokenAccessEnabled(boolean traditionalApiTokenAccessEnabled) { - this.traditionalApiTokenAccessEnabled = traditionalApiTokenAccessEnabled; + public void setAllowTokenAccessWithoutOicSession(boolean allowTokenAccessWithoutOicSession) { + this.allowTokenAccessWithoutOicSession = allowTokenAccessWithoutOicSession; } @DataBoundSetter @@ -1409,15 +1409,11 @@ public boolean handleTokenExpiration(HttpServletRequest httpRequest, HttpServlet User user = User.get2(authentication); - if (isTraditionalApiTokenAccessEnabled()) { + if (isAllowTokenAccessWithoutOicSession()) { // check if this is a valid api token based request String authHeader = httpRequest.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Basic ")) { - String token = new String( - Base64.getDecoder() - .decode(authHeader - .substring(6)), - StandardCharsets.UTF_8) + String token = new String(Base64.getDecoder().decode(authHeader.substring(6)), StandardCharsets.UTF_8) .split(":")[1]; if (user.getProperty(ApiTokenProperty.class).matchesPassword(token)) { diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly index c868db01..6f758789 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.jelly @@ -113,7 +113,7 @@ - + diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties index 4b846b6b..daf01cf1 100644 --- a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties +++ b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/config.properties @@ -39,4 +39,4 @@ WellknownConfigurationEndpoint=Well-known configuration endpoint UseRefreshTokens=Enable Token Refresh using Refresh Tokens DisableTokenExpirationCheck=Disable Token Expiration Check AllowedTokenExpirationClockSkewSeconds=Token Expiry Expiration Clock Skew -EnableTraditionalApiTokenAccess=Enable Traditional Jenkins API token access \ No newline at end of file +AllowTokenAccessWithoutOicSession=Allow access using a Jenkins API token without an OIDC Session \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html b/src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-allowTokenAccessWithoutOicSession.html similarity index 100% rename from src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-traditionalApiTokenAccessEnabled.html rename to src/main/resources/org/jenkinsci/plugins/oic/OicSecurityRealm/help-allowTokenAccessWithoutOicSession.html From 8f1e9036a3ba63f55ec79dd4705b89f774defcaa Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Wed, 4 Sep 2024 09:42:32 -0400 Subject: [PATCH 7/8] make the test more deterministic --- src/test/java/org/jenkinsci/plugins/oic/PluginTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java index 62379377..9e23c6cb 100644 --- a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java +++ b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java @@ -982,6 +982,10 @@ public void testAccessUsingJenkinsApiTokens() throws Exception { mockAuthorizationRedirectsToFinishLogin(); configureWellKnown(null, null, "authorization_code"); jenkins.setSecurityRealm(new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, AUTO_CONFIG_FIELD)); + // explicitly ensure allowTokenAccessWithoutOicSession is disabled + TestRealm testRealm = (TestRealm) jenkins.getSecurityRealm(); + testRealm.setAllowTokenAccessWithoutOicSession(true); + // login and assert normal auth is working mockTokenReturnsIdTokenWithGroup(PluginTest::withoutRefreshToken); mockUserInfoWithTestGroups(); @@ -1012,8 +1016,7 @@ public void testAccessUsingJenkinsApiTokens() throws Exception { MatcherAssert.assertThat("response should have been 401\n" + rsp.body(), rsp.statusCode(), is(401)); // enable "traditional api token access" - TestRealm tr = (TestRealm) jenkins.getSecurityRealm(); - tr.setTraditionalApiTokenAccessEnabled(true); + testRealm.setAllowTokenAccessWithoutOicSession(true); // verify that jenkins api token is now working again rsp = getPageWithGet(TEST_USER_USERNAME, token, "/whoAmI/api/xml"); From 791ef3c11961e6165b4216c25cc86483af8ca0a9 Mon Sep 17 00:00:00 2001 From: mike cirioli Date: Wed, 4 Sep 2024 13:15:58 -0400 Subject: [PATCH 8/8] fix broken test --- src/test/java/org/jenkinsci/plugins/oic/PluginTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java index 9e23c6cb..c30a9e8c 100644 --- a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java +++ b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java @@ -984,7 +984,7 @@ public void testAccessUsingJenkinsApiTokens() throws Exception { jenkins.setSecurityRealm(new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, AUTO_CONFIG_FIELD)); // explicitly ensure allowTokenAccessWithoutOicSession is disabled TestRealm testRealm = (TestRealm) jenkins.getSecurityRealm(); - testRealm.setAllowTokenAccessWithoutOicSession(true); + testRealm.setAllowTokenAccessWithoutOicSession(false); // login and assert normal auth is working mockTokenReturnsIdTokenWithGroup(PluginTest::withoutRefreshToken);