0
votes

I have a Grails react app with spring security core using basic authentication implementation.

Login dialog for invalid requestsMy react front end is bundled with Grails app. All my requests to back end (my grails app), they are post requests. Now i just want status 401/403 BUT NOT login dialog prompts for invalid requests or bad requests just like in POSTMAN. Because of this problem my whole system is not proper as for every invalid requests a login dialog as shown in the picture.

Is there any way to avoid this login dialog and just let the front end deal with the status response?

Grails version : 3.3.5 Spring security core version : 3.2.3

2
Are you using spring-security-rest? - Jeff Scott Brown
@JeffScottBrown No i am not using spring-security-rest. I see the above doc which uses both spring-security-core and spring-security-rest. So for my concern, do i need to use spring-security-rest anyway? - Prabin Upreti
"do i need to use spring-security-rest anyway" - Strictly speaking you don't need to, but doing so will likely be more simple than if you wrote all the support yourself, depending on what your security requirements are. - Jeff Scott Brown

2 Answers

1
votes

When using basic auth, the thing, that triggers the login dialog of the browser is the existence of a WWW-Authenticate header in the 401 response. So your goal here is to remove that.

With a default spring security setup the reason the headers gets sent is BasicAuthenticationEntryPoint.

Since this also shows the realm to the user, here are hooks in the basic auth configurer to replace the entrypoint (where BasicAuthenticationEntryPoint is the default if not set).

So here is an example with plain spring security to set this up:

@Configuration
@EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                    .disable()
                .httpBasic()
                    .authenticationEntryPoint(new BasicAuthenticationEntryPointWithoutWWWAuthenticate())
    }
}

// See org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
class BasicAuthenticationEntryPointWithoutWWWAuthenticate implements AuthenticationEntryPoint {
    void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // XXX don't set the header, that triggers the browser to show the login form
        // response.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\"");
        response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
    }
}
1
votes

I wanted a quick and easier way to resolve this with my existing implementation without adding spring-security-rest. So i followed @cfrick's answer to remove header "WWW-Authenticate" in my response. Here are the steps i took :

  1. Create a custom spring filter which extends GenericFilterBean of spring, register it as documented here : spring-security-grails-doc
  2. Create a custom response wrapper to modify the response inside the filter.
  3. In the response wrapper's addHeader method set all the headers except WWW-Authenticate.

Here is my filter code :

class RemoveLoginPromptFilter extends GenericFilterBean{

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException{
        HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse)response){
            @Override
            public void addHeader(String name, String value){
                if(!name.equalsIgnoreCase("www-authenticate")){
                    this.setHeader(name,value)
                }
            }
        }
        chain.doFilter(request,wrapper)
    }
}