Grails:Spring Security CAS 在 2.2.3 中工作,但在 2.3.0 中不工作
Posted
技术标签:
【中文标题】Grails:Spring Security CAS 在 2.2.3 中工作,但在 2.3.0 中不工作【英文标题】:Grails: Spring Security CAS working in 2.2.3 but not in 2.3.0 【发布时间】:2013-10-23 12:21:11 【问题描述】:我有一个使用 Groovy 2.0 的 Grails 2.2.3 项目。我用 Spring Security 设置了它,使用 CAS 进行身份验证,使用 LDAP 作为用户角色。当我运行该应用程序时,一切正常:任何人都允许访问 /appcontext/ 并且 /appcontext/admin/ 下的任何内容都由 CAS 和来自 LDAP 的管理员角色保护。我现在正在尝试使用最新版本的 Grails 和 Groovy。我安装了 GGTS 3.4.0.RELEASE 并且正在使用 Grails 2.3.0 和 Groovy 2.1。我创建了一个新项目,制作了一个简单的域类和控制器并添加到安全设置中。
这是我在使用 Grails 2.2.3 和 Groovy 2.0 运行应用程序时使用 GGTS 3.3.0.RELEASE 时的输出:(注意“服务器正在运行”消息的位置)
| 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
这是我在使用 Grails 2.3.0 和 Groovy 2.1 运行应用程序时使用 GGTS 3.4.0.RELEASE 时的输出(注意“服务器正在运行”消息的位置):
| 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 Security CAS,但我的控制器仍然不安全。我认为它与那个奇怪的加载顺序有关,应用服务器说它正在运行,然后它加载 Spring Security、LDAP 和 CAS。一位同事建议取出我的 InterceptUrlMap 并使用 @Secured 注释来查看它是否是加载顺序(因为在一切启动并运行后无法更新 InterceptUrlMap)。我摆脱了rejectIfNoRule、securityConfigType 和interceptUrlMap 设置,并向控制器添加了@Secured(['ROLE_ADMIN'])。该应用现在可以按预期运行,并且该控制器是安全的。
因此,Grails 2.3.0 和 Spring Security 的事件顺序仍然存在问题,但这是一种解决方法。
相关问题:https://***.com/questions/19411102/grails-2-3-0-spring-security-ldap-and-cas-load-after-server-starts
【问题讨论】:
【参考方案1】:我看到同样的事情。看起来DefaultCasSecurityConfig.groovy 的 CAS 插件默认值在 Grails 2.3.0 下没有正确合并。可能值得一个 JIRA。同时,您可以通过将默认值添加到 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
【讨论】:
不错。好吧,添加这些设置会导致它在控制台输出中添加“正在配置 Spring Security CAS ... ...完成配置 Spring Security CAS”,但应用程序仍然不安全。 我想知道它是否与事情发生的顺序有关(即,在 Grails 2.2.3 中,安全性、ldap 和 cas 在应用程序服务器之前加载的事实运行,在 Grails 2.3 中,它们会在之后加载。 这似乎是一个很好的线索。我没有任何其他直接建议。希望贝克威思先生能插话…… 知道了!我将使用我的其余解决方案向页面添加一个编辑,但我会接受你的,因为它解决了我的 CAS 配置问题。我的解决方案使它适用于我......加载顺序仍然存在问题。 我遇到了同样的问题:我刚刚使用 grails 2.3.1 启动了一个新应用程序。而且 spring-security-core 插件似乎没有注册自己:我什至无法执行 s2-quickstart 脚本【参考方案2】:我知道这个线程有点老了,但是当我在 2.0-RC1 中遇到同样的问题时,我偶然发现了它。
我发现 SpringSecurityCasGrailsPlugin.groovy 中没有加载默认配置。这是在很久以前修复的 Tomcat 上部署 .War 文件时发生的问题。为该修复添加的代码(如果允许执行)为我修复了这个新问题。我只是强制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语句,其余代码用于说明)。
我不知道这可能会带来什么副作用(我还不能说...)。似乎 run-app 命令可能有所不同,使其表现得像 .war 部署或其他东西。无论如何,我肯定会犹豫以这种方式部署生产应用程序,并会选择手动创建所有配置选项,就像在接受的答案中一样。但也许这会给能够找出真正问题的人提供洞察力。
【讨论】:
以上是关于Grails:Spring Security CAS 在 2.2.3 中工作,但在 2.3.0 中不工作的主要内容,如果未能解决你的问题,请参考以下文章
grails-spring-security-rest 插件和悲观锁定
Grails + spring-security-core:用户登录后如何分配角色?