Grails: Spring Security CAS работает в 2.2.3, но не в 2.3.0

У меня есть проект в 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


person Buns of Aluminum    schedule 15.10.2013    source источник


Ответы (2)


Я вижу то же самое. Похоже, что настройки плагина CAS по умолчанию из DefaultCasSecurityConfig.groovy неправильно объединены в 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
person Andrew    schedule 16.10.2013
comment
Отлично. Что ж, добавление этих параметров привело к добавлению настройки Spring Security CAS ... ... настройка Spring Security CAS завершена в вывод консоли, но приложение все еще не защищено. - person Buns of Aluminum; 16.10.2013
comment
Мне интересно, имеет ли это какое-либо отношение к порядку, в котором что-то происходит (то есть к тому факту, что в Grails 2.2.3 безопасность, ldap и cas загружаются до запуска сервера приложений, а в Grails 2.3 они загружаются впоследствии. - person Buns of Aluminum; 16.10.2013
comment
Это похоже на хорошую зацепку. Других предложений на ближайшее время у меня нет. Надеюсь, мистер Беквит вмешается ... - person Andrew; 16.10.2013
comment
Понятно! Я собираюсь внести правку на страницу с остальной частью своего решения, но я приму ваше, поскольку оно решило мои проблемы с конфигурацией CAS. Мое решение просто заставляет меня работать ... проблема с порядком загрузки все еще существует. - person Buns of Aluminum; 16.10.2013
comment
У меня такая же проблема: я только что запустил новое приложение с grails 2.3.1. и плагин spring-security-core, похоже, просто не регистрируется: я даже не могу выполнить сценарий s2-quickstart - person Hans Westerbeek; 30.10.2013

Я знаю, что эта ветка устарела, но я просто наткнулся на нее, когда столкнулся с той же проблемой в 2.0-RC1.

Я обнаружил, что конфигурация по умолчанию не загружалась в SpringSecurityCasGrailsPlugin.groovy. Это была проблема, которая возникла при развертывании файлов .War на Tomcat, и она была исправлена ​​давно. Код, добавленный для этого исправления, если он разрешен для выполнения, исправил эту новую проблему для меня. Я просто заставил условие if всегда выполняться, как показано ниже (код взят примерно из строки 105 в SpringSecurityCasGrailsPlugin.groovy):

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 или что-то в этом роде. В любом случае, я определенно не решился бы развернуть производственное приложение таким образом и предпочел бы создать все параметры конфигурации вручную, как в принятом ответе. Но, возможно, это даст понимание того, кто сможет понять настоящую проблему.

person S. McIntosh    schedule 10.04.2014