Skip to content

Commit

Permalink
PLATFORM-6607| add configurable session refresh time window
Browse files Browse the repository at this point in the history
  • Loading branch information
harnash committed Jan 11, 2022
1 parent f7f808f commit 92383e9
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 3 deletions.
5 changes: 5 additions & 0 deletions driver/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ const (
ViperKeySessionPersistentCookie = "session.cookie.persistent"
ViperKeySessionWhoAmIAAL = "session.whoami.required_aal"
ViperKeySessionWhoAmIRefresh = "session.whoami.refresh"
ViperKeySessionRefreshTimeWindow = "session.refresh_time_window"
ViperKeyCookieSameSite = "cookies.same_site"
ViperKeyCookieDomain = "cookies.domain"
ViperKeyCookiePath = "cookies.path"
Expand Down Expand Up @@ -1034,6 +1035,10 @@ func (p *Config) SessionWhoAmIRefresh() bool {
return p.p.Bool(ViperKeySessionWhoAmIRefresh)
}

func (p *Config) SessionRefreshTimeWindow() time.Duration {
return p.p.DurationF(ViperKeySessionRefreshTimeWindow, p.SessionLifespan()/2)
}

func (p *Config) SelfServiceSettingsRequiredAAL() string {
return p.p.String(ViperKeySelfServiceSettingsRequiredAAL)
}
Expand Down
12 changes: 12 additions & 0 deletions embedx/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,18 @@
}
},
"additionalProperties": false
},
"refresh_time_window": {
"title": "Session refresh time window",
"description": "Time window when session can be refreshed to avoid excess refreshes. It is calculated as duration from the session expiration time.",
"type": "string",
"pattern": "^[0-9]+(ns|us|ms|s|m|h)$",
"default": "12h",
"examples": [
"1h",
"1m",
"1s"
]
}
}
},
Expand Down
7 changes: 4 additions & 3 deletions session/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, ps httprouter.P
}

var aalErr *ErrAALNotSatisfied
if err := h.r.SessionManager().DoesSessionSatisfy(r, s, h.r.Config(r.Context()).SessionWhoAmIAAL()); errors.As(err, &aalErr) {
c := h.r.Config(r.Context())
if err := h.r.SessionManager().DoesSessionSatisfy(r, s, c.SessionWhoAmIAAL()); errors.As(err, &aalErr) {
h.r.Audit().WithRequest(r).WithError(err).Info("Session was found but AAL is not satisfied for calling this endpoint.")
h.r.Writer().WriteError(w, r, err)
return
Expand All @@ -182,8 +183,8 @@ func (h *Handler) whoami(w http.ResponseWriter, r *http.Request, ps httprouter.P

// Refresh session if param was true
refresh := r.URL.Query().Get("refresh")
if h.r.Config(r.Context()).SessionWhoAmIRefresh() && refresh == "true" {
if err := h.r.SessionPersister().UpsertSession(r.Context(), s.Refresh(h.r.Config(r.Context()))); err != nil {
if c.SessionWhoAmIRefresh() && refresh == "true" && s.CanBeRefreshed(c) {
if err := h.r.SessionPersister().UpsertSession(r.Context(), s.Refresh(c)); err != nil {
h.r.Writer().WriteError(w, r, err)
return
}
Expand Down
8 changes: 8 additions & 0 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type lifespanProvider interface {
SessionLifespan() time.Duration
}

type refreshWindowProvider interface {
SessionRefreshTimeWindow() time.Duration
}

// A Session
//
// swagger:model session
Expand Down Expand Up @@ -161,6 +165,10 @@ func (s *Session) Refresh(c lifespanProvider) *Session {
return s
}

func (s *Session) CanBeRefreshed(c refreshWindowProvider) bool {
return time.Now().Add(c.SessionRefreshTimeWindow()).After(s.ExpiresAt)
}

func (s *Session) IsActive() bool {
return s.Active && s.ExpiresAt.After(time.Now()) && (s.Identity == nil || s.Identity.IsActive())
}
Expand Down
9 changes: 9 additions & 0 deletions session/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ func TestSession(t *testing.T) {
assert.Empty(t, s.AuthenticatedAt)
})

t.Run("case=session refresh", func(t *testing.T) {
s := session.NewInactiveSession()
assert.False(t, s.CanBeRefreshed(conf), "fresh session is not refreshable")

s.ExpiresAt = time.Now().Add(13 * time.Hour)
assert.True(t, s.CanBeRefreshed(conf), "session is refreshable after 13hrs")

})

t.Run("case=aal", func(t *testing.T) {
for _, tc := range []struct {
d string
Expand Down

0 comments on commit 92383e9

Please sign in to comment.