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-60410] Add stack trace suppression into core as a standard behavior. #4389

Merged
merged 76 commits into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
5f8f935
Add stack trace suppression into core as a standard.
jeffret-b Dec 6, 2019
ab78008
Clean up suppression filter.
jeffret-b Dec 9, 2019
cece2b4
Minor review comments.
jeffret-b Dec 9, 2019
b720e27
Handle two review comments.
jeffret-b Jan 9, 2020
64dc4de
Better handle AccessDeniedException.
jeffret-b Jan 9, 2020
4a01311
First pass at adding tests.
jeffret-b Jan 13, 2020
cf29446
Convert to not show the trace to admins.
jeffret-b Jan 13, 2020
0e3be66
Remove some unrelated tests.
jeffret-b Jan 13, 2020
4a7684e
Add test for basic exception.
jeffret-b Jan 14, 2020
8f3e14a
Shift to using HttpResponse.SHOW_STACK_TRACE.
jeffret-b Jan 14, 2020
fa27840
Adjust comment.
jeffret-b Jan 14, 2020
cfe722b
Rename class for better clarity.
jeffret-b Jan 14, 2020
2b6aed9
Need a new Stapler release or incremental for these tests.
jeffret-b Jan 14, 2020
8efba8a
Finish cleanup of Stapler separation.
jeffret-b Jan 15, 2020
70503e2
Add a couple more tests and some comments about the error source.
jeffret-b Jan 15, 2020
a441cbb
Add logging ID to uncaught exception handler.
jeffret-b Jan 21, 2020
e9d80f0
Revert inadvertent changes to SimpleJobTest.
jeffret-b Jan 21, 2020
e00d41c
Stop adding filter for now.
jeffret-b Jan 21, 2020
3e9444a
Small adjustments to oops.jelly.
jeffret-b Jan 21, 2020
4f22304
Fix tests.
jeffret-b Jan 21, 2020
6a14185
Catch embedded security exceptions.
jeffret-b Jan 21, 2020
86bad5a
Remove messages that aren't used after all.
jeffret-b Jan 21, 2020
20e3c78
Remove the unused messages.
jeffret-b Jan 21, 2020
232edf5
Use the stapler incremental now that's republished.
jeffret-b Jan 22, 2020
354ee66
Don't use public static boolean property.
jeffret-b Jan 23, 2020
e0c528c
Adjust tests.
jeffret-b Jan 27, 2020
3301898
Don't handle embedded security exceptions.
jeffret-b Jan 27, 2020
eef3a30
Remove now unused method.
jeffret-b Jan 28, 2020
c8f8b11
Adopt Daniel's suggestion for tying Stapler change to Jenkins.
jeffret-b Jan 28, 2020
92c24c6
Adjust naming.
jeffret-b Jan 29, 2020
dfee356
Use released Stapler.
jeffret-b Feb 10, 2020
8b50892
Add stack trace suppression into core as a standard.
jeffret-b Dec 6, 2019
a4f0f8f
Clean up suppression filter.
jeffret-b Dec 9, 2019
9472660
Minor review comments.
jeffret-b Dec 9, 2019
c3e39ef
Handle two review comments.
jeffret-b Jan 9, 2020
3cf878f
Better handle AccessDeniedException.
jeffret-b Jan 9, 2020
fff47bb
First pass at adding tests.
jeffret-b Jan 13, 2020
d41b0cb
Convert to not show the trace to admins.
jeffret-b Jan 13, 2020
1eb11af
Remove some unrelated tests.
jeffret-b Jan 13, 2020
b380e62
Add test for basic exception.
jeffret-b Jan 14, 2020
9b6aeba
Shift to using HttpResponse.SHOW_STACK_TRACE.
jeffret-b Jan 14, 2020
e6e261f
Adjust comment.
jeffret-b Jan 14, 2020
452128c
Rename class for better clarity.
jeffret-b Jan 14, 2020
c18b81b
Need a new Stapler release or incremental for these tests.
jeffret-b Jan 14, 2020
aad2b10
Finish cleanup of Stapler separation.
jeffret-b Jan 15, 2020
eead355
Add a couple more tests and some comments about the error source.
jeffret-b Jan 15, 2020
bcf587b
Add logging ID to uncaught exception handler.
jeffret-b Jan 21, 2020
45e2f5c
Revert inadvertent changes to SimpleJobTest.
jeffret-b Jan 21, 2020
e00a860
Stop adding filter for now.
jeffret-b Jan 21, 2020
c936bd1
Small adjustments to oops.jelly.
jeffret-b Jan 21, 2020
8638289
Fix tests.
jeffret-b Jan 21, 2020
b56a380
Catch embedded security exceptions.
jeffret-b Jan 21, 2020
ed53793
Remove messages that aren't used after all.
jeffret-b Jan 21, 2020
acebd93
Remove the unused messages.
jeffret-b Jan 21, 2020
b848f85
Use the stapler incremental now that's republished.
jeffret-b Jan 22, 2020
354a054
Don't use public static boolean property.
jeffret-b Jan 23, 2020
83148e0
Adjust tests.
jeffret-b Jan 27, 2020
8baddd2
Don't handle embedded security exceptions.
jeffret-b Jan 27, 2020
13d4a37
Remove now unused method.
jeffret-b Jan 28, 2020
4a01463
Adopt Daniel's suggestion for tying Stapler change to Jenkins.
jeffret-b Jan 28, 2020
cfc5e52
Adjust naming.
jeffret-b Jan 29, 2020
76e64fc
Use released Stapler.
jeffret-b Feb 10, 2020
39fc974
Pass the HTTP status code on to the oops page.
jeffret-b Feb 13, 2020
19b25ed
Merge branch 'suppressStack' of github.com:jeffret-b/jenkins into sup…
jeffret-b Feb 13, 2020
313d198
Update to use newer jenkins-test-harness.
jeffret-b Feb 13, 2020
d4b5d3f
Show stack trace for jetty:run.
jeffret-b Feb 14, 2020
df385a8
Adjust jelly for popup.
jeffret-b Feb 20, 2020
ec707b3
Change popup dialog size.
jeffret-b Feb 21, 2020
a9c3910
Adjust math operations for clarity.
jeffret-b Feb 21, 2020
7cc0628
Merge branch 'master' into suppressStack
daniel-beck Feb 22, 2020
4786a1c
Merge branch 'master' into suppressStack
jeffret-b Feb 24, 2020
984601d
Merge branch 'suppressStack' of github.com:jeffret-b/jenkins into sup…
jeffret-b Feb 24, 2020
6b68c9e
Merge branch 'master' into suppressStack
jeffret-b Feb 24, 2020
4510307
Adjust test for new permission changes.
jeffret-b Feb 24, 2020
feb6aa5
Merge branch 'suppressStack' of github.com:jeffret-b/jenkins into sup…
jeffret-b Feb 24, 2020
215319d
Update test/pom.xml
timja Feb 26, 2020
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
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ THE SOFTWARE.

