Search code examples
javaauthenticationrestletrestlet-2.3.1

Restlet 2.3 Override WWW-Authenticate Header


In Restlet 2.3 I am using a ChallengeAuthenticator with ChallengeScheme.HTTP_BASIC to protect application resources. When the server receives an incorrect set of credentials the server correctly returns a 401 Unauthorized response. Also correctly it adds the following header:

WWW-Authenticate → Basic realm="My security Realm"

The problem is when that response goes back to a browser rather than a server (as is the case with the AngularJS application GUI), the browser natively interprets that 401 response and launches an 'Authentication Required' modal.

enter image description here

What I would like to try and achieve is to read the request headers (easily done) and if the X-Requested-With: XMLHttpRequest header is present I would like to suppress the WWW-Authenticate header in the '401' response.

Currently the WWW-Authenticate header is automatically set so my question is how can I override this default header being set and handle it manually?


Solution

  • In your case, you should use a filter to remove the header WWW-Authenticate from the response. This header corresponds to a challenge request in the response.

    Here is the content of the filter:

    public class SecurityPostProcessingFilter extends Filter {
        public SecurityPostProcessingFilter(
                  Context context, Restlet next) {
            super(context, next);
        }
    
        @Override
        protected void afterHandle(Request request, Response response) {
            String requestedWith
               = request.getHeaders().getFirstValue("X-Requested-With");
            if ("XMLHttpRequest".equals(requestedWith)) {
                response.getChallengeRequests().clear();
            }
        }
    }
    

    You need to add it within the createInboundRoot method of your Restlet application, as described below

    public class RestletApplication extends Application {
        (...)
    
        @Override
        public Restlet createInboundRoot() {
            Router router = new Router(getContext());
            (...)
    
            ChallengeAuthenticator guard = new ChallengeAuthenticator(
                    null, ChallengeScheme.HTTP_BASIC, "testRealm");
            (...)
            guard.setNext(router);
    
            Filter filter = new SecurityPostProcessingFilter(
                 getContext(), guard);
    
            return filter;
        }
    }
    

    This will remove the header WWW-Authenticate from the response when the value of the header X-Requested-From is equals to XMLHttpRequest in the request.

    FYI, there is a page on the Restlet web site that describes the mapping between HTTP headers and the Restlet API: http://restlet.com/technical-resources/restlet-framework/guide/2.2/core/http-headers-mapping.

    Hope it helps you, Thierry