Currently, in master branch, we can't secure an API with:
@Secured(AuthoritiesConstants.ADMIN)
I will complete this ticket later, if needed
@Secured(AuthoritiesConstants.ADMIN)entityName.json files generated in the .jhipster directory@pascalgrimaud does @PreAuthorize("hasRole('ROLE_USER')") work?
I will test.
I created the ticket during the formation, with Julien and Pierre, didn't investigate enough.
This is crazy.
So we used to add @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) to the SecurityConfiguration bean.
To be precise, here is how it looks like:
@Configuration
@Import(SecurityProblemSupport.class)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
But if you add it on a monolith application, it won't start, and will crash with the following message:
java.lang.RuntimeException: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer@2000ae4c to already built object
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.afterSingletonsInstantiated(GlobalMethodSecurityConfiguration.java:153)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:777)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
at fr.manpower.BugTrackerApp.main(BugTrackerApp.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$EnableGlobalAuthenticationAutowiredConfigurer@2000ae4c to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:196)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:147)
at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:116)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.authenticationManager(GlobalMethodSecurityConfiguration.java:321)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.initializeMethodSecurityInterceptor(GlobalMethodSecurityConfiguration.java:194)
at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.afterSingletonsInstantiated(GlobalMethodSecurityConfiguration.java:150)
... 13 common frames omitted
I've spent the evening on this and have no idea how to fix this.
To prevent this issue in the future, we'll also need to do some unit tests using the @WithMockUser annotation, but this should be done later.
I've found the cause, this is crashing because of:
@Bean
@Override
public AuthenticationManager authenticationManager() {
In the SecurityConfiguration Bean. This was working with JHipster 4, however.
So this "AuthenticationManager" part used to be configured using a @PostConstruct annotation and now this is a Spring Bean, which makes this fail.
The smartass who did this change is me, of course :-)
And I have no idea why :-))
The issue is that this change looks required by Spring Boot 2.0, and if we don't do it, it looks like we have no AuthenticationManager anymore. So there seems to be a good reason initially to do this change.
Thanks Julien for the full details.
As discussed yesterday, I confirm we have the same issue in Registry, but as there is only 1 ROLE_ADMIN there, it's not really important.
Here the 2 links of Security part with Spring Boot 2, in the case of someone wants to help:
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#security
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Security-2.0
@deepu105 : just tried your suggestion, it doesn't work, because @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) is missing
I found a fix for this problem. The AuthenticationManager bean is injected into UserJWTController bean. With JHipster 4, this "AuthenticationManager" is configured using the @PostContruct annotation. I think that it's not a good idea to create directly the AuthenticationManager. I prefer to delegate this instantiation using a AuthenticationManagerBean, the bean is created by Spring Security. See the documentation for more details.
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#authenticationmanager-bean
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
Thanks @juliensadaoui - OK I know how to do this, let me do this over the week-end
EDIT: Actually, sorry. This issue is about @Secured not working. That is not the case for me. @Secured works fine, but using @WithMockUser in an integration test does not work for me.
Original:
Any update on this? I'm still seeing this issue with v5.2.0. Using the @Secured annotation works fine "In Real Life", but none of the tests that JHipster generates will fail if I add the @Secured annotation and use @WithMockUser in the test.
Steps to reproduce:
@Secured(AuthoritiesConstants.ADMIN) to a rest method that didn't already have it.@WithMockUser(username = "user", password = "password", roles = "USER") to a corresponding test, so that it __should__ fail (but doesn't)For tests it's a different issue, it's just that the Spring test context doesn't configure security. I guess the idea is that we just test business methods, and also that'll easier to setup and faster to run.
But I'm like you, I would like to be able to test this, for me that's a limitation with Spring tests.
In my JHipster 5 tutorial, I was able to use @WithMockUser w/o any issues. I'm not using the @Secured annotation, but @WithMockUser works for me.
Oh yes, @WithMockUser works, I use it very often. It's only the @Secured.
Of course @cbornet has the best answer: https://github.com/jhipster/generator-jhipster/issues/7806#issuecomment-398165015
I got it to work, without having to use @cbornet's suggestion in https://github.com/jhipster/generator-jhipster/issues/7806#issuecomment-398165015, which was throwing an exception (see https://github.com/jhipster/generator-jhipster/issues/7806#issuecomment-417109949).
I annotated the service method with @Secured(AuthoritiesConstants.ADMIN), rather than the rest controller method. It actually feels better to do it that way anyway, so I really don't have to change the rest controllers at all and all of my logic lives in the service.
Even better than that, I was able to annotate the service __interface's__ method, rather than the service method, and it worked.
Oh thanks @RothAndrew - yes I understand the services work, as they are not mocked. I'll keep this in mind, I wanted to add more tests on this part, and that's a way to achieve it.