У меня есть проект в Grails 2.2.3 с использованием Groovy 2.0. Я настроил его с помощью Spring Security, чтобы использовать 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 Security 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