Change session from method tracking

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-12-19 15:43:16 +01:00
parent 811bebca48
commit a4964e817c
3 changed files with 57 additions and 30 deletions

View File

@@ -0,0 +1,24 @@
CREATE TYPE session_auth_method AS ENUM (
'PASSWORD',
'SAML'
);
ALTER TABLE sessions ADD COLUMN auth_method session_auth_method;
ALTER TABLE sessions ADD COLUMN authenticated_at TIMESTAMP;
-- Expire all existing sessions as they are not backward compatible
UPDATE sessions SET
expire_reason = 'revoked',
expired_at = NOW(),
updated_at = NOW(),
auth_method = 'PASSWORD',
authenticated_at = created_at
WHERE expire_reason IS NULL;
UPDATE sessions SET
auth_method = 'PASSWORD',
authenticated_at = created_at
WHERE auth_method IS NULL;
ALTER TABLE sessions ALTER COLUMN auth_method SET NOT NULL;
ALTER TABLE sessions ALTER COLUMN authenticated_at SET NOT NULL;

View File

@@ -35,6 +35,8 @@ type (
TenantID *gid.TenantID `db:"tenant_id"` TenantID *gid.TenantID `db:"tenant_id"`
ParentSessionID *gid.GID `db:"parent_session_id"` ParentSessionID *gid.GID `db:"parent_session_id"`
Data SessionData `db:"data"` Data SessionData `db:"data"`
AuthMethod AuthMethod `db:"auth_method"`
AuthenticatedAt time.Time `db:"authenticated_at"`
UserAgent string `db:"user_agent"` UserAgent string `db:"user_agent"`
IPAddress net.IP `db:"ip_address"` IPAddress net.IP `db:"ip_address"`
ExpireReason *ExpireReason `db:"expire_reason"` ExpireReason *ExpireReason `db:"expire_reason"`
@@ -45,25 +47,26 @@ type (
Sessions []*Session Sessions []*Session
SessionData struct { SessionData struct{}
PasswordAuthenticated bool `json:"password_authenticated"`
SAMLAuthenticatedOrgs map[string]SAMLAuthInfo `json:"saml_authenticated_orgs,omitempty"`
}
SAMLAuthInfo struct { AuthMethod string
AuthenticatedAt time.Time `json:"authenticated_at"`
SAMLConfigID gid.GID `json:"saml_config_id"`
SAMLSubject string `json:"saml_subject"`
}
) )
func NewRootSession(userID gid.GID, duration time.Duration) *Session { const (
AuthMethodPassword AuthMethod = "PASSWORD"
AuthMethodSAML AuthMethod = "SAML"
)
func NewRootSession(userID gid.GID, method AuthMethod, duration time.Duration) *Session {
now := time.Now()
return &Session{ return &Session{
ID: gid.New(gid.NilTenant, SessionEntityType), ID: gid.New(gid.NilTenant, SessionEntityType),
UserID: userID, UserID: userID,
ExpiredAt: time.Now().Add(duration), ExpiredAt: now.Add(duration),
CreatedAt: time.Now(), AuthMethod: method,
UpdatedAt: time.Now(), AuthenticatedAt: now,
CreatedAt: now,
UpdatedAt: now,
} }
} }
@@ -100,6 +103,8 @@ SELECT
tenant_id, tenant_id,
data, data,
parent_session_id, parent_session_id,
auth_method,
authenticated_at,
expire_reason, expire_reason,
user_agent, user_agent,
ip_address, ip_address,
@@ -139,13 +144,15 @@ func (s *Session) Insert(
) error { ) error {
q := ` q := `
INSERT INTO INSERT INTO
sessions (id, user_id, tenant_id, data, parent_session_id, expire_reason, user_agent, ip_address, expired_at, created_at, updated_at) sessions (id, user_id, tenant_id, data, parent_session_id, auth_method, authenticated_at, expire_reason, user_agent, ip_address, expired_at, created_at, updated_at)
VALUES ( VALUES (
@session_id, @session_id,
@user_id, @user_id,
@tenant_id, @tenant_id,
@data, @data,
@parent_session_id, @parent_session_id,
@auth_method,
@authenticated_at,
@expire_reason, @expire_reason,
@user_agent, @user_agent,
@ip_address, @ip_address,
@@ -161,6 +168,8 @@ VALUES (
"tenant_id": s.TenantID, "tenant_id": s.TenantID,
"data": s.Data, "data": s.Data,
"parent_session_id": s.ParentSessionID, "parent_session_id": s.ParentSessionID,
"auth_method": s.AuthMethod,
"authenticated_at": s.AuthenticatedAt,
"expire_reason": s.ExpireReason, "expire_reason": s.ExpireReason,
"user_agent": s.UserAgent, "user_agent": s.UserAgent,
"ip_address": s.IPAddress, "ip_address": s.IPAddress,
@@ -220,6 +229,8 @@ SELECT
tenant_id, tenant_id,
data, data,
parent_session_id, parent_session_id,
auth_method,
authenticated_at,
expire_reason, expire_reason,
user_agent, user_agent,
ip_address, ip_address,
@@ -309,6 +320,8 @@ SELECT
tenant_id, tenant_id,
data, data,
parent_session_id, parent_session_id,
auth_method,
authenticated_at,
expire_reason, expire_reason,
user_agent, user_agent,
ip_address, ip_address,

View File

@@ -172,7 +172,7 @@ func (s *AuthService) CreateIdentityFromInvitation(
return fmt.Errorf("cannot insert user: %w", err) return fmt.Errorf("cannot insert user: %w", err)
} }
session = coredata.NewRootSession(user.ID, s.sessionDuration) session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, s.sessionDuration)
err = session.Insert(ctx, tx) err = session.Insert(ctx, tx)
if err != nil { if err != nil {
return fmt.Errorf("cannot insert session: %w", err) return fmt.Errorf("cannot insert session: %w", err)
@@ -330,17 +330,7 @@ func (s AuthService) CreateIdentityWithPassword(
UpdatedAt: now, UpdatedAt: now,
} }
session = &coredata.Session{ session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, 24*time.Hour*7)
ID: gid.New(gid.NilTenant, coredata.SessionEntityType),
UserID: user.ID,
Data: coredata.SessionData{
PasswordAuthenticated: true,
SAMLAuthenticatedOrgs: make(map[string]coredata.SAMLAuthInfo),
},
ExpiredAt: now.Add(24 * time.Hour * 7), // 7 days, TODO must to be hardcoded here
CreatedAt: now,
UpdatedAt: now,
}
) )
confirmationToken, err := statelesstoken.NewToken( confirmationToken, err := statelesstoken.NewToken(
@@ -416,7 +406,7 @@ func (s AuthService) OpenSessionWithSAML(ctx context.Context, userID gid.GID, or
err := s.pg.WithTx( err := s.pg.WithTx(
ctx, ctx,
func(conn pg.Conn) (err error) { func(conn pg.Conn) (err error) {
session = coredata.NewRootSession(userID, s.sessionDuration) session = coredata.NewRootSession(userID, coredata.AuthMethodSAML, s.sessionDuration)
err = session.Insert(ctx, conn) err = session.Insert(ctx, conn)
if err != nil { if err != nil {
return fmt.Errorf("cannot insert session: %w", err) return fmt.Errorf("cannot insert session: %w", err)
@@ -474,7 +464,7 @@ func (s AuthService) OpenSessionWithPassword(ctx context.Context, email mail.Add
return NewInvalidCredentialsError("invalid email or password") return NewInvalidCredentialsError("invalid email or password")
} }
session = coredata.NewRootSession(user.ID, s.sessionDuration) session = coredata.NewRootSession(user.ID, coredata.AuthMethodPassword, s.sessionDuration)
err = session.Insert(ctx, conn) err = session.Insert(ctx, conn)
if err != nil { if err != nil {
return fmt.Errorf("cannot insert session: %w", err) return fmt.Errorf("cannot insert session: %w", err)