Extending SpEL with own methods in Grails? - grails

I'd like to add custom SpEL methods in Grails applciation, like it's done for plain Spring-Security application in this question, by overriding EvaluationContext. Will this work?
How do I plug global-method-security into security config? I can configure security, but what to add there? Something like
grails.plugins.springsecurity = {
'global-method-security' {
'expression-handler' {
ref("myMethodSecurityExpressionHandler")
}
}
}
? But what code will interpret it?
Looking into SpringSecurityCoreGrailsPlugin.groovy also gives me no insights.

This is only available if you also have the spring-security-acl plugin installed. It configures the expressionHandler bean:
expressionHandler(DefaultMethodSecurityExpressionHandler) {
parameterNameDiscoverer = ref('parameterNameDiscoverer')
permissionEvaluator = ref('permissionEvaluator')
roleHierarchy = ref('roleHierarchy')
trustResolver = ref('authenticationTrustResolver')
}
So if you have your own subclass of DefaultMethodSecurityExpressionHandler you can replace the bean in resources.groovy like this:
import com.mycompany.myapp.MyMethodSecurityExpressionHandler
beans = {
expressionHandler(MyMethodSecurityExpressionHandler) {
parameterNameDiscoverer = ref('parameterNameDiscoverer')
permissionEvaluator = ref('permissionEvaluator')
roleHierarchy = ref('roleHierarchy')
trustResolver = ref('authenticationTrustResolver')
}
}

Related

Wiring in custom security custom security evaluator in grails app

I was trying to simplify the code of security checks in my grails app and I found that there is a way to drive the security on a service class.
Some of the references I found related to that:
https://www.mscharhag.com/grails/spring-security-call-bean-method-in-spel-expression
Grails custom security evaluator
and some others...
So I tried wiring everything in and seems pretty straightforward, but when I am configuring my custom beans into resources.groovy I am getting this error.
A component required a bean named 'parameterNameDiscoverer' that could not be found.
My resources.groovy looks like this:
import com.auth0.client.auth.AuthAPI
import grails.plugin.springsecurity.rest.RestAuthenticationProvider
import priz.auth0.Auth0APIService
import priz.auth0.Auth0TokenStorageService
import priz.auth0.Auth0TokenVerificationService
import priz.auth0.Auth0UserResolverService
import priz.security.GrailsBeanResolver
import priz.security.GrailsExpressionHandler
import priz.security.UserPasswordEncoderListener
// Place your Spring DSL code here
beans = {
expressionHandler(GrailsExpressionHandler) {
beanResolver = ref('beanResolver')
parameterNameDiscoverer = ref('parameterNameDiscoverer')
permissionEvaluator = ref('permissionEvaluator')
roleHierarchy = ref('roleHierarchy')
trustResolver = ref('authenticationTrustResolver')
}
beanResolver(GrailsBeanResolver) {
grailsApplication = ref('grailsApplication')
}
userPasswordEncoderListener(UserPasswordEncoderListener)
authApi(AuthAPI) { beanDefinition ->
beanDefinition.constructorArgs = [
'${priz.auth0.api.domain}',
'${priz.auth0.api.clientId}',
'${priz.auth0.api.clientSecret}'
]
}
auth0APIService(Auth0APIService) {
authAPI = ref('authApi')
}
auth0TokenVerificationService(Auth0TokenVerificationService)
auth0UserResolverService(Auth0UserResolverService)
tokenStorageService(Auth0TokenStorageService) {
jwtService = ref('jwtService')
userDetailsService = ref('userDetailsService')
auth0TokenVerificationService = ref('auth0TokenVerificationService')
auth0APIService = ref('auth0APIService')
auth0UserResolverService = ref('auth0UserResolverService')
}
/* restAuthenticationProvider */
restAuthenticationProvider(RestAuthenticationProvider) {
tokenStorageService = ref('tokenStorageService')
useJwt = false
jwtService = ref('jwtService')
}
}
Of course, I don't have parameterNameDiscoverer specifically defined in the resources, but I expected that since I didn't customize any of these dependencies are already provided by the Spring Security plugins. But it seems like they cannot be found.
What am I missing? Do I need to define the entire dependency tree in resources?
This should be as simple as creating the bean instance of the implementation you want by adding something like the following to your resources.groovy
parameterNameDiscoverer(DefaultSecurityParameterNameDiscoverer)
Assuming you want the default implementation that is provided with Spring Security (v3.2+). It's not clear what implementation you want, so you may browse the java docs.

