Merge branch 'master' of https://gitbox.apache.org/repos/asf/brooklyn-server
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/BrooklynSecurityProviderFilterJersey.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/BrooklynSecurityProviderFilterJersey.java
index 75e890f..d2c91f2 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/BrooklynSecurityProviderFilterJersey.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/filter/BrooklynSecurityProviderFilterJersey.java
@@ -19,19 +19,25 @@
 package org.apache.brooklyn.rest.filter;
 
 import java.io.IOException;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.annotation.Priority;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ContainerRequestFilter;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.ext.ContextResolver;
 import javax.ws.rs.ext.Provider;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.rest.security.provider.SecurityProvider;
 import org.apache.brooklyn.rest.security.provider.SecurityProvider.SecurityProviderDeniedAuthentication;
 import org.apache.brooklyn.util.text.Strings;
 import org.eclipse.jetty.http.HttpHeader;
@@ -46,6 +52,11 @@
     private static final Logger log = LoggerFactory.getLogger(BrooklynSecurityProviderFilterJersey.class);
     public static final String LOGIN_PAGE_HEADER = "X_BROOKLYN_LOGIN_PAGE";
 
+    private final Set<String> headersToForward = ImmutableSet.of(
+            HttpHeaders.WWW_AUTHENTICATE, // defines the HTTP authentication methods ("challenges") that might be used to gain access to a specific resource
+            SecurityProvider.UNAUTHORIZED_MESSAGE_HEADER // helper message from the security provider
+            );
+
     @Context
     HttpServletRequest webRequest;
 
@@ -78,7 +89,15 @@
                     Strings.isNonBlank(mgmt.getConfig().getConfig(BrooklynSecurityProviderFilterJavax.LOGIN_FORM))) {
                 rin = Response.status(Status.UNAUTHORIZED).entity("Authentication is required").header(LOGIN_PAGE_HEADER, mgmt.getConfig().getConfig(BrooklynSecurityProviderFilterJavax.LOGIN_FORM)).build();
             }
-
+            // adding headers in `headersToForward` if they are present in the original response
+            MultivaluedMap<String, Object> responseHeaders = e.getResponse().getHeaders();
+            if(responseHeaders != null && !responseHeaders.isEmpty()){
+                for(String headerKey: headersToForward) {
+                    if(responseHeaders.containsKey(headerKey)) {
+                        rin = Response.fromResponse(rin).header(headerKey, responseHeaders.get(headerKey).stream().map(Object::toString).collect(Collectors.joining(", "))).build();
+                    }
+                };
+            }
             requestContext.abortWith(rin);
         }
     }
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/SecurityProvider.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/SecurityProvider.java
index fbd1b3e..458df7f 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/SecurityProvider.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/SecurityProvider.java
@@ -34,6 +34,12 @@
  */
 public interface SecurityProvider {
 
+    /**
+     * Header for return to the user a helper message related to the unauthorized response
+     */
+    public static final String UNAUTHORIZED_MESSAGE_HEADER = "X_BROOKLYN_UNAUTHORIZED_MESSAGE";
+
+
     /** If user supplied a value session, this passes that in so the {@link SecurityProvider}
      * can check whether the user has previously authenticated, e.g. via an {@link HttpSession#setAttribute(String, Object)}
      * done by {@link #authenticate(HttpServletRequest, Supplier, String, String)}.
@@ -78,6 +84,7 @@
     public boolean logout(HttpSession session);
     
     public static class SecurityProviderDeniedAuthentication extends Exception {
+
         private static final long serialVersionUID = -3048228939219746783L;
         private final Response response;
         public SecurityProviderDeniedAuthentication() { this(null); }