Grails:Spring Security CAS 在 2.2.3 中工作,但在 2.3.0 中不起作用



我在Grails 2.2.3中使用Groovy 2.0有一个项目。我用 Spring 安全性设置了它,以使用 CAS 进行身份验证,使用 LDAP 进行用户角色。当我运行该应用程序时,一切都可以正常工作:任何人都可以访问/appcontext/,/appcontext/admin/下的任何内容都由 CAS 和 LDAP 的管理员角色保护。我现在正在尝试使用最新版本的Grails和Groovy。我安装了GGTS 3.4.0.RELEASE,正在使用Grails 2.3.0和Groovy 2.1。我创建了一个新项目,制作了一个简单的域类和控制器,并添加了安全设置。

以下是我使用 GGTS 3.3.0.RELEASE 运行应用程序时,使用 Grails 2.2.3 和 Groovy 2.0 的输出:(请注意"服务器正在运行"消息的位置)

| Loading Grails 2.2.3
| Configuring classpath.
| Environment set to development.....
| Packaging Grails application.....
| Running Grails application
Configuring Spring Security Core ...
... finished configuring Spring Security Core
Configuring Spring Security CAS ...
... finished configuring Spring Security CAS
Configuring Spring Security LDAP ...
... finished configuring Spring Security LDAP
| Server running. Browse to http://localhost:8080/appcontext

以下是我使用 GGTS 3.4.0.RELEASE 运行应用程序时的输出,使用 Grails 2.3.0 和 Groovy 2.1(请注意"服务器正在运行"消息的位置):

| Loading Grails 2.3.0
| Configuring classpath.
| Environment set to development.....
| Packaging Grails application.....
| Compiling 1 source files.....
| Running Grails application
| Server running. Browse to http://localhost:8080/appcontext
Configuring Spring Security Core ...
... finished configuring Spring Security Core
Configuring Spring Security LDAP ...
... finished configuring Spring Security LDAP
Error initializing the application: No bean named 'casAuthenticationProvider' is defined
    org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'casAuthenticationProvider' is defined
        at SpringSecurityCoreGrailsPlugin$_createBeanList_closure22.doCall(SpringSecurityCoreGrailsPlugin.groovy:686)
        at SpringSecurityCoreGrailsPlugin.createBeanList(SpringSecurityCoreGrailsPlugin.groovy:686)
        at SpringSecurityCoreGrailsPlugin$_closure4.doCall(SpringSecurityCoreGrailsPlugin.groovy:615)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
| Error 2013-10-15 11:33:02,925 [localhost-startStop-1] ERROR context.GrailsContextLoader  - Error initializing the application: No bean named 'casAuthenticationProvider' is defined
Message: No bean named 'casAuthenticationProvider' is defined
   Line | Method
->> 686 | doCall         in SpringSecurityCoreGrailsPlugin$_createBeanList_closure22
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   615 | doCall         in SpringSecurityCoreGrailsPlugin$_closure4
|   303 | innerRun . . . in java.util.concurrent.FutureTask$Sync
|   138 | run            in java.util.concurrent.FutureTask
|   886 | runTask . . .  in java.util.concurrent.ThreadPoolExecutor$Worker
|   908 | run            in     ''
^   662 | run . . . . .  in java.lang.Thread
schema export unsuccessful
org.h2.jdbc.JdbcSQLException: Database is already closed (to disable automatic closing     at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-170]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:169)
    at org.h2.message.DbException.get(DbException.java:146)
    at org.h2.message.DbException.get(DbException.java:135)
    at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1391)
    at org.h2.jdbc.JdbcConnection.checkClosed(JdbcConnection.java:1366)
    at org.h2.jdbc.JdbcConnection.getAutoCommit(JdbcConnection.java:424)
    at java.lang.Thread.run(Thread.java:662)
| Error 2013-10-15 11:33:03,071 [Thread-9] ERROR hbm2ddl.SchemaExport  - schema export unsuccessful
Message: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-170]
    Line | Method
->>  329 | getJdbcSQLException in org.h2.message.DbException
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    169 | get                 in     ''
|    146 | get . . . . . . . . in     ''
|    135 | get                 in     ''
|   1391 | checkClosed . . . . in org.h2.jdbc.JdbcConnection
|   1366 | checkClosed         in     ''
|    424 | getAutoCommit . . . in     ''
^    662 | run                 in java.lang.Thread
| Error Forked Grails VM exited with error

这是我的基本安全设置:

conf/spring/resources.groovy

import org.apache.commons.lang.StringEscapeUtils
// Place your Spring DSL code here
beans = {
    // load ldap roles from spring security
    def ldapUrl = StringEscapeUtils.escapeJava('${ldap.defaultUrl}')
    def ldapUser = StringEscapeUtils.escapeJava('${ldap.username}')
    def ldapPassword = StringEscapeUtils.escapeJava('${ldap.password}')
    def ldapBase = StringEscapeUtils.escapeJava('${ldap.base}')
    def ldapRoleSearchBase = StringEscapeUtils.escapeJava('${ldap.roleSearchBase}')
    initialDirContextFactory(org.springframework.security.ldap.DefaultSpringSecurityContextSource, ldapUrl){
        userDn = ldapUser
        password = ldapPassword
    }
    ldapUserSearch(org.springframework.security.ldap.search.FilterBasedLdapUserSearch,
        ldapBase, 'sAMAccountName={0}', initialDirContextFactory){ }
    ldapAuthoritiesPopulator(org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator,
        initialDirContextFactory, ldapRoleSearchBase){
            groupRoleAttribute = 'cn'
            groupSearchFilter = 'member={0}'
            searchSubtree = true
            rolePrefix = 'ROLE_'
            convertToUpperCase = true
            ignorePartialResultException = true
        }
    userDetailsService(org.springframework.security.ldap.userdetails.LdapUserDetailsService,ldapUserSearch,ldapAuthoritiesPopulator){ }

}

conf/Config.groovy