Grails create a service from a factory

I would like to utilize a service written in Java in my Grails app using dependency injection. Creating it in Java without injection would look like this:
ServiceFactory.newInstance().getElementService()
I would like to use this in the same way services are injected for controllers, services, and jobs.
class ImportJob {
def elementService
...
}
I know this should go into resources.groovy and this is what I have so far:
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
}
elementService(ElementService) {
}
I have found few resources in the documentation to help with this. How do I complete the elementService so it is creating the object as described above? Should I use a BeanBuilder?
You could create a FactoryBean for this since it's not as direct as calling a method in a class:
package com.mycompany
import org.springframework.beans.factory.FactoryBean
import org.springframework.beans.factory.InitializingBean
class ElementServiceFactoryBean implements FactoryBean<ElementService>, InitializingBean {
private ElementService elementService
ElementService getObject() { elementService }
Class<ElementService> getObjectType() { ElementService }
boolean isSingleton() { true }
void afterPropertiesSet() {
elementService = ServiceFactory.newInstance().elementService
}
}
and you'd register it in resources.groovy as
elementService(ElementServiceFactoryBean)
Use bean.factoryMethod and bean.factoryBean in the elementService bean.
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
bean.scope = 'singleton'
}
elementService(ElementService) { bean ->
bean.factoryMethod = 'getElementService'
bean.factoryBean = 'serviceFactory'
}
This is a simple solution especially if ServiceFactory is external and cannot be changed.

grailsuser MissingPropertyException

I am trying to use <sec:loggedInUserInfo field="firstName"/> and I am getting MissingPropertyException. I extended User and have in configured as below. I am not sure what I am missing...
resources.groovy
preAuthenticatedAuthenticationProvider(org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('preAuthenticatedUserDetailsService')
}
preAuthenticatedUserDetailsService(org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper) {
userDetailsService = ref('userService' )
}
userService(org.codehaus.groovy.grails.plugins.springsecurity.GormUserDetailsService){
grailsApplication = ref('grailsApplication')
}
I also have my domain classes configured in Config.groovy
grails.plugins.springsecurity.providerNames = ['preAuthenticatedAuthenticationProvider' ,'anonymousAuthenticationProvider']
// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'com.administration.AuthUser'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'com.administration.AuthUserAuthRole'
grails.plugins.springsecurity.authority.className = 'com.administration.AuthRole'

Set datasource values during run time

