snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
659
weed/iamapi/iamapi_test.go
Normal file
659
weed/iamapi/iamapi_test.go
Normal file
@@ -0,0 +1,659 @@
|
||||
package iamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/jinzhu/copier"
|
||||
"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"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/request_id"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var GetS3ApiConfiguration func(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||
var PutS3ApiConfiguration func(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||
var GetPolicies func(policies *Policies) (err error)
|
||||
var PutPolicies func(policies *Policies) (err error)
|
||||
|
||||
var s3config = iam_pb.S3ApiConfiguration{}
|
||||
var policiesFile = Policies{Policies: make(map[string]policy_engine.PolicyDocument)}
|
||||
var ias = IamApiServer{s3ApiConfig: iamS3ApiConfigureMock{}}
|
||||
|
||||
type iamS3ApiConfigureMock struct{}
|
||||
|
||||
func (iam iamS3ApiConfigureMock) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||
_ = copier.Copy(&s3cfg.Identities, &s3config.Identities)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iam iamS3ApiConfigureMock) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||
_ = copier.Copy(&s3config.Identities, &s3cfg.Identities)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iam iamS3ApiConfigureMock) GetPolicies(policies *Policies) (err error) {
|
||||
_ = copier.Copy(&policies, &policiesFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (iam iamS3ApiConfigureMock) PutPolicies(policies *Policies) (err error) {
|
||||
_ = copier.Copy(&policiesFile, &policies)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestCreateUser(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
params := &iam.CreateUserInput{UserName: userName}
|
||||
req, _ := iam.New(session.New()).CreateUserRequest(params)
|
||||
_ = req.Build()
|
||||
out := CreateUserResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
//assert.Equal(t, out.XMLName, "lol")
|
||||
}
|
||||
|
||||
func TestListUsers(t *testing.T) {
|
||||
params := &iam.ListUsersInput{}
|
||||
req, _ := iam.New(session.New()).ListUsersRequest(params)
|
||||
_ = req.Build()
|
||||
out := ListUsersResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestListUsersRequestIdMatchesResponseHeader(t *testing.T) {
|
||||
params := &iam.ListUsersInput{}
|
||||
req, _ := iam.New(session.New()).ListUsersRequest(params)
|
||||
_ = req.Build()
|
||||
|
||||
out := ListUsersResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
headerRequestID := response.Header().Get(request_id.AmzRequestIDHeader)
|
||||
assert.NotEmpty(t, headerRequestID)
|
||||
assert.Equal(t, headerRequestID, extractRequestID(response))
|
||||
}
|
||||
|
||||
func TestListAccessKeys(t *testing.T) {
|
||||
svc := iam.New(session.New())
|
||||
params := &iam.ListAccessKeysInput{}
|
||||
req, _ := svc.ListAccessKeysRequest(params)
|
||||
_ = req.Build()
|
||||
out := ListAccessKeysResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestUpdateAccessKey(t *testing.T) {
|
||||
svc := iam.New(session.New())
|
||||
|
||||
createReq, _ := svc.CreateAccessKeyRequest(&iam.CreateAccessKeyInput{UserName: aws.String("Test")})
|
||||
_ = createReq.Build()
|
||||
createOut := CreateAccessKeyResponse{}
|
||||
response, err := executeRequest(createReq.HTTPRequest, createOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
var createResp CreateAccessKeyResponse
|
||||
err = xml.Unmarshal(response.Body.Bytes(), &createResp)
|
||||
assert.Equal(t, nil, err)
|
||||
accessKeyId := createResp.CreateAccessKeyResult.AccessKey.AccessKeyId
|
||||
if accessKeyId == nil {
|
||||
t.Fatalf("expected access key id to be set")
|
||||
}
|
||||
|
||||
updateReq, _ := svc.UpdateAccessKeyRequest(&iam.UpdateAccessKeyInput{
|
||||
UserName: aws.String("Test"),
|
||||
AccessKeyId: accessKeyId,
|
||||
Status: aws.String("Inactive"),
|
||||
})
|
||||
_ = updateReq.Build()
|
||||
updateOut := UpdateAccessKeyResponse{}
|
||||
response, err = executeRequest(updateReq.HTTPRequest, updateOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
listReq, _ := svc.ListAccessKeysRequest(&iam.ListAccessKeysInput{UserName: aws.String("Test")})
|
||||
_ = listReq.Build()
|
||||
listOut := ListAccessKeysResponse{}
|
||||
response, err = executeRequest(listReq.HTTPRequest, listOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
var listResp ListAccessKeysResponse
|
||||
err = xml.Unmarshal(response.Body.Bytes(), &listResp)
|
||||
assert.Equal(t, nil, err)
|
||||
found := false
|
||||
for _, key := range listResp.ListAccessKeysResult.AccessKeyMetadata {
|
||||
if key.AccessKeyId != nil && *key.AccessKeyId == *accessKeyId {
|
||||
found = true
|
||||
if assert.NotNil(t, key.Status) {
|
||||
assert.Equal(t, "Inactive", *key.Status)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
}
|
||||
|
||||
func TestGetUser(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
params := &iam.GetUserInput{UserName: userName}
|
||||
req, _ := iam.New(session.New()).GetUserRequest(params)
|
||||
_ = req.Build()
|
||||
out := GetUserResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
// Todo flat statement
|
||||
func TestCreatePolicy(t *testing.T) {
|
||||
params := &iam.CreatePolicyInput{
|
||||
PolicyName: aws.String("S3-read-only-example-bucket"),
|
||||
PolicyDocument: aws.String(`
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:Get*",
|
||||
"s3:List*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET",
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
}
|
||||
req, _ := iam.New(session.New()).CreatePolicyRequest(params)
|
||||
_ = req.Build()
|
||||
out := CreatePolicyResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
// isolatedIamConfig is a self-contained IamS3ApiConfig backing whose state lives
|
||||
// on the instance (not the package globals that executeRequest shares), so
|
||||
// policy-version tests stay order-independent under -shuffle.
|
||||
type isolatedIamConfig struct {
|
||||
identities []*iam_pb.Identity
|
||||
groups []*iam_pb.Group
|
||||
policies Policies
|
||||
}
|
||||
|
||||
func newIsolatedIamServer() *IamApiServer {
|
||||
return &IamApiServer{s3ApiConfig: &isolatedIamConfig{
|
||||
policies: Policies{Policies: make(map[string]policy_engine.PolicyDocument)},
|
||||
}}
|
||||
}
|
||||
|
||||
func (m *isolatedIamConfig) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
_ = copier.Copy(&s3cfg.Identities, &m.identities)
|
||||
_ = copier.Copy(&s3cfg.Groups, &m.groups)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *isolatedIamConfig) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
_ = copier.Copy(&m.identities, &s3cfg.Identities)
|
||||
_ = copier.Copy(&m.groups, &s3cfg.Groups)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *isolatedIamConfig) GetPolicies(policies *Policies) error {
|
||||
_ = copier.Copy(&policies, &m.policies)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *isolatedIamConfig) PutPolicies(policies *Policies) error {
|
||||
_ = copier.Copy(&m.policies, &policies)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestCreatePolicyVersion reproduces issue #9785: the AWS Terraform provider
|
||||
// updates a managed policy in place via CreatePolicyVersion, which previously
|
||||
// returned 501 NotImplemented. The whole read/update surface Terraform relies on
|
||||
// is exercised here: GetPolicy (DefaultVersionId), CreatePolicyVersion,
|
||||
// GetPolicyVersion and ListPolicyVersions.
|
||||
func TestCreatePolicyVersion(t *testing.T) {
|
||||
srv := newIsolatedIamServer()
|
||||
svc := iam.New(session.New())
|
||||
policyName := "tf-managed-policy"
|
||||
policyArn := aws.String("arn:aws:iam:::policy/" + policyName)
|
||||
|
||||
// Create the managed policy.
|
||||
createReq, _ := svc.CreatePolicyRequest(&iam.CreatePolicyInput{
|
||||
PolicyName: aws.String(policyName),
|
||||
PolicyDocument: aws.String(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*","s3:List*"],"Resource":["arn:aws:s3:::EXAMPLE-BUCKET"]}]}`),
|
||||
})
|
||||
_ = createReq.Build()
|
||||
resp, err := executeRequestWith(srv, createReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
|
||||
// Update it in place (what Terraform does). This used to return 501.
|
||||
cpvReq, _ := svc.CreatePolicyVersionRequest(&iam.CreatePolicyVersionInput{
|
||||
PolicyArn: policyArn,
|
||||
PolicyDocument: aws.String(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*"],"Resource":["arn:aws:s3:::EXAMPLE-BUCKET"]}]}`),
|
||||
SetAsDefault: aws.Bool(true),
|
||||
})
|
||||
_ = cpvReq.Build()
|
||||
resp, err = executeRequestWith(srv, cpvReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
var cpvResp CreatePolicyVersionResponse
|
||||
require.NoError(t, xml.Unmarshal(resp.Body.Bytes(), &cpvResp))
|
||||
require.NotNil(t, cpvResp.CreatePolicyVersionResult.PolicyVersion.VersionId)
|
||||
assert.Equal(t, "v1", *cpvResp.CreatePolicyVersionResult.PolicyVersion.VersionId)
|
||||
require.NotNil(t, cpvResp.CreatePolicyVersionResult.PolicyVersion.IsDefaultVersion)
|
||||
assert.True(t, *cpvResp.CreatePolicyVersionResult.PolicyVersion.IsDefaultVersion)
|
||||
|
||||
// GetPolicy must advertise a default version so Terraform's read can chain
|
||||
// into GetPolicyVersion.
|
||||
gpReq, _ := svc.GetPolicyRequest(&iam.GetPolicyInput{PolicyArn: policyArn})
|
||||
_ = gpReq.Build()
|
||||
resp, err = executeRequestWith(srv, gpReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
var gpResp GetPolicyResponse
|
||||
require.NoError(t, xml.Unmarshal(resp.Body.Bytes(), &gpResp))
|
||||
require.NotNil(t, gpResp.GetPolicyResult.Policy.DefaultVersionId)
|
||||
assert.Equal(t, "v1", *gpResp.GetPolicyResult.Policy.DefaultVersionId)
|
||||
|
||||
// GetPolicyVersion must return the updated document (Get* only, List* gone).
|
||||
gpvReq, _ := svc.GetPolicyVersionRequest(&iam.GetPolicyVersionInput{PolicyArn: policyArn, VersionId: aws.String("v1")})
|
||||
_ = gpvReq.Build()
|
||||
resp, err = executeRequestWith(srv, gpvReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
var gpvResp GetPolicyVersionResponse
|
||||
require.NoError(t, xml.Unmarshal(resp.Body.Bytes(), &gpvResp))
|
||||
require.NotNil(t, gpvResp.GetPolicyVersionResult.PolicyVersion.Document)
|
||||
assert.Contains(t, *gpvResp.GetPolicyVersionResult.PolicyVersion.Document, "s3:Get*")
|
||||
assert.NotContains(t, *gpvResp.GetPolicyVersionResult.PolicyVersion.Document, "s3:List*")
|
||||
|
||||
// ListPolicyVersions must report exactly the single default version.
|
||||
lpvReq, _ := svc.ListPolicyVersionsRequest(&iam.ListPolicyVersionsInput{PolicyArn: policyArn})
|
||||
_ = lpvReq.Build()
|
||||
resp, err = executeRequestWith(srv, lpvReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
var lpvResp ListPolicyVersionsResponse
|
||||
require.NoError(t, xml.Unmarshal(resp.Body.Bytes(), &lpvResp))
|
||||
require.Len(t, lpvResp.ListPolicyVersionsResult.Versions, 1)
|
||||
assert.Equal(t, "v1", *lpvResp.ListPolicyVersionsResult.Versions[0].VersionId)
|
||||
}
|
||||
|
||||
// TestCreatePolicyVersionMissingPolicy verifies a NoSuchEntity (404) when the
|
||||
// target policy does not exist, matching AWS.
|
||||
func TestCreatePolicyVersionMissingPolicy(t *testing.T) {
|
||||
srv := newIsolatedIamServer()
|
||||
req, _ := iam.New(session.New()).CreatePolicyVersionRequest(&iam.CreatePolicyVersionInput{
|
||||
PolicyArn: aws.String("arn:aws:iam:::policy/does-not-exist"),
|
||||
PolicyDocument: aws.String(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*"],"Resource":["arn:aws:s3:::EXAMPLE-BUCKET"]}]}`),
|
||||
SetAsDefault: aws.Bool(true),
|
||||
})
|
||||
_ = req.Build()
|
||||
resp, err := executeRequestWith(srv, req.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusNotFound, resp.Code)
|
||||
code, _ := extractErrorCodeAndMessage(resp)
|
||||
assert.Equal(t, "NoSuchEntity", code)
|
||||
}
|
||||
|
||||
// TestCreatePolicyVersionRequiresSetAsDefault verifies that, given the
|
||||
// single-version model, a request that does not set SetAsDefault=true is
|
||||
// rejected rather than silently overwriting the active document.
|
||||
func TestCreatePolicyVersionRequiresSetAsDefault(t *testing.T) {
|
||||
srv := newIsolatedIamServer()
|
||||
svc := iam.New(session.New())
|
||||
policyArn := aws.String("arn:aws:iam:::policy/tf-managed-policy")
|
||||
|
||||
createReq, _ := svc.CreatePolicyRequest(&iam.CreatePolicyInput{
|
||||
PolicyName: aws.String("tf-managed-policy"),
|
||||
PolicyDocument: aws.String(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Get*"],"Resource":["arn:aws:s3:::EXAMPLE-BUCKET"]}]}`),
|
||||
})
|
||||
_ = createReq.Build()
|
||||
resp, err := executeRequestWith(srv, createReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
|
||||
// SetAsDefault omitted (defaults to false) must be rejected.
|
||||
cpvReq, _ := svc.CreatePolicyVersionRequest(&iam.CreatePolicyVersionInput{
|
||||
PolicyArn: policyArn,
|
||||
PolicyDocument: aws.String(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:Put*"],"Resource":["arn:aws:s3:::EXAMPLE-BUCKET"]}]}`),
|
||||
})
|
||||
_ = cpvReq.Build()
|
||||
resp, err = executeRequestWith(srv, cpvReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusBadRequest, resp.Code)
|
||||
code, _ := extractErrorCodeAndMessage(resp)
|
||||
assert.Equal(t, "InvalidInput", code)
|
||||
|
||||
// The live document must be untouched (still Get*, not Put*).
|
||||
gpvReq, _ := svc.GetPolicyVersionRequest(&iam.GetPolicyVersionInput{PolicyArn: policyArn, VersionId: aws.String("v1")})
|
||||
_ = gpvReq.Build()
|
||||
resp, err = executeRequestWith(srv, gpvReq.HTTPRequest, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
var gpvResp GetPolicyVersionResponse
|
||||
require.NoError(t, xml.Unmarshal(resp.Body.Bytes(), &gpvResp))
|
||||
require.NotNil(t, gpvResp.GetPolicyVersionResult.PolicyVersion.Document)
|
||||
assert.Contains(t, *gpvResp.GetPolicyVersionResult.PolicyVersion.Document, "s3:Get*")
|
||||
assert.NotContains(t, *gpvResp.GetPolicyVersionResult.PolicyVersion.Document, "s3:Put*")
|
||||
}
|
||||
|
||||
func TestPutUserPolicy(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
params := &iam.PutUserPolicyInput{
|
||||
UserName: userName,
|
||||
PolicyName: aws.String("S3-read-only-example-bucket"),
|
||||
PolicyDocument: aws.String(
|
||||
`{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:Get*",
|
||||
"s3:List*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET",
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
}
|
||||
req, _ := iam.New(session.New()).PutUserPolicyRequest(params)
|
||||
_ = req.Build()
|
||||
out := PutUserPolicyResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestPutUserPolicyError(t *testing.T) {
|
||||
userName := aws.String("InvalidUser")
|
||||
params := &iam.PutUserPolicyInput{
|
||||
UserName: userName,
|
||||
PolicyName: aws.String("S3-read-only-example-bucket"),
|
||||
PolicyDocument: aws.String(
|
||||
`{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:Get*",
|
||||
"s3:List*"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET",
|
||||
"arn:aws:s3:::EXAMPLE-BUCKET/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`),
|
||||
}
|
||||
req, _ := iam.New(session.New()).PutUserPolicyRequest(params)
|
||||
_ = req.Build()
|
||||
response, err := executeRequest(req.HTTPRequest, nil)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusNotFound, response.Code)
|
||||
|
||||
expectedMessage := "the user with name InvalidUser cannot be found"
|
||||
expectedCode := "NoSuchEntity"
|
||||
|
||||
code, message := extractErrorCodeAndMessage(response)
|
||||
|
||||
assert.Equal(t, expectedMessage, message)
|
||||
assert.Equal(t, expectedCode, code)
|
||||
assert.Contains(t, response.Body.String(), "<RequestId>")
|
||||
assert.NotContains(t, response.Body.String(), "<ResponseMetadata>")
|
||||
assert.Equal(t, response.Header().Get(request_id.AmzRequestIDHeader), extractRequestID(response))
|
||||
}
|
||||
|
||||
func extractErrorCodeAndMessage(response *httptest.ResponseRecorder) (string, string) {
|
||||
pattern := `<Error><Code>(.*)</Code><Message>(.*)</Message><Type>(.*)</Type></Error>`
|
||||
re := regexp.MustCompile(pattern)
|
||||
|
||||
code := re.FindStringSubmatch(response.Body.String())[1]
|
||||
message := re.FindStringSubmatch(response.Body.String())[2]
|
||||
return code, message
|
||||
}
|
||||
|
||||
func extractRequestID(response *httptest.ResponseRecorder) string {
|
||||
re := regexp.MustCompile(`<RequestId>([^<]+)</RequestId>`)
|
||||
matches := re.FindStringSubmatch(response.Body.String())
|
||||
if len(matches) < 2 {
|
||||
return ""
|
||||
}
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
func TestGetUserPolicy(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
params := &iam.GetUserPolicyInput{UserName: userName, PolicyName: aws.String("S3-read-only-example-bucket")}
|
||||
req, _ := iam.New(session.New()).GetUserPolicyRequest(params)
|
||||
_ = req.Build()
|
||||
out := GetUserPolicyResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestUpdateUser(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
newUserName := aws.String("Test-New")
|
||||
params := &iam.UpdateUserInput{NewUserName: newUserName, UserName: userName}
|
||||
req, _ := iam.New(session.New()).UpdateUserRequest(params)
|
||||
_ = req.Build()
|
||||
out := UpdateUserResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
userName := aws.String("Test-New")
|
||||
params := &iam.DeleteUserInput{UserName: userName}
|
||||
req, _ := iam.New(session.New()).DeleteUserRequest(params)
|
||||
_ = req.Build()
|
||||
out := DeleteUserResponse{}
|
||||
response, err := executeRequest(req.HTTPRequest, out)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func executeRequest(req *http.Request, v interface{}) (*httptest.ResponseRecorder, error) {
|
||||
rr := httptest.NewRecorder()
|
||||
apiRouter := mux.NewRouter().SkipClean(true)
|
||||
apiRouter.Path("/").Methods(http.MethodPost).HandlerFunc(ias.DoActions)
|
||||
apiRouter.ServeHTTP(rr, req)
|
||||
return rr, xml.Unmarshal(rr.Body.Bytes(), &v)
|
||||
}
|
||||
|
||||
func TestHandleImplicitUsername(t *testing.T) {
|
||||
// Create a mock IamApiServer with credential store
|
||||
// The handleImplicitUsername function now looks up the username from the
|
||||
// credential store based on AccessKeyId, not from the region field in the auth header.
|
||||
// Note: Using obviously fake access keys to avoid CI secret scanner false positives
|
||||
|
||||
// Create IAM directly as struct literal (same pattern as other tests)
|
||||
iam := &s3api.IdentityAccessManagement{}
|
||||
|
||||
// Load test credentials - map access key to identity name
|
||||
testConfig := &iam_pb.S3ApiConfiguration{
|
||||
Identities: []*iam_pb.Identity{
|
||||
{
|
||||
Name: "testuser1",
|
||||
Credentials: []*iam_pb.Credential{
|
||||
{AccessKey: "AKIATESTFAKEKEY000001", SecretKey: "testsecretfake"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := iam.LoadS3ApiConfigurationFromBytes(mustMarshalJSON(t, testConfig))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load test config: %v", err)
|
||||
}
|
||||
|
||||
iama := &IamApiServer{
|
||||
iam: iam,
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
r *http.Request
|
||||
values url.Values
|
||||
userName string
|
||||
}{
|
||||
// No authorization header - should not set username
|
||||
{&http.Request{}, url.Values{}, ""},
|
||||
// Valid auth header with known access key - should look up and find "testuser1"
|
||||
{&http.Request{Header: http.Header{"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIATESTFAKEKEY000001/20220420/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=fakesignature0123456789abcdef"}}}, url.Values{}, "testuser1"},
|
||||
// Malformed auth header (no Credential=) - should not set username
|
||||
{&http.Request{Header: http.Header{"Authorization": []string{"AWS4-HMAC-SHA256 =AKIATESTFAKEKEY000001/20220420/test1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=fakesignature0123456789abcdef"}}}, url.Values{}, ""},
|
||||
// Unknown access key - should not set username
|
||||
{&http.Request{Header: http.Header{"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIATESTUNKNOWN000000/20220420/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=fakesignature0123456789abcdef"}}}, url.Values{}, ""},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
iama.handleImplicitUsername(test.r, test.values)
|
||||
if un := test.values.Get("UserName"); un != test.userName {
|
||||
t.Errorf("No.%d: Got: %v, Expected: %v", i, un, test.userName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustMarshalJSON(t *testing.T, v interface{}) []byte {
|
||||
t.Helper()
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal JSON: %v", err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// iamApiServerWithCredentialManager builds an IamApiServer backed by a real
|
||||
// in-memory credential store. Used for tests that exercise the targeted
|
||||
// credentialManager paths (e.g. CreateUser) instead of the legacy mock.
|
||||
func iamApiServerWithCredentialManager() (*IamApiServer, *credential.CredentialManager, *countingConfigSaver) {
|
||||
store := &memory.MemoryStore{}
|
||||
store.Initialize(nil, "")
|
||||
cm := &credential.CredentialManager{Store: store}
|
||||
|
||||
counter := &countingConfigSaver{cm: cm}
|
||||
iamInstance := &s3api.IdentityAccessManagement{}
|
||||
// Wire up the credential manager so GetCredentialManager() returns it.
|
||||
iamInstance.SetCredentialManagerForTest(cm)
|
||||
|
||||
srv := &IamApiServer{
|
||||
s3ApiConfig: counter,
|
||||
iam: iamInstance,
|
||||
}
|
||||
return srv, cm, counter
|
||||
}
|
||||
|
||||
// countingConfigSaver wraps the credential manager and counts full-config saves.
|
||||
type countingConfigSaver struct {
|
||||
cm *credential.CredentialManager
|
||||
putCalled int
|
||||
}
|
||||
|
||||
func (c *countingConfigSaver) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
config, err := c.cm.LoadConfiguration(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s3cfg.Identities = config.Identities
|
||||
s3cfg.Policies = config.Policies
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *countingConfigSaver) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) error {
|
||||
c.putCalled++
|
||||
return c.cm.SaveConfiguration(context.Background(), s3cfg)
|
||||
}
|
||||
|
||||
func (c *countingConfigSaver) GetPolicies(policies *Policies) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *countingConfigSaver) PutPolicies(policies *Policies) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func executeRequestWith(srv *IamApiServer, req *http.Request, v interface{}) (*httptest.ResponseRecorder, error) {
|
||||
rr := httptest.NewRecorder()
|
||||
apiRouter := mux.NewRouter().SkipClean(true)
|
||||
apiRouter.Path("/").Methods(http.MethodPost).HandlerFunc(srv.DoActions)
|
||||
apiRouter.ServeHTTP(rr, req)
|
||||
return rr, xml.Unmarshal(rr.Body.Bytes(), &v)
|
||||
}
|
||||
|
||||
// TestCreateUserDoesNotSaveAllUsers is a regression test for the bug where
|
||||
// creating a new user triggered a full SaveConfiguration over all existing
|
||||
// identities (causing N file writes + reload cycles in the filer_etc store).
|
||||
// The fix uses credentialManager.CreateUser for a targeted single-file write.
|
||||
func TestCreateUserDoesNotSaveAllUsers(t *testing.T) {
|
||||
srv, cm, counter := iamApiServerWithCredentialManager()
|
||||
ctx := context.Background()
|
||||
|
||||
// Pre-populate three existing users.
|
||||
for _, name := range []string{"existing-1", "existing-2", "existing-3"} {
|
||||
require.NoError(t, cm.CreateUser(ctx, &iam_pb.Identity{Name: name}))
|
||||
}
|
||||
|
||||
// Create a new user via the HTTP API.
|
||||
params := &iam.CreateUserInput{UserName: aws.String("new-user")}
|
||||
req, _ := iam.New(session.New()).CreateUserRequest(params)
|
||||
_ = req.Build()
|
||||
out := CreateUserResponse{}
|
||||
resp, err := executeRequestWith(srv, req.HTTPRequest, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, resp.Code)
|
||||
|
||||
// The new user must appear in the store.
|
||||
newUser, userErr := cm.GetUser(ctx, "new-user")
|
||||
require.NoError(t, userErr)
|
||||
require.Equal(t, "new-user", newUser.Name)
|
||||
|
||||
// Critical: full SaveConfiguration (PutS3ApiConfiguration) must NOT have
|
||||
// been called. Before the fix it was called once per CreateUser, rewriting
|
||||
// every existing user file and triggering a cascade of reload events.
|
||||
assert.Equal(t, 0, counter.putCalled,
|
||||
"CreateUser must not trigger a full PutS3ApiConfiguration over all users")
|
||||
|
||||
// All pre-existing users must still be intact.
|
||||
for _, name := range []string{"existing-1", "existing-2", "existing-3"} {
|
||||
u, err := cm.GetUser(ctx, name)
|
||||
require.NoError(t, err, "pre-existing user %s should still exist", name)
|
||||
assert.Equal(t, name, u.Name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user