Skip to content

Commit

Permalink
Restructure and split tests
Browse files Browse the repository at this point in the history
  • Loading branch information
eva-mueller-coremedia committed Dec 19, 2024
1 parent e64f086 commit f01051e
Show file tree
Hide file tree
Showing 6 changed files with 1,047 additions and 811 deletions.
109 changes: 109 additions & 0 deletions src/test/java/org/jenkinsci/plugins/oic/PluginApiTokenTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.jenkinsci.plugins.oic;

Check warning on line 1 in src/test/java/org/jenkinsci/plugins/oic/PluginApiTokenTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (misc) NewlineAtEndOfFile: Expected line ending for file is LF(\n), but CRLF(\r\n) is detected.

import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import hudson.model.User;
import java.net.http.HttpResponse;
import jenkins.model.Jenkins;
import jenkins.security.ApiTokenProperty;
import org.hamcrest.MatcherAssert;
import org.jenkinsci.plugins.oic.plugintest.Mocks;
import org.jenkinsci.plugins.oic.plugintest.TestHelper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.DisableOnDebug;
import org.jvnet.hudson.test.JenkinsRule;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;

/**
* goes through a login scenario, the openid provider is mocked and always
* returns state. We aren't checking if openid connect or if the openid
* connect implementation works. Rather we are only checking if the jenkins
* interaction works and if the plugin code works.
*/
public class PluginApiTokenTest {

@Rule
public WireMockRule wireMockRule = new WireMockRule(
new WireMockConfiguration()
.dynamicPort()
.dynamicHttpsPort()
.notifier(new ConsoleNotifier(new DisableOnDebug(null).isDebugging())),
true);

@Rule
public JenkinsRule jenkinsRule = new JenkinsRule();

private JenkinsRule.WebClient webClient;
private Jenkins jenkins;

@Before
public void setUp() {
jenkins = jenkinsRule.getInstance();
webClient = jenkinsRule.createWebClient();
if (new DisableOnDebug(null).isDebugging()) {
webClient.getOptions().setTimeout(0);
}
}

@Test
public void testAccessJenkinsUsingApiTokens() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code");

TestRealm testRealm = new TestRealm.Builder(wireMockRule)
.WithMinimalDefaults()
.WithAutomanualconfigure(true)
// explicitly ensure allowTokenAccessWithoutOicSession is disabled
.WithAllowTokenAccessWithoutOicSession(false)
.build();

jenkins.setSecurityRealm(testRealm);

// login and assert normal auth is working
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule, TestHelper::withoutRefreshToken);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
TestHelper.assertTestUser(webClient);

User user = User.getById(TestHelper.TEST_USER_USERNAME, false);
assertNotNull("User must not be null", user);

// create a jenkins api token for the test user
String token = user.getProperty(ApiTokenProperty.class).generateNewToken("foo").plainValue;

// validate that the token can be used
HttpResponse<String> rsp =
TestHelper.getPageWithGet(jenkinsRule, TestHelper.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("<authenticated>true</authenticated>"));

// expired oic session tokens, do not refreshed
TestHelper.expire(webClient);

// the default behavior expects there to be a valid oic session, so token based
// access should now fail (unauthorized)
rsp = TestHelper.getPageWithGet(jenkinsRule, TestHelper.TEST_USER_USERNAME, token, "/whoAmI/api/xml");
MatcherAssert.assertThat("response should have been 302\n" + rsp.body(), rsp.statusCode(), is(302));

// enable "traditional api token access"
testRealm.setAllowTokenAccessWithoutOicSession(true);

// verify that jenkins api token is now working again
rsp = TestHelper.getPageWithGet(jenkinsRule, TestHelper.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("<authenticated>true</authenticated>"));
}
}
194 changes: 194 additions & 0 deletions src/test/java/org/jenkinsci/plugins/oic/PluginRefreshTokenTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package org.jenkinsci.plugins.oic;

Check warning on line 1 in src/test/java/org/jenkinsci/plugins/oic/PluginRefreshTokenTest.java

View check run for this annotation

ci.jenkins.io / Java Compiler

checkstyle:check

ERROR: (misc) NewlineAtEndOfFile: Expected line ending for file is LF(\n), but CRLF(\r\n) is detected.

