Skip to content

Commit

Permalink
feat: option to update session cookie expiry time on session refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
aarmam committed Apr 19, 2022
1 parent 222a01b commit d9a22b2
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 1 deletion.
2 changes: 1 addition & 1 deletion consent/strategy_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re
}
}

if !session.Remember || session.LoginRequest.Skip {
if !session.Remember || session.LoginRequest.Skip && !session.RefreshRememberFor {
// If the user doesn't want to remember the session, we do not store a cookie.
// If login was skipped, it means an authentication cookie was present and
// we don't want to touch it (in order to preserve its original expiry date)
Expand Down
96 changes: 96 additions & 0 deletions consent/strategy_oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,102 @@ func TestStrategyLoginConsentNext(t *testing.T) {
})
})

t.Run("case=should pass if both login and consent are granted and check remember flows with refresh session cookie", func(t *testing.T) {

subject := "subject-1"
c := createDefaultClient(t)
testhelpers.NewLoginConsentUI(t, reg.Config(),
acceptLoginHandler(t, subject, &models.AcceptLoginRequest{
Remember: true,
}),
acceptConsentHandler(t, &models.AcceptConsentRequest{
Remember: true,
GrantScope: []string{"openid"},
Session: &models.ConsentRequestSession{
AccessToken: map[string]interface{}{"foo": "bar"},
IDToken: map[string]interface{}{"bar": "baz"},
},
}))

hc := testhelpers.NewEmptyJarClient(t)

followUpHandler := func(refreshRememberFor bool) {
rememberFor := int64(12345)
testhelpers.NewLoginConsentUI(t, reg.Config(),
checkAndAcceptLoginHandler(t, adminClient.Admin, subject, func(t *testing.T, res *admin.GetLoginRequestOK, err error) *models.AcceptLoginRequest {
require.NoError(t, err)
assert.True(t, *res.Payload.Skip)
assert.Equal(t, subject, *res.Payload.Subject)
assert.Empty(t, res.Payload.Client.ClientSecret)
return &models.AcceptLoginRequest{
Subject: &subject,
Remember: true,
RememberFor: rememberFor,
RefreshRememberFor: refreshRememberFor,
Context: map[string]interface{}{"foo": "bar"},
}
}),
checkAndAcceptConsentHandler(t, adminClient.Admin, func(t *testing.T, res *admin.GetConsentRequestOK, err error) *models.AcceptConsentRequest {
require.NoError(t, err)
assert.True(t, res.Payload.Skip)
assert.Equal(t, subject, res.Payload.Subject)
assert.Empty(t, res.Payload.Client.ClientSecret)
return &models.AcceptConsentRequest{
Remember: true,
GrantScope: []string{"openid"},
Session: &models.ConsentRequestSession{
AccessToken: map[string]interface{}{"foo": "bar"},
IDToken: map[string]interface{}{"bar": "baz"},
},
}
}))

hc := &http.Client{
Jar: hc.Jar,
Transport: &http.Transport{},
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}

_, oauthRes := makeOAuth2Request(t, reg, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}, "scope": {"openid"}})
assert.EqualValues(t, http.StatusFound, oauthRes.StatusCode)
loginChallengeRedirect, err := oauthRes.Location()
require.NoError(t, err)
defer oauthRes.Body.Close()

loginChallengeRes, err := hc.Get(loginChallengeRedirect.String())
require.NoError(t, err)
defer loginChallengeRes.Body.Close()
loginVerifierRedirect, err := loginChallengeRes.Location()

loginVerifierRes, err := hc.Get(loginVerifierRedirect.String())
require.NoError(t, err)
defer loginVerifierRes.Body.Close()

setCookieHeader := loginVerifierRes.Header.Get("set-cookie")
assert.NotNil(t, setCookieHeader)
if refreshRememberFor {
assert.Regexp(t, fmt.Sprintf("oauth2_authentication_session_insecure=.*; Path=/; Expires=.*Max-Age=%d; HttpOnly; SameSite=Lax", rememberFor), setCookieHeader)
} else {
assert.NotContains(t, setCookieHeader, "oauth2_authentication_session_insecure")
}
}

t.Run("perform first flow", func(t *testing.T) {
makeRequestAndExpectCode(t, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]},
"scope": {"openid"}})
})

t.Run("perform follow up flow with refresh_remember_for=false", func(t *testing.T) {
followUpHandler(false)
})

t.Run("perform follow up flow with refresh_remember_for=true", func(t *testing.T) {
followUpHandler(true)
})
})

t.Run("case=should pass and check if login context is set properly", func(t *testing.T) {
// This should pass because login was remembered and session id should be set and session context should also work
subject := "aeneas-rekkas"
Expand Down
3 changes: 3 additions & 0 deletions consent/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ type HandledLoginRequest struct {
// authorization will be remembered for the duration of the browser session (using a session cookie).
RememberFor int `json:"remember_for" db:"remember_for"`

// RefreshRememberFor, if set to true, session cookie expiry time will be reset when session is refreshed (skip==true).
RefreshRememberFor bool `json:"refresh_remember_for" db:"refresh_remember_for"`

// ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it
// to express that, for example, a user authenticated using two factor authentication.
ACR string `json:"acr" db:"acr"`
Expand Down
3 changes: 3 additions & 0 deletions internal/httpclient/models/accept_login_request.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled DROP COLUMN refresh_remember_for;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled ADD refresh_remember_for BOOLEAN NOT NULL DEFAULT FALSE;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled DROP COLUMN refresh_remember_for;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled ADD COLUMN refresh_remember_for BOOLEAN NOT NULL DEFAULT FALSE;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled DROP COLUMN refresh_remember_for;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled ADD refresh_remember_for BOOLEAN NOT NULL DEFAULT FALSE;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled DROP COLUMN refresh_remember_for;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE hydra_oauth2_authentication_request_handled ADD refresh_remember_for BOOLEAN NOT NULL DEFAULT FALSE;

0 comments on commit d9a22b2

Please sign in to comment.