如何自定义现有的Grails插件功能,修改doWithSpring方法的行为

时间:2017-10-23 22:56:34

标签: grails grails-plugin spring-ldap

我是grails的新手,在使用Spring Security LDAP插件时,发现它只接受纯文本的ldap服务器密码。手头的任务是传递一个加密的密码,该密码在插件在初始化阶段被使用之前被解密。

我已经搜索了所有可能的博客和stackoverflow问题但是找不到扩展主插件类的方法来简单地覆盖doWithSpring()方法,这样我就可以简单地为Ldap服务器密码添加所需的解密逻辑。任何帮助将不胜感激。

我已经看过并尝试了jasypt插件,但如果密码存储在某个外部文件而不是应用程序yml中,它也无法正常工作。所以我正在寻找扩展Spring安全性插件主类的解决方案,添加所需的行为并注册自定义类。

修改

从Grails LDAP Security插件添加片段,我试图覆盖它。因此,如果我能够在插件加载之前成功更新securityConfig对象的值,那么目的就会解决。

插件中的一些代码段:

    int newValue = ++atomicCount;

2 个答案:

答案 0 :(得分:0)

您无需覆盖现有插件中的doWithSpring()方法。您可以提供自己的插件,在您想要影响的插件之后加载,并让doWithSpring()在上下文中添加您想要的任何内容。如果您添加与其他插件添加的bean同名的bean,只要您将插件配置为在另一个插件之后加载,您的将替换另一个插件提供的bean。同样,如果您不想为此编写插件,您可以在应用的resources.groovy中进行相同的思考。

您还有其他选择。您可以编写一个bean后处理器或bean定义后处理器,它会影响另一个插件创建的bean。根据具体情况,这可能是一个更好的主意。

修改

在看到下面的评论之后,我创建了一个简单的示例,展示了如何使用定义后处理器。请参阅https://github.com/jeffbrown/postprocessordemo上的项目。

有趣的一点:

https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomeBean.groovy

package demo

class SomeBean {

    String someValue

}

https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomePostProcessor.groovy

package demo

import org.springframework.beans.BeansException
import org.springframework.beans.MutablePropertyValues
import org.springframework.beans.PropertyValue
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

class SomePostProcessor implements BeanDefinitionRegistryPostProcessor{
    @Override
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinition definition = registry.getBeanDefinition('someBean')
        MutablePropertyValues values = definition.getPropertyValues()
        PropertyValue value = values.getPropertyValue('someValue')
        def originalValue = value.getValue()

        // this is where you could do your decrypting...
        values.addPropertyValue('someValue', "MODIFIED: ${originalValue}".toString())
    }

    @Override
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/conf/spring/resources.groovy

beans = {
    someBean(demo.SomeBean) {
        someValue = 'Some Value'
    }

    somePostProcessor demo.SomePostProcessor
}

https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/init/postprocessordemo/BootStrap.groovy

package postprocessordemo

import demo.SomeBean

class BootStrap {

    SomeBean someBean

    def init = { servletContext ->
        log.info "The Value: ${someBean.someValue}"
    }

    def destroy = {
    }
}

在应用程序启动时,您将看到类似于此的日志输出...

2017-10-23 19:04:54.356  INFO --- [           main] postprocessordemo.BootStrap              : The Value: MODIFIED: Some Value

“MODIFIED”有证据表明bean定义后处理器修改了bean中的属性值。在我的例子中,我只是将一些文本添加到字符串中。在您的实现中,您可以解密密码或做您想做的任何事情。

我希望有所帮助。

答案 1 :(得分:0)

在我的用例中尝试使用Jasypt插件和BeanPostProcessor解决方案失败后,我发现下面的解决方案可以很好地工作。

再次描述问题陈述, a)我们必须将密码以加密格式保存在属性文件中 b)并且鉴于我们打包为war文件,因此不得在战争中保留属性以允许自动部署脚本根据环境更新加密密码

Jasypt插件是用例a)的完美解决方案,但它无法涵盖b)场景 此外,Grails LDAP Security插件很早就被加载了,因此Bean Post处理器也没有帮到这里。

解决方案: 通过实现SpringApplicationRunListener接口创建了一个新类。扩展其方法并使用YamlPropertySourceLoader

解析属性文件

示例代码:

YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); 
  PropertySource<?> applicationYamlPropertySource = loader.load( 
    "application.yml", new ClassPathResource("application.yml"),"default"); 
  return applicationYamlPropertySource;

在MapPropertySource对象中加载属性后,解析它们的加密值并应用解密逻辑。

整个实现是在Grails启动过程中初始化任何插件之前执行的。

希望它能帮助别人。