通过 SAML 登录 Grails 应用程序时,无法访问 LogoutController 中的 UserDetailsS​​ervice

Posted

技术标签:

【中文标题】通过 SAML 登录 Grails 应用程序时,无法访问 LogoutController 中的 UserDetailsS​​ervice【英文标题】:No Access To UserDetailsService in LogoutController When Logged into Grails Application via SAML 【发布时间】:2017-02-01 10:32:47 【问题描述】:

使用 Spring SAML Security,我已将我们的应用程序启用为服务提供者。这很好用,我使用了自定义的 WickedUserDetails(从 GrailsUser 扩展),并且所有内容都按应有的方式填充。

现在我正在尝试为 SAML 实现全局注销,但甚至在我可以做任何“花哨的”事情之前,我就注意到当我点击我们的常规 LogoutController 时,我无法访问 WickedUserDetails。我只有一个匿名的 grails 用户。

当我尝试访问 /logout/index 和 /logout/special 时会发生这种情况。当我使用 SlogoutController 时,它按预期工作。

class LogoutController 

    def springSecurityService

    /**
    * Index action. Redirects to the Spring security logout uri.
    */
    def index = 
        // Populates with ANONYMOUS GRAILS USER when logged in via SAML
        // but with WickedUserDetails when logged in via the "normal" Spring Security mechanism
        def check = springSecurityService.principal

        redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
    

    def special = 
        // Populates with ANONYMOUS GRAILS USER when logged in via SAML
        // but with WickedUserDetails when logged in via the "normal" Spring Security mechanism
        def check = springSecurityService.principal

        redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
    


class SlogoutController 

    def springSecurityService

    def special = 
        // Populates with WickedUserDetails
        def check = springSecurityService.principal

        redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
    

    // Populates with WickedUserDetails
    def index = 
        def check = springSecurityService.principal

        redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
    


在我的 Config.groovy 中,我没有设置任何特殊的拦截器 URL,我对注销 URL 的唯一引用是:

grails.plugin.springsecurity.secureChannel.definition = [
    '/login/**'  :      'REQUIRES_SECURE_CHANNEL',
    '/logout/**' :      'REQUIRES_INSECURE_CHANNEL'
]

这是我在 UrlMappings 中设置的唯一参考:

"/logout/$action?"(controller: "logout")    

有人可以向我解释为什么会发生这种行为吗?我可以在我的应用中想出一个解决方法,但我对发生了什么非常好奇。

【问题讨论】:

【参考方案1】:

好的,问题是我走捷径。最初在身份验证提供程序中,我没有使用 SAML 凭据更新定制令牌

Authentication authenticate(Authentication authentication) 

    if (authentication instanceof SAMLAuthenticationToken) 

        def samlToken = super.authenticate(authentication)
        if (samlToken) 
            String username = samlToken.principal
            LightweightContact contact = new LightweightContact(username: username)                         

            contact = contact.findByUsername()

            boolean isContactValid = contactValid(contact, samlToken)

            if (isContactValid) 
                WickedAuthenticationToken wickedToken = MyNormalSpringCustomWickedAuthenticationProvider.getWickedAuthenticationToken(contact)
                // -------- I needed to explicitly set the credentials here -----------------------
                wickedToken.setCredentials(samlToken.credentials)
                return wickedToken
            
        
    

    // the authentication token was not of the correct class
    // or no user was found for it
    return null

【讨论】:

以上是关于通过 SAML 登录 Grails 应用程序时,无法访问 LogoutController 中的 UserDetailsS​​ervice的主要内容,如果未能解决你的问题,请参考以下文章

基于 SAML 响应在 Grails 中分配 Spring 安全角色

如何结合单点注销和无状态身份验证

无法使用 grails 通过 CAS 单点登录登录

安装 SAML 2.x

SAML简介

Confluence 6 数据中心的 SAML 单点登录最佳实践和故障排除