diff --git a/core/pom.xml b/core/pom.xml
index 4594bbbfd5..3ac3989649 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -39,7 +39,7 @@ THE SOFTWARE.
true
- 1.258
+ 1.259-rc1392.509f64eb3d44
2.5.6.SEC03
2.4.12
diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
index 3a404a49e5..274f25ebfd 100644
--- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
@@ -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);
diff --git a/core/src/main/java/jenkins/security/SuppressionFilter.java b/core/src/main/java/jenkins/security/SuppressionFilter.java
new file mode 100644
index 0000000000..ed647b1def
--- /dev/null
+++ b/core/src/main/java/jenkins/security/SuppressionFilter.java
@@ -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("
"+Messages.SuppressionFilter_Title()+"");
+ w.println(""+Messages.SuppressionFilter_ContactAdmin(errorId)+"
");
+ w.println("");
+ 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());
+}
diff --git a/core/src/main/resources/jenkins/security/Messages.properties b/core/src/main/resources/jenkins/security/Messages.properties
index 5ff4e1274b..b332c171b2 100644
--- a/core/src/main/resources/jenkins/security/Messages.properties
+++ b/core/src/main/resources/jenkins/security/Messages.properties
@@ -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
+