diff --git a/core/src/main/java/hudson/security/AccessDeniedException2.java b/core/src/main/java/hudson/security/AccessDeniedException2.java index 34324d979fa1..0f5da052b264 100644 --- a/core/src/main/java/hudson/security/AccessDeniedException2.java +++ b/core/src/main/java/hudson/security/AccessDeniedException2.java @@ -2,6 +2,10 @@ import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; +import org.acegisecurity.GrantedAuthority; + +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; /** * {@link AccessDeniedException} with more information. @@ -28,4 +32,36 @@ public AccessDeniedException2(Throwable t, Authentication authentication, Permis this.authentication = authentication; this.permission = permission; } + + /** + * Reports the details of the access failure in HTTP headers to assist diagnosis. + */ + public void reportAsHeaders(HttpServletResponse rsp) { + rsp.addHeader("X-You-Are-Authenticated-As",authentication.getName()); + for (GrantedAuthority auth : authentication.getAuthorities()) { + rsp.addHeader("X-You-Are-In-Group",auth.getAuthority()); + } + rsp.addHeader("X-Required-Permission", permission.getId()); + for (Permission p=permission.impliedBy; p!=null; p=p.impliedBy) { + rsp.addHeader("X-Permission-Implied-By", p.getId()); + } + } + + /** + * Reports the details of the access failure. + * This method is similar to {@link #reportAsHeaders(HttpServletResponse)} for the intention + * but instead of using HTTP headers, this version is meant to go inside the payload. + */ + public void report(PrintWriter w) { + w.println("You are authenticated as: "+authentication.getName()); + w.println("Groups that you are in:"); + for (GrantedAuthority auth : authentication.getAuthorities()) { + w.println(" "+auth.getAuthority()); + } + + w.println("Permission you need to have (but didn't): "+permission.getId()); + for (Permission p=permission.impliedBy; p!=null; p=p.impliedBy) { + w.println(" ... which is implied by: "+p.getId()); + } + } } diff --git a/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java b/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java index eec3dab9cbf9..94497cf87cc0 100644 --- a/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java +++ b/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java @@ -26,19 +26,14 @@ import jenkins.model.Jenkins; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.ui.AccessDeniedHandler; -import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.WebApp; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Enumeration; -import java.util.Vector; /** * Handles {@link AccessDeniedException} happened during request processing. @@ -47,12 +42,16 @@ * @author Kohsuke Kawaguchi */ public class AccessDeniedHandlerImpl implements AccessDeniedHandler { - public void handle(ServletRequest request, ServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + public void handle(ServletRequest request, ServletResponse response, AccessDeniedException cause) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rsp = (HttpServletResponse) response; rsp.setStatus(HttpServletResponse.SC_FORBIDDEN); - req.setAttribute("exception",accessDeniedException); + req.setAttribute("exception",cause); + + if (cause instanceof AccessDeniedException2) { + ((AccessDeniedException2)cause).reportAsHeaders(rsp); + } WebApp.get(Jenkins.getInstance().servletContext).getSomeStapler() .invoke(req,rsp, Jenkins.getInstance(), "/accessDenied"); diff --git a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java index bf07ea05437c..64aaff2ba02a 100644 --- a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java +++ b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java @@ -25,7 +25,6 @@ import com.google.common.base.Strings; import org.acegisecurity.AuthenticationException; -import org.acegisecurity.GrantedAuthority; import org.acegisecurity.InsufficientAuthenticationException; import org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint; @@ -82,18 +81,12 @@ public void commence(ServletRequest request, ServletResponse response, Authentic rsp.setStatus(SC_FORBIDDEN); rsp.setContentType("text/html;charset=UTF-8"); + AccessDeniedException2 cause = null; // report the diagnosis information if possible if (reason instanceof InsufficientAuthenticationException) { if (reason.getCause() instanceof AccessDeniedException2) { - AccessDeniedException2 cause = (AccessDeniedException2) reason.getCause(); - rsp.addHeader("X-You-Are-Authenticated-As",cause.authentication.getName()); - for (GrantedAuthority auth : cause.authentication.getAuthorities()) { - rsp.addHeader("X-You-Are-In-Group",auth.getAuthority()); - } - rsp.addHeader("X-Required-Permission", cause.permission.getId()); - for (Permission p=cause.permission.impliedBy; p!=null; p=p.impliedBy) { - rsp.addHeader("X-Permission-Implied-By", p.getId()); - } + cause = (AccessDeniedException2) reason.getCause(); + cause.reportAsHeaders(rsp); } } @@ -108,9 +101,17 @@ public void commence(ServletRequest request, ServletResponse response, Authentic "" + "" + " " + - "" + - "Authentication required", loginForm - ); + "\n" + + "\n\n"+ + "Authentication required\n"+ + "\n\n"+ + ""); // Turn Off "Show Friendly HTTP Error Messages" Feature on the Server Side. // See http://support.microsoft.com/kb/294807 for (int i=0; i < 10; i++) diff --git a/core/src/main/java/jenkins/security/ExceptionTranslationFilter.java b/core/src/main/java/jenkins/security/ExceptionTranslationFilter.java index 458a2a41eeb6..f0a785db6d8d 100644 --- a/core/src/main/java/jenkins/security/ExceptionTranslationFilter.java +++ b/core/src/main/java/jenkins/security/ExceptionTranslationFilter.java @@ -220,7 +220,7 @@ protected void sendStartAuthentication(ServletRequest request, ServletResponse r // existing Authentication is no longer considered valid SecurityContextHolder.getContext().setAuthentication(null); - authenticationEntryPoint.commence(httpRequest, (HttpServletResponse) response, reason); + authenticationEntryPoint.commence(httpRequest, response, reason); } public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {