Grails:Spring安全CA在2.2.3中工作,但在2.3.0中不工作
我在Grails2.2.3中有一个使用Groovy 2.0的项目。我使用SpringSecurity设置了CAS进行身份验证,使用LDAP进行用户角色验证。当我运行应用程序时,一切正常:任何人都允许访问/appcontext/,而/appcontext/admin/下的任何内容都由CAS和LDAP中的管理员角色保护。我现在正在尝试使用Grails和Groovy的最新版本。我安装了GGTS3.4.0.RELEASE,并使用Grails2.3.0和Groovy 2.1。我创建了一个新项目,创建了一个简单的域类和控制器,并添加了安全设置 这是我使用Grails 2.2.3和Groovy 2.0运行GGTS 3.3.0.RELEASE应用程序时的输出:(注意“服务器正在运行”消息的位置) 这是我使用Grails 2.3.0和Groovy 2.1运行GGTS 3.4.0.RELEASE应用程序时的输出(注意“服务器正在运行”消息的位置):Grails:Spring安全CA在2.2.3中工作,但在2.3.0中不工作,grails,spring-security,cas,Grails,Spring Security,Cas,我在Grails2.2.3中有一个使用Groovy 2.0的项目。我使用SpringSecurity设置了CAS进行身份验证,使用LDAP进行用户角色验证。当我运行应用程序时,一切正常:任何人都允许访问/appcontext/,而/appcontext/admin/下的任何内容都由CAS和LDAP中的管理员角色保护。我现在正在尝试使用Grails和Groovy的最新版本。我安装了GGTS3.4.0.RELEASE,并使用Grails2.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){ }
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/Config.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){ }
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"
编辑
使用下面接受的答案的建议,我能够让SpringSecurityCAS正确配置,但我的控制器仍然不安全。我认为这与奇怪的加载顺序有关,应用服务器说它正在运行,然后加载SpringSecurity、LDAP和CAS。一位同事建议拿出我的InterceptUrlMap,并使用@Secured注释查看它是否是加载顺序(因为在一切都启动并运行后,InterceptUrlMap无法更新)。我去掉了rejectIfNoRule、securityConfigType和interceptUrlMap设置,并在控制器中添加了@Secured(['ROLE_ADMIN'])。该应用程序现在可以正常工作,并且该控制器是安全的
因此,Grails2.3.0和Spring安全性的事件顺序仍然存在问题,但这是一个解决方法
相关问题:我也看到了同样的事情。看起来来自的CAS插件默认值没有在Grails 2.3.0下正确合并。可能值一吉拉。同时,您可以通过将默认值添加到Config.groovy(针对您的环境进行覆盖)来向前推进:
我知道这个线程有点旧,但我只是在2.0-RC1中遇到同样的问题时偶然发现了它 我发现SpringSecurityCasGrailsPlugin.groovy中没有加载默认配置。这是在Tomcat上部署.War文件时发生的一个问题,很久以前就解决了。为该修复程序添加的代码(如果允许执行)为我修复了这个新问题。我只是强迫
if
条件始终为true,如下所示(代码来自SpringSecurityCasGrailsPlugin.groovy中大约第105行):
(只有if语句是change,其余代码用于说明)
我不知道这会带来什么副作用(我还不知道…)。看起来run app命令可能有所不同,使其行为类似于.war部署或其他。无论如何,我肯定不会以这种方式部署生产应用程序,我会选择手动创建所有配置选项,就像公认的答案一样。但也许这会给那些能够找出真正问题的人带来深刻的见解。Nice。嗯,添加这些设置导致它将“配置Spring Security CAS……完成配置Spring Security CAS”添加到控制台输出,但该应用程序仍然不安全。我想知道这是否与事件发生的顺序有关(即,在Grails 2.2.3中,安全、ldap和cas在应用服务器运行之前加载,而在Grails 2.3中,它们在运行之后加载。这似乎是一个很好的线索。我没有任何其他立即的建议。希望Beckwith先生会插话……明白了!我将在页面中添加一个编辑,包括我的其余解决方案,但我会接受。)它解决了我的CAS配置问题。我的解决方案只是让它适合我…加载顺序仍然存在问题。我有同样的问题:我刚刚用grails 2.3.1启动了一个新的应用程序。而spring security core插件似乎没有注册自己:我甚至无法执行s2 quickstart脚本
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
}