Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-75205] Render HTTP 500 error pages as the current user #10232

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.init.Initializer;
import hudson.security.ACL;
import hudson.security.ACLContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -10,6 +12,7 @@
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.ErrorAttributeFilter;
import jenkins.model.Jenkins;
import org.kohsuke.MetaInfServices;
import org.kohsuke.accmod.Restricted;
Expand All @@ -20,6 +23,7 @@
import org.kohsuke.stapler.StaplerResponse2;
import org.kohsuke.stapler.UncaughtExceptionFilter;
import org.kohsuke.stapler.WebApp;
import org.springframework.security.core.Authentication;

/**
* Deals with exceptions that get thrown all the way up to the Stapler rendering layer.
Expand Down Expand Up @@ -56,7 +60,14 @@
req.setAttribute("jakarta.servlet.error.exception", e);
rsp.setStatus(code);
try {
WebApp.get(j.getServletContext()).getSomeStapler().invoke(req, rsp, j, "/oops");
final Object attribute = req.getAttribute(ErrorAttributeFilter.USER_ATTRIBUTE);
if (attribute instanceof Authentication) {

Check warning on line 64 in core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 64 is only partially covered, one branch is missing
try (ACLContext unused = ACL.as2((Authentication) attribute)) {
WebApp.get(j.getServletContext()).getSomeStapler().invoke(req, rsp, j, "/oops");
}
} else {
WebApp.get(j.getServletContext()).getSomeStapler().invoke(req, rsp, j, "/oops");

Check warning on line 69 in core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 69 is not covered by tests
}
} catch (ServletException | IOException x) {
if (!Stapler.isSocketException(x)) {
throw x;
Expand Down
42 changes: 42 additions & 0 deletions test/src/test/java/jenkins/model/ErrorPageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,48 @@ public void nice404ErrorPage() throws Exception {
}
}

@Test
@Issue("JENKINS-75205")
public void nice500ErrorPage() throws Exception {
try (JenkinsRule.WebClient wc = j.createWebClient()) {
Dispatcher.TRACE = false;

/* Start with no security realm configured */

{
final FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("exception"));
assertEquals(500, ex.getStatusCode());
final String content = ex.getResponse().getContentAsString(StandardCharsets.UTF_8);
assertThat(content, not(containsString(j.contextPath + "/login?from=")));
}

/* Set up security realm and request as anonymous, we expect login link and hedged response */
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().toAuthenticated().grant(Jenkins.READ).everywhere().toEveryone());

{
final FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("exception"));
assertEquals(500, ex.getStatusCode());
final String content = ex.getResponse().getContentAsString(StandardCharsets.UTF_8);
assertThat(content, containsString(j.contextPath + "/login?from=" + j.contextPath.replace("/", "%2F") + "%2Fexception"));
assertThat(content, not(containsString(j.contextPath + "/login?from=" + j.contextPath.replace("/", "%2F") + "%2Foops")));
}

/* With the security realm still set up, log in and expect the profile link to show */
wc.login("alice");

{
final FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("exception"));
assertEquals(500, ex.getStatusCode());
final String content = ex.getResponse().getContentAsString(StandardCharsets.UTF_8);
assertThat(content, not(containsString(j.contextPath + "/login?from=")));
assertThat(content, containsString("user/alice"));
}
} finally {
Dispatcher.TRACE = true;
}
}

@Test
@Issue("JENKINS-71087")
public void kindaNice404ErrorPageOnResourceDomain() throws Exception {
Expand Down
Loading