在 SAML 中,注销需要在客户端和服务提供者中执行哪些操作?
In SAML, what are the actions that need to be performed in the client and service provider to logout?
我在 Go 程序中使用 crewjam/saml 和 SAML 模式下的 Keycloak IDP 获得了 SAML 登录(我相信这是使用 SAMLv2 但不是肯定的)。基本原理是,在成功登录后,IDP 向程序发送用户的 SAML 属性,Go SAML 库将其转换为 JWT 并将其设置为 HTTP Cookie。此时 IDP 标记用户与服务有会话,用户可以通过 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
但是导航到此页面只是 returns 404。
那么如何告诉 IDP 用户的会话已完成?我应该自己删除 JWT cookie 还是会被处理?
将注销 SAML 请求发送到 http://{url}:{port}/auth/realms/{realm}/protocol/saml
单一注销服务 (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 to send to the SLO for the NameID
that was previously sent by the IdP (with the entityID
https://idp.com/shibboleth) 当该用户登录时:
<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>
以下似乎可以完成我的要求:
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,它在元数据文件中发送,并且默认为 crewjam/gosaml 中的 /saml/slo
。我只是在 URL 上有一个处理程序来向用户确认他们不再登录。
http.Handle("/saml/slo", &SLOHandle{})
请注意 /saml/slo
URL 不应受 SAML 保护,否则您将再次触发 SAML 登录。
我在 Go 程序中使用 crewjam/saml 和 SAML 模式下的 Keycloak IDP 获得了 SAML 登录(我相信这是使用 SAMLv2 但不是肯定的)。基本原理是,在成功登录后,IDP 向程序发送用户的 SAML 属性,Go SAML 库将其转换为 JWT 并将其设置为 HTTP Cookie。此时 IDP 标记用户与服务有会话,用户可以通过 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
但是导航到此页面只是 returns 404。
那么如何告诉 IDP 用户的会话已完成?我应该自己删除 JWT cookie 还是会被处理?
将注销 SAML 请求发送到 http://{url}:{port}/auth/realms/{realm}/protocol/saml
单一注销服务 (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 to send to the SLO for the NameID
that was previously sent by the IdP (with the entityID
https://idp.com/shibboleth) 当该用户登录时:
<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>
以下似乎可以完成我的要求:
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,它在元数据文件中发送,并且默认为 crewjam/gosaml 中的 /saml/slo
。我只是在 URL 上有一个处理程序来向用户确认他们不再登录。
http.Handle("/saml/slo", &SLOHandle{})
请注意 /saml/slo
URL 不应受 SAML 保护,否则您将再次触发 SAML 登录。