refactor(session/data): separate into object groups

This commit is contained in:
Trong Huu Nguyen
2022-08-29 08:35:03 +02:00
parent 1d9339e139
commit cdd07838f4
4 changed files with 96 additions and 66 deletions

View File

@@ -174,29 +174,29 @@ func TestHandler_SessionInfo(t *testing.T) {
assert.NoError(t, err)
allowedSkew := 5 * time.Second
assert.WithinDuration(t, time.Now(), data.SessionCreatedAt, allowedSkew)
assert.WithinDuration(t, time.Now().Add(cfg.Session.MaxLifetime), data.SessionEndsAt, allowedSkew)
assert.WithinDuration(t, time.Now().Add(idp.ProviderHandler.TokenDuration), data.TokensExpireAt, allowedSkew)
assert.WithinDuration(t, time.Now(), data.TokensRefreshedAt, allowedSkew)
assert.WithinDuration(t, time.Now(), data.Session.CreatedAt, allowedSkew)
assert.WithinDuration(t, time.Now().Add(cfg.Session.MaxLifetime), data.Session.EndsAt, allowedSkew)
assert.WithinDuration(t, time.Now().Add(idp.ProviderHandler.TokenDuration), data.Tokens.ExpireAt, allowedSkew)
assert.WithinDuration(t, time.Now(), data.Tokens.RefreshedAt, allowedSkew)
sessionEndDuration := time.Duration(data.SessionEndsInSeconds) * time.Second
sessionEndDuration := time.Duration(data.Session.EndsInSeconds) * time.Second
// 1 second < time until session ends <= configured max session lifetime
assert.LessOrEqual(t, sessionEndDuration, cfg.Session.MaxLifetime)
assert.Greater(t, sessionEndDuration, time.Second)
tokenExpiryDuration := time.Duration(data.TokensExpireInSeconds) * time.Second
tokenExpiryDuration := time.Duration(data.Tokens.ExpireInSeconds) * time.Second
// 1 second < time until token expires <= max duration for tokens from IDP
assert.LessOrEqual(t, tokenExpiryDuration, idp.ProviderHandler.TokenDuration)
assert.Greater(t, tokenExpiryDuration, time.Second)
// 1 second < next token refresh <= seconds until token expires
assert.LessOrEqual(t, data.TokensNextRefreshInSeconds, data.TokensExpireInSeconds)
assert.Greater(t, data.TokensNextRefreshInSeconds, int64(1))
assert.LessOrEqual(t, data.Tokens.NextAutoRefreshInSeconds, data.Tokens.ExpireInSeconds)
assert.Greater(t, data.Tokens.NextAutoRefreshInSeconds, int64(1))
assert.True(t, data.TokensRefreshCooldown)
assert.True(t, data.Tokens.RefreshCooldown)
// 1 second < refresh cooldown <= minimum refresh interval
assert.LessOrEqual(t, data.TokensRefreshCooldownSeconds, session.RefreshMinInterval)
assert.Greater(t, data.TokensRefreshCooldownSeconds, int64(1))
assert.LessOrEqual(t, data.Tokens.RefreshCooldownSeconds, session.RefreshMinInterval)
assert.Greater(t, data.Tokens.RefreshCooldownSeconds, int64(1))
}
func TestHandler_SessionInfo_Disabled(t *testing.T) {
@@ -249,7 +249,7 @@ func TestHandler_SessionRefresh(t *testing.T) {
err = json.Unmarshal([]byte(resp.Body), &temp)
assert.NoError(t, err)
if !temp.TokensRefreshCooldown {
if !temp.Tokens.RefreshCooldown {
return
}
}
@@ -264,35 +264,35 @@ func TestHandler_SessionRefresh(t *testing.T) {
assert.NoError(t, err)
// session create and end times should be unchanged
assert.WithinDuration(t, data.SessionCreatedAt, refreshedData.SessionCreatedAt, 0)
assert.WithinDuration(t, data.SessionEndsAt, refreshedData.SessionEndsAt, 0)
assert.WithinDuration(t, data.Session.CreatedAt, refreshedData.Session.CreatedAt, 0)
assert.WithinDuration(t, data.Session.EndsAt, refreshedData.Session.EndsAt, 0)
// token expiration and refresh times should be later than before
assert.True(t, refreshedData.TokensExpireAt.After(data.TokensExpireAt))
assert.True(t, refreshedData.TokensRefreshedAt.After(data.TokensRefreshedAt))
assert.True(t, refreshedData.Tokens.ExpireAt.After(data.Tokens.ExpireAt))
assert.True(t, refreshedData.Tokens.RefreshedAt.After(data.Tokens.RefreshedAt))
allowedSkew := 5 * time.Second
assert.WithinDuration(t, time.Now().Add(idp.ProviderHandler.TokenDuration), refreshedData.TokensExpireAt, allowedSkew)
assert.WithinDuration(t, time.Now(), refreshedData.TokensRefreshedAt, allowedSkew)
assert.WithinDuration(t, time.Now().Add(idp.ProviderHandler.TokenDuration), refreshedData.Tokens.ExpireAt, allowedSkew)
assert.WithinDuration(t, time.Now(), refreshedData.Tokens.RefreshedAt, allowedSkew)
sessionEndDuration := time.Duration(refreshedData.SessionEndsInSeconds) * time.Second
sessionEndDuration := time.Duration(refreshedData.Session.EndsInSeconds) * time.Second
// 1 second < time until session ends <= configured max session lifetime
assert.LessOrEqual(t, sessionEndDuration, cfg.Session.MaxLifetime)
assert.Greater(t, sessionEndDuration, time.Second)
tokenExpiryDuration := time.Duration(refreshedData.TokensExpireInSeconds) * time.Second
tokenExpiryDuration := time.Duration(refreshedData.Tokens.ExpireInSeconds) * time.Second
// 1 second < time until token expires <= max duration for tokens from IDP
assert.LessOrEqual(t, tokenExpiryDuration, idp.ProviderHandler.TokenDuration)
assert.Greater(t, tokenExpiryDuration, time.Second)
// 1 second < next token refresh <= seconds until token expires
assert.LessOrEqual(t, refreshedData.TokensNextRefreshInSeconds, refreshedData.TokensExpireInSeconds)
assert.Greater(t, refreshedData.TokensNextRefreshInSeconds, int64(1))
assert.LessOrEqual(t, refreshedData.Tokens.NextAutoRefreshInSeconds, refreshedData.Tokens.ExpireInSeconds)
assert.Greater(t, refreshedData.Tokens.NextAutoRefreshInSeconds, int64(1))
assert.True(t, refreshedData.TokensRefreshCooldown)
assert.True(t, refreshedData.Tokens.RefreshCooldown)
// 1 second < refresh cooldown <= minimum refresh interval
assert.LessOrEqual(t, refreshedData.TokensRefreshCooldownSeconds, session.RefreshMinInterval)
assert.Greater(t, refreshedData.TokensRefreshCooldownSeconds, int64(1))
assert.LessOrEqual(t, refreshedData.Tokens.RefreshCooldownSeconds, session.RefreshMinInterval)
assert.Greater(t, refreshedData.Tokens.RefreshCooldownSeconds, int64(1))
}
func TestHandler_SessionRefresh_Disabled(t *testing.T) {

View File

@@ -100,28 +100,40 @@ func (in *Data) HasRefreshToken() bool {
}
type Metadata struct {
// SessionCreatedAt is the time when the session was created.
SessionCreatedAt time.Time `json:"session_created_at"`
// SessionEndsAt is the time when the session will end, i.e. the absolute lifetime/time-to-live for the session.
SessionEndsAt time.Time `json:"session_ends_at"`
// TokensExpireAt is the time when the tokens within the session expires.
TokensExpireAt time.Time `json:"tokens_expire_at"`
// TokensRefreshedAt is the time when the tokens within the session was refreshed.
TokensRefreshedAt time.Time `json:"tokens_refreshed_at"`
Session MetadataSession `json:"session"`
Tokens MetadataTokens `json:"tokens"`
}
type MetadataSession struct {
// CreatedAt is the time when the session was created.
CreatedAt time.Time `json:"created_at"`
// EndsAt is the time when the session will end, i.e. the absolute lifetime/time-to-live for the session.
EndsAt time.Time `json:"ends_at"`
}
type MetadataTokens struct {
// ExpireAt is the time when the tokens will expire.
ExpireAt time.Time `json:"expire_at"`
// RefreshedAt is the time when the tokens were last refreshed.
RefreshedAt time.Time `json:"refreshed_at"`
}
func NewMetadata(expiresIn time.Duration, endsIn time.Duration) *Metadata {
now := time.Now()
return &Metadata{
SessionCreatedAt: now,
SessionEndsAt: now.Add(endsIn),
TokensRefreshedAt: now,
TokensExpireAt: now.Add(expiresIn),
Session: MetadataSession{
CreatedAt: now,
EndsAt: now.Add(endsIn),
},
Tokens: MetadataTokens{
ExpireAt: now.Add(expiresIn),
RefreshedAt: now,
},
}
}
func (in *Metadata) IsExpired() bool {
return time.Now().After(in.TokensExpireAt)
return time.Now().After(in.Tokens.ExpireAt)
}
func (in *Metadata) IsRefreshOnCooldown() bool {
@@ -130,7 +142,7 @@ func (in *Metadata) IsRefreshOnCooldown() bool {
func (in *Metadata) NextRefresh() time.Time {
// subtract the leeway to ensure that we refresh before expiry
next := in.TokensExpireAt.Add(-RefreshLeeway)
next := in.Tokens.ExpireAt.Add(-RefreshLeeway)
// try to refresh at the first opportunity if the next refresh is in the past
if next.Before(time.Now()) {
@@ -142,12 +154,12 @@ func (in *Metadata) NextRefresh() time.Time {
func (in *Metadata) Refresh(nextExpirySeconds int64) {
now := time.Now()
in.TokensRefreshedAt = now
in.TokensExpireAt = now.Add(time.Duration(nextExpirySeconds) * time.Second)
in.Tokens.RefreshedAt = now
in.Tokens.ExpireAt = now.Add(time.Duration(nextExpirySeconds) * time.Second)
}
func (in *Metadata) RefreshCooldown() time.Time {
refreshed := in.TokensRefreshedAt
refreshed := in.Tokens.RefreshedAt
tokenLifetime := in.TokenLifetime()
// if token lifetime is less than the minimum refresh interval * 2, we'll allow refreshes at the token half-life
@@ -167,33 +179,47 @@ func (in *Metadata) ShouldRefresh() bool {
}
func (in *Metadata) TokenLifetime() time.Duration {
return in.TokensExpireAt.Sub(in.TokensRefreshedAt)
return in.Tokens.ExpireAt.Sub(in.Tokens.RefreshedAt)
}
func (in *Metadata) Verbose() MetadataVerbose {
now := time.Now()
expireTime := in.TokensExpireAt
endTime := in.SessionEndsAt
expireTime := in.Tokens.ExpireAt
endTime := in.Session.EndsAt
nextRefreshTime := in.NextRefresh()
return MetadataVerbose{
Metadata: *in,
SessionEndsInSeconds: toSeconds(endTime.Sub(now)),
TokensExpireInSeconds: toSeconds(expireTime.Sub(now)),
TokensNextRefreshInSeconds: toSeconds(nextRefreshTime.Sub(now)),
TokensRefreshCooldown: in.IsRefreshOnCooldown(),
TokensRefreshCooldownSeconds: toSeconds(in.RefreshCooldown().Sub(now)),
Session: MetadataSessionVerbose{
MetadataSession: in.Session,
EndsInSeconds: toSeconds(endTime.Sub(now)),
},
Tokens: MetadataTokensVerbose{
MetadataTokens: in.Tokens,
ExpireInSeconds: toSeconds(expireTime.Sub(now)),
NextAutoRefreshInSeconds: toSeconds(nextRefreshTime.Sub(now)),
RefreshCooldown: in.IsRefreshOnCooldown(),
RefreshCooldownSeconds: toSeconds(in.RefreshCooldown().Sub(now)),
},
}
}
type MetadataVerbose struct {
Metadata
SessionEndsInSeconds int64 `json:"session_ends_in_seconds"`
TokensExpireInSeconds int64 `json:"tokens_expire_in_seconds"`
TokensNextRefreshInSeconds int64 `json:"tokens_next_refresh_in_seconds"`
TokensRefreshCooldown bool `json:"tokens_refresh_cooldown"`
TokensRefreshCooldownSeconds int64 `json:"tokens_refresh_cooldown_seconds"`
Session MetadataSessionVerbose `json:"session"`
Tokens MetadataTokensVerbose `json:"tokens"`
}
type MetadataSessionVerbose struct {
MetadataSession
EndsInSeconds int64 `json:"ends_in_seconds"`
}
type MetadataTokensVerbose struct {
MetadataTokens
ExpireInSeconds int64 `json:"expire_in_seconds"`
NextAutoRefreshInSeconds int64 `json:"next_auto_refresh_in_seconds"`
RefreshCooldown bool `json:"refresh_cooldown"`
RefreshCooldownSeconds int64 `json:"refresh_cooldown_seconds"`
}
func toSeconds(d time.Duration) int64 {

View File

@@ -12,6 +12,14 @@ func TestData_HasRefreshToken(t *testing.T) {
// TODO
}
func TestMetadata_IsExpired(t *testing.T) {
// TODO
}
func TestMetadata_IsRefreshOnCooldown(t *testing.T) {
// TODO
}
func TestMetadata_NextRefresh(t *testing.T) {
// TODO
}
@@ -24,15 +32,11 @@ func TestMetadata_RefreshCooldown(t *testing.T) {
// TODO
}
func TestMetadata_RefreshOnCooldown(t *testing.T) {
// TODO
}
func TestMetadata_ShouldRefresh(t *testing.T) {
// TODO
}
func TestMetadata_TokenAge(t *testing.T) {
func TestMetadata_TokenLifetime(t *testing.T) {
// TODO
}

View File

@@ -21,10 +21,10 @@ func decryptedEqual(t *testing.T, expected, actual *session.Data) {
assert.Equal(t, expected.IDTokenJwtID, actual.IDTokenJwtID)
assert.Equal(t, expected.ExternalSessionID, actual.ExternalSessionID)
assert.WithinDuration(t, expected.Metadata.SessionCreatedAt, actual.Metadata.SessionCreatedAt, 0)
assert.WithinDuration(t, expected.Metadata.SessionEndsAt, actual.Metadata.SessionEndsAt, 0)
assert.WithinDuration(t, expected.Metadata.TokensExpireAt, actual.Metadata.TokensExpireAt, 0)
assert.WithinDuration(t, expected.Metadata.TokensRefreshedAt, actual.Metadata.TokensRefreshedAt, 0)
assert.WithinDuration(t, expected.Metadata.Session.CreatedAt, actual.Metadata.Session.CreatedAt, 0)
assert.WithinDuration(t, expected.Metadata.Session.EndsAt, actual.Metadata.Session.EndsAt, 0)
assert.WithinDuration(t, expected.Metadata.Tokens.ExpireAt, actual.Metadata.Tokens.ExpireAt, 0)
assert.WithinDuration(t, expected.Metadata.Tokens.RefreshedAt, actual.Metadata.Tokens.RefreshedAt, 0)
}
func makeCrypter(t *testing.T) crypto.Crypter {