So essentially I'm trying to get my project up and running on AppFog. The datasource information is stored in an enviornment variable, which is essentially JSON. My goal is to take this data and set my datasource config from it.
Here is what I have tried:
Code to set the datasource config which is a method in a POGO. The POGO is instantiated and the method called at the beginning of DataSource.groovy:
import appfog.ParseDataSource
new ParseDataSource().setConfig()
dataSource {
...
}
class ParseDataSource {
void setConfig() {
String env = java.lang.System.getenv("VCAP_SERVICES")
if (env) {
def config = JSON.parse(env)
config = config["mysql-5.1"][0].credentials
grailsApplication.config.environments.production.dataSource.username = config.username
grailsApplication.config.environments.production.dataSource.password = config.password
grailsApplication.config.environments.production.dataSource.url = "jdbc:mysql://" + config.host + ":" + config.port + "/" + config.name
}
}
}
The problem is that grailsApplication is always null. I've tried registering a spring bean in resources.groovy:
beans = {
parseDataSource(appfog.ParseDataSource) {
grailsApplication = ref('grailsApplication')
}
}
class ParseDataSource {
def grailsAPplication
...
}
I've also tried getting it via Holders:
GrailsApplication grailsApplication = Holders.grailsApplication
Either way it is null so I'm not doing something right. Any ideas?
I think you are making this overly complex. Overwriting the grails config object while still in the process of building it would cause an order of operations issue that would make the code very fragile.
Simply setting the values directly seems more straightforward:
Datasource.groovy:
def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
def mysqlConfig = configJson["mysql-5.1"][0].credentials
dataSource = {
production = {
username = mysqlConfig.username
// etc.
}
}
If you wanted to keep parsing in its own class for clarity's sake, make the values properties and read them in the dataSource block rather than trying to put them in the grails config object:
config parsing:
class EnvironmentConfigParser {
String username
String password
String url
EnvironmentConfigParser() {
def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
def mysqlConfig = configJson["mysql-5.1"][0].credentials
username = mysqlConfig.username
password = mysqlConfig.password
url = "jdbc:mysql://${mysqlConfig.host}:${mysqlConfig.port}/${mysqlConfig.name}"
}
}
in Datasource.groovy:
def parser = new EnvironmentConfigParser()
dataSource = {
production = {
username = parser.username
// etc
}
}
You should be able to access grailsApplication the way you have injected in resources.groovy provided you are injecting the bean parseDataSource somewhere in your application in any artefact.
In your special case you need the bean to be available in datasource.groovy. You were instantiating the POGO which will not help you injecting grailsApplication to the POGO. On the other hand, you cannot actually inject the POGO to datasource.groovy like
def parseDataSource
because it(datasource) is a config object during bootstrap.
The best way remains will be to metaClass the pogo at BootStrap and make grailsApplication available to it. Burt has shown it here exactly that way.
I was also thinking whether BeanPostProcessor can be useful in this case but I am not sure whether config per environment will be achieved. But you can give it a try if it helps in achieving your business need. It generally goes like:
//src/groovy
import org.springframework.beans.factory.config.BeanPostProcessor
class DatasourcePostProcessor implements BeanPostProcessor{
def parseDataSource
#Override
Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean
}
#Override
Object postProcessAfterInitialization(Object bean, String beanName) {
if(beanName == 'dataSource') {
//Set values to dataSource bean as required
parseDataSource.setConfig(bean)
}
return bean
}
}
//resources.groovy
parseDataSource(ParseDataSource){
grailsApplication = ref('grailsApplication')
}
datasourcePostProcessor(DatasourcePostProcessor){
parseDataSource = ref('parseDataSource')
}

springSecurityService in resources.groovy grails file?

I'm having trouble accessing springSecurityService from resources.groovy file, I'm trying to load user locale setting and create LocaleResolver
import User
beans = {
localeResolver(org.springframework.web.servlet.i18n.SessionLocaleResolver) {
def user = User.get(springSecurityService.principal.id)
if (user?.settings?.locale) {
defaultLocale = new Locale(user?.settings?.locale)
java.util.Locale.setDefault(defaultLocale)
}
}
}
Thanks,
Mika
Your code above doesn't make a lot of sense. In resources.groovy you're supposed to define the implementation class of Spring beans and set their dependencies. It looks like you're trying to actually write the implementation class in resources.groovy.
Instead you should write your own LocaleResolver class
package org.example
class MyLocaleResolver extends AbstractLocaleResolver {
def springSecurityService
// implementation of methods omitted, because I haven't clue how you want to resolve Locales
}
Then in resources.groovy, define a bean of this type that replaces the default localeResolver bean
beans = {
localeResolver(org.example.MyLocaleResolver) {
springSecurityService = ref('springSecurityService')
}
}

Resources