import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.nimbusds.oauth2.sdk.GrantType;
import java.net.http.HttpResponse;
import jenkins.model.Jenkins;
import org.hamcrest.MatcherAssert;
import org.jenkinsci.plugins.oic.plugintest.Mocks;
import org.jenkinsci.plugins.oic.plugintest.TestHelper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.DisableOnDebug;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.Url;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.containing;
import static com.github.tomakehurst.wiremock.client.WireMock.notMatching;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static org.hamcrest.Matchers.is;
import static org.jenkinsci.plugins.oic.TestRealm.EMAIL_FIELD;
import static org.jenkinsci.plugins.oic.TestRealm.GROUPS_FIELD;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
* goes through a login scenario, the openid provider is mocked and always
* returns state. We aren't checking if openid connect or if the openid
* connect implementation works. Rather we are only checking if the jenkins
* interaction works and if the plugin code works.
*/
@Url("https://jenkins.io/blog/2018/01/13/jep-200/")
public class PluginRefreshTokenTest {

private static final String[] TEST_USER_GROUPS_REFRESHED = new String[] {"group1", "group2", "group3"};

@Rule
public WireMockRule wireMockRule = new WireMockRule(
new WireMockConfiguration()
.dynamicPort()
.dynamicHttpsPort()
.notifier(new ConsoleNotifier(new DisableOnDebug(null).isDebugging())),
true);

@Rule
public JenkinsRule jenkinsRule = new JenkinsRule();

private JenkinsRule.WebClient webClient;
private Jenkins jenkins;

@Before
public void setUp() {
jenkins = jenkinsRule.getInstance();
webClient = jenkinsRule.createWebClient();
if (new DisableOnDebug(null).isDebugging()) {
webClient.getOptions().setTimeout(0);
}
}

@Test
public void testConfigurationWithAutoConfiguration_withRefreshToken() throws Exception {
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code", "refresh_token");
TestRealm testRealm = new TestRealm.Builder(wireMockRule)
.WithMinimalDefaults().WithAutomanualconfigure(true).build();
jenkins.setSecurityRealm(testRealm);
assertTrue(
"Refresh token should be enabled",
testRealm
.getServerConfiguration()
.toProviderMetadata()
.getGrantTypes()
.contains(GrantType.REFRESH_TOKEN));
}

@Test
public void testRefreshToken_validAndExtendedToken() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code", "refresh_token");
jenkins.setSecurityRealm(new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, true));
// user groups on first login
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
var user = TestHelper.assertTestUser(webClient);
assertFalse(
"User should not be part of group " + TEST_USER_GROUPS_REFRESHED[2],
user.getAuthorities().contains(TEST_USER_GROUPS_REFRESHED[2]));

// refresh user with different groups
Mocks.mockTokenReturnsIdTokenWithValues(
wireMockRule, TestHelper.setUpKeyValuesWithGroup(TEST_USER_GROUPS_REFRESHED));
Mocks.mockUserInfoWithGroups(wireMockRule, TEST_USER_GROUPS_REFRESHED);
TestHelper.expire(webClient);
webClient.goTo(jenkins.getSearchUrl());

user = TestHelper.assertTestUser(webClient);
assertTrue(
"User should be part of group " + TEST_USER_GROUPS_REFRESHED[2],
user.getAuthorities().contains(TEST_USER_GROUPS_REFRESHED[2]));

verify(postRequestedFor(urlPathEqualTo("/token")).withRequestBody(containing("grant_type=refresh_token")));
}

@Test
public void testRefreshTokenAndTokenExpiration_withoutRefreshToken() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code");
jenkins.setSecurityRealm(new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, true));
// login
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule, TestHelper::withoutRefreshToken);
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
TestHelper.assertTestUser(webClient);
// expired token not refreshed
TestHelper.expire(webClient);
// use an actual HttpClient to make checking redirects easier
HttpResponse<String> rsp = TestHelper.getPageWithGet(jenkinsRule, "/manage");
MatcherAssert.assertThat("response should have been 302\n" + rsp.body(), rsp.statusCode(), is(302));
verify(postRequestedFor(urlPathEqualTo("/token")).withRequestBody(notMatching(".*grant_type=refresh_token.*")));
}

@Test
public void testRefreshTokenWithTokenExpirationCheckDisabled_withoutRefreshToken() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code");
var realm = new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, true);
realm.setTokenExpirationCheckDisabled(true);
jenkins.setSecurityRealm(realm);
// login
Mocks.mockTokenReturnsIdTokenWithoutValues(wireMockRule);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
TestHelper.assertTestUser(webClient);

TestHelper.expire(webClient);
webClient.goTo(jenkins.getSearchUrl());

verify(postRequestedFor(urlPathEqualTo("/token")).withRequestBody(notMatching(".*grant_type=refresh_token.*")));
}

@Test
public void testRefreshTokenWithTokenExpirationCheckDisabled_expiredRefreshToken() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code", "refresh_token");
TestRealm testRealm = new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, true);
testRealm.setTokenExpirationCheckDisabled(true);
jenkins.setSecurityRealm(testRealm);
// login
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
TestHelper.assertTestUser(webClient);

wireMockRule.stubFor(post(urlPathEqualTo("/token"))
.willReturn(aResponse()
.withStatus(400)
.withHeader("Content-Type", "application/json")
.withBody("{ \"error\": \"invalid_grant\" }")));
TestHelper.expire(webClient);
webClient.goTo(jenkins.getSearchUrl(), "");

verify(postRequestedFor(urlPathEqualTo("/token")).withRequestBody(containing("grant_type=refresh_token")));
}

@Test
public void testRefreshTokenAndTokenExpiration_expiredRefreshToken() throws Exception {
Mocks.mockAuthorizationRedirectsToFinishLogin(wireMockRule, jenkins);
TestHelper.configureWellKnown(wireMockRule, null, null, "authorization_code", "refresh_token");
TestRealm testRealm = new TestRealm(wireMockRule, null, EMAIL_FIELD, GROUPS_FIELD, true);
jenkins.setSecurityRealm(testRealm);
// login
Mocks.mockTokenReturnsIdTokenWithGroup(wireMockRule);
Mocks.mockUserInfoWithTestGroups(wireMockRule);
TestHelper.browseLoginPage(webClient, jenkins);
TestHelper.assertTestUser(webClient);

wireMockRule.stubFor(post(urlPathEqualTo("/token"))
.willReturn(aResponse()
.withStatus(400)
.withHeader("Content-Type", "application/json")
.withBody("{ \"error\": \"invalid_grant\" }")));
TestHelper.expire(webClient);
webClient.assertFails(jenkins.getSearchUrl(), 500);

verify(postRequestedFor(urlPathEqualTo("/token")).withRequestBody(containing("grant_type=refresh_token")));
}
}
Loading

0 comments on commit f01051e

Please sign in to comment.