mirror of
https://github.com/minio/minio.git
synced 2025-11-09 13:39:46 -05:00
Add LDAP policy entities API (#15908)
This commit is contained in:
committed by
GitHub
parent
ddeca9f12a
commit
76d822bf1e
88
cmd/admin-handlers-idp-ldap.go
Normal file
88
cmd/admin-handlers-idp-ldap.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// 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 cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/minio/madmin-go"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
iampolicy "github.com/minio/pkg/iam/policy"
|
||||
)
|
||||
|
||||
// ListLDAPPolicyMappingEntities lists users/groups mapped to given/all policies.
|
||||
//
|
||||
// GET <admin-prefix>/idp/ldap/policy-entities?[query-params]
|
||||
//
|
||||
// Query params:
|
||||
//
|
||||
// user=... -> repeatable query parameter, specifying users to query for
|
||||
// policy mapping
|
||||
//
|
||||
// group=... -> repeatable query parameter, specifying groups to query for
|
||||
// policy mapping
|
||||
//
|
||||
// policy=... -> repeatable query parameter, specifying policy to query for
|
||||
// user/group mapping
|
||||
//
|
||||
// When all query parameters are omitted, returns mappings for all policies.
|
||||
func (a adminAPIHandlers) ListLDAPPolicyMappingEntities(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := newContext(r, w, "ListLDAPPolicyMappingEntities")
|
||||
|
||||
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
|
||||
|
||||
// Check authorization.
|
||||
|
||||
objectAPI, cred := validateAdminReq(ctx, w, r,
|
||||
iampolicy.ListGroupsAdminAction, iampolicy.ListUsersAdminAction, iampolicy.ListUserPoliciesAdminAction)
|
||||
if objectAPI == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Validate API arguments.
|
||||
|
||||
q := madmin.PolicyEntitiesQuery{
|
||||
Users: r.Form["user"],
|
||||
Groups: r.Form["group"],
|
||||
Policy: r.Form["policy"],
|
||||
}
|
||||
|
||||
// Query IAM
|
||||
|
||||
res, err := globalIAMSys.QueryLDAPPolicyEntities(r.Context(), q)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// Encode result and send response.
|
||||
|
||||
data, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
password := cred.SecretKey
|
||||
econfigData, err := madmin.EncryptData(password, data)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
writeSuccessResponseJSON(w, econfigData)
|
||||
}
|
||||
@@ -190,6 +190,9 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) {
|
||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/idp-config/{type}/{name}").HandlerFunc(gz(httpTraceHdrs(adminAPI.GetIdentityProviderCfg)))
|
||||
adminRouter.Methods(http.MethodDelete).Path(adminVersion + "/idp-config/{type}/{name}").HandlerFunc(gz(httpTraceHdrs(adminAPI.DeleteIdentityProviderCfg)))
|
||||
|
||||
// LDAP IAM operations
|
||||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/idp/ldap/policy-entities").HandlerFunc(gz(httpTraceHdrs(adminAPI.ListLDAPPolicyMappingEntities)))
|
||||
|
||||
// -- END IAM APIs --
|
||||
|
||||
// GetBucketQuotaConfig
|
||||
|
||||
164
cmd/iam-store.go
164
cmd/iam-store.go
@@ -23,6 +23,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -1252,6 +1253,169 @@ func (store *IAMStoreSys) GetUsers() map[string]madmin.UserInfo {
|
||||
return result
|
||||
}
|
||||
|
||||
// Assumes store is locked by caller. If users is empty, returns all user mappings.
|
||||
func (store *IAMStoreSys) listLDAPUserPolicyMappings(cache *iamCache, users []string,
|
||||
isLDAPUserDN func(string) bool,
|
||||
) []madmin.UserPolicyEntities {
|
||||
var r []madmin.UserPolicyEntities
|
||||
usersSet := set.CreateStringSet(users...)
|
||||
for user, mappedPolicy := range cache.iamUserPolicyMap {
|
||||
if !isLDAPUserDN(user) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !usersSet.IsEmpty() && !usersSet.Contains(user) {
|
||||
continue
|
||||
}
|
||||
|
||||
ps := mappedPolicy.toSlice()
|
||||
sort.Strings(ps)
|
||||
r = append(r, madmin.UserPolicyEntities{
|
||||
User: user,
|
||||
Policies: ps,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(r, func(i, j int) bool {
|
||||
return r[i].User < r[j].User
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Assumes store is locked by caller. If groups is empty, returns all group mappings.
|
||||
func (store *IAMStoreSys) listLDAPGroupPolicyMappings(cache *iamCache, groups []string,
|
||||
isLDAPGroupDN func(string) bool,
|
||||
) []madmin.GroupPolicyEntities {
|
||||
var r []madmin.GroupPolicyEntities
|
||||
groupsSet := set.CreateStringSet(groups...)
|
||||
for group, mappedPolicy := range cache.iamGroupPolicyMap {
|
||||
if !isLDAPGroupDN(group) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !groupsSet.IsEmpty() && !groupsSet.Contains(group) {
|
||||
continue
|
||||
}
|
||||
|
||||
ps := mappedPolicy.toSlice()
|
||||
sort.Strings(ps)
|
||||
r = append(r, madmin.GroupPolicyEntities{
|
||||
Group: group,
|
||||
Policies: ps,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(r, func(i, j int) bool {
|
||||
return r[i].Group < r[j].Group
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Assumes store is locked by caller. If policies is empty, returns all policy mappings.
|
||||
func (store *IAMStoreSys) listLDAPPolicyMappings(cache *iamCache, policy []string,
|
||||
isLDAPUserDN, isLDAPGroupDN func(string) bool,
|
||||
) []madmin.PolicyEntities {
|
||||
queryPolSet := set.CreateStringSet(policy...)
|
||||
|
||||
policyToUsersMap := make(map[string]set.StringSet)
|
||||
for user, mappedPolicy := range cache.iamUserPolicyMap {
|
||||
if !isLDAPUserDN(user) {
|
||||
continue
|
||||
}
|
||||
|
||||
commonPolicySet := mappedPolicy.policySet()
|
||||
if !queryPolSet.IsEmpty() {
|
||||
commonPolicySet = commonPolicySet.Intersection(queryPolSet)
|
||||
}
|
||||
for _, policy := range commonPolicySet.ToSlice() {
|
||||
s, ok := policyToUsersMap[policy]
|
||||
if !ok {
|
||||
policyToUsersMap[policy] = set.CreateStringSet(user)
|
||||
} else {
|
||||
s.Add(user)
|
||||
policyToUsersMap[policy] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
policyToGroupsMap := make(map[string]set.StringSet)
|
||||
for group, mappedPolicy := range cache.iamGroupPolicyMap {
|
||||
if !isLDAPGroupDN(group) {
|
||||
continue
|
||||
}
|
||||
|
||||
commonPolicySet := mappedPolicy.policySet()
|
||||
if !queryPolSet.IsEmpty() {
|
||||
commonPolicySet = commonPolicySet.Intersection(queryPolSet)
|
||||
}
|
||||
for _, policy := range commonPolicySet.ToSlice() {
|
||||
s, ok := policyToUsersMap[policy]
|
||||
if !ok {
|
||||
policyToGroupsMap[policy] = set.CreateStringSet(group)
|
||||
} else {
|
||||
s.Add(group)
|
||||
policyToGroupsMap[policy] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m := make(map[string]madmin.PolicyEntities, len(policyToGroupsMap))
|
||||
for policy, groups := range policyToGroupsMap {
|
||||
s := groups.ToSlice()
|
||||
sort.Strings(s)
|
||||
m[policy] = madmin.PolicyEntities{
|
||||
Policy: policy,
|
||||
Groups: s,
|
||||
}
|
||||
}
|
||||
for policy, users := range policyToUsersMap {
|
||||
s := users.ToSlice()
|
||||
sort.Strings(s)
|
||||
|
||||
// Update existing value in map
|
||||
pe := m[policy]
|
||||
pe.Policy = policy
|
||||
pe.Users = s
|
||||
m[policy] = pe
|
||||
}
|
||||
|
||||
policyEntities := make([]madmin.PolicyEntities, 0, len(m))
|
||||
for _, v := range m {
|
||||
policyEntities = append(policyEntities, v)
|
||||
}
|
||||
|
||||
sort.Slice(policyEntities, func(i, j int) bool {
|
||||
return policyEntities[i].Policy < policyEntities[j].Policy
|
||||
})
|
||||
|
||||
return policyEntities
|
||||
}
|
||||
|
||||
// ListLDAPPolicyMappings - return LDAP users/groups mapped to policies.
|
||||
func (store *IAMStoreSys) ListLDAPPolicyMappings(q madmin.PolicyEntitiesQuery,
|
||||
isLDAPUserDN, isLDAPGroupDN func(string) bool,
|
||||
) madmin.PolicyEntitiesResult {
|
||||
cache := store.rlock()
|
||||
defer store.runlock()
|
||||
|
||||
var result madmin.PolicyEntitiesResult
|
||||
|
||||
isAllPoliciesQuery := len(q.Users) == 0 && len(q.Groups) == 0 && len(q.Policy) == 0
|
||||
|
||||
if len(q.Users) > 0 {
|
||||
result.UserMappings = store.listLDAPUserPolicyMappings(cache, q.Users, isLDAPUserDN)
|
||||
}
|
||||
if len(q.Groups) > 0 {
|
||||
result.GroupMappings = store.listLDAPGroupPolicyMappings(cache, q.Groups, isLDAPGroupDN)
|
||||
}
|
||||
if len(q.Policy) > 0 || isAllPoliciesQuery {
|
||||
result.PolicyMappings = store.listLDAPPolicyMappings(cache, q.Policy, isLDAPUserDN, isLDAPGroupDN)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetUsersWithMappedPolicies - safely returns the name of access keys with associated policies
|
||||
func (store *IAMStoreSys) GetUsersWithMappedPolicies() map[string]string {
|
||||
cache := store.rlock()
|
||||
|
||||
20
cmd/iam.go
20
cmd/iam.go
@@ -786,6 +786,26 @@ func (sys *IAMSys) ListLDAPUsers(ctx context.Context) (map[string]madmin.UserInf
|
||||
}
|
||||
}
|
||||
|
||||
// QueryLDAPPolicyEntities - queries policy associations for LDAP users/groups/policies.
|
||||
func (sys *IAMSys) QueryLDAPPolicyEntities(ctx context.Context, q madmin.PolicyEntitiesQuery) (*madmin.PolicyEntitiesResult, error) {
|
||||
if !sys.Initialized() {
|
||||
return nil, errServerNotInitialized
|
||||
}
|
||||
|
||||
if sys.usersSysType != LDAPUsersSysType {
|
||||
return nil, errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
select {
|
||||
case <-sys.configLoaded:
|
||||
pe := sys.store.ListLDAPPolicyMappings(q, sys.ldapConfig.IsLDAPUserDN, sys.ldapConfig.IsLDAPGroupDN)
|
||||
pe.Timestamp = UTCNow()
|
||||
return &pe, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// IsTempUser - returns if given key is a temporary user.
|
||||
func (sys *IAMSys) IsTempUser(name string) (bool, string, error) {
|
||||
if !sys.Initialized() {
|
||||
|
||||
Reference in New Issue
Block a user