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))