package orgpolicy import ( "strings" "github.com/ultisuite/ulti-backend/internal/auth" ) type IdentityProviderPolicy struct { ID string Slug string Type string Enabled bool AllowedEmailDomains []string AllowedIdentities []string AllowedOrganizations []string } type AuthAccessPolicy struct { AllowSelfEnrollment bool Providers []IdentityProviderPolicy } func (p AuthAccessPolicy) AllowsIdentity(email string, claims *auth.Claims) bool { enabled := make([]IdentityProviderPolicy, 0) for _, provider := range p.Providers { if provider.Enabled { enabled = append(enabled, provider) } } if len(enabled) == 0 { return true } if claims != nil && strings.TrimSpace(claims.Source) != "" { for _, provider := range enabled { if provider.Slug == claims.Source && providerAllows(provider, email, claims) { return true } } } hasRestrictions := false for _, provider := range enabled { if providerHasRestrictions(provider) { hasRestrictions = true if providerAllows(provider, email, claims) { return true } } } if !hasRestrictions { return true } return false } func providerHasRestrictions(provider IdentityProviderPolicy) bool { return len(provider.AllowedEmailDomains) > 0 || len(provider.AllowedIdentities) > 0 || len(provider.AllowedOrganizations) > 0 } func providerAllows(provider IdentityProviderPolicy, email string, claims *auth.Claims) bool { if len(provider.AllowedIdentities) > 0 { if !containsFold(provider.AllowedIdentities, email) { return false } } if len(provider.AllowedEmailDomains) > 0 { if !emailDomainAllowed(email, provider.AllowedEmailDomains) { return false } } if len(provider.AllowedOrganizations) > 0 { if claims == nil || !organizationAllowed(claims, provider.AllowedOrganizations) { return false } } return true } func emailDomainAllowed(email string, domains []string) bool { email = strings.ToLower(strings.TrimSpace(email)) at := strings.LastIndex(email, "@") if at < 0 { return false } domain := email[at+1:] for _, allowed := range domains { allowed = strings.ToLower(strings.TrimSpace(strings.TrimPrefix(allowed, "@"))) if allowed == "" { continue } if domain == allowed || strings.HasSuffix(domain, "."+allowed) { return true } } return false } func organizationAllowed(claims *auth.Claims, orgs []string) bool { candidates := []string{ claims.HD, claims.TID, claims.Org, } for _, org := range orgs { org = strings.TrimSpace(org) if org == "" { continue } for _, candidate := range candidates { if strings.EqualFold(strings.TrimSpace(candidate), org) { return true } } } return false } func containsFold(list []string, value string) bool { value = strings.ToLower(strings.TrimSpace(value)) for _, item := range list { if strings.ToLower(strings.TrimSpace(item)) == value { return true } } return false } func stringSlice(v any) []string { raw, ok := v.([]any) if !ok { return nil } out := make([]string, 0, len(raw)) for _, item := range raw { if s, ok := item.(string); ok && strings.TrimSpace(s) != "" { out = append(out, strings.TrimSpace(s)) } } return out }