diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..d6ab6c3 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @jenkinsci/reverse-proxy-auth-plugin-developers diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 94df459..bd90db4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,15 +1,18 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +--- version: 2 updates: -- package-ecosystem: maven - directory: "/" - schedule: - interval: weekly - ignore: - - dependency-name: "org.jenkins-ci.main:jenkins-core" - open-pull-requests-limit: 10 - target-branch: master - reviewers: - - rda1ton - - sboardwell - labels: - - skip-changelog + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" + ignore: + - dependency-name: "org.jenkins-ci.main:jenkins-core" + open-pull-requests-limit: 10 + reviewers: + - rda1ton + - sboardwell + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..da8cb13 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,6 @@ +# https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc +--- +_extends: .github +tag-template: reverse-proxy-auth-plugin-$NEXT_PATCH_VERSION +name-template: $NEXT_PATCH_VERSION +version-template: $MAJOR.$MINOR.$PATCH diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..4fc3d2c --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,16 @@ +# Automates creation of Release Drafts using Release Drafter +# More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc +--- +on: + push: + branches: + - master + +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 70660d7..0834364 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ +target + +# mvn hpi:run +work + +# IntelliJ IDEA project files *.iml *.iws *.ipr -target -work -/.idea -/.classpath -/.project -/.settings -.vscode +.idea + +# Eclipse project files +.settings +.classpath +.project diff --git a/Jenkinsfile b/Jenkinsfile index ec8ac5f..09d365a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,2 +1,5 @@ // Build the plugin using https://github.com/jenkins-infra/pipeline-library -buildPlugin(jdkVersions: [11,17]) +buildPlugin(configurations: [ + [platform: 'linux', jdk: 21], + [platform: 'windows', jdk: 17], +]) diff --git a/pom.xml b/pom.xml index 860520a..5878ecb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.79 + 4.88 @@ -13,7 +13,7 @@ hpi Jenkins Reverse Proxy Auth Plugin - https://github.com/jenkinsci/reverse-proxy-auth-plugin + https://github.com/jenkinsci/${project.artifactId} @@ -45,13 +45,25 @@ 1.7.8 -SNAPSHOT - jenkinsci/reverse-proxy-auth-plugin - 2.387.3 + jenkinsci/${project.artifactId} + 2.426 + ${jenkins.baseline}.3 Max - true false + + + + io.jenkins.tools.bom + bom-${jenkins.baseline}.x + 3208.vb_21177d4b_cd9 + pom + import + + + + @@ -121,7 +133,29 @@ org.jenkins-ci.plugins mailer - 463.vedf8358e006b_ + + + org.jenkins-ci.plugins + jackson2-api + test + + + org.testcontainers + testcontainers + 1.20.3 + test + + + + com.fasterxml.jackson.core + jackson-annotations + + + + org.apache.commons + commons-compress + + diff --git a/src/main/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealm.java b/src/main/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealm.java index 363d957..ed449f2 100644 --- a/src/main/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealm.java +++ b/src/main/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealm.java @@ -271,6 +271,7 @@ public class ReverseProxySecurityRealm extends SecurityRealm { public final String customLogOutUrl; @DataBoundConstructor + @SuppressFBWarnings(value = "PA_PUBLIC_PRIMITIVE_ATTRIBUTE", justification = "API compatibility") public ReverseProxySecurityRealm( String forwardedUser, String forwardedEmail, diff --git a/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealmTest.java b/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealmTest.java index 73cc58f..b1dad82 100644 --- a/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealmTest.java +++ b/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/ReverseProxySecurityRealmTest.java @@ -68,9 +68,9 @@ public Authentication call() { private ReverseProxySecurityRealm createBasicRealm() { return new ReverseProxySecurityRealm( "X-Forwarded-User", // forwardedUser - "X-Forwarded-Groups", // headerGroups "X-Forwarded-Email", // forwardedEmail "X-Forwarded-DisplayName", // forwardedDisplayName + "X-Forwarded-Groups", // headerGroups "|", // headerGroupsDelimiter "", // customLogInUrl "", // customLogOutUrl diff --git a/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/docker/PlanetExpressTest.java b/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/docker/PlanetExpressTest.java new file mode 100644 index 0000000..a28bcd7 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/reverse_proxy_auth/docker/PlanetExpressTest.java @@ -0,0 +1,107 @@ +package org.jenkinsci.plugins.reverse_proxy_auth.docker; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import hudson.Functions; +import hudson.tasks.MailAddressResolver; +import hudson.util.Secret; +import org.acegisecurity.userdetails.ldap.LdapUserDetails; +import org.jenkinsci.plugins.reverse_proxy_auth.ReverseProxySecurityRealm; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.RealJenkinsRule; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; + +/** + * Tests the plugin when logging in to rroemhild/test-openldap + */ +public class PlanetExpressTest { + + static final String TEST_IMAGE = + "rroemhild/test-openldap@sha256:b4e433bbcba1f17899d6bcb0a8e854bbe52c754faa4e785d0c27a2b55eb12cd8"; + static final String DN = "dc=planetexpress,dc=com"; + static final String MANAGER_DN = "cn=admin,dc=planetexpress,dc=com"; + static final String MANAGER_SECRET = "GoodNewsEveryone"; + + @BeforeClass + public static void requiresDocker() { + assumeTrue(DockerClientFactory.instance().isDockerAvailable()); + } + + @BeforeClass + public static void linuxOnly() { + assumeFalse( + "Windows CI builders now have Docker installed…but it does not support Linux images", + Functions.isWindows() && System.getenv("JENKINS_URL") != null); + } + + @SuppressWarnings("rawtypes") + @Rule + public GenericContainer container = new GenericContainer(TEST_IMAGE).withExposedPorts(389); + + @Rule + public RealJenkinsRule rr = new RealJenkinsRule(); + + @Test + public void login() throws Throwable { + String server = container.getHost() + ":" + container.getFirstMappedPort(); + rr.then(new Login(server)); + } + + private static class Login implements RealJenkinsRule.Step { + private final String server; + + Login(String server) { + this.server = server; + } + + @Override + public void run(JenkinsRule j) throws Throwable { + ReverseProxySecurityRealm realm = new ReverseProxySecurityRealm( + "X-Forwarded-User", // forwardedUser + "X-Forwarded-Email", // forwardedEmail + "X-Forwarded-DisplayName", // forwardedDisplayName + "X-Forwarded-Groups", // headerGroups + "|", // headerGroupsDelimiter + "", // customLogInUrl + "", // customLogOutUrl + server, // server + DN, // rootDN + false, // inhibitInferRootDN + "", // userSearchBase + "", // userSearch + "", // groupSearchBase + "", // groupSearchFilter + "", // groupMembershipFilter + "", // groupNameAttribute + MANAGER_DN, // managerDN + Secret.fromString(MANAGER_SECRET), // managerPassword + 15, // updateInterval + false, // disableLdapEmailResolver + "cn", // displayNameLdapAttribute + "mail" // emailAddressLdapAttribute + ); + j.jenkins.setSecurityRealm(realm); + j.configRoundtrip(); + try (JenkinsRule.WebClient wc = j.createWebClient()) { + wc.addRequestHeader(realm.getForwardedUser(), "fry"); + String content = wc.login("fry", "fry").goTo("whoAmI").getBody().getTextContent(); + assertThat(content, containsString("Philip J. Fry")); + } + + LdapUserDetails zoidberg = + (LdapUserDetails) j.jenkins.getSecurityRealm().loadUserByUsername("zoidberg"); + assertEquals("cn=John A. Zoidberg,ou=people,dc=planetexpress,dc=com", zoidberg.getDn()); + + String leelaEmail = MailAddressResolver.resolve(j.jenkins.getUser("leela")); + assertEquals("leela@planetexpress.com", leelaEmail); + } + } +}