| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- package sts
- import (
- "fmt"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- "github.com/seaweedfs/seaweedfs/weed/iam/oidc"
- "github.com/seaweedfs/seaweedfs/weed/iam/providers"
- )
- // ProviderFactory creates identity providers from configuration
- type ProviderFactory struct{}
- // NewProviderFactory creates a new provider factory
- func NewProviderFactory() *ProviderFactory {
- return &ProviderFactory{}
- }
- // CreateProvider creates an identity provider from configuration
- func (f *ProviderFactory) CreateProvider(config *ProviderConfig) (providers.IdentityProvider, error) {
- if config == nil {
- return nil, fmt.Errorf(ErrConfigCannotBeNil)
- }
- if config.Name == "" {
- return nil, fmt.Errorf(ErrProviderNameEmpty)
- }
- if config.Type == "" {
- return nil, fmt.Errorf(ErrProviderTypeEmpty)
- }
- if !config.Enabled {
- glog.V(2).Infof("Provider %s is disabled, skipping", config.Name)
- return nil, nil
- }
- glog.V(2).Infof("Creating provider: name=%s, type=%s", config.Name, config.Type)
- switch config.Type {
- case ProviderTypeOIDC:
- return f.createOIDCProvider(config)
- case ProviderTypeLDAP:
- return f.createLDAPProvider(config)
- case ProviderTypeSAML:
- return f.createSAMLProvider(config)
- default:
- return nil, fmt.Errorf(ErrUnsupportedProviderType, config.Type)
- }
- }
- // createOIDCProvider creates an OIDC provider from configuration
- func (f *ProviderFactory) createOIDCProvider(config *ProviderConfig) (providers.IdentityProvider, error) {
- oidcConfig, err := f.convertToOIDCConfig(config.Config)
- if err != nil {
- return nil, fmt.Errorf("failed to convert OIDC config: %w", err)
- }
- provider := oidc.NewOIDCProvider(config.Name)
- if err := provider.Initialize(oidcConfig); err != nil {
- return nil, fmt.Errorf("failed to initialize OIDC provider: %w", err)
- }
- return provider, nil
- }
- // createLDAPProvider creates an LDAP provider from configuration
- func (f *ProviderFactory) createLDAPProvider(config *ProviderConfig) (providers.IdentityProvider, error) {
- // TODO: Implement LDAP provider when available
- return nil, fmt.Errorf("LDAP provider not implemented yet")
- }
- // createSAMLProvider creates a SAML provider from configuration
- func (f *ProviderFactory) createSAMLProvider(config *ProviderConfig) (providers.IdentityProvider, error) {
- // TODO: Implement SAML provider when available
- return nil, fmt.Errorf("SAML provider not implemented yet")
- }
- // convertToOIDCConfig converts generic config map to OIDC config struct
- func (f *ProviderFactory) convertToOIDCConfig(configMap map[string]interface{}) (*oidc.OIDCConfig, error) {
- config := &oidc.OIDCConfig{}
- // Required fields
- if issuer, ok := configMap[ConfigFieldIssuer].(string); ok {
- config.Issuer = issuer
- } else {
- return nil, fmt.Errorf(ErrIssuerRequired)
- }
- if clientID, ok := configMap[ConfigFieldClientID].(string); ok {
- config.ClientID = clientID
- } else {
- return nil, fmt.Errorf(ErrClientIDRequired)
- }
- // Optional fields
- if clientSecret, ok := configMap[ConfigFieldClientSecret].(string); ok {
- config.ClientSecret = clientSecret
- }
- if jwksUri, ok := configMap[ConfigFieldJWKSUri].(string); ok {
- config.JWKSUri = jwksUri
- }
- if userInfoUri, ok := configMap[ConfigFieldUserInfoUri].(string); ok {
- config.UserInfoUri = userInfoUri
- }
- // Convert scopes array
- if scopesInterface, ok := configMap[ConfigFieldScopes]; ok {
- scopes, err := f.convertToStringSlice(scopesInterface)
- if err != nil {
- return nil, fmt.Errorf("failed to convert scopes: %w", err)
- }
- config.Scopes = scopes
- }
- // Convert claims mapping
- if claimsMapInterface, ok := configMap["claimsMapping"]; ok {
- claimsMap, err := f.convertToStringMap(claimsMapInterface)
- if err != nil {
- return nil, fmt.Errorf("failed to convert claimsMapping: %w", err)
- }
- config.ClaimsMapping = claimsMap
- }
- // Convert role mapping
- if roleMappingInterface, ok := configMap["roleMapping"]; ok {
- roleMapping, err := f.convertToRoleMapping(roleMappingInterface)
- if err != nil {
- return nil, fmt.Errorf("failed to convert roleMapping: %w", err)
- }
- config.RoleMapping = roleMapping
- }
- glog.V(3).Infof("Converted OIDC config: issuer=%s, clientId=%s, jwksUri=%s",
- config.Issuer, config.ClientID, config.JWKSUri)
- return config, nil
- }
- // convertToStringSlice converts interface{} to []string
- func (f *ProviderFactory) convertToStringSlice(value interface{}) ([]string, error) {
- switch v := value.(type) {
- case []string:
- return v, nil
- case []interface{}:
- result := make([]string, len(v))
- for i, item := range v {
- if str, ok := item.(string); ok {
- result[i] = str
- } else {
- return nil, fmt.Errorf("non-string item in slice: %v", item)
- }
- }
- return result, nil
- default:
- return nil, fmt.Errorf("cannot convert %T to []string", value)
- }
- }
- // convertToStringMap converts interface{} to map[string]string
- func (f *ProviderFactory) convertToStringMap(value interface{}) (map[string]string, error) {
- switch v := value.(type) {
- case map[string]string:
- return v, nil
- case map[string]interface{}:
- result := make(map[string]string)
- for key, val := range v {
- if str, ok := val.(string); ok {
- result[key] = str
- } else {
- return nil, fmt.Errorf("non-string value for key %s: %v", key, val)
- }
- }
- return result, nil
- default:
- return nil, fmt.Errorf("cannot convert %T to map[string]string", value)
- }
- }
- // LoadProvidersFromConfig creates providers from configuration
- func (f *ProviderFactory) LoadProvidersFromConfig(configs []*ProviderConfig) (map[string]providers.IdentityProvider, error) {
- providersMap := make(map[string]providers.IdentityProvider)
- for _, config := range configs {
- if config == nil {
- glog.V(1).Infof("Skipping nil provider config")
- continue
- }
- glog.V(2).Infof("Loading provider: %s (type: %s, enabled: %t)",
- config.Name, config.Type, config.Enabled)
- if !config.Enabled {
- glog.V(2).Infof("Provider %s is disabled, skipping", config.Name)
- continue
- }
- provider, err := f.CreateProvider(config)
- if err != nil {
- glog.Errorf("Failed to create provider %s: %v", config.Name, err)
- return nil, fmt.Errorf("failed to create provider %s: %w", config.Name, err)
- }
- if provider != nil {
- providersMap[config.Name] = provider
- glog.V(1).Infof("Successfully loaded provider: %s", config.Name)
- }
- }
- glog.V(1).Infof("Loaded %d identity providers from configuration", len(providersMap))
- return providersMap, nil
- }
- // convertToRoleMapping converts interface{} to *providers.RoleMapping
- func (f *ProviderFactory) convertToRoleMapping(value interface{}) (*providers.RoleMapping, error) {
- roleMappingMap, ok := value.(map[string]interface{})
- if !ok {
- return nil, fmt.Errorf("roleMapping must be an object")
- }
- roleMapping := &providers.RoleMapping{}
- // Convert rules
- if rulesInterface, ok := roleMappingMap["rules"]; ok {
- rulesSlice, ok := rulesInterface.([]interface{})
- if !ok {
- return nil, fmt.Errorf("rules must be an array")
- }
- rules := make([]providers.MappingRule, len(rulesSlice))
- for i, ruleInterface := range rulesSlice {
- ruleMap, ok := ruleInterface.(map[string]interface{})
- if !ok {
- return nil, fmt.Errorf("rule must be an object")
- }
- rule := providers.MappingRule{}
- if claim, ok := ruleMap["claim"].(string); ok {
- rule.Claim = claim
- }
- if value, ok := ruleMap["value"].(string); ok {
- rule.Value = value
- }
- if role, ok := ruleMap["role"].(string); ok {
- rule.Role = role
- }
- if condition, ok := ruleMap["condition"].(string); ok {
- rule.Condition = condition
- }
- rules[i] = rule
- }
- roleMapping.Rules = rules
- }
- // Convert default role
- if defaultRole, ok := roleMappingMap["defaultRole"].(string); ok {
- roleMapping.DefaultRole = defaultRole
- }
- return roleMapping, nil
- }
- // ValidateProviderConfig validates a provider configuration
- func (f *ProviderFactory) ValidateProviderConfig(config *ProviderConfig) error {
- if config == nil {
- return fmt.Errorf("provider config cannot be nil")
- }
- if config.Name == "" {
- return fmt.Errorf("provider name cannot be empty")
- }
- if config.Type == "" {
- return fmt.Errorf("provider type cannot be empty")
- }
- if config.Config == nil {
- return fmt.Errorf("provider config cannot be nil")
- }
- // Type-specific validation
- switch config.Type {
- case "oidc":
- return f.validateOIDCConfig(config.Config)
- case "ldap":
- return f.validateLDAPConfig(config.Config)
- case "saml":
- return f.validateSAMLConfig(config.Config)
- default:
- return fmt.Errorf("unsupported provider type: %s", config.Type)
- }
- }
- // validateOIDCConfig validates OIDC provider configuration
- func (f *ProviderFactory) validateOIDCConfig(config map[string]interface{}) error {
- if _, ok := config[ConfigFieldIssuer]; !ok {
- return fmt.Errorf("OIDC provider requires '%s' field", ConfigFieldIssuer)
- }
- if _, ok := config[ConfigFieldClientID]; !ok {
- return fmt.Errorf("OIDC provider requires '%s' field", ConfigFieldClientID)
- }
- return nil
- }
- // validateLDAPConfig validates LDAP provider configuration
- func (f *ProviderFactory) validateLDAPConfig(config map[string]interface{}) error {
- // TODO: Implement when LDAP provider is available
- return nil
- }
- // validateSAMLConfig validates SAML provider configuration
- func (f *ProviderFactory) validateSAMLConfig(config map[string]interface{}) error {
- // TODO: Implement when SAML provider is available
- return nil
- }
- // GetSupportedProviderTypes returns list of supported provider types
- func (f *ProviderFactory) GetSupportedProviderTypes() []string {
- return []string{ProviderTypeOIDC}
- }
|