mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-14 10:30:45 +02:00
* Refactor parseDurationSeconds into a STSHandlers method Convert the parseDurationSeconds wrapper from a package-level function into a method on STSHandlers so it can reach the configured STS service. No behavior change; the three AssumeRole* handlers now invoke it via their receiver. * Respect MaxSessionLength config in STS DurationSeconds validation parseDurationSeconds validated DurationSeconds against a hardcoded 43200s (12h) ceiling, so raising maxSessionLength in iam.json above 12h had no effect on AssumeRole, AssumeRoleWithWebIdentity, or AssumeRoleWithLDAPIdentity — requests were rejected at the handler before reaching the service layer. Derive the upper bound from the configured STS MaxSessionLength, falling back to maxDurationSeconds (43200s) when unset. The service layer (calculateSessionDuration) already caps the issued duration at MaxSessionLength, so this only relaxes the input-validation gate. * Add tests for STS DurationSeconds MaxSessionLength bound Cover the configured MaxSessionLength upper bound, rejection above it, fallback to the 43200s default when STS config is unset, the 900s minimum, and the empty-parameter nil path. * Refactor validateSessionDurationSeconds into a STSService method Convert validateSessionDurationSeconds from a package-level function into a method on STSService so it can reach the configured STS config. No behavior change; the three assume-role entry points in the service (AssumeRoleForPrincipal, validateAssumeRoleWithWebIdentityRequest, validateAssumeRoleWithCredentialsRequest) now invoke it via their receiver. * Respect MaxSessionLength config in STS service DurationSeconds validation The STS service validateSessionDurationSeconds rejected DurationSeconds above a hardcoded 43200s (12h) ceiling, so even after the handler accepted a longer duration it was rejected again in the service layer for AssumeRoleForPrincipal, AssumeRoleWithWebIdentity, and AssumeRoleWithCredentials. Derive the upper bound from the configured MaxSessionLength, falling back to DefaultMaxSessionLength (43200s) when unset. The issued duration is still capped at MaxSessionLength by calculateSessionDuration. * Add tests for STS service DurationSeconds MaxSessionLength bound Cover the configured MaxSessionLength upper bound, rejection above it, fallback to the 43200s default when STS config is unset, the 900s minimum, and the nil DurationSeconds path. * Preserve capping when MaxSessionLength is below the API minimum Deriving the DurationSeconds upper bound directly from MaxSessionLength created an empty valid range when MaxSessionLength is configured below the 900s API minimum, rejecting every explicit DurationSeconds that the old code silently capped via calculateSessionDuration. Only apply the configured MaxSessionLength as the upper bound when it is at least minDurationSeconds; otherwise keep the default bound and let calculateSessionDuration enforce the shorter configured limit. * Add tests for sub-minimum MaxSessionLength capping behavior Verify that a MaxSessionLength below the 900s API minimum keeps the default upper bound so explicit DurationSeconds within the default range are still accepted (and later capped by calculateSessionDuration).
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
package s3api
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/iam/sts"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func newDurationSecondsRequest(t *testing.T, seconds string) *http.Request {
|
|
t.Helper()
|
|
form := url.Values{}
|
|
if seconds != "" {
|
|
form.Set("DurationSeconds", seconds)
|
|
}
|
|
req, err := http.NewRequest("POST", "/", strings.NewReader(form.Encode()))
|
|
require.NoError(t, err)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
require.NoError(t, req.ParseForm())
|
|
return req
|
|
}
|
|
|
|
func newSTSHandlersWithMaxSession(t *testing.T, maxSession time.Duration) *STSHandlers {
|
|
t.Helper()
|
|
s := sts.NewSTSService()
|
|
require.NoError(t, s.Initialize(&sts.STSConfig{
|
|
Issuer: "test-issuer",
|
|
SigningKey: []byte("test-signing-key-at-least-32-bytes-long-for-security"),
|
|
TokenDuration: sts.FlexibleDuration{Duration: time.Hour},
|
|
MaxSessionLength: sts.FlexibleDuration{Duration: maxSession},
|
|
}))
|
|
return NewSTSHandlers(s, nil)
|
|
}
|
|
|
|
func TestParseDurationSeconds_RespectsConfiguredMaxSessionLength(t *testing.T) {
|
|
h := newSTSHandlersWithMaxSession(t, 168*time.Hour)
|
|
|
|
ds, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, "604800"))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, STSErrorCode(""), errCode)
|
|
if assert.NotNil(t, ds) {
|
|
assert.Equal(t, int64(604800), *ds)
|
|
}
|
|
}
|
|
|
|
func TestParseDurationSeconds_RejectsAboveConfiguredMaxSessionLength(t *testing.T) {
|
|
h := newSTSHandlersWithMaxSession(t, 24*time.Hour)
|
|
|
|
ds, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, "90000"))
|
|
assert.Error(t, err)
|
|
assert.Equal(t, STSErrInvalidParameterValue, errCode)
|
|
assert.Nil(t, ds)
|
|
}
|
|
|
|
func TestParseDurationSeconds_FallsBackToDefaultWhenUnset(t *testing.T) {
|
|
h := &STSHandlers{stsService: nil}
|
|
|
|
ds, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, "43200"))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, STSErrorCode(""), errCode)
|
|
if assert.NotNil(t, ds) {
|
|
assert.Equal(t, int64(43200), *ds)
|
|
}
|
|
|
|
_, errCode, err = h.parseDurationSeconds(newDurationSecondsRequest(t, "43201"))
|
|
assert.Error(t, err)
|
|
assert.Equal(t, STSErrInvalidParameterValue, errCode)
|
|
}
|
|
|
|
func TestParseDurationSeconds_EnforcesMinimum(t *testing.T) {
|
|
h := newSTSHandlersWithMaxSession(t, 168*time.Hour)
|
|
|
|
_, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, "899"))
|
|
assert.Error(t, err)
|
|
assert.Equal(t, STSErrInvalidParameterValue, errCode)
|
|
}
|
|
|
|
func TestParseDurationSeconds_EmptyReturnsNil(t *testing.T) {
|
|
h := newSTSHandlersWithMaxSession(t, 168*time.Hour)
|
|
|
|
ds, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, ""))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, STSErrorCode(""), errCode)
|
|
assert.Nil(t, ds)
|
|
}
|
|
|
|
func TestParseDurationSeconds_SubMinimumMaxSessionLengthKeepsCapping(t *testing.T) {
|
|
h := newSTSHandlersWithMaxSession(t, 5*time.Minute)
|
|
|
|
ds, errCode, err := h.parseDurationSeconds(newDurationSecondsRequest(t, "900"))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, STSErrorCode(""), errCode)
|
|
if assert.NotNil(t, ds) {
|
|
assert.Equal(t, int64(900), *ds)
|
|
}
|
|
|
|
_, errCode, err = h.parseDurationSeconds(newDurationSecondsRequest(t, "43201"))
|
|
assert.Error(t, err)
|
|
assert.Equal(t, STSErrInvalidParameterValue, errCode)
|
|
}
|