1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/handler/tenant_assignment_policy.go

159 lines
3.9 KiB
Go

package handler
import (
"baron-sso-backend/internal/domain"
"baron-sso-backend/internal/service"
"context"
"errors"
"fmt"
"strings"
"github.com/google/uuid"
)
func representativeTenantIDFromTraits(traits map[string]any) string {
if value := tenantClaimString(traits, "tenant_id"); value != "" {
return value
}
if value := tenantClaimString(traits, "primaryTenantId"); value != "" {
return value
}
if metadata, ok := traits["metadata"].(map[string]any); ok {
if value := tenantClaimString(metadata, "primaryTenantId"); value != "" {
return value
}
}
appointments := tenantAssignmentAppointmentsFromTraits(traits)
for _, appointment := range appointments {
if tenantAssignmentBool(appointment, "isPrimary", "primary", "representative", "isRepresentative") {
if value := tenantAssignmentTenantID(appointment); value != "" {
return value
}
}
}
for _, appointment := range appointments {
if value := tenantAssignmentTenantID(appointment); value != "" {
return value
}
}
for _, tenantID := range tenantNamespaceIDsFromTraits(traits) {
return tenantID
}
return ""
}
func joinedTenantIDsFromTraits(traits map[string]any, representativeTenantID string) []string {
values := make([]string, 0)
if representativeTenantID != "" {
values = append(values, representativeTenantID)
}
if value := tenantClaimString(traits, "tenant_id"); value != "" {
values = append(values, value)
}
for _, appointment := range tenantAssignmentAppointmentsFromTraits(traits) {
if value := tenantAssignmentTenantID(appointment); value != "" {
values = append(values, value)
}
}
values = append(values, tenantNamespaceIDsFromTraits(traits)...)
return uniqueSortedStrings(values)
}
func tenantAssignmentAppointmentsFromTraits(traits map[string]any) []map[string]any {
raw := rawAdditionalAppointments(traits)
switch values := raw.(type) {
case []any:
appointments := make([]map[string]any, 0, len(values))
for _, item := range values {
if appointment, ok := item.(map[string]any); ok {
appointments = append(appointments, appointment)
}
}
return appointments
case []map[string]any:
return values
default:
return nil
}
}
func tenantAssignmentTenantID(appointment map[string]any) string {
for _, key := range []string{"tenantId", "tenant_id"} {
if value := tenantClaimString(appointment, key); value != "" {
return value
}
}
return ""
}
func tenantAssignmentBool(values map[string]any, keys ...string) bool {
for _, key := range keys {
raw, ok := values[key]
if !ok || raw == nil {
continue
}
switch value := raw.(type) {
case bool:
if value {
return true
}
case string:
normalized := strings.ToLower(strings.TrimSpace(value))
if normalized == "true" || normalized == "1" || normalized == "yes" {
return true
}
}
}
return false
}
func tenantNamespaceIDsFromTraits(traits map[string]any) []string {
if traits == nil {
return nil
}
ids := make([]string, 0)
for key, value := range traits {
if key == "" || isReservedTenantTraitKey(key) {
continue
}
switch value.(type) {
case map[string]any:
ids = append(ids, key)
}
}
return uniqueSortedStrings(ids)
}
func createPersonalTenantForUser(ctx context.Context, tenantService service.TenantService, email string) (*domain.Tenant, error) {
if tenantService == nil {
return nil, errors.New("tenant service unavailable")
}
normalizedEmail := strings.ToLower(strings.TrimSpace(email))
if normalizedEmail == "" {
normalizedEmail = "user"
}
slug := "personal-" + strings.ReplaceAll(uuid.NewString(), "-", "")
if len(slug) > 32 {
slug = slug[:32]
}
tenant, err := tenantService.RegisterTenant(
ctx,
fmt.Sprintf("Personal - %s", normalizedEmail),
slug,
domain.TenantTypePersonal,
"Automatically provisioned personal tenant",
nil,
nil,
"",
)
if err != nil {
return nil, err
}
if tenant == nil {
return nil, errors.New("personal tenant not created")
}
return tenant, nil
}