fix: create function for externalSessionId add random string generator. fix tests to reflect provider with checkSessionIframe Session management.

This commit is contained in:
ybelMekk
2022-01-23 21:37:36 +01:00
parent 65a0b5de52
commit e4c47f59e8
6 changed files with 90 additions and 13 deletions

View File

@@ -188,7 +188,11 @@ func (ip *identityProviderHandler) Token(w http.ResponseWriter, r *http.Request)
idToken.Set("acr", auth.AcrLevel)
idToken.Set("iat", time.Now().Unix())
idToken.Set("exp", time.Now().Unix()+expires)
idToken.Set("sid", sid)
if !ip.Provider.OpenIDConfiguration.GetCheckSessionIframe() {
idToken.Set("sid", sid)
} else {
idToken.Set("session_state", sid)
}
signedIdToken, err := ip.signToken(idToken)
if err != nil {

View File

@@ -6,8 +6,7 @@ import (
"github.com/go-chi/chi/v5"
)
func IdentityProviderServer() (*httptest.Server, TestProvider) {
provider := NewTestProvider()
func IdentityProviderServer(provider TestProvider) (*httptest.Server, TestProvider) {
handler := newIdentityProviderHandler(provider)
router := identityProviderRouter(handler)
server := httptest.NewServer(router)

View File

@@ -31,6 +31,11 @@ func (p TestProvider) PrivateJwkSet() *jwk.Set {
return &p.JwksPair.Private
}
func (p TestProvider) WithCheckSessionIframe() TestProvider {
p.OpenIDConfiguration.CheckSessionIframe = "https://some-url/checksession"
return p
}
func NewTestProvider() TestProvider {
jwksPair, err := crypto.NewJwkSet()
if err != nil {

View File

@@ -73,12 +73,8 @@ func (c *Configuration) FetchJwkSet(ctx context.Context) (*jwk.Set, error) {
return &jwkSet, nil
}
func (c *Configuration) FetchCheckSessionIframe() bool {
if c.CheckSessionIframe == "" {
return false
}
return true
func (c *Configuration) GetCheckSessionIframe() bool {
return c.CheckSessionIframe != ""
}
func (c *Configuration) SidClaimRequired() bool {

View File

@@ -123,7 +123,7 @@ func (h *Handler) ExternalSessionId(idToken *openid.IDToken) (string, error) {
switch {
case openIDconfig.SidClaimRequired():
externalSessionID, err = idToken.GetStringClaim("sid")
case openIDconfig.FetchCheckSessionIframe():
case openIDconfig.GetCheckSessionIframe():
externalSessionID, err = idToken.GetStringClaim("session_state")
default:
externalSessionID = h.GenerateExternalSessionID()

View File

@@ -44,7 +44,7 @@ func newHandler(provider openid.Provider) *router.Handler {
}
func TestHandler_Login(t *testing.T) {
idpserver, idp := mock.IdentityProviderServer()
idpserver, idp := mock.IdentityProviderServer(mock.NewTestProvider())
h := newHandler(idp)
r := router.New(h)
@@ -100,7 +100,7 @@ func TestHandler_Login(t *testing.T) {
}
func TestHandler_Callback_and_Logout(t *testing.T) {
idpserver, idp := mock.IdentityProviderServer()
idpserver, idp := mock.IdentityProviderServer(mock.NewTestProvider())
h := newHandler(idp)
r := router.New(h)
@@ -195,7 +195,80 @@ func TestHandler_Callback_and_Logout(t *testing.T) {
}
func TestHandler_FrontChannelLogout(t *testing.T) {
_, idp := mock.IdentityProviderServer()
_, idp := mock.IdentityProviderServer(mock.NewTestProvider())
h := newHandler(idp)
r := router.New(h)
server := httptest.NewServer(r)
idp.ClientConfiguration.RedirectURI = server.URL + "/oauth2/callback"
idp.ClientConfiguration.PostLogoutRedirectURI = server.URL
jar, err := cookiejar.New(nil)
assert.NoError(t, err)
client := server.Client()
client.Jar = jar
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
// First, run /oauth2/login to set cookies
resp, err := client.Get(server.URL + "/oauth2/login")
assert.NoError(t, err)
assert.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
defer resp.Body.Close()
// Get authorization URL
location := resp.Header.Get("location")
u, err := url.Parse(location)
assert.NoError(t, err)
// Follow redirect to authorize with idporten
resp, err = client.Get(u.String())
assert.NoError(t, err)
assert.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
defer resp.Body.Close()
// Get callback URL after successful auth
location = resp.Header.Get("location")
callbackURL, err := url.Parse(location)
assert.NoError(t, err)
// Follow redirect to callback
resp, err = client.Get(callbackURL.String())
assert.NoError(t, err)
assert.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
cookies := client.Jar.Cookies(callbackURL)
sessionCookie := getCookieFromJar(router.SessionCookieName, cookies)
assert.NotNil(t, sessionCookie)
// Trigger front-channel logout
ciphertext, err := base64.StdEncoding.DecodeString(sessionCookie.Value)
assert.NoError(t, err)
sid, err := h.Crypter.Decrypt(ciphertext)
assert.NoError(t, err)
frontchannelLogoutURL, err := url.Parse(server.URL)
assert.NoError(t, err)
frontchannelLogoutURL.Path = "/oauth2/logout/frontchannel"
values := url.Values{}
values.Add("sid", string(sid))
values.Add("iss", idp.GetOpenIDConfiguration().Issuer)
frontchannelLogoutURL.RawQuery = values.Encode()
resp, err = client.Get(frontchannelLogoutURL.String())
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
defer resp.Body.Close()
}
func TestHandler_FrontChannelLogoutWithCheckSessionIframe(t *testing.T) {
_, idp := mock.IdentityProviderServer(mock.NewTestProvider().WithCheckSessionIframe())
h := newHandler(idp)
r := router.New(h)
server := httptest.NewServer(r)