mirror of
				https://github.com/minio/minio.git
				synced 2025-10-26 22:01:30 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			620 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			620 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2015-2022 MinIO, Inc.
 | |
| //
 | |
| // This file is part of MinIO Object Storage stack
 | |
| //
 | |
| // This program is free software: you can redistribute it and/or modify
 | |
| // it under the terms of the GNU Affero General Public License as published by
 | |
| // the Free Software Foundation, either version 3 of the License, or
 | |
| // (at your option) any later version.
 | |
| //
 | |
| // This program is distributed in the hope that it will be useful
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| // GNU Affero General Public License for more details.
 | |
| //
 | |
| // You should have received a copy of the GNU Affero General Public License
 | |
| // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| package openid
 | |
| 
 | |
| import (
 | |
| 	"crypto/sha1"
 | |
| 	"encoding/base64"
 | |
| 	"errors"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/minio/madmin-go/v3"
 | |
| 	"github.com/minio/minio-go/v7/pkg/set"
 | |
| 	"github.com/minio/minio/internal/arn"
 | |
| 	"github.com/minio/minio/internal/auth"
 | |
| 	"github.com/minio/minio/internal/config"
 | |
| 	"github.com/minio/minio/internal/config/identity/openid/provider"
 | |
| 	"github.com/minio/minio/internal/hash/sha256"
 | |
| 	xnet "github.com/minio/pkg/v2/net"
 | |
| 	"github.com/minio/pkg/v2/policy"
 | |
| )
 | |
| 
 | |
| // OpenID keys and envs.
 | |
| const (
 | |
| 	ClientID      = "client_id"
 | |
| 	ClientSecret  = "client_secret"
 | |
| 	ConfigURL     = "config_url"
 | |
| 	ClaimName     = "claim_name"
 | |
| 	ClaimUserinfo = "claim_userinfo"
 | |
| 	RolePolicy    = "role_policy"
 | |
| 	DisplayName   = "display_name"
 | |
| 
 | |
| 	Scopes             = "scopes"
 | |
| 	RedirectURI        = "redirect_uri"
 | |
| 	RedirectURIDynamic = "redirect_uri_dynamic"
 | |
| 	Vendor             = "vendor"
 | |
| 
 | |
| 	// Vendor specific ENV only enabled if the Vendor matches == "vendor"
 | |
| 	KeyCloakRealm    = "keycloak_realm"
 | |
| 	KeyCloakAdminURL = "keycloak_admin_url"
 | |
| 
 | |
| 	// Removed params
 | |
| 	JwksURL     = "jwks_url"
 | |
| 	ClaimPrefix = "claim_prefix"
 | |
| )
 | |
| 
 | |
| // DefaultKVS - default config for OpenID config
 | |
