mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-03 10:37:35 +01:00
s3api: refactor embedded IAM to use CredentialManager directly
This commit is contained in:
1 parent
3a14821223
commit
9012f27af8
2 files changed
+30
-65
No files matched your search
@@ -35,9 +35,7 @@ type EmbeddedIamApi struct {
|
||||
iam *IdentityAccessManagement
|
||||
policyLock sync.RWMutex
|
||||
// Test hook
|
||||
getS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error
|
||||
putS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error
|
||||
reloadConfigurationFunc func() error
|
||||
reloadConfigurationFunc func() error
|
||||
}
|
||||
|
||||
// NewEmbeddedIamApi creates a new embedded IAM API handler.
|
||||
@@ -167,27 +165,6 @@ func (e *EmbeddedIamApi) writeIamErrorResponse(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
// GetS3ApiConfiguration loads the S3 API configuration from the credential manager.
|
||||
func (e *EmbeddedIamApi) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
if e.getS3ApiConfigurationFunc != nil {
|
||||
return e.getS3ApiConfigurationFunc(s3cfg)
|
||||
}
|
||||
config, err := e.credentialManager.LoadConfiguration(context.Background())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load configuration: %w", err)
|
||||
}
|
||||
proto.Merge(s3cfg, config)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutS3ApiConfiguration saves the S3 API configuration to the credential manager.
|
||||
func (e *EmbeddedIamApi) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
if e.putS3ApiConfigurationFunc != nil {
|
||||
return e.putS3ApiConfigurationFunc(s3cfg)
|
||||
}
|
||||
return e.credentialManager.SaveConfiguration(context.Background(), s3cfg)
|
||||
}
|
||||
|
||||
// ReloadConfiguration reloads the IAM configuration from the credential manager.
|
||||
func (e *EmbeddedIamApi) ReloadConfiguration() error {
|
||||
if e.reloadConfigurationFunc != nil {
|
||||
@@ -1049,8 +1026,14 @@ func (e *EmbeddedIamApi) ExecuteAction(values url.Values) (interface{}, *iamErro
|
||||
defer e.policyLock.Unlock()
|
||||
|
||||
s3cfg := &iam_pb.S3ApiConfiguration{}
|
||||
if err := e.GetS3ApiConfiguration(s3cfg); err != nil && !errors.Is(err, filer_pb.ErrNotFound) {
|
||||
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrInternalError).Code, Error: fmt.Errorf("failed to get s3 api configuration: %v", err)}
|
||||
|
||||
config, err := e.credentialManager.LoadConfiguration(context.Background())
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), filer_pb.ErrNotFound.Error()) {
|
||||
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrInternalError).Code, Error: fmt.Errorf("failed to get s3 api configuration: %v", err)}
|
||||
}
|
||||
} else {
|
||||
proto.Merge(s3cfg, config)
|
||||
}
|
||||
|
||||
glog.V(4).Infof("IAM ExecuteAction: %+v", values)
|
||||
@@ -1165,7 +1148,7 @@ func (e *EmbeddedIamApi) ExecuteAction(values url.Values) (interface{}, *iamErro
|
||||
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrNotImplemented).Code, Error: errors.New(s3err.GetAPIError(s3err.ErrNotImplemented).Description)}
|
||||
}
|
||||
if changed {
|
||||
if err := e.PutS3ApiConfiguration(s3cfg); err != nil {
|
||||
if err := e.credentialManager.SaveConfiguration(context.Background(), s3cfg); err != nil {
|
||||
iamErr = &iamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
return nil, iamErr
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
@@ -16,6 +17,8 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/seaweedfs/seaweedfs/weed/credential"
|
||||
_ "github.com/seaweedfs/seaweedfs/weed/credential/memory"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
@@ -36,40 +39,18 @@ func NewEmbeddedIamApiForTest() *EmbeddedIamApiForTest {
|
||||
},
|
||||
mockConfig: &iam_pb.S3ApiConfiguration{},
|
||||
}
|
||||
e.getS3ApiConfigurationFunc = func(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
if e.mockConfig != nil {
|
||||
cloned := proto.Clone(e.mockConfig).(*iam_pb.S3ApiConfiguration)
|
||||
proto.Merge(s3cfg, cloned)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
e.putS3ApiConfigurationFunc = func(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
e.mockConfig = proto.Clone(s3cfg).(*iam_pb.S3ApiConfiguration)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initialize credential manager with memory store for ExecuteAction tests
|
||||
cm, _ := credential.NewCredentialManager("memory", nil, "")
|
||||
e.credentialManager = cm
|
||||
e.EmbeddedIamApi.iam.credentialManager = cm // Also set on internal IAM if needed (though EmbeddedIamApi has its own pointer)
|
||||
|
||||
e.reloadConfigurationFunc = func() error {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Override GetS3ApiConfiguration for testing
|
||||
func (e *EmbeddedIamApiForTest) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
// Use proto.Clone for proper deep copy semantics
|
||||
if e.mockConfig != nil {
|
||||
cloned := proto.Clone(e.mockConfig).(*iam_pb.S3ApiConfiguration)
|
||||
proto.Merge(s3cfg, cloned)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Override PutS3ApiConfiguration for testing
|
||||
func (e *EmbeddedIamApiForTest) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
// Use proto.Clone for proper deep copy semantics
|
||||
e.mockConfig = proto.Clone(s3cfg).(*iam_pb.S3ApiConfiguration)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DoActions handles IAM API actions for testing
|
||||
func (e *EmbeddedIamApiForTest) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
@@ -78,9 +59,10 @@ func (e *EmbeddedIamApiForTest) DoActions(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
values := r.PostForm
|
||||
s3cfg := &iam_pb.S3ApiConfiguration{}
|
||||
if err := e.GetS3ApiConfiguration(s3cfg); err != nil {
|
||||
http.Error(w, "Internal error", http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
if e.mockConfig != nil {
|
||||
cloned := proto.Clone(e.mockConfig).(*iam_pb.S3ApiConfiguration)
|
||||
proto.Merge(s3cfg, cloned)
|
||||
}
|
||||
|
||||
var response interface{}
|
||||
@@ -176,10 +158,7 @@ func (e *EmbeddedIamApiForTest) DoActions(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
if changed {
|
||||
if err := e.PutS3ApiConfiguration(s3cfg); err != nil {
|
||||
http.Error(w, "Internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
e.mockConfig = proto.Clone(s3cfg).(*iam_pb.S3ApiConfiguration)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
@@ -1699,7 +1678,10 @@ func TestEmbeddedIamExecuteAction(t *testing.T) {
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "ExecuteActionUser", *createResp.CreateUserResult.User.UserName)
|
||||
|
||||
// Verify persistence
|
||||
assert.Len(t, api.mockConfig.Identities, 1)
|
||||
assert.Equal(t, "ExecuteActionUser", api.mockConfig.Identities[0].Name)
|
||||
// Verify persistence via credentialManager
|
||||
// The new logic saves to credentialManager, not mockConfig (which is only for DoActions override)
|
||||
config, err := api.credentialManager.LoadConfiguration(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, config.Identities, 1)
|
||||
assert.Equal(t, "ExecuteActionUser", config.Identities[0].Name)
|
||||
}
|
||||
Reference in new issue
Block a user