Rafael Lima
Rafael Lima

Reputation: 3535

how to override default error messages on spring-security

I'm using DaoAuthenticationProvider to provide authentication to my client requests. It is working fine in case the username/password combination is invalid it throws an AuthenticationException with a message: Bad credentials

This is good and expected behavior, but I'm trying to have more friendly messages so i would like to replace it with an error message of my own.

I found that this message comes from

public SpringSecurityMessageSource() {
        setBasename("org.springframework.security.messages");
    }

//a bunch of authentication code
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials")

I tried to replace this message by creating a file

resources/org/springframework/security/messages.properties  

and having its content as: AbstractUserDetailsAuthenticationProvider.badCredentials=anything else

but the bad message is still being thrown... what i am doing wrong? how to redefine default org.springframework.security.messages

Upvotes: 1

Views: 1337

Answers (2)

Vlad Yavorsky
Vlad Yavorsky

Reputation: 11

Find Spring Security class, which messages you need to override, it will have such field:

protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

This class also should implement MessageSourceAware interface. This interface have only one method that you need to use: void setMessageSource(MessageSource messageSource)

For example I use DaoAuthenticationProvider. It extends AbstractUserDetailsAuthenticationProvider, that implements MessageSourceAware.

From Spring Security source code:

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
   ...
}

public abstract class AbstractUserDetailsAuthenticationProvider
        implements AuthenticationProvider, InitializingBean, MessageSourceAware {
    ...
    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    ...
    @Override
    public void setMessageSource(MessageSource messageSource) {
        this.messages = new MessageSourceAccessor(messageSource);
    }
    ...
}

So, I'm overriding default DaoAuthenticationProvider and set my message source.

My code:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor // lombok
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final MessageSource messageSource;
    private final UserDetailsService userDetailsService;

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasenames("messages", "org/springframework/security/messages"); // my messages will override spring security messages, if message code the same
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService); // set my custom user details service
        provider.setMessageSource(messageSource); // set my custom messages
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authProvider()); // set dao provider with my custom messages
    }

}

My overriden messages /src/main/resources/messages.properties:

AbstractUserDetailsAuthenticationProvider.disabled=Account is not activated. Please, activate your account. The activation link is sent in email
...etc...

All available codes for messages you can find here:

org.springframework.security:spring-security-core:[version]

/org/springframework/security/messages.properties

Upvotes: 1

goldthelocks
goldthelocks

Reputation: 173

Here's what you can try using AuthenticationEntryPoint:

  1. Create a class implementing AuthenticationEntryPoint then modify .write(..) according to your desired format and message:
public class MyEntryPoint implements AuthenticationEntryPoint {
    
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, 
                 AuthenticationException authException) throws IOException {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Set your custom message here");
        }
    
}
  1. Set the custom entry point in your security config:
@Override
  protected void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling()
        .authenticationEntryPoint(new MyEntryPoint());
  }

Upvotes: 1

Related Questions