| var (
 | |
| 	DefaultKVS = config.KVS{
 | |
| 		config.KV{
 | |
| 			Key:   config.Enable,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   DisplayName,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ConfigURL,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ClientID,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ClientSecret,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ClaimName,
 | |
| 			Value: policy.PolicyName,
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ClaimUserinfo,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   RolePolicy,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ClaimPrefix,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   RedirectURI,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   RedirectURIDynamic,
 | |
| 			Value: "off",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   Scopes,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   Vendor,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   KeyCloakRealm,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   KeyCloakAdminURL,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 	}
 | |
| )
 | |
| 
 | |
| var errSingleProvider = config.Errorf("Only one OpenID provider can be configured if not using role policy mapping")
 | |
| 
 | |
| // DummyRoleARN is used to indicate that the user associated with it was
 | |
| // authenticated via policy-claim based OpenID provider.
 | |
| var DummyRoleARN = func() arn.ARN {
 | |
| 	v, err := arn.NewIAMRoleARN("dummy-internal", "")
 | |
| 	if err != nil {
 | |
| 		panic("should not happen!")
 | |
| 	}
 | |
| 	return v
 | |
| }()
 | |
| 
 | |
| // Config - OpenID Config
 | |
| type Config struct {
 | |
| 	Enabled bool
 | |
| 
 | |
| 	// map of roleARN to providerCfg's
 | |
| 	arnProviderCfgsMap map[arn.ARN]*providerCfg
 | |
| 
 | |
| 	// map of config names to providerCfg's
 | |
| 	ProviderCfgs map[string]*providerCfg
 | |
| 
 | |
| 	pubKeys          publicKeys
 | |
| 	roleArnPolicyMap map[arn.ARN]string
 | |
| 
 | |
| 	transport   http.RoundTripper
 | |
| 	closeRespFn func(io.ReadCloser)
 | |
| }
 | |
| 
 | |
| // Clone returns a cloned copy of OpenID config.
 | |
| func (r *Config) Clone() Config {
 | |
| 	if r == nil {
 | |
| 		return Config{}
 | |
| 	}
 | |
| 	cfg := Config{
 | |
| 		Enabled:            r.Enabled,
 | |
| 		arnProviderCfgsMap: make(map[arn.ARN]*providerCfg, len(r.arnProviderCfgsMap)),
 | |
| 		ProviderCfgs:       make(map[string]*providerCfg, len(r.ProviderCfgs)),
 | |
| 		pubKeys:            r.pubKeys,
 | |
| 		roleArnPolicyMap:   make(map[arn.ARN]string, len(r.roleArnPolicyMap)),
 | |
| 		transport:          r.transport,
 | |
| 		closeRespFn:        r.closeRespFn,
 | |
| 	}
 | |
| 	for k, v := range r.arnProviderCfgsMap {
 | |
| 		cfg.arnProviderCfgsMap[k] = v
 | |
| 	}
 | |
| 	for k, v := range r.ProviderCfgs {
 | |
| 		cfg.ProviderCfgs[k] = v
 | |
| 	}
 | |
| 	for k, v := range r.roleArnPolicyMap {
 | |
| 		cfg.roleArnPolicyMap[k] = v
 | |
| 	}
 | |
| 	return cfg
 | |
| }
 | |
| 
 | |
| // LookupConfig lookup jwks from config, override with any ENVs.
 | |
| func LookupConfig(s config.Config, transport http.RoundTripper, closeRespFn func(io.ReadCloser), serverRegion string) (c Config, err error) {
 | |
| 	openIDClientTransport := http.DefaultTransport
 | |
| 	if transport != nil {
 | |
| 		openIDClientTransport = transport
 | |
| 	}
 | |
| 	c = Config{
 | |
| 		Enabled:            false,
 | |
| 		arnProviderCfgsMap: map[arn.ARN]*providerCfg{},
 | |
| 		ProviderCfgs:       map[string]*providerCfg{},
 | |
| 		pubKeys: publicKeys{
 | |
| 			RWMutex: &sync.RWMutex{},
 | |
| 			pkMap:   map[string]interface{}{},
 | |
| 		},
 | |
| 		roleArnPolicyMap: map[arn.ARN]string{},
 | |
| 		transport:        openIDClientTransport,
 | |
| 		closeRespFn:      closeRespFn,
 | |
| 	}
 | |
| 
 | |
| 	seenClientIDs := set.NewStringSet()
 | |
| 
 | |
| 	deprecatedKeys := []string{JwksURL}
 | |
| 
 | |
| 	// remove this since we have removed support for this already.
 | |
| 	for k := range s[config.IdentityOpenIDSubSys] {
 | |
| 		for _, dk := range deprecatedKeys {
 | |
| 			kvs := s[config.IdentityOpenIDSubSys][k]
 | |
| 			kvs.Delete(dk)
 | |
| 			s[config.IdentityOpenIDSubSys][k] = kvs
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if err := s.CheckValidKeys(config.IdentityOpenIDSubSys, deprecatedKeys); err != nil {
 | |
| 		return c, err
 | |
| 	}
 | |
| 
 | |
| 	openIDTargets, err := s.GetAvailableTargets(config.IdentityOpenIDSubSys)
 | |
| 	if err != nil {
 | |
| 		return c, err
 | |
| 	}
 | |
| 
 | |
| 	for _, cfgName := range openIDTargets {
 | |
| 		getCfgVal := func(cfgParam string) string {
 | |
| 			// As parameters are already validated, we skip checking
 | |
| 			// if the config param was found.
 | |
| 			val, _, _ := s.ResolveConfigParam(config.IdentityOpenIDSubSys, cfgName, cfgParam, false)
 | |
| 			return val
 | |
| 		}
 | |
| 
 | |
| 		// In the past, when only one openID provider was allowed, there
 | |
| 		// was no `enable` parameter - the configuration is turned off
 | |
| 		// by clearing the values. With multiple providers, we support
 | |
| 		// individually enabling/disabling provider configurations. If
 | |
| 		// the enable parameter's value is non-empty, we use that
 | |
| 		// setting, otherwise we treat it as enabled if some important
 | |
| 		// parameters are non-empty.
 | |
| 		var (
 | |
| 			cfgEnableVal        = getCfgVal(config.Enable)
 | |
| 			isExplicitlyEnabled = cfgEnableVal != ""
 | |
| 		)
 | |
| 
 | |
| 		var enabled bool
 | |
| 		if isExplicitlyEnabled {
 | |
| 			enabled, err = config.ParseBool(cfgEnableVal)
 | |
| 			if err != nil {
 | |
| 				return c, err
 | |
| 			}
 | |
| 			// No need to continue loading if the config is not enabled.
 | |
| 			if !enabled {
 | |
| 				continue
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		p := newProviderCfgFromConfig(getCfgVal)
 | |
| 		configURL := getCfgVal(ConfigURL)
 | |
| 
 | |
| 		if !isExplicitlyEnabled {
 | |
| 			enabled = true
 | |
| 			if p.ClientID == "" && p.ClientSecret == "" && configURL == "" {
 | |
| 				enabled = false
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// No need to continue loading if the config is not enabled.
 | |
| 		if !enabled {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// Validate that client ID has not been duplicately specified.
 | |
| 		if seenClientIDs.Contains(p.ClientID) {
 | |
| 			return c, config.Errorf("Client ID %s is present with multiple OpenID configurations", p.ClientID)
 | |
| 		}
 | |
| 		seenClientIDs.Add(p.ClientID)
 | |
| 
 | |
| 		p.URL, err = xnet.ParseHTTPURL(configURL)
 | |
| 		if err != nil {
 | |
| 			return c, err
 | |
| 		}
 | |
| 		configURLDomain := p.URL.Hostname()
 | |
| 		p.DiscoveryDoc, err = parseDiscoveryDoc(p.URL, transport, closeRespFn)
 | |
| 		if err != nil {
 | |
| 			return c, err
 | |
| 		}
 | |
| 
 | |
| 		if p.ClaimUserinfo && configURL == "" {
 | |
| 			return c, errors.New("please specify config_url to enable fetching claims from UserInfo endpoint")
 | |
| 		}
 | |
| 
 | |
| 		if scopeList := getCfgVal(Scopes); scopeList != "" {
 | |
| 			var scopes []string
 | |
| 			for _, scope := range strings.Split(scopeList, ",") {
 | |
| 				scope = strings.TrimSpace(scope)
 | |
| 				if scope == "" {
 | |
| 					return c, config.Errorf("empty scope value is not allowed '%s', please refer to our documentation", scopeList)
 | |
| 				}
 | |
| 				scopes = append(scopes, scope)
 | |
| 			}
 | |
| 			// Replace the discovery document scopes by client customized scopes.
 | |
| 			p.DiscoveryDoc.ScopesSupported = scopes
 | |
| 		}
 | |
| 
 | |
| 		// Check if claim name is the non-default value and role policy is set.
 | |
| 		if p.ClaimName != policy.PolicyName && p.RolePolicy != "" {
 | |
| 			// In the unlikely event that the user specifies
 | |
| 			// `policy.PolicyName` as the claim name explicitly and sets
 | |
| 			// a role policy, this check is thwarted, but we will be using
 | |
| 			// the role policy anyway.
 | |
| 			return c, config.Errorf("Role Policy (=`%s`) and Claim Name (=`%s`) cannot both be set", p.RolePolicy, p.ClaimName)
 | |
| 		}
 | |
| 
 | |
| 		jwksURL := p.DiscoveryDoc.JwksURI
 | |
| 		if jwksURL == "" {
 | |
| 			return c, config.Errorf("no JWKS URI found in your provider's discovery doc (config_url=%s)", configURL)
 | |
| 		}
 | |
| 
 | |
| 		p.JWKS.URL, err = xnet.ParseHTTPURL(jwksURL)
 | |
| 		if err != nil {
 | |
| 			return c, err
 | |
| 		}
 | |
| 
 | |
| 		if p.RolePolicy != "" {
 | |
| 			// RolePolicy is validated by IAM System during its
 | |
| 			// initialization.
 | |
| 
 | |
| 			// Generate role ARN as combination of provider domain and
 | |
| 			// prefix of client ID.
 | |
| 			domain := configURLDomain
 | |
| 			if domain == "" {
 | |
| 				// Attempt to parse the JWKs URI.
 | |
| 				domain = p.JWKS.URL.Hostname()
 | |
| 				if domain == "" {
 | |
| 					return c, config.Errorf("unable to parse a domain from the OpenID config")
 | |
| 				}
 | |
| 			}
 | |
| 			if p.ClientID == "" {
 | |
| 				return c, config.Errorf("client ID must not be empty")
 | |
| 			}
 | |
| 
 | |
| 			// We set the resource ID of the role arn as a hash of client
 | |
| 			// ID, so we can get a short roleARN that stays the same on
 | |
| 			// restart.
 | |
| 			var resourceID string
 | |
| 			{
 | |
| 				h := sha1.New()
 | |
| 				h.Write([]byte(p.ClientID))
 | |
| 				bs := h.Sum(nil)
 | |
| 				resourceID = base64.RawURLEncoding.EncodeToString(bs)
 | |
| 			}
 | |
| 			p.roleArn, err = arn.NewIAMRoleARN(resourceID, serverRegion)
 | |
| 			if err != nil {
 | |
| 				return c, config.Errorf("unable to generate ARN from the OpenID config: %v", err)
 | |
| 			}
 | |
| 
 | |
| 			c.roleArnPolicyMap[p.roleArn] = p.RolePolicy
 | |
| 		} else if p.ClaimName == "" {
 | |
| 			return c, config.Errorf("A role policy or claim name must be specified")
 | |
| 		}
 | |
| 
 | |
| 		if err = p.initializeProvider(getCfgVal, c.transport); err != nil {
 | |
| 			return c, err
 | |
| 		}
 | |
| 
 | |
| 		arnKey := p.roleArn
 | |
| 		if p.RolePolicy == "" {
 | |
| 			arnKey = DummyRoleARN
 | |
| 			// Ensure that at most one JWT policy claim based provider may be
 | |
| 			// defined.
 | |
| 			if _, ok := c.arnProviderCfgsMap[DummyRoleARN]; ok {
 | |
| 				return c, errSingleProvider
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		c.arnProviderCfgsMap[arnKey] = &p
 | |
| 		c.ProviderCfgs[cfgName] = &p
 | |
| 
 | |
| 		if err = c.PopulatePublicKey(arnKey); err != nil {
 | |
| 			return c, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	c.Enabled = true
 | |
| 
 | |
| 	return c, nil
 | |
| }
 | |
| 
 | |
| // ErrProviderConfigNotFound - represents a non-existing provider error.
 | |
| var ErrProviderConfigNotFound = errors.New("provider configuration not found")
 | |
| 
 | |
| // GetConfigInfo - returns configuration and related info for the given IDP
 | |
| // provider.
 | |
| func (r *Config) GetConfigInfo(s config.Config, cfgName string) ([]madmin.IDPCfgInfo, error) {
 | |
| 	openIDConfigs, err := s.GetAvailableTargets(config.IdentityOpenIDSubSys)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	present := false
 | |
| 	for _, cfg := range openIDConfigs {
 | |
| 		if cfg == cfgName {
 | |
| 			present = true
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if !present {
 | |
| 		return nil, ErrProviderConfigNotFound
 | |
| 	}
 | |
| 
 | |
| 	kvsrcs, err := s.GetResolvedConfigParams(config.IdentityOpenIDSubSys, cfgName, true)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	res := make([]madmin.IDPCfgInfo, 0, len(kvsrcs)+1)
 | |
| 	for _, kvsrc := range kvsrcs {
 | |
| 		// skip returning default config values.
 | |
| 		if kvsrc.Src == config.ValueSourceDef {
 | |
| 			if kvsrc.Key != madmin.EnableKey {
 | |
| 				continue
 | |
| 			}
 | |
| 			// for EnableKey we set an explicit on/off from live configuration
 | |
| 			// if it is present.
 | |
| 			if _, ok := r.ProviderCfgs[cfgName]; !ok {
 | |
| 				// No live config is present
 | |
| 				continue
 | |
| 			}
 | |
| 			if r.Enabled {
 | |
| 				kvsrc.Value = "on"
 | |
| 			} else {
 | |
| 				kvsrc.Value = "off"
 | |
| 			}
 | |
| 		}
 | |
| 		res = append(res, madmin.IDPCfgInfo{
 | |
| 			Key:   kvsrc.Key,
 | |
| 			Value: kvsrc.Value,
 | |
| 			IsCfg: true,
 | |
| 			IsEnv: kvsrc.Src == config.ValueSourceEnv,
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	if provCfg, exists := r.ProviderCfgs[cfgName]; exists && provCfg.RolePolicy != "" {
 | |
| 		// Append roleARN
 | |
| 		res = append(res, madmin.IDPCfgInfo{
 | |
| 			Key:   "roleARN",
 | |
| 			Value: provCfg.roleArn.String(),
 | |
| 			IsCfg: false,
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	// sort the structs by the key
 | |
| 	sort.Slice(res, func(i, j int) bool {
 | |
| 		return res[i].Key < res[j].Key
 | |
| 	})
 | |
| 
 | |
| 	return res, nil
 | |
| }
 | |
| 
 | |
| // GetConfigList - list openID configurations
 | |
| func (r *Config) GetConfigList(s config.Config) ([]madmin.IDPListItem, error) {
 | |
| 	openIDConfigs, err := s.GetAvailableTargets(config.IdentityOpenIDSubSys)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var res []madmin.IDPListItem
 | |
| 	for _, cfg := range openIDConfigs {
 | |
| 		pcfg, ok := r.ProviderCfgs[cfg]
 | |
| 		if !ok {
 | |
| 			res = append(res, madmin.IDPListItem{
 | |
| 				Type:    "openid",
 | |
| 				Name:    cfg,
 | |
| 				Enabled: false,
 | |
| 			})
 | |
| 		} else {
 | |
| 			var roleARN string
 | |
| 			if pcfg.RolePolicy != "" {
 | |
| 				roleARN = pcfg.roleArn.String()
 | |
| 			}
 | |
| 			res = append(res, madmin.IDPListItem{
 | |
| 				Type:    "openid",
 | |
| 				Name:    cfg,
 | |
| 				Enabled: r.Enabled,
 | |
| 				RoleARN: roleARN,
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return res, nil
 | |
| }
 | |
| 
 | |
| // Enabled returns if configURL is enabled.
 | |
| func Enabled(kvs config.KVS) bool {
 | |
| 	return kvs.Get(ConfigURL) != ""
 | |
| }
 | |
| 
 | |
| // GetSettings - fetches OIDC settings for site-replication related validation.
 | |
| // NOTE that region must be populated by caller as this package does not know.
 | |
| func (r *Config) GetSettings() madmin.OpenIDSettings {
 | |
| 	res := madmin.OpenIDSettings{}
 | |
| 	if !r.Enabled {
 | |
| 		return res
 | |
| 	}
 | |
| 	h := sha256.New()
 | |
| 	for arn, provCfg := range r.arnProviderCfgsMap {
 | |
| 		hashedSecret := ""
 | |
| 		{
 | |
| 			h.Reset()
 | |
| 			h.Write([]byte(provCfg.ClientSecret))
 | |
| 			hashedSecret = base64.RawURLEncoding.EncodeToString(h.Sum(nil))
 | |
| 		}
 | |
| 		if arn != DummyRoleARN {
 | |
| 			if res.Roles == nil {
 | |
| 				res.Roles = make(map[string]madmin.OpenIDProviderSettings)
 | |
| 			}
 | |
| 			res.Roles[arn.String()] = madmin.OpenIDProviderSettings{
 | |
| 				ClaimUserinfoEnabled: provCfg.ClaimUserinfo,
 | |
| 				RolePolicy:           provCfg.RolePolicy,
 | |
| 				ClientID:             provCfg.ClientID,
 | |
| 				HashedClientSecret:   hashedSecret,
 | |
| 			}
 | |
| 		} else {
 | |
| 			res.ClaimProvider = madmin.OpenIDProviderSettings{
 | |
| 				ClaimUserinfoEnabled: provCfg.ClaimUserinfo,
 | |
| 				RolePolicy:           provCfg.RolePolicy,
 | |
| 				ClientID:             provCfg.ClientID,
 | |
| 				HashedClientSecret:   hashedSecret,
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // GetIAMPolicyClaimName - returns the policy claim name for the (at most one)
 | |
| // provider configured without a role policy.
 | |
| func (r *Config) GetIAMPolicyClaimName() string {
 | |
| 	pCfg, ok := r.arnProviderCfgsMap[DummyRoleARN]
 | |
| 	if !ok {
 | |
| 		return ""
 | |
| 	}
 | |
| 	return pCfg.ClaimPrefix + pCfg.ClaimName
 | |
| }
 | |
| 
 | |
| // LookupUser lookup userid for the provider
 | |
| func (r Config) LookupUser(roleArn, userid string) (provider.User, error) {
 | |
| 	// Can safely ignore error here as empty or invalid ARNs will not be
 | |
| 	// mapped.
 | |
| 	arnVal, _ := arn.Parse(roleArn)
 | |
| 	pCfg, ok := r.arnProviderCfgsMap[arnVal]
 | |
| 	if ok {
 | |
| 		user, err := pCfg.provider.LookupUser(userid)
 | |
| 		if err != nil && err != provider.ErrAccessTokenExpired {
 | |
| 			return user, err
 | |
| 		}
 | |
| 		if err == provider.ErrAccessTokenExpired {
 | |
| 			if err = pCfg.provider.LoginWithClientID(pCfg.ClientID, pCfg.ClientSecret); err != nil {
 | |
| 				return user, err
 | |
| 			}
 | |
| 			user, err = pCfg.provider.LookupUser(userid)
 | |
| 		}
 | |
| 		return user, err
 | |
| 	}
 | |
| 	// Without any specific logic for a provider, all accounts
 | |
| 	// are always enabled.
 | |
| 	return provider.User{ID: userid, Enabled: true}, nil
 | |
| }
 | |
| 
 | |
| // ProviderEnabled returns true if any vendor specific provider is enabled.
 | |
| func (r Config) ProviderEnabled() bool {
 | |
| 	if !r.Enabled {
 | |
| 		return false
 | |
| 	}
 | |
| 	for _, v := range r.arnProviderCfgsMap {
 | |
| 		if v.provider != nil {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // GetRoleInfo - returns ARN to policies map if a role policy based openID
 | |
| // provider is configured. Otherwise returns nil.
 | |
| func (r Config) GetRoleInfo() map[arn.ARN]string {
 | |
| 	for _, p := range r.arnProviderCfgsMap {
 | |
| 		if p.RolePolicy != "" {
 | |
| 			return r.roleArnPolicyMap
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetDefaultExpiration - returns the expiration seconds expected.
 | |
| func GetDefaultExpiration(dsecs string) (time.Duration, error) {
 | |
| 	defaultExpiryDuration := time.Duration(60) * time.Minute // Defaults to 1hr.
 | |
| 	if dsecs != "" {
 | |
| 		expirySecs, err := strconv.ParseInt(dsecs, 10, 64)
 | |
| 		if err != nil {
 | |
| 			return 0, auth.ErrInvalidDuration
 | |
| 		}
 | |
| 
 | |
| 		// The duration, in seconds, of the role session.
 | |
| 		// The value can range from 900 seconds (15 minutes)
 | |
| 		// up to 365 days.
 | |
| 		if expirySecs < 900 || expirySecs > 31536000 {
 | |
| 			return 0, auth.ErrInvalidDuration
 | |
| 		}
 | |
| 
 | |
| 		defaultExpiryDuration = time.Duration(expirySecs) * time.Second
 | |
| 	}
 | |
| 	return defaultExpiryDuration, nil
 | |
| }
 |