mirror of
https://github.com/nais/wonderwall.git
synced 2026-02-14 09:39:52 +00:00
feat(openid): support logout_hint for RP-initiated logouts
This commit is contained in:
@@ -13,12 +13,14 @@ import (
|
|||||||
|
|
||||||
type Logout struct {
|
type Logout struct {
|
||||||
*Client
|
*Client
|
||||||
Cookie *openid.LogoutCookie
|
Cookie *openid.LogoutCookie
|
||||||
logoutCallbackURL string
|
LogoutHint string
|
||||||
|
|
||||||
|
callbackURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogout(c *Client, r *http.Request) (*Logout, error) {
|
func NewLogout(c *Client, r *http.Request) (*Logout, error) {
|
||||||
logoutCallbackURL, err := urlpkg.LogoutCallback(r)
|
callbackURL, err := urlpkg.LogoutCallback(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("generating logout callback url: %w", err)
|
return nil, fmt.Errorf("generating logout callback url: %w", err)
|
||||||
}
|
}
|
||||||
@@ -33,21 +35,25 @@ func NewLogout(c *Client, r *http.Request) (*Logout, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Logout{
|
return &Logout{
|
||||||
Client: c,
|
Client: c,
|
||||||
Cookie: logoutCookie,
|
Cookie: logoutCookie,
|
||||||
logoutCallbackURL: logoutCallbackURL,
|
LogoutHint: r.URL.Query().Get("logout_hint"),
|
||||||
|
callbackURL: callbackURL,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *Logout) SingleLogoutURL(idToken string) string {
|
func (in *Logout) SingleLogoutURL(idToken string) string {
|
||||||
endSessionEndpoint := in.cfg.Provider().EndSessionEndpointURL()
|
endSessionEndpoint := in.cfg.Provider().EndSessionEndpointURL()
|
||||||
v := endSessionEndpoint.Query()
|
v := endSessionEndpoint.Query()
|
||||||
v.Set("post_logout_redirect_uri", in.logoutCallbackURL)
|
v.Set("post_logout_redirect_uri", in.callbackURL)
|
||||||
v.Set("state", in.Cookie.State)
|
v.Set("state", in.Cookie.State)
|
||||||
|
|
||||||
if len(idToken) > 0 {
|
if len(idToken) > 0 {
|
||||||
v.Set("id_token_hint", idToken)
|
v.Set("id_token_hint", idToken)
|
||||||
}
|
}
|
||||||
|
if len(in.LogoutHint) > 0 {
|
||||||
|
v.Set("logout_hint", in.LogoutHint)
|
||||||
|
}
|
||||||
|
|
||||||
endSessionEndpoint.RawQuery = v.Encode()
|
endSessionEndpoint.RawQuery = v.Encode()
|
||||||
return endSessionEndpoint.String()
|
return endSessionEndpoint.String()
|
||||||
|
|||||||
@@ -70,6 +70,37 @@ func TestLogout_SingleLogoutURL(t *testing.T) {
|
|||||||
logoutUrl.RawQuery = ""
|
logoutUrl.RawQuery = ""
|
||||||
assert.Equal(t, EndSessionEndpoint, logoutUrl.String())
|
assert.Equal(t, EndSessionEndpoint, logoutUrl.String())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("with logout_hint claim", func(t *testing.T) {
|
||||||
|
logout := newLogout(t)
|
||||||
|
logout.LogoutHint = "some-logout-hint"
|
||||||
|
idToken := ""
|
||||||
|
state := logout.Cookie.State
|
||||||
|
|
||||||
|
raw := logout.SingleLogoutURL(idToken)
|
||||||
|
assert.NotEmpty(t, raw)
|
||||||
|
|
||||||
|
logoutUrl, err := url.Parse(raw)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
query := logoutUrl.Query()
|
||||||
|
assert.Len(t, query, 3)
|
||||||
|
|
||||||
|
assert.Contains(t, query, "logout_hint")
|
||||||
|
assert.Equal(t, logout.LogoutHint, query.Get("logout_hint"))
|
||||||
|
|
||||||
|
assert.NotContains(t, query, "id_token_hint")
|
||||||
|
assert.Equal(t, idToken, query.Get("id_token_hint"))
|
||||||
|
|
||||||
|
assert.Contains(t, query, "post_logout_redirect_uri")
|
||||||
|
assert.Equal(t, LogoutCallbackURI, query.Get("post_logout_redirect_uri"))
|
||||||
|
|
||||||
|
assert.Contains(t, query, "state")
|
||||||
|
assert.Equal(t, state, query.Get("state"))
|
||||||
|
|
||||||
|
logoutUrl.RawQuery = ""
|
||||||
|
assert.Equal(t, EndSessionEndpoint, logoutUrl.String())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogout(t *testing.T) *client.Logout {
|
func newLogout(t *testing.T) *client.Logout {
|
||||||
|
|||||||
Reference in New Issue
Block a user