Skip to content

Commit

Permalink
refactor: add sessions refactors (#728)
Browse files Browse the repository at this point in the history
Co-authored-by: joel@joellee.org <joel@joellee.org>
  • Loading branch information
J0 and joel@joellee.org committed Oct 4, 2022
1 parent ef4891f commit b3963f8
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 4 deletions.
1 change: 1 addition & 0 deletions migrations/20221003041349_add_mfa_schema.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ comment on table {{ index .Options "Namespace" }}.mfa_challenges is 'auth: store


-- add factor_id and amr claims to session

create table if not exists {{ index .Options "Namespace" }}.mfa_amr_claims(
session_id uuid not null,
created_at timestamptz not null,
Expand Down
4 changes: 2 additions & 2 deletions models/factor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (ts *FactorTestSuite) TestUpdateStatus() {
u, err := NewUser("", "", "", "", nil)
require.NoError(ts.T(), err)

f, err := NewFactor(u, "A1B2C3", "some-secret", FactorUnverifiedState, "")
f, err := NewFactor(u, "A1B2C3", TOTP, FactorUnverifiedState, "some-secret")
require.NoError(ts.T(), err)
require.NoError(ts.T(), f.UpdateStatus(ts.db, newFactorStatus))
require.Equal(ts.T(), newFactorStatus, f.Status)
Expand All @@ -75,7 +75,7 @@ func (ts *FactorTestSuite) TestUpdateFriendlyName() {
u, err := NewUser("", "", "", "", nil)
require.NoError(ts.T(), err)

f, err := NewFactor(u, "A1B2C3", "some-secret", FactorUnverifiedState, "")
f, err := NewFactor(u, "A1B2C3", TOTP, FactorUnverifiedState, "some-secret")
require.NoError(ts.T(), err)
require.NoError(ts.T(), f.UpdateFriendlyName(ts.db, newSimpleName))
require.Equal(ts.T(), newSimpleName, f.FriendlyName)
Expand Down
21 changes: 19 additions & 2 deletions models/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@ func (aal AuthenticatorAssuranceLevel) String() string {
}
}

// AMREntry represents a method that a user has logged in together with the corresponding time
type AMREntry struct {
Method string `json:"method"`
Timestamp int64 `json:"timestamp"`
}

type Session struct {
ID uuid.UUID `json:"-" db:"id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
FactorID *uuid.UUID `json:"factor_id" db:"factor_id"`
AMRClaims []AMRClaim `json:"amr_claims" has_many:"amr_claims"`
AMRClaims []AMRClaim `json:"amr_claims,omitempty" has_many:"amr_claims"`
AAL string `json:"aal" db:"aal"`
}

Expand Down Expand Up @@ -114,7 +120,6 @@ func LogoutSession(tx *storage.Connection, sessionId uuid.UUID) error {

func (s *Session) UpdateAssociatedFactor(tx *storage.Connection, factorID *uuid.UUID) error {
s.FactorID = factorID
s.AAL = AAL2.String()
return tx.Update(s)

}
Expand All @@ -123,3 +128,15 @@ func (s *Session) UpdateAAL(tx *storage.Connection, aal string) error {
s.AAL = aal
return tx.Update(s)
}

func (s *Session) CalculateAALAndAMR() (aal string, amr []AMREntry) {
amr, aal = []AMREntry{}, AAL1.String()
for _, claim := range s.AMRClaims {
if claim.AuthenticationMethod == TOTPSignIn.String() {
aal = AAL2.String()
}
amr = append(amr, AMREntry{Method: claim.AuthenticationMethod, Timestamp: claim.UpdatedAt.Unix()})

}
return aal, amr
}
63 changes: 63 additions & 0 deletions models/sessions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package models

import (
"github.com/gofrs/uuid"
"github.com/netlify/gotrue/conf"
"github.com/netlify/gotrue/storage"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"time"
)

type SessionsTestSuite struct {
suite.Suite
db *storage.Connection
Config *conf.GlobalConfiguration
}

func (ts *SessionsTestSuite) SetupTest() {
TruncateAll(ts.db)
email := "test@example.com"
user, err := NewUser("", email, "secret", "test", nil)
require.NoError(ts.T(), err)

err = ts.db.Create(user)
require.NoError(ts.T(), err)
}

func (ts *SessionsTestSuite) TestCalculateAALAndAMR() {
totalDistinctClaims := 2
u, err := FindUserByEmailAndAudience(ts.db, "test@example.com", ts.Config.JWT.Aud)
require.NoError(ts.T(), err)
session, err := CreateSession(ts.db, u, &uuid.Nil)
require.NoError(ts.T(), err)

err = AddClaimToSession(ts.db, session, PasswordGrant)
require.NoError(ts.T(), err)

firstClaimAddedTime := time.Now().Unix()
err = AddClaimToSession(ts.db, session, TOTPSignIn)
require.NoError(ts.T(), err)

aal, amr := session.CalculateAALAndAMR()

require.Equal(ts.T(), AAL2.String(), aal)
require.Equal(ts.T(), totalDistinctClaims, len(amr))

err = AddClaimToSession(ts.db, session, TOTPSignIn)
require.NoError(ts.T(), err)

aal, amr = session.CalculateAALAndAMR()

require.Equal(ts.T(), AAL2.String(), aal)
require.Equal(ts.T(), totalDistinctClaims, len(amr))
found := false
for _, claim := range session.AMRClaims {
if claim.AuthenticationMethod == TOTPSignIn.String() {
require.True(ts.T(), firstClaimAddedTime < claim.UpdatedAt.Unix())
found = true
}
}
require.True(ts.T(), found)

}

0 comments on commit b3963f8

Please sign in to comment.