mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-10 02:26:18 +00:00
Add stack trace suppression into core as a standard.
This commit is contained in:
1 parent
a8f5167dae
commit
8b50892bd8
4 files changed
+136
-2
No files matched your search
+1
-1
@@ -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>
|
||||
|
||||
@@ -251,7 +251,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
|
||||
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package jenkins.security;
|
||||
|
||||
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.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 {
|
||||
|
||||
@Initializer(after = InitMilestone.STARTED)
|
||||
public static void init() throws ServletException {
|
||||
HttpResponses.setErrorDetailsFilter((code, cause) -> showStackTrace(cause));
|
||||
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 (Throwable e) {
|
||||
if (e instanceof AccessDeniedException) {
|
||||
throw (AccessDeniedException) e;
|
||||
}
|
||||
if (e instanceof ServletException) {
|
||||
if (((ServletException)e).getRootCause() instanceof AccessDeniedException)
|
||||
throw (ServletException)e; // this exception needs to be pass through since Jenkins has a filter that reacts to this
|
||||
}
|
||||
if (Stapler.isSocketException(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showStackTrace(e)) {
|
||||
// thing we can throw without wrapping
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
if (e instanceof ServletException)
|
||||
throw (ServletException)e;
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
|
||||
// ServletException chaining is messed up. We go extra mile here to really
|
||||
// chain the cause.
|
||||
ServletException x = new ServletException("Request processing failed", e);
|
||||
try {
|
||||
if (x.getCause() == null) x.initCause(e);
|
||||
} catch (IllegalStateException _) {
|
||||
// just in case.
|
||||
}
|
||||
|
||||
throw x;
|
||||
} else if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
|
||||
// We cannot decorate the stuff for non-Http responses
|
||||
String errorId = reportError((HttpServletRequest) request,e);
|
||||
|
||||
try {
|
||||
HttpServletResponse rsp = (HttpServletResponse)response;
|
||||
rsp.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
rsp.setContentType("text/html;charset=UTF-8");
|
||||
rsp.setHeader("Cache-Control","no-cache,must-revalidate");
|
||||
PrintWriter w = null;
|
||||
try {
|
||||
w = rsp.getWriter();
|
||||
} catch (IllegalStateException x) {
|
||||
// stream mode?
|
||||
w = new PrintWriter(new OutputStreamWriter(rsp.getOutputStream(),"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; // We propagate errors upstairs
|
||||
} 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error and then generate a unique ID for that error.
|
||||
*/
|
||||
protected String reportError(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we show this stack trace to the requesting user?
|
||||
*/
|
||||
private static boolean showStackTrace(Throwable t) {
|
||||
// TODO: define a permission for this
|
||||
return Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(SuppressionFilter.class.getName());
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user