mirror of
https://github.com/minio/minio.git
synced 2025-11-08 21:24:55 -05:00
LDAP STS API (#8091)
Add LDAP based users-groups system This change adds support to integrate an LDAP server for user authentication. This works via a custom STS API for LDAP. Each user accessing the MinIO who can be authenticated via LDAP receives temporary credentials to access the MinIO server. LDAP is enabled only over TLS. User groups are also supported via LDAP. The administrator may configure an LDAP search query to find the group attribute of a user - this may correspond to any attribute in the LDAP tree (that the user has access to view). One or more groups may be returned by such a query. A group is mapped to an IAM policy in the usual way, and the server enforces a policy corresponding to all the groups and the user's own mapped policy. When LDAP is configured, the internal MinIO users system is disabled.
This commit is contained in:
committed by
kannappanr
parent
94e5cb7576
commit
a0456ce940
166
cmd/iam.go
166
cmd/iam.go
@@ -30,6 +30,20 @@ import (
|
||||
"github.com/minio/minio/pkg/madmin"
|
||||
)
|
||||
|
||||
// UsersSysType - defines the type of users and groups system that is
|
||||
// active on the server.
|
||||
type UsersSysType string
|
||||
|
||||
// Types of users configured in the server.
|
||||
const (
|
||||
// This mode uses the internal users system in MinIO.
|
||||
MinIOUsersSysType UsersSysType = "MinIOUsersSys"
|
||||
|
||||
// This mode uses users and groups from a configured LDAP
|
||||
// server.
|
||||
LDAPUsersSysType UsersSysType = "LDAPUsersSys"
|
||||
)
|
||||
|
||||
const (
|
||||
// IAM configuration directory.
|
||||
iamConfigPrefix = minioConfigPrefix + "/iam"
|
||||
@@ -145,6 +159,9 @@ func newMappedPolicy(policy string) MappedPolicy {
|
||||
// IAMSys - config system.
|
||||
type IAMSys struct {
|
||||
sync.RWMutex
|
||||
|
||||
usersSysType UsersSysType
|
||||
|
||||
// map of policy names to policy definitions
|
||||
iamPolicyDocsMap map[string]iampolicy.Policy
|
||||
// map of usernames to credentials
|
||||
@@ -463,6 +480,13 @@ func (sys *IAMSys) DeleteUser(accessKey string) error {
|
||||
return errServerNotInitialized
|
||||
}
|
||||
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
// It is ok to ignore deletion error on the mapped policy
|
||||
sys.store.deleteMappedPolicy(accessKey, false, false)
|
||||
err := sys.store.deleteUserIdentity(accessKey, false)
|
||||
@@ -472,9 +496,6 @@ func (sys *IAMSys) DeleteUser(accessKey string) error {
|
||||
err = nil
|
||||
}
|
||||
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
delete(sys.iamUsersMap, accessKey)
|
||||
delete(sys.iamUserPolicyMap, accessKey)
|
||||
|
||||
@@ -533,6 +554,10 @@ func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return nil, errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
for k, v := range sys.iamUsersMap {
|
||||
users[k] = madmin.UserInfo{
|
||||
PolicyName: sys.iamUserPolicyMap[k].Policy,
|
||||
@@ -553,6 +578,12 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return madmin.UserInfo{
|
||||
PolicyName: sys.iamUserPolicyMap[name].Policy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
creds, found := sys.iamUsersMap[name]
|
||||
if !found {
|
||||
return u, errNoSuchUser
|
||||
@@ -580,6 +611,10 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus)
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
cred, ok := sys.iamUsersMap[accessKey]
|
||||
if !ok {
|
||||
return errNoSuchUser
|
||||
@@ -614,6 +649,10 @@ func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error {
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
if err := sys.store.saveUserIdentity(accessKey, false, u); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -636,6 +675,10 @@ func (sys *IAMSys) SetUserSecretKey(accessKey string, secretKey string) error {
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
cred, ok := sys.iamUsersMap[accessKey]
|
||||
if !ok {
|
||||
return errNoSuchUser
|
||||
@@ -675,6 +718,10 @@ func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
// Validate that all members exist.
|
||||
for _, member := range members {
|
||||
_, ok := sys.iamUsersMap[member]
|
||||
@@ -729,6 +776,10 @@ func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
// Validate that all members exist.
|
||||
for _, member := range members {
|
||||
_, ok := sys.iamUsersMap[member]
|
||||
@@ -802,6 +853,10 @@ func (sys *IAMSys) SetGroupStatus(group string, enabled bool) error {
|
||||
sys.Lock()
|
||||
defer sys.Unlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
if group == "" {
|
||||
return errInvalidArgument
|
||||
}
|
||||
@@ -830,6 +885,7 @@ func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err e
|
||||
if err != nil {
|
||||
return gd, err
|
||||
}
|
||||
|
||||
// A group may be mapped to at most one policy.
|
||||
policy := ""
|
||||
if len(ps) > 0 {
|
||||
@@ -839,6 +895,13 @@ func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err e
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return madmin.GroupDesc{
|
||||
Name: group,
|
||||
Policy: policy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
gi, ok := sys.iamGroupsMap[group]
|
||||
if !ok {
|
||||
return gd, errNoSuchGroup
|
||||
@@ -852,15 +915,19 @@ func (sys *IAMSys) GetGroupDescription(group string) (gd madmin.GroupDesc, err e
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListGroups - lists groups
|
||||
func (sys *IAMSys) ListGroups() (r []string) {
|
||||
// ListGroups - lists groups.
|
||||
func (sys *IAMSys) ListGroups() (r []string, err error) {
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
if sys.usersSysType != MinIOUsersSysType {
|
||||
return nil, errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
for k := range sys.iamGroupsMap {
|
||||
r = append(r, k)
|
||||
}
|
||||
return r
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// PolicyDBSet - sets a policy for a user or group in the
|
||||
@@ -889,13 +956,16 @@ func (sys *IAMSys) policyDBSet(objectAPI ObjectLayer, name, policy string, isSTS
|
||||
if _, ok := sys.iamPolicyDocsMap[policy]; !ok {
|
||||
return errNoSuchPolicy
|
||||
}
|
||||
if !isGroup {
|
||||
if _, ok := sys.iamUsersMap[name]; !ok {
|
||||
return errNoSuchUser
|
||||
}
|
||||
} else {
|
||||
if _, ok := sys.iamGroupsMap[name]; !ok {
|
||||
return errNoSuchGroup
|
||||
|
||||
if sys.usersSysType == MinIOUsersSysType {
|
||||
if !isGroup {
|
||||
if _, ok := sys.iamUsersMap[name]; !ok {
|
||||
return errNoSuchUser
|
||||
}
|
||||
} else {
|
||||
if _, ok := sys.iamGroupsMap[name]; !ok {
|
||||
return errNoSuchGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,6 +1050,63 @@ func (sys *IAMSys) policyDBGet(name string, isGroup bool) ([]string, error) {
|
||||
// which implements claims validation and verification other than
|
||||
// applying policies.
|
||||
func (sys *IAMSys) IsAllowedSTS(args iampolicy.Args) bool {
|
||||
// If it is an LDAP request, check that user and group
|
||||
// policies allow the request.
|
||||
if userIface, ok := args.Claims[ldapUser]; ok {
|
||||
var user string
|
||||
if u, ok := userIface.(string); ok {
|
||||
user = u
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
var groups []string
|
||||
groupsVal := args.Claims[ldapGroups]
|
||||
if g, ok := groupsVal.([]interface{}); ok {
|
||||
for _, eachG := range g {
|
||||
if eachGStr, ok := eachG.(string); ok {
|
||||
groups = append(groups, eachGStr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
// We look up the policy mapping directly to bypass
|
||||
// users exists, group exists validations that do not
|
||||
// apply here.
|
||||
var policies []iampolicy.Policy
|
||||
if policy, ok := sys.iamUserPolicyMap[user]; ok {
|
||||
p, found := sys.iamPolicyDocsMap[policy.Policy]
|
||||
if found {
|
||||
policies = append(policies, p)
|
||||
}
|
||||
}
|
||||
for _, group := range groups {
|
||||
policy, ok := sys.iamGroupPolicyMap[group]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
p, found := sys.iamPolicyDocsMap[policy.Policy]
|
||||
if found {
|
||||
policies = append(policies, p)
|
||||
}
|
||||
}
|
||||
if len(policies) == 0 {
|
||||
return false
|
||||
}
|
||||
combinedPolicy := policies[0]
|
||||
for i := 1; i < len(policies); i++ {
|
||||
combinedPolicy.Statements =
|
||||
append(combinedPolicy.Statements,
|
||||
policies[i].Statements...)
|
||||
}
|
||||
return combinedPolicy.IsAllowed(args)
|
||||
}
|
||||
|
||||
pname, ok := args.Claims[iampolicy.PolicyName]
|
||||
if !ok {
|
||||
// When claims are set, it should have a "policy" field.
|
||||
@@ -1155,7 +1282,20 @@ func (sys *IAMSys) removeGroupFromMembershipsMap(group string) {
|
||||
|
||||
// NewIAMSys - creates new config system object.
|
||||
func NewIAMSys() *IAMSys {
|
||||
// Check global server configuration to determine the type of
|
||||
// users system configured.
|
||||
|
||||
// The default users system
|
||||
var utype UsersSysType
|
||||
switch {
|
||||
case globalServerConfig.LDAPServerConfig.ServerAddr != "":
|
||||
utype = LDAPUsersSysType
|
||||
default:
|
||||
utype = MinIOUsersSysType
|
||||
}
|
||||
|
||||
return &IAMSys{
|
||||
usersSysType: utype,
|
||||
iamUsersMap: make(map[string]auth.Credentials),
|
||||
iamPolicyDocsMap: make(map[string]iampolicy.Policy),
|
||||
iamUserPolicyMap: make(map[string]MappedPolicy),
|
||||
|
||||
Reference in New Issue
Block a user