<properties>
<staplerFork>true</staplerFork>
<stapler.version>1.258</stapler.version>
<stapler.version>1.259-rc1392.509f64eb3d44</stapler.version>
<spring.version>2.5.6.SEC03</spring.version>
<groovy.version>2.4.12</groovy.version>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public User doCreateAccount(StaplerRequest req, StaplerResponse rsp) throws IOEx

private User _doCreateAccount(StaplerRequest req, StaplerResponse rsp, String formView) throws ServletException, IOException {
if(!allowsSignup())
throw HttpResponses.error(SC_UNAUTHORIZED,new Exception("User sign up is prohibited"));
throw HttpResponses.errorWithoutStack(SC_UNAUTHORIZED, "User sign up is prohibited");

boolean firstUser = !hasSomeUser();
User u = createAccount(req, rsp, enableCaptcha, formView);
Expand Down
137 changes: 137 additions & 0 deletions core/src/main/java/jenkins/security/SuppressionFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package jenkins.security;
jeffret-b marked this conversation as resolved.
Show resolved Hide resolved

import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.util.PluginServletFilter;
import jenkins.model.Jenkins;
import org.acegisecurity.AccessDeniedException;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.Stapler;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

@Restricted(NoExternalUse.class)
public class SuppressionFilter implements Filter {

private static final Logger LOGGER = Logger.getLogger(SuppressionFilter.class.getName());

@Initializer(after = InitMilestone.STARTED)
public static void init() throws ServletException {
HttpResponses.setErrorDetailsFilter((code, cause) -> showStackTrace());
PluginServletFilter.addFilter(new SuppressionFilter());
}

public void init(FilterConfig filterConfig) throws ServletException {
// no-op
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request,response);
} catch (Exception e) {
if (containsAccessDeniedException(e)) {
throw e;
}
if (Stapler.isSocketException(e)) {
return;
}

if (showStackTrace()) {
if (e instanceof IOException || e instanceof ServletException || e instanceof RuntimeException) {
// thing we can throw without wrapping
throw e;
}
throwServletException(e);
} else if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
String errorId = logException((HttpServletRequest) request,e);

respondWithSimpleErrorPage((HttpServletResponse) response, errorId);
}
}
}

