Closed daptordarattler closed 6 years ago
please check the referenced sample app (csrf protection disabled to make it shorter).
seems like spring-security-5.x does not work ootb with grails-3.3.x (or rather spring-boot-1.5.x).
so please try using the spring security version the spring-boot bom defines (by removing the versions from the spring security dependencies).
while i was not able to reproduce your problem exactly, i got another exception with spring-security-5.x:
Error creating bean with name 'mvcContentNegotiationManager' defined in org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.accept.ContentNegotiationManager]: Factory method 'mvcContentNegotiationManager' threw exception; nested exception is java.lang.AbstractMethodError: org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration.configureContentNegotiation(Lorg/springframework/web/servlet/config/annotation/ContentNegotiationConfigurer;)
readme updated accordingly on master.
Update: Got it working by checking the spring-security-core version to be 4.2.4 and used that version for
compile 'org.grails.plugins:spring-security-core:3.2.1'
// compile "org.springframework.security:spring-security-config:4.2.4.RELEASE"
compile "org.springframework.security:spring-security-messaging:4.2.4.RELEASE"
compile "org.springframework.security:spring-security-web:4.2.4.RELEASE"
NOTE: spring-security-config:4.2.4.RELEASE is commented out
But when I include it like this:
compile "org.springframework.security:spring-security-config:4.2.4.RELEASE"
I get the following error:
2018-04-23 11:47:15.322 ERROR --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean named 'mvcHandlerMappingIntrospector' that could not be found.
Action:
Consider defining a bean named 'mvcHandlerMappingIntrospector' in your configuration.
Trying to figure out what spring-security-config needs or how to get a bean called mvcHandlerMappingIntrospector
as the sample app i referenced works there has to be something going on with your setup, i think.
e.g. now i see you are using the spring-security-core grails plugin. the readme and the sample app do not. that changes a lot. ref #63, for example.
also, without spring-security-config
, you will be missing important classes for websocket security configuration like AbstractSecurityWebSocketMessageBrokerConfigurer
.
a sample app replicating your setup and reproducing your problem/exception/stacktrace would be helpful. everything else means playing a guessing game..
Ok after referencing issue u mentioned. the application runs fine with the right spring-security-core dependencies:
compile 'org.grails.plugins:spring-security-core:3.2.1'
compile "org.springframework.security:spring-security-config"
compile "org.springframework.security:spring-security-messaging"
But I am not able to bind my WebSecurityConfig.groovy file. It always gives an error
2018-04-23 12:21:05.702 ERROR --- [ main] o.s.boot.SpringApplication : Application startup failed
java.lang.IllegalArgumentException: Class name [org.grails.spring.aop.autoproxy.GroovyAwareInfrastructureAdvisorAutoProxyCreator] is not a known auto-proxy creator class
at org.springframework.aop.config.AopConfigUtils.findPriorityForClass(AopConfigUtils.java:140)
at org.springframework.aop.config.AopConfigUtils.registerOrEscalateApcAsRequired(AopConfigUtils.java:113)
at org.springframework.aop.config.AopConfigUtils.registerAutoProxyCreatorIfNecessary(AopConfigUtils.java:74)
at org.springframework.aop.config.AopConfigUtils.registerAutoProxyCreatorIfNecessary(AopConfigUtils.java:70)
at org.springframework.context.annotation.AutoProxyRegistrar.registerBeanDefinitions(AutoProxyRegistrar.java:72)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:354)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:143)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:320)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at com.play521.Application.main(Application.groovy:12)
2018-04-23 12:21:05.710 ERROR --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Destroy method on bean with name 'grailsApplicationPostProcessor' threw an exception
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@21694e53: startup date [Mon Apr 23 12:21:00 GMT 2018]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:414)
at org.springframework.context.support.ApplicationListenerDetector.postProcessBeforeDestruction(ApplicationListenerDetector.java:97)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:253)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:961)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:968)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1030)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1006)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:958)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at com.play521.Application.main(Application.groovy:12)
2018-04-23 12:21:05.711 ERROR --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Destroy method on bean with name 'org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory' threw an exception
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@21694e53: startup date [Mon Apr 23 12:21:00 GMT 2018]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:414)
at org.springframework.context.support.ApplicationListenerDetector.postProcessBeforeDestruction(ApplicationListenerDetector.java:97)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:253)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:961)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:968)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1030)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1006)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:958)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at com.play521.Application.main(Application.groovy:12)
And you keep mentioning a sample app, but I dont see it anywhere in the README.md, unless your talking about the sample code show in README.md, and currently I have not customized anything, yet I am still having the error
i am talking about this comment https://github.com/zyro23/grails-spring-websocket/issues/64#issuecomment-383291099 referencing this sample app for your issue: https://github.com/zyro23/grails-spring-websocket-issue-64/commit/760eeca6b8dcc2caf8c071f722fee2e6b9deb277
now i added a second branch spring-security-core-plugin
that shows all is fine with the plugin being used, too... https://github.com/zyro23/grails-spring-websocket-issue-64/commit/f2e71685c8fd6d8f2c8e7a144a82f397f23c4ccb
OK. Thanks for the sample application and feedback. I was able to get the application running, by doing it the way its defined in your sample. The problem is that, anytime I updated the WebSocketSecurityConfig, i would go and autowire it in the resources.groovy file like this:
import com.myapp.WebSocketSecurityConfig
// Place your Spring DSL code here
beans = {
webSocketSecurityConfig(WebSocketSecurityConfig)
}
After getting rid of that line, the app runs fine.
However, endpoints access is not working as I would expect. For example, I have permitAll set on the /stomps/ in static rules `[pattern: '/stomp/', access: ['permitAll']]` but yet when I run the app, after connection is successfull, all the endpoints are not able to subscribe to any channels. This is the structure of my WebSocketSecurityConfig configureInbound method:
@Override
void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
println "Testing websocket filters"
messages
.nullDestMatcher().authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
.simpDestMatchers("/app/**").permitAll()
.simpDestMatchers("/bet/**").permitAll()
.simpSubscribeDestMatchers("/user/**", "/topic/**").permitAll()
.simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).permitAll()
.anyMessage().permitAll()
}
I get the feeling this is happening because the WebSocketSecurityConfig is not wired properly. Also I in your example, a user account is required to access the route, hence once logged in, there are no errors. It should be possible to permitAll on the stomp routes for testing or on certain channel subscription endpoints , right?
Thanks again, and hoping to get your feedback soon.
please provide a sample app reproducing the problem. i will take a look.
Thanks, figured it out. Seems the security configuration inside the application.groovy does not affect the websocket endpoints and can only be controlled by the WebSocketSecurityConfig.groovy file. Hence After probing, I saw that I only had to update the configureInbound method like this to get it working:
@Override
void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
println "Testing websocket filters"
messages
.nullDestMatcher().anonymous()
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
.simpDestMatchers("/app/**").permitAll()
.simpDestMatchers("/bet/**").permitAll()
.simpSubscribeDestMatchers("/user/**", "/topic/**").permitAll()
.simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
.anyMessage().denyAll()
}
Then for specific roles the following works:
@Override
void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
println "Testing websocket filters"
messages
.nullDestMatcher().anonymous()
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
.simpDestMatchers("/app/**").hasRole("USER")
.simpDestMatchers("/bet/**").hasRole("USER")
.simpSubscribeDestMatchers("/user/**", "/topic/**").hasRole("USER")
.simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
.anyMessage().denyAll()
}
The key is in the line that checks for .nullDestMatcher().anonymous()
where for all authenticated endpoints it should be .nullDestMatcher().authenticated()
Thanks for the back and forth. Appreciated
just for the sake of completeness, the security config in application.groovy (i.e. spring security web) does work. it secures the initial http request to /stomp/**
.
now you changed the messaging security config from .nullDestMatcher().authenticated()
to .nullDestMatcher().anonymous()
. that configures the policy for the initial stomp messages (CONNECT
or STOMP
frames). as long as you have unauthenticated users which should be able to connect to the stomp broker, that has to be allowed (maybe permitAll
should be preferred as that will work for anonymous as well as logged-in users).
glad you figured it out.
So i was looking at the sample to implement spring security over websockets, and I run into this problem
Also added these to my dependency to try to solve the problem:
instead of this:
And customized my WebSecurityConfig a bit like this:
I am very sure the problem is from the spring-security-config, message, & web dependencies. Because when I take them out and remove the config class, everything works fine again. here are my env details
Let me know if you need more details to help me resolve this problem. thanks in advance