【问题标题】:Grails 3 with SAML - authentication failure带有 SAML 的 Grails 3 - 身份验证失败
【发布时间】:2018-12-22 06:25:08
【问题描述】:

我已经使用 Grails Spring Security SAML Plugin (v3.3.0)。 不幸的是,我很难得到它 正确配置。这是一个名为“同事”的项目,所以你 将看到在不同的地方引用该名称(如下)。我们正在使用 PingFederate 用于我们的 SAML 身份验证。

问题:身份验证似乎在 PingFederate 端有效,但是 然后浏览器被发送到一个无限循环,在我的应用程序和 PingFederate 之间来回切换(更新:无限循环有 已修复,但问题的根源仍然存在)。日志显示MetadataProviderException(请参阅下面的堆栈跟踪末尾)。

非常感谢任何帮助!

这是我的application.yml 配置文件的一部分:

---
grails:
    plugin:
        springsecurity:
            saml:
                active: true  # false does not work as of saml plugin v3.3.0
                afterLoginUrl: '/'
                afterLogoutUrl: '/'
                responseSkew: 300
                signatureAlgorithm: 'rsa-sha256'
                digestAlgorithm: 'sha256'
                userGroupAttribute: 'roles'
                autoCreate:
                    active: false  # If you want the plugin to generate users in the DB as they are authenticated via SAML
                    key: 'id'
                    assignAuthorities: false  # If you want the plugin to assign the authorities that come from the SAML message
                metadata:
                    defaultIdp: 'fed.saml2'  # 'coworkers' # @see https://github.com/jeffwils/grails-spring-security-saml/issues/34#issuecomment-396524285
                    url: '/saml/metadata'
                    providers:
                        ping: 'security/idp.xml'
                    sp:
                        file: 'security/sp.xml'
                        defaults:
                            local: false
                            entityId: 'coworkers'
                            alias: 'coworkers'
                            securityProfile: 'metaiop'  # 'pkix' or 'metaiop'
                            signingKey: 'coworkers'
                            encryptionKey: 'coworkers'
                            tlsKey: 'coworkers'
                            requireArtifactResolveSigned: false
                            requireLogoutRequestSigned: false
                            requireLogoutResponseSigned: false
                keyManager:
                    storeFile: 'classpath:security/mykeystore.jks'
                    storePass: 'mypassword'
                    passwords:
                        coworkers: 'mypassword'
                    defaultKey: ''

这是我的sp.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
  <md:EntityDescriptor entityID="coworkers" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
    <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:Extensions>
      <idpdisco:DiscoveryResponse xmlns:idpdisco="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="http://myserver/login/auth/alias/coworkers?disco=false"/>
    </md:Extensions>
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data>
          <ds:X509Certificate>CERTIFICATEREMOVED</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://myserver/saml/SingleLogout/alias/coworkers"/>
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://myserver/saml/SingleLogout/alias/coworkers"/>
    <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://myserver/saml/SingleLogout/alias/coworkers"/>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://myserver/saml/SSO/alias/coworkers" index="0" isDefault="true"/>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="http://myserver/saml/SSO/alias/coworkers" index="1" isDefault="false"/>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="http://myserver/saml/SSO/alias/coworkers" index="2" isDefault="false"/>
  </md:SPSSODescriptor>
</md:EntityDescriptor>

这是我的idp.xml 文件:

<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="byhfqDHEyvF6TnZ1-nhQEyP0.kQ" cacheDuration="PT1440M" entityID="fed.saml2">
  <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAuthnRequestsSigned="true">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data>
          <ds:X509Certificate>CERTIFICATEREMOVED</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
    <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://fed/idp/SSO.saml2"/>
    <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://fed/idp/SSO.saml2"/>
  </md:IDPSSODescriptor>
</md:EntityDescriptor>

这是来自日志的堆栈跟踪:

2018-07-13 14:29:00.184 [] DEBUG --- [p-nio-80-exec-3] o.s.security.saml.SAMLProcessingFilter   : Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Error determining metadata contracts

org.springframework.security.authentication.AuthenticationServiceException: Error determining metadata contracts
        at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:94)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.saml.metadata.MetadataDisplayFilter.doFilter(MetadataDisplayFilter.java:84)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.saml.SAMLEntryPoint.doFilter(SAMLEntryPoint.java:103)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at grails.plugin.springsecurity.web.SecurityRequestHolderFilter.doFilter(SecurityRequestHolderFilter.groovy:58)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.opensaml.saml2.metadata.provider.MetadataProviderException: No local entity found for alias coworkers, verify your configuration.
        at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalEntityId(SAMLContextProviderImpl.java:279)
        at org.springframework.security.saml.context.SAMLContextProviderImpl.getLocalEntity(SAMLContextProviderImpl.java:106)
        at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:79)
        ... 50 common frames omitted

【问题讨论】:

    标签: grails saml spring-saml


    【解决方案1】:

    我可以看到您在 application.yml 中提到“entityId”为“https://coworkers/”,但在您的 SP 元数据文件中 entityId 为“http://myserver/coworkers”。使它们都相同,然后重试。

    【讨论】:

    • 感谢您向我指出这一点。这一定是我的编辑错误。我检查了我的实际文件,它们是正确的。
    • “没有为别名同事找到本地实体”在您提到的链接中,在示例配置中,entityId 和别名是相同的。你试过吗??
    • 感谢您的建议。我刚刚尝试在 sp.xml 文件中创建 entityId="coworkers" 。不幸的是,它没有任何效果。
    • 由于身份验证失败,至少根据 SAML 插件,它记录了以下消息:Delegating to authentication failure handler...,在插件中硬编码为 /log4J/logging,它不存在。所以我创建了一个带有“日志”操作的“log4J”控制器,只是为了看看会发生什么。现在无限循环已经停止,但浏览器只是在/log4J/logging URL 上停止,没有进一步的反应。仍然抛出相同的异常。
    【解决方案2】:

    经过大量试验,我终于尝试将saml.metadata.sp.defaults.local 设置为true。这似乎解决了我的问题!我显然误解了这个设置的描述。 @Agam,非常感谢您的帮助。

    【讨论】:

    • 哎呀!!我们错过了:(现在一切都说得通了。很高兴你解决了这个问题。;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 2014-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 2013-11-13
    相关资源
    最近更新 更多