org
This commit is contained in:
57
kms/internal/domain/duration.go
Normal file
57
kms/internal/domain/duration.go
Normal file
@ -0,0 +1,57 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is a wrapper around time.Duration that can unmarshal from both
|
||||
// string duration formats (like "168h") and nanosecond integers
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler interface
|
||||
func (d *Duration) UnmarshalJSON(data []byte) error {
|
||||
// Try to unmarshal as string first (e.g., "168h", "24h", "30m")
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
duration, err := time.ParseDuration(str)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration format: %s", str)
|
||||
}
|
||||
d.Duration = duration
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try to unmarshal as integer (nanoseconds)
|
||||
var ns int64
|
||||
if err := json.Unmarshal(data, &ns); err == nil {
|
||||
d.Duration = time.Duration(ns)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("duration must be either a string (e.g., '168h') or integer nanoseconds")
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler interface
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
// Always marshal as nanoseconds for consistency
|
||||
return json.Marshal(int64(d.Duration))
|
||||
}
|
||||
|
||||
// String returns the string representation of the duration
|
||||
func (d Duration) String() string {
|
||||
return d.Duration.String()
|
||||
}
|
||||
|
||||
// Int64 returns the duration in nanoseconds for validator compatibility
|
||||
func (d Duration) Int64() int64 {
|
||||
return int64(d.Duration)
|
||||
}
|
||||
|
||||
// IsZero returns true if the duration is zero
|
||||
func (d Duration) IsZero() bool {
|
||||
return d.Duration == 0
|
||||
}
|
||||
240
kms/internal/domain/models.go
Normal file
240
kms/internal/domain/models.go
Normal file
@ -0,0 +1,240 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// ApplicationType represents the type of application
|
||||
type ApplicationType string
|
||||
|
||||
const (
|
||||
ApplicationTypeStatic ApplicationType = "static"
|
||||
ApplicationTypeUser ApplicationType = "user"
|
||||
)
|
||||
|
||||
// OwnerType represents the type of owner
|
||||
type OwnerType string
|
||||
|
||||
const (
|
||||
OwnerTypeIndividual OwnerType = "individual"
|
||||
OwnerTypeTeam OwnerType = "team"
|
||||
)
|
||||
|
||||
// TokenType represents the type of token
|
||||
type TokenType string
|
||||
|
||||
const (
|
||||
TokenTypeStatic TokenType = "static"
|
||||
TokenTypeUser TokenType = "user"
|
||||
)
|
||||
|
||||
// Owner represents ownership information
|
||||
type Owner struct {
|
||||
Type OwnerType `json:"type" validate:"required,oneof=individual team"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Owner string `json:"owner" validate:"required,min=1,max=255"`
|
||||
}
|
||||
|
||||
// Application represents an application in the system
|
||||
type Application struct {
|
||||
AppID string `json:"app_id" validate:"required,min=1,max=255" db:"app_id"`
|
||||
AppLink string `json:"app_link" validate:"required,url,max=500" db:"app_link"`
|
||||
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user" db:"type"`
|
||||
CallbackURL string `json:"callback_url" validate:"required,url,max=500" db:"callback_url"`
|
||||
HMACKey string `json:"hmac_key" validate:"required,min=1,max=255" db:"hmac_key"`
|
||||
TokenPrefix string `json:"token_prefix" validate:"omitempty,min=2,max=4,uppercase" db:"token_prefix"`
|
||||
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required,min=1" db:"token_renewal_duration"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration" validate:"required,min=1" db:"max_token_duration"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// StaticToken represents a static API token
|
||||
type StaticToken struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
AppID string `json:"app_id" validate:"required" db:"app_id"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
KeyHash string `json:"-" validate:"required" db:"key_hash"` // Hidden from JSON
|
||||
Type string `json:"type" validate:"required,eq=hmac" db:"type"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// AvailablePermission represents a permission in the global catalog
|
||||
type AvailablePermission struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
Scope string `json:"scope" validate:"required,min=1,max=255" db:"scope"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255" db:"name"`
|
||||
Description string `json:"description" validate:"required" db:"description"`
|
||||
Category string `json:"category" validate:"required,min=1,max=100" db:"category"`
|
||||
ParentScope *string `json:"parent_scope,omitempty" db:"parent_scope"`
|
||||
IsSystem bool `json:"is_system" db:"is_system"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
CreatedBy string `json:"created_by" validate:"required" db:"created_by"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
UpdatedBy string `json:"updated_by" validate:"required" db:"updated_by"`
|
||||
}
|
||||
|
||||
// GrantedPermission represents a permission granted to a token
|
||||
type GrantedPermission struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
TokenType TokenType `json:"token_type" validate:"required,eq=static" db:"token_type"`
|
||||
TokenID uuid.UUID `json:"token_id" validate:"required" db:"token_id"`
|
||||
PermissionID uuid.UUID `json:"permission_id" validate:"required" db:"permission_id"`
|
||||
Scope string `json:"scope" validate:"required" db:"scope"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
CreatedBy string `json:"created_by" validate:"required" db:"created_by"`
|
||||
Revoked bool `json:"revoked" db:"revoked"`
|
||||
}
|
||||
|
||||
// UserToken represents a user token (JWT-based)
|
||||
type UserToken struct {
|
||||
AppID string `json:"app_id"`
|
||||
UserID string `json:"user_id"`
|
||||
Permissions []string `json:"permissions"`
|
||||
IssuedAt time.Time `json:"iat"`
|
||||
ExpiresAt time.Time `json:"exp"`
|
||||
MaxValidAt time.Time `json:"max_valid_at"`
|
||||
TokenType TokenType `json:"token_type"`
|
||||
Claims map[string]string `json:"claims,omitempty"`
|
||||
}
|
||||
|
||||
// VerifyRequest represents a token verification request
|
||||
type VerifyRequest struct {
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
UserID string `json:"user_id,omitempty"` // Required for user tokens
|
||||
Token string `json:"token" validate:"required"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// VerifyResponse represents a token verification response
|
||||
type VerifyResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
Permitted bool `json:"permitted"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
Permissions []string `json:"permissions"`
|
||||
PermissionResults map[string]bool `json:"permission_results,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
MaxValidAt *time.Time `json:"max_valid_at,omitempty"`
|
||||
TokenType TokenType `json:"token_type"`
|
||||
Claims map[string]string `json:"claims,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// LoginRequest represents a user login request
|
||||
type LoginRequest struct {
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
RedirectURI string `json:"redirect_uri,omitempty"`
|
||||
}
|
||||
|
||||
// LoginResponse represents a user login response
|
||||
type LoginResponse struct {
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
State string `json:"state,omitempty"`
|
||||
}
|
||||
|
||||
// RenewRequest represents a token renewal request
|
||||
type RenewRequest struct {
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
UserID string `json:"user_id" validate:"required"`
|
||||
Token string `json:"token" validate:"required"`
|
||||
}
|
||||
|
||||
// RenewResponse represents a token renewal response
|
||||
type RenewResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
MaxValidAt time.Time `json:"max_valid_at"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CreateApplicationRequest represents a request to create a new application
|
||||
type CreateApplicationRequest struct {
|
||||
AppID string `json:"app_id" validate:"required,min=1,max=255"`
|
||||
AppLink string `json:"app_link" validate:"required,url,max=500"`
|
||||
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user"`
|
||||
CallbackURL string `json:"callback_url" validate:"required,url,max=500"`
|
||||
TokenPrefix string `json:"token_prefix" validate:"omitempty,min=2,max=4,uppercase"`
|
||||
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration" validate:"required"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
}
|
||||
|
||||
// UpdateApplicationRequest represents a request to update an existing application
|
||||
type UpdateApplicationRequest struct {
|
||||
AppLink *string `json:"app_link,omitempty" validate:"omitempty,url,max=500"`
|
||||
Type *[]ApplicationType `json:"type,omitempty" validate:"omitempty,min=1,dive,oneof=static user"`
|
||||
CallbackURL *string `json:"callback_url,omitempty" validate:"omitempty,url,max=500"`
|
||||
HMACKey *string `json:"hmac_key,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
TokenPrefix *string `json:"token_prefix,omitempty" validate:"omitempty,min=2,max=4,uppercase"`
|
||||
TokenRenewalDuration *Duration `json:"token_renewal_duration,omitempty"`
|
||||
MaxTokenDuration *Duration `json:"max_token_duration,omitempty"`
|
||||
Owner *Owner `json:"owner,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
// CreateStaticTokenRequest represents a request to create a static token
|
||||
type CreateStaticTokenRequest struct {
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
Permissions []string `json:"permissions" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
// CreateStaticTokenResponse represents a response for creating a static token
|
||||
type CreateStaticTokenResponse struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Token string `json:"token"` // Only returned once during creation
|
||||
Permissions []string `json:"permissions"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// CreateTokenRequest represents a request to create a token
|
||||
type CreateTokenRequest struct {
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
Type TokenType `json:"type" validate:"required,oneof=static user"`
|
||||
UserID string `json:"user_id,omitempty"` // Required for user tokens
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// CreateTokenResponse represents a response for creating a token
|
||||
type CreateTokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
TokenType TokenType `json:"token_type"`
|
||||
}
|
||||
|
||||
// AuthContext represents the authentication context for a request
|
||||
type AuthContext struct {
|
||||
UserID string `json:"user_id"`
|
||||
TokenType TokenType `json:"token_type"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Claims map[string]string `json:"claims"`
|
||||
AppID string `json:"app_id"`
|
||||
}
|
||||
|
||||
// TokenResponse represents the OAuth2 token response
|
||||
type TokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
IDToken string `json:"id_token,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// UserInfo represents user information from the OAuth2/OIDC provider
|
||||
type UserInfo struct {
|
||||
Sub string `json:"sub"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
Name string `json:"name"`
|
||||
GivenName string `json:"given_name"`
|
||||
FamilyName string `json:"family_name"`
|
||||
Picture string `json:"picture"`
|
||||
PreferredUsername string `json:"preferred_username"`
|
||||
}
|
||||
153
kms/internal/domain/session.go
Normal file
153
kms/internal/domain/session.go
Normal file
@ -0,0 +1,153 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// SessionStatus represents the status of a user session
|
||||
type SessionStatus string
|
||||
|
||||
const (
|
||||
SessionStatusActive SessionStatus = "active"
|
||||
SessionStatusExpired SessionStatus = "expired"
|
||||
SessionStatusRevoked SessionStatus = "revoked"
|
||||
SessionStatusSuspended SessionStatus = "suspended"
|
||||
)
|
||||
|
||||
// SessionType represents the type of session
|
||||
type SessionType string
|
||||
|
||||
const (
|
||||
SessionTypeWeb SessionType = "web"
|
||||
SessionTypeMobile SessionType = "mobile"
|
||||
SessionTypeAPI SessionType = "api"
|
||||
)
|
||||
|
||||
// UserSession represents a user session in the system
|
||||
type UserSession struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID string `json:"user_id" validate:"required" db:"user_id"`
|
||||
AppID string `json:"app_id" validate:"required" db:"app_id"`
|
||||
SessionType SessionType `json:"session_type" validate:"required,oneof=web mobile api" db:"session_type"`
|
||||
Status SessionStatus `json:"status" validate:"required,oneof=active expired revoked suspended" db:"status"`
|
||||
AccessToken string `json:"-" db:"access_token"` // Hidden from JSON for security
|
||||
RefreshToken string `json:"-" db:"refresh_token"` // Hidden from JSON for security
|
||||
IDToken string `json:"-" db:"id_token"` // Hidden from JSON for security
|
||||
IPAddress string `json:"ip_address" db:"ip_address"`
|
||||
UserAgent string `json:"user_agent" db:"user_agent"`
|
||||
LastActivity time.Time `json:"last_activity" db:"last_activity"`
|
||||
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
RevokedAt *time.Time `json:"revoked_at,omitempty" db:"revoked_at"`
|
||||
RevokedBy *string `json:"revoked_by,omitempty" db:"revoked_by"`
|
||||
Metadata SessionMetadata `json:"metadata" db:"metadata"`
|
||||
}
|
||||
|
||||
// SessionMetadata contains additional session information
|
||||
type SessionMetadata struct {
|
||||
DeviceInfo string `json:"device_info,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
LoginMethod string `json:"login_method,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Claims map[string]string `json:"claims,omitempty"`
|
||||
RefreshCount int `json:"refresh_count"`
|
||||
LastRefresh *time.Time `json:"last_refresh,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSessionRequest represents a request to create a new session
|
||||
type CreateSessionRequest struct {
|
||||
UserID string `json:"user_id" validate:"required"`
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
SessionType SessionType `json:"session_type" validate:"required,oneof=web mobile api"`
|
||||
IPAddress string `json:"ip_address" validate:"required,ip"`
|
||||
UserAgent string `json:"user_agent" validate:"required"`
|
||||
ExpiresAt time.Time `json:"expires_at" validate:"required"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Claims map[string]string `json:"claims,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateSessionRequest represents a request to update a session
|
||||
type UpdateSessionRequest struct {
|
||||
Status *SessionStatus `json:"status,omitempty" validate:"omitempty,oneof=active expired revoked suspended"`
|
||||
LastActivity *time.Time `json:"last_activity,omitempty"`
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
IPAddress *string `json:"ip_address,omitempty" validate:"omitempty,ip"`
|
||||
UserAgent *string `json:"user_agent,omitempty"`
|
||||
}
|
||||
|
||||
// SessionListRequest represents a request to list sessions
|
||||
type SessionListRequest struct {
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
AppID string `json:"app_id,omitempty"`
|
||||
Status *SessionStatus `json:"status,omitempty"`
|
||||
SessionType *SessionType `json:"session_type,omitempty"`
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Offset int `json:"offset" validate:"min=0"`
|
||||
}
|
||||
|
||||
// SessionListResponse represents a response for listing sessions
|
||||
type SessionListResponse struct {
|
||||
Sessions []*UserSession `json:"sessions"`
|
||||
Total int `json:"total"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
// IsActive checks if the session is currently active
|
||||
func (s *UserSession) IsActive() bool {
|
||||
return s.Status == SessionStatusActive && time.Now().Before(s.ExpiresAt)
|
||||
}
|
||||
|
||||
// IsExpired checks if the session has expired
|
||||
func (s *UserSession) IsExpired() bool {
|
||||
return time.Now().After(s.ExpiresAt) || s.Status == SessionStatusExpired
|
||||
}
|
||||
|
||||
// IsRevoked checks if the session has been revoked
|
||||
func (s *UserSession) IsRevoked() bool {
|
||||
return s.Status == SessionStatusRevoked
|
||||
}
|
||||
|
||||
// CanRefresh checks if the session can be refreshed
|
||||
func (s *UserSession) CanRefresh() bool {
|
||||
return s.IsActive() && s.RefreshToken != ""
|
||||
}
|
||||
|
||||
// UpdateActivity updates the last activity timestamp
|
||||
func (s *UserSession) UpdateActivity() {
|
||||
s.LastActivity = time.Now()
|
||||
s.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
// Revoke marks the session as revoked
|
||||
func (s *UserSession) Revoke(revokedBy string) {
|
||||
now := time.Now()
|
||||
s.Status = SessionStatusRevoked
|
||||
s.RevokedAt = &now
|
||||
s.RevokedBy = &revokedBy
|
||||
s.UpdatedAt = now
|
||||
}
|
||||
|
||||
// Expire marks the session as expired
|
||||
func (s *UserSession) Expire() {
|
||||
s.Status = SessionStatusExpired
|
||||
s.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
// Suspend marks the session as suspended
|
||||
func (s *UserSession) Suspend() {
|
||||
s.Status = SessionStatusSuspended
|
||||
s.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
// Activate marks the session as active
|
||||
func (s *UserSession) Activate() {
|
||||
s.Status = SessionStatusActive
|
||||
s.UpdatedAt = time.Now()
|
||||
}
|
||||
307
kms/internal/domain/tenant.go
Normal file
307
kms/internal/domain/tenant.go
Normal file
@ -0,0 +1,307 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// TenantStatus represents the status of a tenant
|
||||
type TenantStatus string
|
||||
|
||||
const (
|
||||
TenantStatusActive TenantStatus = "active"
|
||||
TenantStatusSuspended TenantStatus = "suspended"
|
||||
TenantStatusInactive TenantStatus = "inactive"
|
||||
)
|
||||
|
||||
// Tenant represents a tenant in the multi-tenant system
|
||||
type Tenant struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255" db:"name"`
|
||||
Slug string `json:"slug" validate:"required,min=1,max=100,alphanum" db:"slug"`
|
||||
Status TenantStatus `json:"status" validate:"required,oneof=active suspended inactive" db:"status"`
|
||||
Domain string `json:"domain,omitempty" validate:"omitempty,fqdn" db:"domain"`
|
||||
Description string `json:"description,omitempty" validate:"max=1000" db:"description"`
|
||||
Settings TenantSettings `json:"settings" db:"settings"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
CreatedBy string `json:"created_by" db:"created_by"`
|
||||
UpdatedBy string `json:"updated_by" db:"updated_by"`
|
||||
}
|
||||
|
||||
// TenantSettings contains tenant-specific configuration
|
||||
type TenantSettings struct {
|
||||
// Authentication settings
|
||||
AuthProvider string `json:"auth_provider,omitempty"` // oauth2, saml, header
|
||||
SAMLSettings *SAMLSettings `json:"saml_settings,omitempty"`
|
||||
OAuth2Settings *OAuth2Settings `json:"oauth2_settings,omitempty"`
|
||||
|
||||
// Session settings
|
||||
SessionTimeout Duration `json:"session_timeout,omitempty"`
|
||||
MaxConcurrentSessions int `json:"max_concurrent_sessions,omitempty"`
|
||||
|
||||
// Security settings
|
||||
RequireMFA bool `json:"require_mfa"`
|
||||
AllowedIPRanges []string `json:"allowed_ip_ranges,omitempty"`
|
||||
PasswordPolicy *PasswordPolicy `json:"password_policy,omitempty"`
|
||||
|
||||
// Token settings
|
||||
DefaultTokenDuration Duration `json:"default_token_duration,omitempty"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration,omitempty"`
|
||||
|
||||
// Feature flags
|
||||
Features map[string]bool `json:"features,omitempty"`
|
||||
|
||||
// Custom attributes
|
||||
CustomAttributes map[string]string `json:"custom_attributes,omitempty"`
|
||||
}
|
||||
|
||||
// SAMLSettings contains SAML-specific configuration for a tenant
|
||||
type SAMLSettings struct {
|
||||
IDPMetadataURL string `json:"idp_metadata_url,omitempty"`
|
||||
SPEntityID string `json:"sp_entity_id,omitempty"`
|
||||
ACSURL string `json:"acs_url,omitempty"`
|
||||
SPPrivateKey string `json:"sp_private_key,omitempty"`
|
||||
SPCertificate string `json:"sp_certificate,omitempty"`
|
||||
AttributeMapping map[string]string `json:"attribute_mapping,omitempty"`
|
||||
}
|
||||
|
||||
// OAuth2Settings contains OAuth2-specific configuration for a tenant
|
||||
type OAuth2Settings struct {
|
||||
ProviderURL string `json:"provider_url,omitempty"`
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
AttributeMapping map[string]string `json:"attribute_mapping,omitempty"`
|
||||
}
|
||||
|
||||
// PasswordPolicy defines password requirements for a tenant
|
||||
type PasswordPolicy struct {
|
||||
MinLength int `json:"min_length"`
|
||||
RequireUppercase bool `json:"require_uppercase"`
|
||||
RequireLowercase bool `json:"require_lowercase"`
|
||||
RequireNumbers bool `json:"require_numbers"`
|
||||
RequireSymbols bool `json:"require_symbols"`
|
||||
MaxAge Duration `json:"max_age,omitempty"`
|
||||
PreventReuse int `json:"prevent_reuse"` // Number of previous passwords to prevent reuse
|
||||
}
|
||||
|
||||
// TenantUser represents a user within a specific tenant
|
||||
type TenantUser struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
TenantID uuid.UUID `json:"tenant_id" validate:"required" db:"tenant_id"`
|
||||
UserID string `json:"user_id" validate:"required" db:"user_id"`
|
||||
Email string `json:"email" validate:"required,email" db:"email"`
|
||||
Name string `json:"name" validate:"required" db:"name"`
|
||||
Roles []string `json:"roles" db:"roles"`
|
||||
Permissions []string `json:"permissions" db:"permissions"`
|
||||
Status UserStatus `json:"status" validate:"required,oneof=active inactive suspended" db:"status"`
|
||||
Metadata map[string]string `json:"metadata,omitempty" db:"metadata"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty" db:"last_login_at"`
|
||||
}
|
||||
|
||||
// UserStatus represents the status of a user within a tenant
|
||||
type UserStatus string
|
||||
|
||||
const (
|
||||
UserStatusActive UserStatus = "active"
|
||||
UserStatusInactive UserStatus = "inactive"
|
||||
UserStatusSuspended UserStatus = "suspended"
|
||||
)
|
||||
|
||||
// TenantRole represents a role within a tenant
|
||||
type TenantRole struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
TenantID uuid.UUID `json:"tenant_id" validate:"required" db:"tenant_id"`
|
||||
Name string `json:"name" validate:"required,min=1,max=100" db:"name"`
|
||||
Description string `json:"description,omitempty" validate:"max=500" db:"description"`
|
||||
Permissions []string `json:"permissions" db:"permissions"`
|
||||
IsSystem bool `json:"is_system" db:"is_system"` // System roles cannot be deleted
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
CreatedBy string `json:"created_by" db:"created_by"`
|
||||
UpdatedBy string `json:"updated_by" db:"updated_by"`
|
||||
}
|
||||
|
||||
// CreateTenantRequest represents a request to create a new tenant
|
||||
type CreateTenantRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Slug string `json:"slug" validate:"required,min=1,max=100,alphanum"`
|
||||
Domain string `json:"domain,omitempty" validate:"omitempty,fqdn"`
|
||||
Description string `json:"description,omitempty" validate:"max=1000"`
|
||||
Settings TenantSettings `json:"settings,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateTenantRequest represents a request to update a tenant
|
||||
type UpdateTenantRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
Status *TenantStatus `json:"status,omitempty" validate:"omitempty,oneof=active suspended inactive"`
|
||||
Domain *string `json:"domain,omitempty" validate:"omitempty,fqdn"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
|
||||
Settings *TenantSettings `json:"settings,omitempty"`
|
||||
}
|
||||
|
||||
// CreateTenantUserRequest represents a request to create a user in a tenant
|
||||
type CreateTenantUserRequest struct {
|
||||
TenantID uuid.UUID `json:"tenant_id" validate:"required"`
|
||||
UserID string `json:"user_id" validate:"required"`
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateTenantUserRequest represents a request to update a tenant user
|
||||
type UpdateTenantUserRequest struct {
|
||||
Email *string `json:"email,omitempty" validate:"omitempty,email"`
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Status *UserStatus `json:"status,omitempty" validate:"omitempty,oneof=active inactive suspended"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// CreateTenantRoleRequest represents a request to create a role in a tenant
|
||||
type CreateTenantRoleRequest struct {
|
||||
TenantID uuid.UUID `json:"tenant_id" validate:"required"`
|
||||
Name string `json:"name" validate:"required,min=1,max=100"`
|
||||
Description string `json:"description,omitempty" validate:"max=500"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateTenantRoleRequest represents a request to update a tenant role
|
||||
type UpdateTenantRoleRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=100"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty,max=500"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// TenantListRequest represents a request to list tenants
|
||||
type TenantListRequest struct {
|
||||
Status *TenantStatus `json:"status,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
Limit int `json:"limit" validate:"min=1,max=100"`
|
||||
Offset int `json:"offset" validate:"min=0"`
|
||||
}
|
||||
|
||||
// TenantListResponse represents a response for listing tenants
|
||||
type TenantListResponse struct {
|
||||
Tenants []*Tenant `json:"tenants"`
|
||||
Total int `json:"total"`
|
||||
Limit int `json:"limit"`
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
// IsActive checks if the tenant is active
|
||||
func (t *Tenant) IsActive() bool {
|
||||
return t.Status == TenantStatusActive
|
||||
}
|
||||
|
||||
// IsSuspended checks if the tenant is suspended
|
||||
func (t *Tenant) IsSuspended() bool {
|
||||
return t.Status == TenantStatusSuspended
|
||||
}
|
||||
|
||||
// HasFeature checks if a feature is enabled for the tenant
|
||||
func (t *Tenant) HasFeature(feature string) bool {
|
||||
if t.Settings.Features == nil {
|
||||
return false
|
||||
}
|
||||
enabled, exists := t.Settings.Features[feature]
|
||||
return exists && enabled
|
||||
}
|
||||
|
||||
// GetAuthProvider returns the authentication provider for the tenant
|
||||
func (t *Tenant) GetAuthProvider() string {
|
||||
if t.Settings.AuthProvider != "" {
|
||||
return t.Settings.AuthProvider
|
||||
}
|
||||
return "header" // default
|
||||
}
|
||||
|
||||
// GetSessionTimeout returns the session timeout for the tenant
|
||||
func (t *Tenant) GetSessionTimeout() time.Duration {
|
||||
if t.Settings.SessionTimeout.Duration > 0 {
|
||||
return t.Settings.SessionTimeout.Duration
|
||||
}
|
||||
return 8 * time.Hour // default
|
||||
}
|
||||
|
||||
// GetMaxConcurrentSessions returns the maximum concurrent sessions for the tenant
|
||||
func (t *Tenant) GetMaxConcurrentSessions() int {
|
||||
if t.Settings.MaxConcurrentSessions > 0 {
|
||||
return t.Settings.MaxConcurrentSessions
|
||||
}
|
||||
return 10 // default
|
||||
}
|
||||
|
||||
// IsActive checks if the tenant user is active
|
||||
func (tu *TenantUser) IsActive() bool {
|
||||
return tu.Status == UserStatusActive
|
||||
}
|
||||
|
||||
// IsSuspended checks if the tenant user is suspended
|
||||
func (tu *TenantUser) IsSuspended() bool {
|
||||
return tu.Status == UserStatusSuspended
|
||||
}
|
||||
|
||||
// HasRole checks if the user has a specific role
|
||||
func (tu *TenantUser) HasRole(role string) bool {
|
||||
for _, r := range tu.Roles {
|
||||
if r == role {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasPermission checks if the user has a specific permission
|
||||
func (tu *TenantUser) HasPermission(permission string) bool {
|
||||
for _, p := range tu.Permissions {
|
||||
if p == permission {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UpdateLastLogin updates the last login timestamp
|
||||
func (tu *TenantUser) UpdateLastLogin() {
|
||||
now := time.Now()
|
||||
tu.LastLoginAt = &now
|
||||
tu.UpdatedAt = now
|
||||
}
|
||||
|
||||
// IsSystemRole checks if the role is a system role
|
||||
func (tr *TenantRole) IsSystemRole() bool {
|
||||
return tr.IsSystem
|
||||
}
|
||||
|
||||
// HasPermission checks if the role has a specific permission
|
||||
func (tr *TenantRole) HasPermission(permission string) bool {
|
||||
for _, p := range tr.Permissions {
|
||||
if p == permission {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TenantContext represents the tenant context for a request
|
||||
type TenantContext struct {
|
||||
TenantID uuid.UUID `json:"tenant_id"`
|
||||
TenantSlug string `json:"tenant_slug"`
|
||||
UserID string `json:"user_id"`
|
||||
Roles []string `json:"roles"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// MultiTenantAuthContext extends AuthContext with tenant information
|
||||
type MultiTenantAuthContext struct {
|
||||
*AuthContext
|
||||
TenantContext *TenantContext `json:"tenant_context,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user