When setting multiple spring message bundles, as advised in https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-internationalization.html: spring.messages.basename=messages,message-commons

Now if a spring-security error occurs, the spring-security error messages are not loaded correctly. The following warning is printed:

ResourceBundle [messages] not found for MessageSource: Can't find bundle for base name messages, locale en

Interestingly, if you change the properties to a non-existing resource bundle, eg: spring.messages.basename=messages,message-commons2

Then the warning disappears!

Reproduce as follows:

@SpringBootApplication
public class ResourcebundleFailureApp {
    public static void main(String[] args) {
        SpringApplication.run(ResourcebundleFailureApp.class, args);
    }
}

@RestController
public class TestController {
    @GetMapping("/test")
    public void test() {
    }
}

application.properties:
spring.messages.basename=messages,message-commons2

message-commons.properties (empty)


Unit test:
@RunWith(SpringRunner.class)
@WebMvcTest(TestController.class)
public class ResourceBundleTest {
    @Autowired
    private MockMvc mvc;

    //fails with 401 unauthorized + prints:
    //'ResourceBundle [messages] not found for MessageSource: Can't find bundle for base name messages, locale en'
    @Test
    public void testBundle() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/test")).andExpect(status().isUnauthorized());
    }
}

Of course the test succeeds, but in the logs you see ResourceBundleMessageSource error. resourcebundle-failure.zip

Comment From: eleftherias

This issue isn't specific to spring-security exceptions. It can be reproduced when spring-security is removed from the dependencies, with a custom exception, for example:

@ResponseStatus(code = HttpStatus.UNAUTHORIZED, reason = "Unauthorized user")
public class CustomException extends RuntimeException {
}

And in the controller:

@RestController
public class TestController {
    @GetMapping("/test")
    public void test() {
        throw new CustomException();
    }
}

@membersound Can you please create this issue at https://github.com/spring-projects/spring-boot/issues?

Furthermore, the error message ResourceBundle [messages] not found for MessageSource: Can't find bundle for base name messages, locale en is expected behaviour, since the file messages.properties does not exist. However, as you mentioned, it is unexpected that the warning disappers when adding 2 non-existing resource bundles, such as spring.messages.basename=messages,message-commons2

Comment From: eleftherias

Closing as invalid since this is part of another project.

Comment From: membersound

Thanks for having a look.

Regarding your statement that this is the expected behavior: is it? I mean, if I add a custom messages.properties where I just set some self-defined message keys that I could eg use in @Controller request parameter validations, why shouldn't error messages fallback to the springs' default message bundle if I did not set my own keys?

I mean, eg I won't add i18n for any exceptions that might occur, like AUTH 401 exceptions, but still would like to receive the spring-default messages.

Or did I get the docs wrong, and I should remove the messages bundle from the definition, and just use my message-commons basename?

Comment From: eleftherias

@membersound if you do not add specific overrides for the exception messages, then spring-security will continue to use the default messages.

If you want to add custom message keys to use in your application, you can create a file named messages.properties and set your key-value pairs in that file e.g:

name.label=First Name

Spring boot will pick up that file by default without any further configuration needed, and spring security will continue to use the default error messages.

Alternatively, if you want to name your message file something else, like message-commons.properties, you can create the file message-commons.properties and tell spring boot that your custom messages can be found in that file by setting spring.messages.basename=message-commons in your application.properties. Then you can add any key-value pairs in that file. Spring security will continue to use the default error messages.

The only time spring security will use a custom exception message is if you specify it in your messages file (whether it be messages.properties or message-comons.properties), e.g:

AbstractAccessDecisionManager.accessDenied=Access denied for my app

Comment From: membersound

So the conclusion is: just name all of your bundles messages.properties, and they won't override each other if you have multiple of them in multiple shared libraries.

Comment From: william566066

i had some problem where create UnanimousBased as a Bean

@Bean
public AccessDecisionManager accessDecisionManager() {

List<AccessDecisionVoter<? extends Object>> decisionVoters
            = Arrays.asList(
            new WebExpressionVoter(),
            // new RoleVoter(),
            //new RoleBasedVoter(),
            new C2RoleVoter(c2Authorization()));
        return new UnanimousBased(decisionVoters);
    }

UnanimousBased implements MessageSourceAware,so default SpringSecurityMessageSource.getAccessor() will overwrite by setMessageSource then i changed to


public void configure(HttpSecurity http) throws Exception {
http
...
.accessDecisionManager(new UnanimousBased(decisionVoters))