mirror of
				https://github.com/minio/minio.git
				synced 2025-10-31 00:01:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			301 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			301 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2015-2021 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 ldap
 | |
| 
 | |
| import (
 | |
| 	"crypto/x509"
 | |
| 	"errors"
 | |
| 	"sort"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/minio/madmin-go/v3"
 | |
| 	"github.com/minio/minio/internal/config"
 | |
| 	"github.com/minio/pkg/v2/ldap"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	defaultLDAPExpiry = time.Hour * 1
 | |
| 
 | |
| 	minLDAPExpiry time.Duration = 15 * time.Minute
 | |
| 	maxLDAPExpiry time.Duration = 365 * 24 * time.Hour
 | |
| )
 | |
| 
 | |
| // Config contains AD/LDAP server connectivity information.
 | |
| type Config struct {
 | |
| 	LDAP ldap.Config
 | |
| 
 | |
| 	stsExpiryDuration time.Duration // contains converted value
 | |
| }
 | |
| 
 | |
| // Enabled returns if LDAP is enabled.
 | |
| func (l *Config) Enabled() bool {
 | |
| 	return l.LDAP.Enabled
 | |
| }
 | |
| 
 | |
| // Clone returns a cloned copy of LDAP config.
 | |
| func (l *Config) Clone() Config {
 | |
| 	if l == nil {
 | |
| 		return Config{}
 | |
| 	}
 | |
| 	cfg := Config{
 | |
| 		LDAP:              l.LDAP.Clone(),
 | |
| 		stsExpiryDuration: l.stsExpiryDuration,
 | |
| 	}
 | |
| 	return cfg
 | |
| }
 | |
| 
 | |
| // LDAP keys and envs.
 | |
| const (
 | |
| 	ServerAddr         = "server_addr"
 | |
| 	SRVRecordName      = "srv_record_name"
 | |
| 	LookupBindDN       = "lookup_bind_dn"
 | |
| 	LookupBindPassword = "lookup_bind_password"
 | |
| 	UserDNSearchBaseDN = "user_dn_search_base_dn"
 | |
| 	UserDNSearchFilter = "user_dn_search_filter"
 | |
| 	GroupSearchFilter  = "group_search_filter"
 | |
| 	GroupSearchBaseDN  = "group_search_base_dn"
 | |
| 	TLSSkipVerify      = "tls_skip_verify"
 | |
| 	ServerInsecure     = "server_insecure"
 | |
| 	ServerStartTLS     = "server_starttls"
 | |
| 
 | |
| 	EnvServerAddr         = "MINIO_IDENTITY_LDAP_SERVER_ADDR"
 | |
| 	EnvSRVRecordName      = "MINIO_IDENTITY_LDAP_SRV_RECORD_NAME"
 | |
| 	EnvTLSSkipVerify      = "MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY"
 | |
| 	EnvServerInsecure     = "MINIO_IDENTITY_LDAP_SERVER_INSECURE"
 | |
| 	EnvServerStartTLS     = "MINIO_IDENTITY_LDAP_SERVER_STARTTLS"
 | |
| 	EnvUsernameFormat     = "MINIO_IDENTITY_LDAP_USERNAME_FORMAT"
 | |
| 	EnvUserDNSearchBaseDN = "MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN"
 | |
| 	EnvUserDNSearchFilter = "MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER"
 | |
| 	EnvGroupSearchFilter  = "MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER"
 | |
| 	EnvGroupSearchBaseDN  = "MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN"
 | |
| 	EnvLookupBindDN       = "MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN"
 | |
| 	EnvLookupBindPassword = "MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD"
 | |
| )
 | |
| 
 | |
| var removedKeys = []string{
 | |
| 	"sts_expiry",
 | |
| 	"username_format",
 | |
| 	"username_search_filter",
 | |
| 	"username_search_base_dn",
 | |
| 	"group_name_attribute",
 | |
| }
 | |
| 
 | |
| // DefaultKVS - default config for LDAP config
 | |