def appName = grails.util.Metadata.current.getApplicationName()
environments {
    development {
        grails.logging.jul.usebridge = true
        host.ip = "12.34.56.78"
        host.port = "8080"
        host.securePort = "8080"
        ldap.username = "ldapUsername"
        ldap.password = "ldapPassword"
        ldap.base = "DC=foo,DC=company,DC=com"
        ldap.roleSearchBase = "OU=bar,DC=foo,DC=company,DC=com"
        ldap.defaultUrl = "ldap://123.45.67.89:389"
        ldap.urls = "ldap://123.45.67.89:389 ldap://123.45.67.89:389"
        cas.url = "https://sso.company.com/cas/"
        cas.loginUrl = "https://sso.company.com/cas/login"
        cas.logoutUrl = "https://sso.company.com/cas/logout"
        grails.plugins.springsecurity.cas.serviceUrl = 'http://${host.ip}:${host.securePort}/' + appName +'/j_spring_cas_security_check'
        grails.plugins.springsecurity.cas.proxyCallbackUrl = 'http://${host.ip}:${host.securePort}/' + appName +'/secure/receptor'
    }
    production {
        grails.logging.jul.usebridge = false
        grails.plugins.springsecurity.cas.serviceUrl = 'https://${host.ip}:${host.securePort}/' + appName +'/j_spring_cas_security_check'
        grails.plugins.springsecurity.cas.proxyCallbackUrl = 'https://${host.ip}:${host.securePort}/' + appName +'/secure/receptor'
    }
}
//spring security core config
grails.plugins.springsecurity.providerNames = ['casAuthenticationProvider']
grails.plugins.springsecurity.rejectIfNoRule = true
grails.plugins.springsecurity.securityConfigType = "InterceptUrlMap"
grails.plugins.springsecurity.interceptUrlMap = [
    '/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    '/css/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    '/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    '/admin/login/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    '/admin/logout/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    '/admin/**': ['hasAnyRole("ROLE_ADMIN")'],
    '/**': ['IS_AUTHENTICATED_ANONYMOUSLY']
]
//cas config
grails.plugins.springsecurity.cas.loginUri = 'login'
grails.plugins.springsecurity.cas.serverUrlPrefix = '${cas.url}'
grails.plugins.springsecurity.cas.proxyReceptorUrl = '/secure/receptor'

conf/BuildConfig.groovy

compile ":spring-security-core:1.2.7.3"
compile ":spring-security-cas:1.0.5"
compile ":spring-security-ldap:1.0.6"

编辑使用下面接受的答案的建议,我能够让 Spring 安全 CAS 正确配置,但我的控制器仍然不安全。我认为这与那个奇怪的加载顺序有关,其中应用程序服务器说它正在运行,然后它加载Spring Security,LDAP和CAS。一位同事建议取出我的 InterceptUrlMap 并使用@Secured注释来查看它是否是加载顺序(因为 InterceptUrlMap 在一切启动并运行后无法更新)。我摆脱了 rejectIfNoRule、securityConfigType 和 interceptUrlMap 设置,并在控制器中添加了一个 @Secured(['ROLE_ADMIN'])。应用现在按预期工作,并且该控制器是安全的。

因此,Grails 2.3.0 和 Spring Security 的事件顺序仍然存在问题,但这是一种解决方法。

相关问题:https://stackoverflow.com/questions/19411102/grails-2-3-0-spring-security-ldap-and-cas-load-after-server-starts

我看到了同样的事情。看起来来自DefaultCasSecurityConfig.groovy的CAS插件默认值在Grails 2.3.0下没有正确合并。 可能值得一个吉拉。 同时,您可以通过将默认值添加到 Config.groovy (覆盖您的环境)来继续前进:

grails.plugins.springsecurity.cas.active = true
grails.plugins.springsecurity.cas.loginUri = null // must be set, e.g. '/login'
grails.plugins.springsecurity.cas.sendRenew = false
grails.plugins.springsecurity.cas.serviceUrl = null // must be set, e.g. 'http://localhost:8080/myapp/j_spring_cas_security_check'
grails.plugins.springsecurity.cas.serverUrlPrefix = null // must be set, e.g. 'http://localhost:9090/cas'
grails.plugins.springsecurity.cas.serverUrlEncoding = 'UTF-8'
grails.plugins.springsecurity.cas.key = 'grails-spring-security-cas'
grails.plugins.springsecurity.cas.artifactParameter = 'ticket'
grails.plugins.springsecurity.cas.serviceParameter = 'service'
grails.plugins.springsecurity.cas.filterProcessesUrl = '/j_spring_cas_security_check'
grails.plugins.springsecurity.cas.proxyCallbackUrl = null // should be set, e.g. 'http://localhost:8080/myapp/secure/receptor'
grails.plugins.springsecurity.cas.proxyReceptorUrl = null // should be set, e.g. '/secure/receptor'
grails.plugins.springsecurity.cas.useSingleSignout = true
我知道

这个线程有点旧,但是在 2.0-RC1 中遇到同样的问题时,我只是偶然发现了它。

我发现默认配置没有加载到SpringSecurityCasGrailsPlugin.groovy中。 这是部署 时发生的问题。很久以前就修复了雄猫上的战争文件。 如果允许执行,为该修复程序添加的代码为我解决了这个新问题。 我只是强制if条件始终为真,如下所示(代码来自 SpringSecurityCasGrailsPlugin.groovy 中的第 105 行):

if (true /*application.warDeployed*/) {
    // need to load secondary here since web.xml was already built, so
    // doWithWebDescriptor isn't called when deployed as war
    SpringSecurityUtils.loadSecondaryConfig 'DefaultCasSecurityConfig'
    conf = SpringSecurityUtils.securityConfig
}

(只有 if 语句是更改的,其余代码用于说明)。

我不知道这可能会带来什么副作用(我还不能说... 似乎运行应用程序命令可能存在差异,使其行为类似于 .war 部署或其他东西。 无论如何,我肯定会犹豫是否以这种方式部署生产应用程序,并且会选择手动创建所有配置选项,就像在接受的答案中一样。 但也许这会为能够找出真正问题的人提供洞察力。

相关内容

最新更新