private void respondWithSimpleErrorPage(HttpServletResponse response, String errorId) throws ServletException {
try {
response.setStatus(SC_INTERNAL_SERVER_ERROR);
jeffret-b marked this conversation as resolved.
Show resolved Hide resolved
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Cache-Control","no-cache,must-revalidate");
PrintWriter w;
try {
w = response.getWriter();
} catch (IllegalStateException x) {
w = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
}
w.println("<html><head><title>"+ Messages.SuppressionFilter_Title()+"</title><body>");
w.println("<p>"+Messages.SuppressionFilter_ContactAdmin(errorId)+"</p>");
w.println("</body></html>");
w.close();
} catch (Error error) {
throw error;
} catch (Throwable x) {
// if we fail to report this error, bail out
throw new ServletException(Messages.SuppressionFilter_ContactAdmin(errorId)); // not chaining x since it might contain something
}
}

private void throwServletException(Exception e) throws ServletException {
// ServletException chaining is messed up. We go extra mile here to really
// chain the cause.
ServletException servletException = new ServletException("Request processing failed", e);
try {
if (servletException.getCause() == null) {
servletException.initCause(e);
}
} catch (IllegalStateException ise) {
// just in case.
}

throw servletException;
}

/**
* Report an error and then generate a unique ID for that error.
*/
private String logException(HttpServletRequest req, Throwable e) {
String id = UUID.randomUUID().toString();
LOGGER.log(Level.WARNING, "Request processing failed. URI=" + req.getRequestURI() + " clientIP=" + req.getRemoteAddr() + " ErrorID=" + id, e);
return id;
}

private static boolean showStackTrace() {
return Jenkins.get().hasPermission(Jenkins.ADMINISTER);
}

public void destroy() {
// no-op
}

private boolean containsAccessDeniedException(Exception exception) {
Throwable currentException = exception;
do {
if (currentException instanceof AccessDeniedException) {
return true;
}
currentException = currentException.getCause();
} while (currentException != null);
jeffret-b marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

}
3 changes: 3 additions & 0 deletions core/src/main/resources/jenkins/security/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ ResourceDomainConfiguration.IOException=Failed to connect: {0}
ResourceDomainConfiguration.Invalid=Not a valid URL.
ResourceDomainConfiguration.SameAsJenkinsRoot=Cannot use the same host name for both Jenkins root URL and resource root URL.
ResourceDomainConfiguration.SameAsCurrent=You are currently accessing Jenkins through a URL similar to the proposed resource root URL. Saving this URL might remove your access to Jenkins.
SuppressionFilter.ContactAdmin=An error occurred processing your request. Ask your Jenkins administrator to look up details. ErrorID\={0}
SuppressionFilter.Title=Error