| var (
 | |
| 	DefaultKVS = config.KVS{
 | |
| 		config.KV{
 | |
| 			Key:   config.Enable,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ServerAddr,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   SRVRecordName,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   UserDNSearchBaseDN,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   UserDNSearchFilter,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   GroupSearchFilter,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   GroupSearchBaseDN,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   TLSSkipVerify,
 | |
| 			Value: config.EnableOff,
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ServerInsecure,
 | |
| 			Value: config.EnableOff,
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   ServerStartTLS,
 | |
| 			Value: config.EnableOff,
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   LookupBindDN,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 		config.KV{
 | |
| 			Key:   LookupBindPassword,
 | |
| 			Value: "",
 | |
| 		},
 | |
| 	}
 | |
| )
 | |
| 
 | |
| // Enabled returns if LDAP config is enabled.
 | |
| func Enabled(kvs config.KVS) bool {
 | |
| 	return kvs.Get(ServerAddr) != ""
 | |
| }
 | |
| 
 | |
| // Lookup - initializes LDAP config, overrides config, if any ENV values are set.
 | |
| func Lookup(s config.Config, rootCAs *x509.CertPool) (l Config, err error) {
 | |
| 	l = Config{}
 | |
| 
 | |
| 	// Purge all removed keys first
 | |
| 	kvs := s[config.IdentityLDAPSubSys][config.Default]
 | |
| 	if len(kvs) > 0 {
 | |
| 		for _, k := range removedKeys {
 | |
| 			kvs.Delete(k)
 | |
| 		}
 | |
| 		s[config.IdentityLDAPSubSys][config.Default] = kvs
 | |
| 	}
 | |
| 
 | |
| 	if err := s.CheckValidKeys(config.IdentityLDAPSubSys, removedKeys); err != nil {
 | |
| 		return l, err
 | |
| 	}
 | |
| 
 | |
| 	getCfgVal := func(cfgParam string) string {
 | |
| 		// As parameters are already validated, we skip checking
 | |
| 		// if the config param was found.
 | |
| 		val, _, _ := s.ResolveConfigParam(config.IdentityLDAPSubSys, config.Default, cfgParam, false)
 | |
| 		return val
 | |
| 	}
 | |
| 
 | |
| 	ldapServer := getCfgVal(ServerAddr)
 | |
| 	if ldapServer == "" {
 | |
| 		return l, nil
 | |
| 	}
 | |
| 	l.LDAP = ldap.Config{
 | |
| 		Enabled:       true,
 | |
| 		RootCAs:       rootCAs,
 | |
| 		ServerAddr:    ldapServer,
 | |
| 		SRVRecordName: getCfgVal(SRVRecordName),
 | |
| 	}
 | |
| 
 | |
| 	// Parse explicitly enable=on/off flag. If not set, defaults to `true`
 | |
| 	// because ServerAddr is set.
 | |
| 	if v := getCfgVal(config.Enable); v != "" {
 | |
| 		l.LDAP.Enabled, err = config.ParseBool(v)
 | |
| 		if err != nil {
 | |
| 			return l, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	l.stsExpiryDuration = defaultLDAPExpiry
 | |
| 
 | |
| 	// LDAP connection configuration
 | |
| 	if v := getCfgVal(ServerInsecure); v != "" {
 | |
| 		l.LDAP.ServerInsecure, err = config.ParseBool(v)
 | |
| 		if err != nil {
 | |
| 			return l, err
 | |
| 		}
 | |
| 	}
 | |
| 	if v := getCfgVal(ServerStartTLS); v != "" {
 | |
| 		l.LDAP.ServerStartTLS, err = config.ParseBool(v)
 | |
| 		if err != nil {
 | |
| 			return l, err
 | |
| 		}
 | |
| 	}
 | |
| 	if v := getCfgVal(TLSSkipVerify); v != "" {
 | |
| 		l.LDAP.TLSSkipVerify, err = config.ParseBool(v)
 | |
| 		if err != nil {
 | |
| 			return l, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Lookup bind user configuration
 | |
| 	l.LDAP.LookupBindDN = getCfgVal(LookupBindDN)
 | |
| 	l.LDAP.LookupBindPassword = getCfgVal(LookupBindPassword)
 | |
| 
 | |
| 	// User DN search configuration
 | |
| 	l.LDAP.UserDNSearchFilter = getCfgVal(UserDNSearchFilter)
 | |
| 	l.LDAP.UserDNSearchBaseDistName = getCfgVal(UserDNSearchBaseDN)
 | |
| 
 | |
| 	// Group search params configuration
 | |
| 	l.LDAP.GroupSearchFilter = getCfgVal(GroupSearchFilter)
 | |
| 	l.LDAP.GroupSearchBaseDistName = getCfgVal(GroupSearchBaseDN)
 | |
| 
 | |
| 	// Validate and test configuration.
 | |
| 	valResult := l.LDAP.Validate()
 | |
| 	if !valResult.IsOk() {
 | |
| 		return l, valResult
 | |
| 	}
 | |
| 
 | |
| 	return l, nil
 | |
| }
 | |
| 
 | |
| // GetConfigList - returns a list of LDAP configurations.
 | |
| func (l *Config) GetConfigList(s config.Config) ([]madmin.IDPListItem, error) {
 | |
| 	ldapConfigs, err := s.GetAvailableTargets(config.IdentityLDAPSubSys)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// For now, ldapConfigs will only have a single entry for the default
 | |
| 	// configuration.
 | |
| 
 | |
| 	var res []madmin.IDPListItem
 | |
| 	for _, cfg := range ldapConfigs {
 | |
| 		res = append(res, madmin.IDPListItem{
 | |
| 			Type:    "ldap",
 | |
| 			Name:    cfg,
 | |
| 			Enabled: l.Enabled(),
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	return res, nil
 | |
| }
 | |
| 
 | |
| // ErrProviderConfigNotFound - represents a non-existing provider error.
 | |
| var ErrProviderConfigNotFound = errors.New("provider configuration not found")
 | |
| 
 | |
| // GetConfigInfo - returns config details for an LDAP configuration.
 | |
| func (l *Config) GetConfigInfo(s config.Config, cfgName string) ([]madmin.IDPCfgInfo, error) {
 | |
| 	// For now only a single LDAP config is supported.
 | |
| 	if cfgName != madmin.Default {
 | |
| 		return nil, ErrProviderConfigNotFound
 | |
| 	}
 | |
| 	kvsrcs, err := s.GetResolvedConfigParams(config.IdentityLDAPSubSys, cfgName, true)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	res := make([]madmin.IDPCfgInfo, 0, len(kvsrcs))
 | |
| 	for _, kvsrc := range kvsrcs {
 | |
| 		// skip default values.
 | |
| 		if kvsrc.Src == config.ValueSourceDef {
 | |
| 			continue
 | |
| 		}
 | |
| 		res = append(res, madmin.IDPCfgInfo{
 | |
| 			Key:   kvsrc.Key,
 | |
| 			Value: kvsrc.Value,
 | |
| 			IsCfg: true,
 | |
| 			IsEnv: kvsrc.Src == config.ValueSourceEnv,
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	// sort the structs by the key
 | |
| 	sort.Slice(res, func(i, j int) bool {
 | |
| 		return res[i].Key < res[j].Key
 | |
| 	})
 | |
| 
 | |
| 	return res, nil
 | |
| }
 |