mirror of
https://github.com/zitadel/zitadel
synced 2024-11-22 00:39:36 +00:00
9ec9ad4314
# Which Problems Are Solved id_tokens issued for auth requests created through the login UI currently do not provide a sid claim. This is due to the fact that (SSO) sessions for the login UI do not have one and are only computed by the userAgent(ID), the user(ID) and the authentication checks of the latter. This prevents client to track sessions and terminate specific session on the end_session_endpoint. # How the Problems Are Solved - An `id` column is added to the `auth.user_sessions` table. - The `id` (prefixed with `V1_`) is set whenever a session is added or updated to active (from terminated) - The id is passed to the `oidc session` (as v2 sessionIDs), to expose it as `sid` claim # Additional Changes - refactored `getUpdateCols` to handle different column value types and add arguments for query # Additional Context - closes #8499 - relates to #8501
284 lines
6.8 KiB
Go
284 lines
6.8 KiB
Go
package domain
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
type AuthRequest struct {
|
|
ID string
|
|
AgentID string
|
|
CreationDate time.Time
|
|
ChangeDate time.Time
|
|
BrowserInfo *BrowserInfo
|
|
ApplicationID string
|
|
CallbackURI string
|
|
TransferState string
|
|
Prompt []Prompt
|
|
PossibleLOAs []LevelOfAssurance
|
|
UiLocales []string
|
|
LoginHint string
|
|
MaxAuthAge *time.Duration
|
|
InstanceID string
|
|
Request Request
|
|
|
|
levelOfAssurance LevelOfAssurance
|
|
UserID string
|
|
UserName string
|
|
LoginName string
|
|
DisplayName string
|
|
AvatarKey string
|
|
PresignedAvatar string
|
|
UserOrgID string
|
|
PreferredLanguage *language.Tag
|
|
RequestedOrgID string
|
|
RequestedOrgName string
|
|
RequestedPrimaryDomain string
|
|
RequestedOrgDomain bool
|
|
ApplicationResourceOwner string
|
|
PrivateLabelingSetting PrivateLabelingSetting
|
|
SelectedIDPConfigID string
|
|
LinkingUsers []*ExternalUser
|
|
PossibleSteps []NextStep `json:"-"`
|
|
PasswordVerified bool
|
|
IDPLoginChecked bool
|
|
MFAsVerified []MFAType
|
|
Audience []string
|
|
AuthTime time.Time
|
|
Code string
|
|
LoginPolicy *LoginPolicy
|
|
AllowedExternalIDPs []*IDPProvider
|
|
LabelPolicy *LabelPolicy
|
|
PrivacyPolicy *PrivacyPolicy
|
|
LockoutPolicy *LockoutPolicy
|
|
PasswordAgePolicy *PasswordAgePolicy
|
|
DefaultTranslations []*CustomText
|
|
OrgTranslations []*CustomText
|
|
SAMLRequestID string
|
|
// orgID the policies were last loaded with
|
|
policyOrgID string
|
|
// SessionID is set to the computed sessionID of the login session table
|
|
SessionID string
|
|
}
|
|
|
|
func (a *AuthRequest) SetPolicyOrgID(id string) {
|
|
a.policyOrgID = id
|
|
}
|
|
|
|
func (a *AuthRequest) PolicyOrgID() string {
|
|
return a.policyOrgID
|
|
}
|
|
|
|
func (a *AuthRequest) AuthMethods() []UserAuthMethodType {
|
|
list := make([]UserAuthMethodType, 0, len(a.MFAsVerified)+2)
|
|
if a.PasswordVerified {
|
|
list = append(list, UserAuthMethodTypePassword)
|
|
}
|
|
if a.IDPLoginChecked {
|
|
list = append(list, UserAuthMethodTypeIDP)
|
|
}
|
|
for _, mfa := range a.MFAsVerified {
|
|
list = append(list, mfa.UserAuthMethodType())
|
|
}
|
|
return slices.Compact(list)
|
|
}
|
|
|
|
type ExternalUser struct {
|
|
IDPConfigID string
|
|
ExternalUserID string
|
|
DisplayName string
|
|
PreferredUsername string
|
|
FirstName string
|
|
LastName string
|
|
NickName string
|
|
Email EmailAddress
|
|
IsEmailVerified bool
|
|
PreferredLanguage language.Tag
|
|
Phone PhoneNumber
|
|
IsPhoneVerified bool
|
|
Metadatas []*Metadata
|
|
}
|
|
|
|
type Prompt int32
|
|
|
|
const (
|
|
PromptUnspecified Prompt = iota
|
|
PromptNone
|
|
PromptLogin
|
|
PromptConsent
|
|
PromptSelectAccount
|
|
PromptCreate
|
|
)
|
|
|
|
func IsPrompt(prompt []Prompt, requestedPrompt Prompt) bool {
|
|
for _, p := range prompt {
|
|
if p == requestedPrompt {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type LevelOfAssurance int
|
|
|
|
const (
|
|
LevelOfAssuranceNone LevelOfAssurance = iota
|
|
)
|
|
|
|
type MFAType int
|
|
|
|
const (
|
|
MFATypeTOTP MFAType = iota
|
|
MFATypeU2F
|
|
MFATypeU2FUserVerification
|
|
MFATypeOTPSMS
|
|
MFATypeOTPEmail
|
|
)
|
|
|
|
func (m MFAType) UserAuthMethodType() UserAuthMethodType {
|
|
switch m {
|
|
case MFATypeTOTP:
|
|
return UserAuthMethodTypeTOTP
|
|
case MFATypeU2F:
|
|
return UserAuthMethodTypeU2F
|
|
case MFATypeU2FUserVerification:
|
|
return UserAuthMethodTypePasswordless
|
|
case MFATypeOTPSMS:
|
|
return UserAuthMethodTypeOTPSMS
|
|
case MFATypeOTPEmail:
|
|
return UserAuthMethodTypeOTPEmail
|
|
default:
|
|
return UserAuthMethodTypeUnspecified
|
|
}
|
|
}
|
|
|
|
type MFALevel int
|
|
|
|
const (
|
|
MFALevelNotSetUp MFALevel = iota
|
|
MFALevelSecondFactor
|
|
MFALevelMultiFactor
|
|
MFALevelMultiFactorCertified
|
|
)
|
|
|
|
type AuthRequestState int
|
|
|
|
const (
|
|
AuthRequestStateUnspecified AuthRequestState = iota
|
|
AuthRequestStateAdded
|
|
AuthRequestStateCodeAdded
|
|
AuthRequestStateCodeExchanged
|
|
AuthRequestStateFailed
|
|
AuthRequestStateSucceeded
|
|
)
|
|
|
|
func NewAuthRequestFromType(requestType AuthRequestType) (*AuthRequest, error) {
|
|
switch requestType {
|
|
case AuthRequestTypeOIDC:
|
|
return &AuthRequest{Request: &AuthRequestOIDC{}}, nil
|
|
case AuthRequestTypeSAML:
|
|
return &AuthRequest{Request: &AuthRequestSAML{}}, nil
|
|
case AuthRequestTypeDevice:
|
|
return &AuthRequest{Request: &AuthRequestDevice{}}, nil
|
|
}
|
|
return nil, zerrors.ThrowInvalidArgument(nil, "DOMAIN-ds2kl", "invalid request type")
|
|
}
|
|
|
|
func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest {
|
|
a.BrowserInfo = info
|
|
return a
|
|
}
|
|
|
|
func (a *AuthRequest) SetUserInfo(userID, userName, loginName, displayName, avatar, userOrgID string) {
|
|
a.UserID = userID
|
|
a.UserName = userName
|
|
a.LoginName = loginName
|
|
a.DisplayName = displayName
|
|
a.AvatarKey = avatar
|
|
a.UserOrgID = userOrgID
|
|
}
|
|
|
|
func (a *AuthRequest) SetOrgInformation(id, name, primaryDomain string, requestedByDomain bool) {
|
|
a.RequestedOrgID = id
|
|
a.RequestedOrgName = name
|
|
a.RequestedPrimaryDomain = primaryDomain
|
|
a.RequestedOrgDomain = requestedByDomain
|
|
}
|
|
|
|
func (a *AuthRequest) MFALevel() MFALevel {
|
|
return -1
|
|
//PLANNED: check a.PossibleLOAs (and Prompt Login?)
|
|
}
|
|
|
|
func (a *AuthRequest) AppendAudIfNotExisting(aud string) {
|
|
for _, a := range a.Audience {
|
|
if a == aud {
|
|
return
|
|
}
|
|
}
|
|
a.Audience = append(a.Audience, aud)
|
|
}
|
|
|
|
func (a *AuthRequest) GetScopeOrgPrimaryDomain() string {
|
|
switch request := a.Request.(type) {
|
|
case *AuthRequestOIDC:
|
|
for _, scope := range request.Scopes {
|
|
if strings.HasPrefix(scope, OrgDomainPrimaryScope) {
|
|
return strings.TrimPrefix(scope, OrgDomainPrimaryScope)
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (a *AuthRequest) GetScopeOrgID() string {
|
|
switch request := a.Request.(type) {
|
|
case *AuthRequestOIDC:
|
|
for _, scope := range request.Scopes {
|
|
if strings.HasPrefix(scope, OrgIDScope) {
|
|
return strings.TrimPrefix(scope, OrgIDScope)
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (a *AuthRequest) Done() bool {
|
|
for _, step := range a.PossibleSteps {
|
|
if step.Type() == NextStepRedirectToCallback {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a *AuthRequest) PrivateLabelingOrgID(defaultID string) string {
|
|
if a.RequestedOrgID != "" {
|
|
return a.RequestedOrgID
|
|
}
|
|
if (a.PrivateLabelingSetting == PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy || a.PrivateLabelingSetting == PrivateLabelingSettingUnspecified) &&
|
|
a.UserOrgID != "" {
|
|
return a.UserOrgID
|
|
}
|
|
if a.PrivateLabelingSetting != PrivateLabelingSettingUnspecified {
|
|
return a.ApplicationResourceOwner
|
|
}
|
|
return defaultID
|
|
}
|
|
|
|
func (a *AuthRequest) UserAuthMethodTypes() []UserAuthMethodType {
|
|
list := make([]UserAuthMethodType, 0, len(a.MFAsVerified)+1)
|
|
if a.PasswordVerified {
|
|
list = append(list, UserAuthMethodTypePassword)
|
|
}
|
|
for _, mfa := range a.MFAsVerified {
|
|
list = append(list, mfa.UserAuthMethodType())
|
|
}
|
|
return list
|
|
}
|