mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved As part of #11035 , this PR implements the Passkey check logic for session validation # How the Problems Are Solved - Refactor webauth FinishLogin to support new domain model - Add webauth config to defaults - Implement passkey check logic and tests - Manual transaction management to avoid stalling the DB while FinishLogin callback is executed - Update passkey Type condition to allow passing a text operation (equal, contains, etc..) # Additional Context This is a cherry-picked PR + minor changes, coming from https://github.com/zitadel/zitadel/pull/11164 - Relates to #11035 --------- Co-authored-by: Fabienne Bühler <[email protected]> Co-authored-by: Gayathri Vijayan <[email protected]>
255 lines
9.5 KiB
Go
255 lines
9.5 KiB
Go
package domain
|
|
|
|
import (
|
|
"time"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/zitadel/zitadel/internal/crypto"
|
|
)
|
|
|
|
type User struct {
|
|
InstanceID string `json:"instanceId,omitempty" db:"instance_id"`
|
|
OrganizationID string `json:"organizationId,omitempty" db:"organization_id"`
|
|
ID string `json:"id,omitempty" db:"id"`
|
|
Username string `json:"username,omitempty" db:"username"`
|
|
LoginNames []LoginName `json:"loginNames,omitempty" db:"login_names"`
|
|
State UserState `json:"state,omitempty" db:"state"`
|
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"`
|
|
|
|
Machine *MachineUser `json:"machine,omitempty" db:"-"`
|
|
Human *HumanUser `json:"human,omitempty" db:"-"`
|
|
Metadata []*Metadata `json:"metadata,omitempty" db:"metadata"`
|
|
}
|
|
|
|
type LoginName struct {
|
|
LoginName string `json:"loginName,omitempty" db:"-"`
|
|
IsPreferred bool `json:"isPreferred,omitempty" db:"-"`
|
|
}
|
|
|
|
type MachineUser struct {
|
|
Name string `json:"name,omitempty" db:"-"`
|
|
Description string `json:"description,omitempty" db:"-"`
|
|
Secret string `json:"secret,omitempty" db:"-"`
|
|
AccessTokenType AccessTokenType `json:"accessTokenType,omitempty" db:"-"`
|
|
|
|
PATs []*PersonalAccessToken `json:"pats,omitempty" db:"-"`
|
|
Keys []*MachineKey `json:"keys,omitempty" db:"-"`
|
|
}
|
|
|
|
type HumanUser struct {
|
|
FirstName string `json:"firstName,omitempty" db:"-"`
|
|
LastName string `json:"lastName,omitempty" db:"-"`
|
|
Nickname string `json:"nickname,omitempty" db:"-"`
|
|
DisplayName string `json:"displayName,omitempty" db:"-"`
|
|
PreferredLanguage language.Tag `json:"preferredLanguage,omitzero" db:"-"`
|
|
Gender HumanGender `json:"gender,omitempty" db:"-"`
|
|
AvatarKey string `json:"avatarKey,omitempty" db:"-"`
|
|
|
|
MultifactorInitializationSkippedAt time.Time `json:"multifactorInitializationSkippedAt,omitzero" db:"-"`
|
|
|
|
Email HumanEmail `json:"email,omitzero" db:"-"`
|
|
Phone *HumanPhone `json:"phone,omitempty" db:"-"`
|
|
Passkeys []*Passkey `json:"passkeys,omitempty" db:"-"`
|
|
Password HumanPassword `json:"password,omitzero" db:"-"`
|
|
TOTP *HumanTOTP `json:"totp,omitempty" db:"-"`
|
|
RecoveryCodes *HumanRecoveryCodes `json:"recoveryCodes,omitempty" db:"-"`
|
|
|
|
IdentityProviderLinks []*IdentityProviderLink `json:"identityProviderLinks,omitempty" db:"-"`
|
|
|
|
Invite *HumanInvite `json:"invite,omitempty" db:"-"`
|
|
|
|
// Verifications are used if the Login does something on behalf of the user that requires verification
|
|
// e.g. starting passkey registration
|
|
Verifications []*Verification `json:"verifications,omitempty" db:"-"`
|
|
}
|
|
|
|
type UserMetadata struct {
|
|
Metadata
|
|
UserID string `json:"userId,omitempty" db:"-"`
|
|
}
|
|
|
|
//go:generate enumer -type UserState -transform lower -trimprefix UserState -sql
|
|
|
|
type UserState uint8
|
|
|
|
const (
|
|
UserStateUnspecified UserState = iota
|
|
UserStateActive
|
|
UserStateInactive
|
|
UserStateLocked
|
|
UserStateInitial
|
|
)
|
|
|
|
//go:generate enumer -type HumanGender -transform lower -trimprefix HumanGender
|
|
|
|
type HumanGender uint8
|
|
|
|
const (
|
|
HumanGenderUnspecified HumanGender = iota
|
|
HumanGenderFemale
|
|
HumanGenderMale
|
|
HumanGenderDiverse
|
|
)
|
|
|
|
type HumanPassword struct {
|
|
// Hash is the hashed password
|
|
Hash string `json:"hash" db:"-"`
|
|
// IsChangeRequired indicates if the user must change their password
|
|
IsChangeRequired bool `json:"isChangeRequired,omitempty" db:"-"`
|
|
// ChangedAt is the time when the current password was last updated
|
|
ChangedAt time.Time `json:"changedAt,omitzero" db:"-"`
|
|
// PendingVerification is the verification data for setting a new password
|
|
// If nil, no password change is in progress
|
|
PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
|
|
// LastSuccessfullyCheckedAt is the time when the password was last successfully checked
|
|
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
|
|
// FailedAttempts is the number of consecutive failed password attempts
|
|
// It is reset to 0 on successful verification
|
|
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
|
|
}
|
|
|
|
type HumanEmail struct {
|
|
Address string `json:"address" db:"-"`
|
|
UnverifiedAddress string `json:"unverifiedAddress,omitempty" db:"-"`
|
|
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
|
|
OTP OTP `json:"otp" db:"-"`
|
|
// PendingVerification is the verification data for UnverifiedAddress
|
|
// If nil, no email change is in progress
|
|
PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
|
|
}
|
|
|
|
type HumanPhone struct {
|
|
Number string `json:"number" db:"-"`
|
|
UnverifiedNumber string `json:"unverifiedNumber,omitempty" db:"-"`
|
|
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
|
|
OTP OTP `json:"otp,omitzero" db:"-"`
|
|
// PendingVerification is the verification data for setting a new phone number
|
|
// If nil, no phone change is in progress
|
|
PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
|
|
}
|
|
|
|
type HumanTOTP struct {
|
|
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
|
|
Secret *crypto.CryptoValue `json:"secret,omitempty" db:"-"`
|
|
// LastSuccessfullyCheckedAt is the time when the TOTP was last successfully checked
|
|
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
|
|
|
|
// FailedAttempts is the number of consecutive failed password attempts
|
|
// It is reset to 0 on successful verification
|
|
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
|
|
}
|
|
|
|
type OTP struct {
|
|
EnabledAt time.Time `json:"enabledAt,omitzero" db:"-"`
|
|
// LastSuccessfullyCheckedAt is the time when the OTP was last successfully checked
|
|
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
|
|
// FailedAttempts is the number of consecutive failed password attempts
|
|
// It is reset to 0 on successful verification
|
|
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
|
|
}
|
|
|
|
type PersonalAccessToken struct {
|
|
ID string `json:"id" db:"-"`
|
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
|
|
ExpiresAt time.Time `json:"expiresAt,omitzero" db:"-"`
|
|
Scopes []string `json:"scopes" db:"-"`
|
|
}
|
|
|
|
//go:generate enumer -type AccessTokenType -transform lower -trimprefix AccessTokenType
|
|
type AccessTokenType uint8
|
|
|
|
const (
|
|
AccessTokenTypeUnspecified AccessTokenType = iota
|
|
AccessTokenTypeBearer
|
|
AccessTokenTypeJWT
|
|
)
|
|
|
|
type MachineKey struct {
|
|
ID string `json:"id" db:"-"`
|
|
PublicKey []byte `json:"publicKey" db:"-"`
|
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
|
|
ExpiresAt time.Time `json:"expiresAt,omitzero" db:"-"`
|
|
Type MachineKeyType `json:"type" db:"-"`
|
|
}
|
|
|
|
//go:generate enumer -type MachineKeyType -transform lower -trimprefix MachineKeyType
|
|
|
|
type MachineKeyType uint8
|
|
|
|
const (
|
|
MachineKeyTypeNone MachineKeyType = iota
|
|
MachineKeyTypeJSON
|
|
)
|
|
|
|
type Passkey struct {
|
|
ID string `json:"id" db:"-"`
|
|
KeyID []byte `json:"keyId" db:"-"`
|
|
Name string `json:"name" db:"-"`
|
|
SignCount uint32 `json:"signCount" db:"-"`
|
|
PublicKey []byte `json:"publicKey" db:"-"`
|
|
AttestationType string `json:"attestationType" db:"-"`
|
|
AuthenticatorAttestationGUID []byte `json:"aaGuid" db:"-"`
|
|
Type PasskeyType `json:"type" db:"-"`
|
|
|
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
|
|
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"-"`
|
|
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
|
|
|
|
// Challenge is used during device registration
|
|
Challenge []byte `json:"challenge" db:"-"`
|
|
// RelyingPartyID is used during device registration
|
|
RelyingPartyID string `json:"rpId" db:"-"`
|
|
|
|
// Initialization is used during user registration
|
|
Initialization *Verification `json:"-" db:"-"`
|
|
}
|
|
|
|
//go:generate enumer -type PasskeyType -transform lower -trimprefix PasskeyType -json -sql
|
|
type PasskeyType uint8
|
|
|
|
const (
|
|
PasskeyTypeUnspecified PasskeyType = iota
|
|
PasskeyTypePasswordless
|
|
PasskeyTypeU2F
|
|
)
|
|
|
|
type IdentityProviderLink struct {
|
|
ProviderID string `json:"providerId" db:"-"`
|
|
ProvidedUserID string `json:"providedUserId" db:"-"`
|
|
ProvidedUsername string `json:"providedUsername" db:"-"`
|
|
|
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
|
|
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"-"`
|
|
}
|
|
|
|
//go:generate enumer -type UserType -transform lower -trimprefix UserType
|
|
|
|
type UserType uint8
|
|
|
|
const (
|
|
UserTypeUnspecified UserType = iota
|
|
UserTypeHuman
|
|
UserTypeMachine
|
|
)
|
|
|
|
type HumanInvite struct {
|
|
AcceptedAt time.Time `json:"acceptedAt,omitzero" db:"-"`
|
|
// PendingVerification is the verification data for UnverifiedAddress
|
|
// If nil, no email change is in progress
|
|
PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
|
|
// FailedAttempts is the number of consecutive failed invite attempts
|
|
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
|
|
}
|
|
|
|
type HumanRecoveryCodes struct {
|
|
// Codes are the hashed recovery codes for the user
|
|
Codes []string `json:"codes" db:"-"`
|
|
// LastSuccessfullyCheckedAt is the time when a recovery code was last successfully checked
|
|
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
|
|
// FailedAttempts is the number of consecutive failed recovery code attempts
|
|
// It is reset to 0 on successful verification
|
|
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
|
|
}
|