4
votes

I'm breaking my grails application into modules by using plugins and then adding the inline plugin locations to BuildConfig.groovy. Right now I have a grails application called 'admin' and a plugin called 'common'.

'common' plugin contains all my shared domain objects and also has the spring-security-core plugin installed. As I understand it, I also needed to install the spring-security-core plugin into 'admin' so I've done that.

I ran s2-quickstart on 'common' and it contains the Domain mappings for User and Role inside Config.groovy. When I run the application, it redirect appropriately on secured content (via the @Secured annotation). However, when I attempt to authenticate, it is still trying to query for Person instead of User.

I added the domain mappings from 'common' Config.groovy into 'admin' and the query now works, but it can't find the additional properties I've added to the User domain that exists in the 'common' plugin.

Am I missing something here? I'd rather not have to put User and Role in the 'admin' application since I want to be able to reuse User and Role in another app that also uses the 'common' plugin.

UPDATE: I realized I had conflicting spring-security-core plugins installed (copy and paste issue). I resolved that which cleaned up the issue with it trying to find Person instead of User. Now, however, I am getting the following stacktrace

java.lang.NullPointerException: Cannot get property 'clazz' on null object

at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56)

at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156)

at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:44)

at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:235)

at org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService.loadUser(GormUserDetailsService.groovy:80)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)

at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)

at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:153)

at org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService.loadUserFromSession(GormUserDetailsService.groovy:72)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)

at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)

at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1003)

at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)

at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)

at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)

at org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService$_loadUserByUsername_closure1.doCall(GormUserDetailsService.groovy:57)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)

at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)

at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070)

at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:886)

at groovy.lang.Closure.call(Closure.java:276)

at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:51)

at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:79)

at $Proxy17.doInTransaction(Unknown Source)

at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:188)

at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)

at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)

at org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService.loadUserByUsername(GormUserDetailsService.groovy:59)

at org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService$loadUserByUsername.callCurrent(Unknown Source)

at org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService.loadUserByUsername(GormUserDetailsService.groovy:68)

at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:86)

at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:129)

at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:130)

at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)

at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:97)

at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)

at org.codehaus.groovy.grails.plugins.springsecurity.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:40)

at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)

at org.codehaus.groovy.grails.plugins.springsecurity.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:79)

at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)

at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)

at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)

at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:167)

at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)

at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:104)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:69)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:65)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)

at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)

at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)

at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)

at java.lang.Thread.run(Thread.java:680)
3
Adding the domain mappings into admin's Config.groovy solved this problem, but I'm not sure why I have to do that.Gregg
A plugin's Config.groovy is used for its local development, testing, etc. but isn't exported, so the app's Config.groovy has to have the settings in it. You could probably configure things in doWithApplicationContext in the 'common' plugin since that runs before any auth attempts would happen.Burt Beckwith
Thanks Burt. I'll take a look at that approach. BTW, getting ready to post a question about ui-performance plugin. So keep your eyes open. :)Gregg
@BurtBeckwith and Gregg: I have a similar question [link].(stackoverflow.com/questions/50494260/…) Any of you think you can take a shot at it?Bmoe

3 Answers

5
votes

So taking Burt's advice, I added the following in my CommonGrailsPlugin.groovy..

def doWithApplicationContext = { applicationContext ->
    SpringSecurityUtils.securityConfig.userLookup.userDomainClassName = 'com.wbr.common.security.User'
    SpringSecurityUtils.securityConfig.userLookup.authorityJoinClassName = 'com.wbr.common.security.UserRole'
    SpringSecurityUtils.securityConfig.authority.className = 'com.wbr.common.security.Role'
}

This keeps me from having to copy this config into all of the application that depend on this plugin. And since those applications don't need to customize this configuration, it works great! Thanks Burt!

1
votes

Just make sure the following lines match your package and domain object names in conf/Config.groovy. Change the package and object names accordingly

// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'THIS.IS.THE PACKAGE.Person'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'THIS.IS.THE.PACKAGE.PersonAuthority'
grails.plugins.springsecurity.authority.className = 'THIS.IS.THE.PACKAGE.Authority'
0
votes

Here's what's happening. For flexibility, the security plugin lets you define the class you use for security in conf/Config.gs. It then dynamically loads that class by doing

def User = AH.application.getDomainClass( SpringSecurityUtils.securityConfig.userLookup.userDomainClassName).clazz )

and using the User class. If you've changed the class name and didn't change the config you'll get this error.