【问题标题】:In SAML, what are the actions that need to be performed in the client and service provider to logout?在 SAML 中,需要在客户端和服务提供商中执行哪些操作才能注销?
【发布时间】:2021-10-15 19:07:57
【问题描述】:

我已经使用crewjam/saml在 Go 程序中使用 SAML 模式下的 Keycloak IDP 进行 SAML 登录(我相信这是使用 SAMLv2 但不是肯定的)。基本原理是,在良好登录后,IDP 向程序发送用户的 SAML 属性,Go SAML 库将其转换为 JWT 并将其设置为 HTTP Cookie。此时 IDP 标记用户与 Service 建立了会话,并且用户可以通过 JWT 访问 API。

我遇到的问题是我不清楚如何注销。该库有一个用于注销的 URL:

// SloURL is the full URL to the SAML Single Logout endpoint on this host.
// i.e. https://example.com/saml/slo
SloURL url.URL

但是导航到这个页面只会返回 404。

那么我如何告诉 IDP 用户的会话已完成?我应该自己删除 JWT cookie 还是会处理?

【问题讨论】:

    标签: go jwt single-sign-on saml


    【解决方案1】:

    单点注销服务 (SLO) URL 位于 IdP 元数据中,例如

    <EntityDescriptor ... entityID="https://idp.com/shibboleth">
      <IDPSSODescriptor ... >
        <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.com/idp/profile/SAML2/POST/SLO"/>
      </IDPSSODescriptor>
    </EntityDescriptor>
    

    然后,您构建一个 logout request 以在该用户登录时将先前由 IdP 发送的 NameID(使用 entityID https://idp.com/shibboleth)发送到 SLO:

    <samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="ONELOGIN_21df91a89767879fc0f7df6a1490c6000c81644d" Version="2.0" IssueInstant="2014-07-18T01:13:06Z" Destination="https://idp.com/idp/profile/SAML2/POST/SLO">
      <saml:Issuer>https://idp.com/shibboleth</saml:Issuer>
      <saml:NameID SPNameQualifier="https://idp.com/shibboleth" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">ONELOGIN_f92cc1834efc0f73e9c09f482fce80037a6251e7</saml:NameID>
    </samlp:LogoutRequest>
    

    并接收logout response:

    <samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_6c3737282f007720e736f0f4028feed8cb9b40291c" Version="2.0" IssueInstant="2014-07-18T01:13:06Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_21df91a89767879fc0f7df6a1490c6000c81644d">
      <saml:Issuer>https://idp.com/shibboleth</saml:Issuer>
      <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
      </samlp:Status>
    </samlp:LogoutResponse>
    

    【讨论】:

    • 我明白了;但是,IDP 仍然没有完全注销用户。
    • 此外,问题的范围是使用 crewjam/sam go libraryl 执行此操作
    • 您无法控制 IdP。如果它没有完全注销用户,那就是 IdP 的政策或问题。让用户退出 IdP 对 SP 也没有任何作用。 SP 也必须注销他们,例如删除他们的会话。
    • 对于 crampjam/sam,它只是将 SAML 发布到 URL
    【解决方案2】:

    以下似乎完成了我的要求:

    type Logout struct {
        SP *samlsp.Middleware
    }
    
    func (l *Logout) ServeHTTP(w http.ResponseWriter, r *http.Request) {
          //Get the JWT information
        session, err := l.SP.Session.GetSession(r)
        if err != nil {
            WebErrorWarn("error get signouturl session: "+err.Error(), http.StatusForbidden, w)
            return
        }
           //Get the JWT information part 2
        attr := session.(samlsp.JWTSessionClaims)
        if err != nil {
            WebErrorWarn("error get signouturl session claims: "+err.Error(), http.StatusForbidden, w)
            return
        }
    
        //use this as the name for the logout request
        url, err := l.SP.ServiceProvider.MakeRedirectLogoutRequest(attr.Subject, "")
        if err != nil {
            WebErrorWarn("error get signouturl: "+err.Error(), http.StatusInternalServerError, w)
            return
        }
    
        //delete the session token from teh browser 
        err = l.SP.Session.DeleteSession(w, r)
        if err != nil {
            WebErrorWarn("error get signouturl: "+err.Error(), http.StatusInternalServerError, w)
            return
        }
    
        //redirect to the IDP Single log out URLwith the SAMLRequests for logout embedded
        http.Redirect(w, r, url.String(), http.StatusFound)
    }
    
    

    我创建自己的注销 URL 以提供此服务

        http.Handle("/logout", samlSP.RequireAccount(&Logout{samlSP}))
    

    最后,IDP 将客户端重定向回 SLO URL,它在元数据文件中发送,并且在 crampjam/gosaml 中也默认为 /saml/slo。我只是在该 URL 上有一个处理程序,以向用户确认他们不再登录。

        http.Handle("/saml/slo", &SLOHandle{})
    

    注意/saml/slo URL 不应受到 SAML 保护,否则您将再次触发 SAML 登录。

    【讨论】:

      【解决方案3】:

      向 http://{url}:{port}/auth/realms/{realm}/protocol/saml 发送注销 SAML 请求

      【讨论】:

      • SP 通常是否通过 REDIRECT 向 IDP 发出该问题?还是浏览器需要弄清楚如何创建该请求?
      猜你喜欢
      • 1970-01-01
      • 2015-04-16
      • 1970-01-01
      • 2020-04-24
      • 2020-12-21
      • 2021-06-03
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      相关资源
      最近更新 更多