mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-10 08:30:47 +02:00
* s3: deny anonymous requests when the identity config loads no identities Naming a config file is the operator asking for authentication. A file that yields no identity - an unpopulated secret mount, or a mistyped top-level key the proto parser silently drops - left the gateway open to every anonymous caller: ListBuckets returned 200, and anonymous PUT could create buckets and write objects. * s3: name the unknown top-level keys in an identity config The proto parser discards what it does not recognise, so a mistyped "identites" loads as an empty config. Naming the dropped keys at startup turns the resulting lockout into a one-line diagnosis. * s3: isolate the auth-enforcement tests from AWS environment credentials * s3: use a singular "identity" as the unrecognised-key example Codespell rejects the misspelling the example used. * s3: cover the empty identity config alongside the unrecognised key * s3: cover a config file whose body is an empty object
69 lines
2.7 KiB
Go
69 lines
2.7 KiB
Go
package s3api
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// A config file the proto parser reads as empty - an unpopulated secret mount,
|
|
// a singular "identity" - used to leave the gateway serving every anonymous
|
|
// request, including ListBuckets and bucket creation.
|
|
func TestConfigWithoutIdentitiesDeniesAnonymous(t *testing.T) {
|
|
for name, config := range map[string]string{
|
|
"no identities key": `{}`,
|
|
"empty": `{"identities":[]}`,
|
|
"unrecognised key": `{"identity":[{"name":"admin","credentials":[{"accessKey":"adminkey","secretKey":"adminsecret"}],"actions":["Admin"]}]}`,
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
resetMemoryStore()
|
|
clearEnvironmentVariableCredentials(t)
|
|
|
|
path := writeTempIamConfig(t, config)
|
|
iam := NewIdentityAccessManagementWithStore(&S3ApiServerOption{Config: path}, nil, "memory")
|
|
|
|
assert.True(t, iam.isEnabled(), "naming a config file asks for authentication, even if it yields no identity")
|
|
|
|
handlerCalled := false
|
|
handler := iam.Auth(func(w http.ResponseWriter, r *http.Request) {
|
|
handlerCalled = true
|
|
}, s3_constants.ACTION_LIST)
|
|
|
|
recorder := httptest.NewRecorder()
|
|
handler.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
|
|
|
|
assert.False(t, handlerCalled, "ListBuckets must not run for an anonymous caller")
|
|
assert.Equal(t, http.StatusForbidden, recorder.Code)
|
|
})
|
|
}
|
|
}
|
|
|
|
// `weed mini` and `docker run seaweedfs` name no config file and stay open.
|
|
func TestNoConfigKeepsAnonymousAllowed(t *testing.T) {
|
|
resetMemoryStore()
|
|
clearEnvironmentVariableCredentials(t)
|
|
|
|
iam := NewIdentityAccessManagementWithStore(&S3ApiServerOption{}, nil, "memory")
|
|
|
|
assert.False(t, iam.isEnabled(), "auth must stay off when no config file and no identities are configured")
|
|
}
|
|
|
|
// AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY register an admin identity of
|
|
// their own, which would decide isAuthEnabled before the config file does.
|
|
func clearEnvironmentVariableCredentials(t *testing.T) {
|
|
t.Setenv("AWS_ACCESS_KEY_ID", "")
|
|
t.Setenv("AWS_SECRET_ACCESS_KEY", "")
|
|
}
|
|
|
|
// The proto parser drops what it does not recognise, so a typo has to be named
|
|
// at startup or the resulting lockout has no visible cause.
|
|
func TestUnknownS3ConfigKeys(t *testing.T) {
|
|
assert.Equal(t, []string{"identity"}, unknownS3ConfigKeys([]byte(`{"identity":[],"accounts":[]}`)))
|
|
assert.Empty(t, unknownS3ConfigKeys([]byte(`{"identities":[],"service_accounts":[],"serviceAccounts":[],"policies":[],"groups":[]}`)))
|
|
assert.Empty(t, unknownS3ConfigKeys([]byte(`{"kms":{},"sts":{},"policy":{},"providers":[],"roles":[]}`)), "sections owned by other subsystems are not typos")
|
|
assert.Empty(t, unknownS3ConfigKeys([]byte(`not json`)))
|
|
}
|