Grails spring security core plugin: how to remove the browser prompt for an ajax request

ajax, grails, spring-security

Solution

In this case as HTTP Basic Authentication is being used (`useBasicAuth = true`), the server returns a 401 reply with `WWW-Authenticate: Basic`, to which the browser replies with a popup for username and password.

That behaviour is present in all browsers and cannot be changed, but there are several alternatives. To avoid the popup we can't use Basic Authentication, but some other mechanism.

The simplest way is to use another header other than the `Authorization` header (used in Basic authentication) to pass the credentials.

To configure spring security to look for credentials on this new header, have a a look at the 17.2.1 section Request-Header Authentication, where an example is given of how to configure a `RequestHeaderAuthenticationFilter` to look into a given header.

This is how the configuration looks for using a header named `X-MyCustomHeader` to pass the credentials:

  <security:http>
    <!-- Additional http configuration omitted -->
    <security:custom-filter position="PRE_AUTH_FILTER" ref="customAuthFilter" />
  </security:http>

    <bean id="customAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="X-MyCustomHeader"/>
    <property name="authenticationManager" ref="authenticationManager" />
  </bean>

  <bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService">
      <bean id="userDetailsServiceWrapper"
          class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
        <property name="userDetailsService" ref="userDetailsService"/>
      </bean>
    </property>
    </bean>

    <security:authentication-manager alias="authenticationManager">
      <security:authentication-provider ref="preauthAuthProvider" />
    </security:authentication-manager>

In general for frontend applications is better not to use basic authentication, as browsers cache those credentials making such an application vulnerable to request forgery (CSRF) attacks.

Problem

I set up a fresh grails application (2.3.5) and installed the spring security core plugin (2.0-RC2) I added the following configuration (my 'secure/**' urlmappings use the basicAuthenicationFilter): ``` grails.plugin.springsecurity.logout.postOnly = false grails.plugin.springsecurity.rejectIfNoRule = true grails.plugin.springsecurity.fii.rejectPublicInvocations = false //Enable Basic Auth Filter grails.plugin.springsecurity.useBasicAuth = true grails.plugin.springsecurity.basic.realmName = "Example" grails.plugin.springsecurity.filterChain.chainMap = [ '/secure/**': 'JOINED_FILTERS,-exceptionTranslationFilter', 'app/**': 'JOINED_FILTERS,-basicAuthenticationFilter,-basicExceptionTranslationFilter' ] grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.car.User' grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.car.UserRole' grails.plugin.springsecurity.authority.className = 'com.car.Role' grails.plugin.springsecurity.controllerAnnotations.staticRules = [ '/app/**': ['permitAll'], '/index': ['permitAll'], '/index.gsp': ['permitAll'], '/**/js/**': ['permitAll'], '/**/css/**': ['permitAll'], '/**/images/**': ['permitAll'], '/**/favicon.ico': ['permitAll'] ] ``` I have an angular application in the web-app folder. Basically when I make an ajax request from it and supply a bad password in the basic authentication header - I am prompted with a default browser prompt. The request is still pending. I am new to understanding this, but I it looks like the code that is intercepting the request has logic to prompt if the header is not present or invalid. I am sure I must be missing something obvious, there must be an easy way to configure the behavior for the request. Is there such a configuration? Or am I supposed to create a custom filter?

Original source