package session import ( "errors" "time" "github.com/authelia/authelia/v4/internal/authentication" "github.com/authelia/authelia/v4/internal/authorization" ) // NewDefaultUserSession create a default user session. func NewDefaultUserSession() UserSession { return UserSession{ KeepMeLoggedIn: false, LastActivity: 0, } } // IsAnonymous returns true if the username is empty or the AuthenticationLevel is authentication.NotAuthenticated. func (s *UserSession) IsAnonymous() bool { return s.AuthenticationLevel(false) == authentication.NotAuthenticated } func (s *UserSession) AuthenticationLevel(passkey2FA bool) authentication.Level { switch { case s.Username == "": return authentication.NotAuthenticated case s.AuthenticationMethodRefs.FactorPossession() && s.AuthenticationMethodRefs.FactorKnowledge(): return authentication.TwoFactor case passkey2FA && s.AuthenticationMethodRefs.WebAuthn && s.AuthenticationMethodRefs.WebAuthnUserVerified: return authentication.TwoFactor case s.AuthenticationMethodRefs.FactorPossession() || s.AuthenticationMethodRefs.FactorKnowledge(): return authentication.OneFactor default: return authentication.NotAuthenticated } } // SetOneFactorPassword sets the 1FA AMR's and expected property values for one factor password authentication. func (s *UserSession) SetOneFactorPassword(now time.Time, details *authentication.UserDetails, keepMeLoggedIn bool) { s.setOneFactor(now, details, keepMeLoggedIn) s.AuthenticationMethodRefs.KnowledgeBasedAuthentication = true s.AuthenticationMethodRefs.UsernameAndPassword = true } // SetOneFactorPasskey sets the 1FA AMR's and expected property values for one factor passkey authentication. func (s *UserSession) SetOneFactorPasskey(now time.Time, details *authentication.UserDetails, keepMeLoggedIn, hardware, userPresence, userVerified bool) { s.setOneFactor(now, details, keepMeLoggedIn) s.setWebAuthn(hardware, userPresence, userVerified) } func (s *UserSession) setOneFactor(now time.Time, details *authentication.UserDetails, keepMeLoggedIn bool) { s.FirstFactorAuthnTimestamp = now.Unix() s.LastActivity = now.Unix() s.KeepMeLoggedIn = keepMeLoggedIn s.Username = details.Username s.SetOneFactorReauthenticate(now, details) } func (s *UserSession) SetOneFactorReauthenticate(now time.Time, details *authentication.UserDetails) { s.FirstFactorAuthnTimestamp = now.Unix() s.LastActivity = now.Unix() s.DisplayName = details.DisplayName s.Groups = details.Groups s.Emails = details.Emails } // SetTwoFactorTOTP sets the relevant TOTP AMR's and sets the factor to 2FA. func (s *UserSession) SetTwoFactorTOTP(now time.Time) { s.setTwoFactor(now) s.AuthenticationMethodRefs.TOTP = true } // SetTwoFactorDuo sets the relevant Duo AMR's and sets the factor to 2FA. func (s *UserSession) SetTwoFactorDuo(now time.Time) { s.setTwoFactor(now) s.AuthenticationMethodRefs.Duo = true } // SetTwoFactorWebAuthn sets the relevant WebAuthn AMR's and sets the factor to 2FA. func (s *UserSession) SetTwoFactorWebAuthn(now time.Time, hardware, userPresence, userVerified bool) { s.setTwoFactor(now) s.setWebAuthn(hardware, userPresence, userVerified) } func (s *UserSession) SetTwoFactorPassword(now time.Time) { s.setTwoFactor(now) s.AuthenticationMethodRefs.KnowledgeBasedAuthentication = true s.AuthenticationMethodRefs.UsernameAndPassword = true } func (s *UserSession) setTwoFactor(now time.Time) { s.SecondFactorAuthnTimestamp = now.Unix() s.LastActivity = now.Unix() } func (s *UserSession) setWebAuthn(hardware, userPresence, userVerified bool) { s.AuthenticationMethodRefs.WebAuthn = true s.AuthenticationMethodRefs.WebAuthnUserPresence, s.AuthenticationMethodRefs.WebAuthnUserVerified = userPresence, userVerified if hardware { s.AuthenticationMethodRefs.WebAuthnHardware = true } else { s.AuthenticationMethodRefs.WebAuthnSoftware = true } s.WebAuthn = nil } func (s *UserSession) GetFirstFactorAuthn() time.Time { return time.Unix(s.FirstFactorAuthnTimestamp, 0).UTC() } func (s *UserSession) GetSecondFactorAuthn() time.Time { return time.Unix(s.SecondFactorAuthnTimestamp, 0).UTC() } // AuthenticatedTime returns the unix timestamp this session authenticated successfully at the given level. func (s *UserSession) AuthenticatedTime(level authorization.Level) (authenticatedTime time.Time, err error) { switch level { case authorization.OneFactor: return s.GetFirstFactorAuthn(), nil case authorization.TwoFactor: return s.GetSecondFactorAuthn(), nil default: return time.Unix(0, 0).UTC(), errors.New("invalid authorization level") } } func (s *UserSession) LastAuthenticatedTime() (authenticated time.Time) { if s.FirstFactorAuthnTimestamp > s.SecondFactorAuthnTimestamp { return s.GetFirstFactorAuthn() } return s.GetSecondFactorAuthn() } // Identity value of the user session. func (s *UserSession) Identity() Identity { identity := Identity{ Username: s.Username, DisplayName: s.DisplayName, } if len(s.Emails) != 0 { identity.Email = s.Emails[0] } return identity } func (s *UserSession) GetUsername() (username string) { return s.Username } func (s *UserSession) GetGroups() (groups []string) { return s.Groups } func (s *UserSession) GetDisplayName() (name string) { return s.DisplayName } func (s *UserSession) GetEmails() (emails []string) { return s.Emails }