How create a custom response when spring-security receives null credentials (username and password)?

3.4k Views Asked by At

I am using postman to send a username and password without value to my server; it's like username=null and password=null.

enter image description here

To control the security of my server, I use spring security 3.2. When it receives these credentials spring-security responds with this error.

Estado HTTP 500 - Fields must not be empty

java.lang.IllegalArgumentException: Cannot pass null or empty values to constructor
    org.springframework.security.core.userdetails.User.<init>(User.java:99)
    org.springframework.security.core.userdetails.User.<init>(User.java:69)
    com.equifax.product.fraud.applicationprocessing.web.rest.interceptors.security.SecurityAuthenticationProvider.retrieveUser(SecurityAuthenticationProvider.java:59)
    org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:168)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
        org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)

I want output JSON with custom message with the error, how can I do that?

This is my security.xml:

    <security:http create-session="never" use-expressions="true"
    auto-config="false">

    <security:intercept-url pattern="/application/**"
        access="isFullyAuthenticated()" />
    <security:anonymous />
    <security:http-basic entry-point-ref="securityAccessDeniedEntryPoint" />
    <security:access-denied-handler ref="securityAccessDeniedHandler" />
</security:http>

<security:authentication-manager alias="authenticationManager"
    erase-credentials="false">
    <security:authentication-provider
        ref="genericSecurityAuthenticationProvider" />
</security:authentication-manager>

I'am using Spring 3.2

4

There are 4 best solutions below

1
On BEST ANSWER

Use the standard exception of spring security, it will handle by itself if you already have an exception handler to transform the messages into Json response.

        catch (Exception exception)
        {
            throw new AuthenticationCredentialsNotFoundException("Fields must not be empty", exception);
        }
3
On

What you can do is define a AuthenticationFailureHandler bean, after you implement this bean, you can do what you want inside the method onAuthenticationFailure().

XML Config:

<beans:bean id="myFailureHandler" class="my.custom.impl.MyCustomAuthenticationFailureHandler"/>
<security:http ....>
<security:form-login authentication-failure-handler-ref="myFailureHandler" />
</security:http>

http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/web/authentication/AuthenticationFailureHandler.html

Obs.: If what you want to do don't work with this solution you can implement a AuthenticationProvider

0
On

You are passing the basic authentication String ":" (after base64 decoding), so as you say this results in an empty password an username. The BasicAuthenticationFilter passes these to the authentication provider, which is your custom code (SecurityAuthenticationProvider) so it's impossible to say exactly what it does. Somewhere in there are you are creating a User instance with those values, which throws the exception you are seeing. Instead you should check for empty values in your AuthenticationProvider and throw an Authenticationexception.

You will also need to override the onUnsuccessfulAuthentication function in the BasicAuthenticationFilter to write the error response you want. You'll have to configure it as a custom filter, rather than using the <security:http-basic /> element.

1
On

I never do it before using spring security, but I think this article describe everything that you need: http://www.mkyong.com/spring-security/customize-http-403-access-denied-page-in-spring-security/