mirror of
https://github.com/minio/minio.git
synced 2025-03-31 09:43:43 -04:00
fix: IAM import/export: remove sts group handling (#19422)
There are no separate STS group mappings to be handled. Also add tests for basic import/export sanity.
This commit is contained in:
parent
91f91d8f47
commit
8ff2a7a2b9
@ -1756,15 +1756,14 @@ func (a adminAPIHandlers) AttachDetachPolicyBuiltin(w http.ResponseWriter, r *ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
allPoliciesFile = "policies.json"
|
allPoliciesFile = "policies.json"
|
||||||
allUsersFile = "users.json"
|
allUsersFile = "users.json"
|
||||||
allGroupsFile = "groups.json"
|
allGroupsFile = "groups.json"
|
||||||
allSvcAcctsFile = "svcaccts.json"
|
allSvcAcctsFile = "svcaccts.json"
|
||||||
userPolicyMappingsFile = "user_mappings.json"
|
userPolicyMappingsFile = "user_mappings.json"
|
||||||
groupPolicyMappingsFile = "group_mappings.json"
|
groupPolicyMappingsFile = "group_mappings.json"
|
||||||
stsUserPolicyMappingsFile = "stsuser_mappings.json"
|
stsUserPolicyMappingsFile = "stsuser_mappings.json"
|
||||||
stsGroupPolicyMappingsFile = "stsgroup_mappings.json"
|
iamAssetsDir = "iam-assets"
|
||||||
iamAssetsDir = "iam-assets"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExportIAMHandler - exports all iam info as a zipped file
|
// ExportIAMHandler - exports all iam info as a zipped file
|
||||||
@ -1813,7 +1812,6 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
userPolicyMappingsFile,
|
userPolicyMappingsFile,
|
||||||
groupPolicyMappingsFile,
|
groupPolicyMappingsFile,
|
||||||
stsUserPolicyMappingsFile,
|
stsUserPolicyMappingsFile,
|
||||||
stsGroupPolicyMappingsFile,
|
|
||||||
}
|
}
|
||||||
for _, f := range iamFiles {
|
for _, f := range iamFiles {
|
||||||
iamFile := pathJoin(iamAssetsDir, f)
|
iamFile := pathJoin(iamAssetsDir, f)
|
||||||
@ -1985,22 +1983,6 @@ func (a adminAPIHandlers) ExportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case stsGroupPolicyMappingsFile:
|
|
||||||
groupPolicyMap := xsync.NewMapOf[string, MappedPolicy]()
|
|
||||||
err := globalIAMSys.store.loadMappedPolicies(ctx, stsUser, true, groupPolicyMap)
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
grpPolData, err := json.Marshal(mappedPoliciesToMap(groupPolicyMap))
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = rawDataFn(bytes.NewReader(grpPolData), iamFile, len(grpPolData)); err != nil {
|
|
||||||
writeErrorResponse(ctx, w, exportError(ctx, err, iamFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2391,35 +2373,6 @@ func (a adminAPIHandlers) ImportIAM(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// import sts group policy mappings
|
|
||||||
{
|
|
||||||
f, err := zr.Open(pathJoin(iamAssetsDir, stsGroupPolicyMappingsFile))
|
|
||||||
switch {
|
|
||||||
case errors.Is(err, os.ErrNotExist):
|
|
||||||
case err != nil:
|
|
||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsGroupPolicyMappingsFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
defer f.Close()
|
|
||||||
var grpPolicyMap map[string]MappedPolicy
|
|
||||||
data, err := io.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrInvalidRequest, err, stsGroupPolicyMappingsFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(data, &grpPolicyMap); err != nil {
|
|
||||||
writeErrorResponseJSON(ctx, w, importErrorWithAPIErr(ctx, ErrAdminConfigBadJSON, err, stsGroupPolicyMappingsFile, ""), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for g, pm := range grpPolicyMap {
|
|
||||||
if _, err := globalIAMSys.PolicyDBSet(ctx, g, pm.Policies, unknownIAMUserType, true); err != nil {
|
|
||||||
writeErrorResponseJSON(ctx, w, importError(ctx, err, stsGroupPolicyMappingsFile, g), r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addExpirationToCondValues(exp *time.Time, condValues map[string][]string) {
|
func addExpirationToCondValues(exp *time.Time, condValues map[string][]string) {
|
||||||
|
@ -18,9 +18,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -752,6 +755,172 @@ func TestIAMWithLDAPNonNormalizedBaseDNConfigServerSuite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIAMExportImportWithLDAP(t *testing.T) {
|
||||||
|
for i, testCase := range iamTestSuites {
|
||||||
|
t.Run(
|
||||||
|
fmt.Sprintf("Test: %d, ServerType: %s", i+1, testCase.ServerTypeDescription),
|
||||||
|
func(t *testing.T) {
|
||||||
|
c := &check{t, testCase.serverType}
|
||||||
|
suite := testCase
|
||||||
|
|
||||||
|
ldapServer := os.Getenv(EnvTestLDAPServer)
|
||||||
|
if ldapServer == "" {
|
||||||
|
c.Skipf("Skipping LDAP test as no LDAP server is provided via %s", EnvTestLDAPServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
iamTestContentCases := []iamTestContent{
|
||||||
|
{
|
||||||
|
policies: map[string][]byte{
|
||||||
|
"mypolicy": []byte(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject","s3:ListBucket","s3:PutObject"],"Resource":["arn:aws:s3:::mybucket/*"]}]}`),
|
||||||
|
},
|
||||||
|
ldapUserPolicyMappings: map[string][]string{
|
||||||
|
"uid=dillon,ou=people,ou=swengg,dc=min,dc=io": {"mypolicy"},
|
||||||
|
"uid=liza,ou=people,ou=swengg,dc=min,dc=io": {"consoleAdmin"},
|
||||||
|
},
|
||||||
|
ldapGroupPolicyMappings: map[string][]string{
|
||||||
|
"cn=projectb,ou=groups,ou=swengg,dc=min,dc=io": {"mypolicy"},
|
||||||
|
"cn=projecta,ou=groups,ou=swengg,dc=min,dc=io": {"consoleAdmin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for caseNum, content := range iamTestContentCases {
|
||||||
|
suite.SetUpSuite(c)
|
||||||
|
suite.SetUpLDAP(c, ldapServer)
|
||||||
|
exportedContent := suite.TestIAMExport(c, caseNum, content)
|
||||||
|
suite.TearDownSuite(c)
|
||||||
|
suite.SetUpSuite(c)
|
||||||
|
suite.SetUpLDAP(c, ldapServer)
|
||||||
|
suite.TestIAMImport(c, exportedContent, caseNum, content)
|
||||||
|
suite.TearDownSuite(c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type iamTestContent struct {
|
||||||
|
policies map[string][]byte
|
||||||
|
ldapUserPolicyMappings map[string][]string
|
||||||
|
ldapGroupPolicyMappings map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestSuiteIAM) TestIAMExport(c *check, caseNum int, content iamTestContent) []byte {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
for policy, policyBytes := range content.policies {
|
||||||
|
err := s.adm.AddCannedPolicy(ctx, policy, policyBytes)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("export %d: policy add error: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for userDN, policies := range content.ldapUserPolicyMappings {
|
||||||
|
_, err := s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
|
||||||
|
Policies: policies,
|
||||||
|
User: userDN,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("export %d: Unable to attach policy: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for groupDN, policies := range content.ldapGroupPolicyMappings {
|
||||||
|
_, err := s.adm.AttachPolicyLDAP(ctx, madmin.PolicyAssociationReq{
|
||||||
|
Policies: policies,
|
||||||
|
Group: groupDN,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("export %d: Unable to attach group policy: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentReader, err := s.adm.ExportIAM(ctx)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("export %d: Unable to export IAM: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
defer contentReader.Close()
|
||||||
|
|
||||||
|
expContent, err := io.ReadAll(contentReader)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("export %d: Unable to read exported content: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expContent
|
||||||
|
}
|
||||||
|
|
||||||
|
type dummyCloser struct {
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummyCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
func (s *TestSuiteIAM) TestIAMImport(c *check, exportedContent []byte, caseNum int, content iamTestContent) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
dummyCloser := dummyCloser{bytes.NewReader(exportedContent)}
|
||||||
|
err := s.adm.ImportIAM(ctx, dummyCloser)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("import %d: Unable to import IAM: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotContent := iamTestContent{
|
||||||
|
policies: make(map[string][]byte),
|
||||||
|
ldapUserPolicyMappings: make(map[string][]string),
|
||||||
|
ldapGroupPolicyMappings: make(map[string][]string),
|
||||||
|
}
|
||||||
|
policyContentMap, err := s.adm.ListCannedPolicies(ctx)
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("import %d: Unable to list policies: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
defaultCannedPolicies := set.CreateStringSet("consoleAdmin", "readwrite", "readonly",
|
||||||
|
"diagnostics", "writeonly")
|
||||||
|
for policy, policyBytes := range policyContentMap {
|
||||||
|
if defaultCannedPolicies.Contains(policy) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gotContent.policies[policy] = policyBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
policyQueryRes, err := s.adm.GetLDAPPolicyEntities(ctx, madmin.PolicyEntitiesQuery{})
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("import %d: Unable to get policy entities: %v", caseNum, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entity := range policyQueryRes.PolicyMappings {
|
||||||
|
m := gotContent.ldapUserPolicyMappings
|
||||||
|
for _, user := range entity.Users {
|
||||||
|
m[user] = append(m[user], entity.Policy)
|
||||||
|
}
|
||||||
|
m = gotContent.ldapGroupPolicyMappings
|
||||||
|
for _, group := range entity.Groups {
|
||||||
|
m[group] = append(m[group], entity.Policy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// We don't compare the values of the canned policies because server is
|
||||||
|
// re-encoding them. (FIXME?)
|
||||||
|
for k := range content.policies {
|
||||||
|
content.policies[k] = nil
|
||||||
|
gotContent.policies[k] = nil
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(content.policies, gotContent.policies) {
|
||||||
|
c.Fatalf("import %d: policies mismatch: expected: %v, got: %v", caseNum, content.policies, gotContent.policies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(content.ldapUserPolicyMappings, gotContent.ldapUserPolicyMappings) {
|
||||||
|
c.Fatalf("import %d: user policy mappings mismatch: expected: %v, got: %v", caseNum, content.ldapUserPolicyMappings, gotContent.ldapUserPolicyMappings)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(content.ldapGroupPolicyMappings, gotContent.ldapGroupPolicyMappings) {
|
||||||
|
c.Fatalf("import %d: group policy mappings mismatch: expected: %v, got: %v", caseNum, content.ldapGroupPolicyMappings, gotContent.ldapGroupPolicyMappings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TestSuiteIAM) TestLDAPSTS(c *check) {
|
func (s *TestSuiteIAM) TestLDAPSTS(c *check) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user