Add session policy support to IAM (#8338)
* Add session policy support to IAM - Implement policy evaluation for session tokens in policy_engine.go - Add session_policy field to session claims for tracking applied policies - Update STS service to include session policies in token generation - Add IAM integration tests for session policy validation - Update IAM manager to support policy attachment to sessions - Extend S3 API STS endpoint to handle session policy restrictions * fix: optimize session policy evaluation and add documentation * sts: add NormalizeSessionPolicy helper for inline session policies * sts: support inline session policies for AssumeRoleWithWebIdentity and credential-based flows * s3api: parse and normalize Policy parameter for STS HTTP handlers * tests: add session policy unit tests and integration tests for inline policy downscoping * tests: add s3tables STS inline policy integration * iam: handle user principals and validate tokens * sts: enforce inline session policy size limit * tests: harden s3tables STS integration config * iam: clarify principal policy resolution errors * tests: improve STS integration endpoint selection
This commit is contained in:
@@ -31,6 +31,8 @@ type STSSessionClaims struct {
|
||||
|
||||
// Authorization data
|
||||
Policies []string `json:"pol,omitempty"` // policies (abbreviated)
|
||||
// SessionPolicy contains inline session policy JSON (optional)
|
||||
SessionPolicy string `json:"spol,omitempty"`
|
||||
|
||||
// Identity provider information
|
||||
IdentityProvider string `json:"idp"` // identity_provider
|
||||
@@ -88,6 +90,7 @@ func (c *STSSessionClaims) ToSessionInfo() *SessionInfo {
|
||||
AssumedRoleUser: c.AssumedRole,
|
||||
Principal: c.Principal,
|
||||
Policies: c.Policies,
|
||||
SessionPolicy: c.SessionPolicy,
|
||||
ExpiresAt: expiresAt,
|
||||
IdentityProvider: c.IdentityProvider,
|
||||
ExternalUserId: c.ExternalUserId,
|
||||
@@ -148,6 +151,12 @@ func (c *STSSessionClaims) WithPolicies(policies []string) *STSSessionClaims {
|
||||
return c
|
||||
}
|
||||
|
||||
// WithSessionPolicy sets the inline session policy JSON for this session
|
||||
func (c *STSSessionClaims) WithSessionPolicy(policy string) *STSSessionClaims {
|
||||
c.SessionPolicy = policy
|
||||
return c
|
||||
}
|
||||
|
||||
// WithIdentityProvider sets identity provider information
|
||||
func (c *STSSessionClaims) WithIdentityProvider(providerName, externalUserId, providerIssuer string) *STSSessionClaims {
|
||||
c.IdentityProvider = providerName
|
||||
|
||||
@@ -89,6 +89,7 @@ func TestSTSSessionClaimsToSessionInfoPreservesAllFields(t *testing.T) {
|
||||
expiresAt := time.Now().Add(2 * time.Hour)
|
||||
|
||||
policies := []string{"policy1", "policy2"}
|
||||
sessionPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject"],"Resource":["arn:aws:s3:::bucket/*"]}]}`
|
||||
requestContext := map[string]interface{}{
|
||||
"sourceIp": "192.168.1.1",
|
||||
"userAgent": "test-agent",
|
||||
@@ -99,6 +100,7 @@ func TestSTSSessionClaimsToSessionInfoPreservesAllFields(t *testing.T) {
|
||||
WithRoleInfo("role-arn", "assumed-role", "principal").
|
||||
WithIdentityProvider("provider", "external-id", "issuer").
|
||||
WithPolicies(policies).
|
||||
WithSessionPolicy(sessionPolicy).
|
||||
WithRequestContext(requestContext).
|
||||
WithMaxDuration(2 * time.Hour)
|
||||
|
||||
@@ -114,6 +116,7 @@ func TestSTSSessionClaimsToSessionInfoPreservesAllFields(t *testing.T) {
|
||||
assert.Equal(t, "external-id", sessionInfo.ExternalUserId)
|
||||
assert.Equal(t, "issuer", sessionInfo.ProviderIssuer)
|
||||
assert.Equal(t, policies, sessionInfo.Policies)
|
||||
assert.Equal(t, sessionPolicy, sessionInfo.SessionPolicy)
|
||||
assert.Equal(t, requestContext, sessionInfo.RequestContext)
|
||||
assert.WithinDuration(t, expiresAt, sessionInfo.ExpiresAt, 1*time.Second)
|
||||
}
|
||||
|
||||
35
weed/iam/sts/session_policy.go
Normal file
35
weed/iam/sts/session_policy.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package sts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/iam/policy"
|
||||
)
|
||||
|
||||
// NormalizeSessionPolicy validates and normalizes inline session policy JSON.
|
||||
// It returns an empty string if the input is empty or whitespace.
|
||||
func NormalizeSessionPolicy(policyJSON string) (string, error) {
|
||||
trimmed := strings.TrimSpace(policyJSON)
|
||||
if trimmed == "" {
|
||||
return "", nil
|
||||
}
|
||||
const maxSessionPolicySize = 2048
|
||||
if len(trimmed) > maxSessionPolicySize {
|
||||
return "", fmt.Errorf("session policy exceeds maximum size of %d characters", maxSessionPolicySize)
|
||||
}
|
||||
|
||||
var policyDoc policy.PolicyDocument
|
||||
if err := json.Unmarshal([]byte(trimmed), &policyDoc); err != nil {
|
||||
return "", fmt.Errorf("invalid session policy JSON: %w", err)
|
||||
}
|
||||
if err := policy.ValidatePolicyDocument(&policyDoc); err != nil {
|
||||
return "", fmt.Errorf("invalid session policy document: %w", err)
|
||||
}
|
||||
normalized, err := json.Marshal(&policyDoc)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to normalize session policy: %w", err)
|
||||
}
|
||||
return string(normalized), nil
|
||||
}
|
||||
@@ -25,174 +25,55 @@ func createSessionPolicyTestJWT(t *testing.T, issuer, subject string) string {
|
||||
return tokenString
|
||||
}
|
||||
|
||||
// TestAssumeRoleWithWebIdentity_SessionPolicy tests the handling of the Policy field
|
||||
// in AssumeRoleWithWebIdentityRequest to ensure users are properly informed that
|
||||
// session policies are not currently supported
|
||||
// TestAssumeRoleWithWebIdentity_SessionPolicy verifies inline session policies are preserved in tokens.
|
||||
func TestAssumeRoleWithWebIdentity_SessionPolicy(t *testing.T) {
|
||||
service := setupTestSTSService(t)
|
||||
|
||||
t.Run("should_reject_request_with_session_policy", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a request with a session policy
|
||||
sessionPolicy := `{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:GetObject",
|
||||
"Resource": "arn:aws:s3:::example-bucket/*"
|
||||
}]
|
||||
}`
|
||||
|
||||
testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user")
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: testToken,
|
||||
RoleSessionName: "test-session",
|
||||
DurationSeconds: nil, // Use default
|
||||
Policy: &sessionPolicy, // ← Session policy provided
|
||||
}
|
||||
|
||||
// Should return an error indicating session policies are not supported
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
|
||||
// Verify the error
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
assert.Contains(t, err.Error(), "session policies are not currently supported")
|
||||
assert.Contains(t, err.Error(), "Policy parameter must be omitted")
|
||||
})
|
||||
|
||||
t.Run("should_succeed_without_session_policy", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user")
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: testToken,
|
||||
RoleSessionName: "test-session",
|
||||
DurationSeconds: nil, // Use default
|
||||
Policy: nil, // ← No session policy
|
||||
}
|
||||
|
||||
// Should succeed without session policy
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
|
||||
// Verify success
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
assert.NotNil(t, response.Credentials)
|
||||
assert.NotEmpty(t, response.Credentials.AccessKeyId)
|
||||
assert.NotEmpty(t, response.Credentials.SecretAccessKey)
|
||||
assert.NotEmpty(t, response.Credentials.SessionToken)
|
||||
})
|
||||
|
||||
t.Run("should_succeed_with_empty_policy_pointer", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user")
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: testToken,
|
||||
RoleSessionName: "test-session",
|
||||
Policy: nil, // ← Explicitly nil
|
||||
}
|
||||
|
||||
// Should succeed with nil policy pointer
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
assert.NotNil(t, response.Credentials)
|
||||
})
|
||||
|
||||
t.Run("should_reject_empty_string_policy", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
emptyPolicy := "" // Empty string, but still a non-nil pointer
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"),
|
||||
RoleSessionName: "test-session",
|
||||
Policy: &emptyPolicy, // ← Non-nil pointer to empty string
|
||||
}
|
||||
|
||||
// Should still reject because pointer is not nil
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
assert.Contains(t, err.Error(), "session policies are not currently supported")
|
||||
})
|
||||
}
|
||||
|
||||
// TestAssumeRoleWithWebIdentity_SessionPolicy_ErrorMessage tests that the error message
|
||||
// is clear and helps users understand what they need to do
|
||||
func TestAssumeRoleWithWebIdentity_SessionPolicy_ErrorMessage(t *testing.T) {
|
||||
service := setupTestSTSService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
complexPolicy := `{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowS3Access",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:PutObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::my-bucket/*",
|
||||
"arn:aws:s3:::my-bucket"
|
||||
],
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"s3:prefix": ["documents/", "images/"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
sessionPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::example-bucket/*"}]}`
|
||||
testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user")
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: testToken,
|
||||
RoleSessionName: "test-session-with-complex-policy",
|
||||
Policy: &complexPolicy,
|
||||
RoleSessionName: "test-session",
|
||||
Policy: &sessionPolicy,
|
||||
}
|
||||
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
|
||||
// Verify error details
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
sessionInfo, err := service.ValidateSessionToken(ctx, response.Credentials.SessionToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
errorMsg := err.Error()
|
||||
normalized, err := NormalizeSessionPolicy(sessionPolicy)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, normalized, sessionInfo.SessionPolicy)
|
||||
|
||||
// The error should be clear and actionable
|
||||
assert.Contains(t, errorMsg, "session policies are not currently supported",
|
||||
"Error should explain that session policies aren't supported")
|
||||
assert.Contains(t, errorMsg, "Policy parameter must be omitted",
|
||||
"Error should specify what action the user needs to take")
|
||||
t.Run("should_succeed_without_session_policy", func(t *testing.T) {
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"),
|
||||
RoleSessionName: "test-session",
|
||||
}
|
||||
|
||||
// Should NOT contain internal implementation details
|
||||
assert.NotContains(t, errorMsg, "nil pointer",
|
||||
"Error should not expose internal implementation details")
|
||||
assert.NotContains(t, errorMsg, "struct field",
|
||||
"Error should not expose internal struct details")
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
|
||||
sessionInfo, err := service.ValidateSessionToken(ctx, response.Credentials.SessionToken)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, sessionInfo.SessionPolicy)
|
||||
})
|
||||
}
|
||||
|
||||
// Test edge case scenarios for the Policy field handling
|
||||
func TestAssumeRoleWithWebIdentity_SessionPolicy_EdgeCases(t *testing.T) {
|
||||
service := setupTestSTSService(t)
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("malformed_json_policy_still_rejected", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("malformed_json_policy_rejected", func(t *testing.T) {
|
||||
malformedPolicy := `{"Version": "2012-10-17", "Statement": [` // Incomplete JSON
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
@@ -202,17 +83,30 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy_EdgeCases(t *testing.T) {
|
||||
Policy: &malformedPolicy,
|
||||
}
|
||||
|
||||
// Should reject before even parsing the policy JSON
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
assert.Contains(t, err.Error(), "session policies are not currently supported")
|
||||
assert.Contains(t, err.Error(), "invalid session policy JSON")
|
||||
})
|
||||
|
||||
t.Run("policy_with_whitespace_still_rejected", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
whitespacePolicy := " \t\n " // Only whitespace
|
||||
t.Run("invalid_policy_document_rejected", func(t *testing.T) {
|
||||
invalidPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow"}]}`
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"),
|
||||
RoleSessionName: "test-session",
|
||||
Policy: &invalidPolicy,
|
||||
}
|
||||
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
assert.Contains(t, err.Error(), "invalid session policy document")
|
||||
})
|
||||
|
||||
t.Run("whitespace_policy_ignored", func(t *testing.T) {
|
||||
whitespacePolicy := " \t\n "
|
||||
|
||||
request := &AssumeRoleWithWebIdentityRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
@@ -221,58 +115,54 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy_EdgeCases(t *testing.T) {
|
||||
Policy: &whitespacePolicy,
|
||||
}
|
||||
|
||||
// Should reject any non-nil policy, even whitespace
|
||||
response, err := service.AssumeRoleWithWebIdentity(ctx, request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, response)
|
||||
assert.Contains(t, err.Error(), "session policies are not currently supported")
|
||||
sessionInfo, err := service.ValidateSessionToken(ctx, response.Credentials.SessionToken)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, sessionInfo.SessionPolicy)
|
||||
})
|
||||
}
|
||||
|
||||
// TestAssumeRoleWithWebIdentity_PolicyFieldDocumentation verifies that the struct
|
||||
// field is properly documented to help developers understand the limitation
|
||||
// TestAssumeRoleWithWebIdentity_PolicyFieldDocumentation verifies that the struct field exists and is optional.
|
||||
func TestAssumeRoleWithWebIdentity_PolicyFieldDocumentation(t *testing.T) {
|
||||
// This test documents the current behavior and ensures the struct field
|
||||
// exists with proper typing
|
||||
request := &AssumeRoleWithWebIdentityRequest{}
|
||||
|
||||
// Verify the Policy field exists and has the correct type
|
||||
assert.IsType(t, (*string)(nil), request.Policy,
|
||||
"Policy field should be *string type for optional JSON policy")
|
||||
|
||||
// Verify initial value is nil (no policy by default)
|
||||
assert.Nil(t, request.Policy,
|
||||
"Policy field should default to nil (no session policy)")
|
||||
|
||||
// Test that we can set it to a string pointer (even though it will be rejected)
|
||||
policyValue := `{"Version": "2012-10-17"}`
|
||||
request.Policy = &policyValue
|
||||
assert.NotNil(t, request.Policy, "Should be able to assign policy value")
|
||||
assert.Equal(t, policyValue, *request.Policy, "Policy value should be preserved")
|
||||
}
|
||||
|
||||
// TestAssumeRoleWithCredentials_NoSessionPolicySupport verifies that
|
||||
// AssumeRoleWithCredentialsRequest doesn't have a Policy field, which is correct
|
||||
// since credential-based role assumption typically doesn't support session policies
|
||||
func TestAssumeRoleWithCredentials_NoSessionPolicySupport(t *testing.T) {
|
||||
// Verify that AssumeRoleWithCredentialsRequest doesn't have a Policy field
|
||||
// This is the expected behavior since session policies are typically only
|
||||
// supported with web identity (OIDC/SAML) flows in AWS STS
|
||||
// TestAssumeRoleWithCredentials_SessionPolicy verifies session policy support for credentials-based flow.
|
||||
func TestAssumeRoleWithCredentials_SessionPolicy(t *testing.T) {
|
||||
service := setupTestSTSService(t)
|
||||
ctx := context.Background()
|
||||
|
||||
sessionPolicy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"filer:CreateEntry","Resource":"arn:aws:filer::path/user-docs/*"}]}`
|
||||
request := &AssumeRoleWithCredentialsRequest{
|
||||
RoleArn: "arn:aws:iam::role/TestRole",
|
||||
Username: "testuser",
|
||||
Password: "testpass",
|
||||
RoleSessionName: "test-session",
|
||||
ProviderName: "ldap",
|
||||
ProviderName: "test-ldap",
|
||||
Policy: &sessionPolicy,
|
||||
}
|
||||
|
||||
// The struct should compile and work without a Policy field
|
||||
assert.NotNil(t, request)
|
||||
assert.Equal(t, "arn:aws:iam::role/TestRole", request.RoleArn)
|
||||
assert.Equal(t, "testuser", request.Username)
|
||||
response, err := service.AssumeRoleWithCredentials(ctx, request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, response)
|
||||
|
||||
// This documents that credential-based assume role does NOT support session policies
|
||||
// which matches AWS STS behavior where session policies are primarily for
|
||||
// web identity (OIDC/SAML) and federation scenarios
|
||||
sessionInfo, err := service.ValidateSessionToken(ctx, response.Credentials.SessionToken)
|
||||
require.NoError(t, err)
|
||||
|
||||
normalized, err := NormalizeSessionPolicy(sessionPolicy)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, normalized, sessionInfo.SessionPolicy)
|
||||
}
|
||||
|
||||
@@ -161,6 +161,9 @@ type AssumeRoleWithCredentialsRequest struct {
|
||||
|
||||
// DurationSeconds is the duration of the role session (optional)
|
||||
DurationSeconds *int64 `json:"DurationSeconds,omitempty"`
|
||||
|
||||
// Policy is an optional session policy (optional)
|
||||
Policy *string `json:"Policy,omitempty"`
|
||||
}
|
||||
|
||||
// AssumeRoleResponse represents the response from assume role operations
|
||||
@@ -237,6 +240,9 @@ type SessionInfo struct {
|
||||
// Policies are the policies associated with this session
|
||||
Policies []string `json:"policies"`
|
||||
|
||||
// SessionPolicy is the inline session policy JSON (optional)
|
||||
SessionPolicy string `json:"sessionPolicy,omitempty"`
|
||||
|
||||
// RequestContext contains additional request context for policy evaluation
|
||||
RequestContext map[string]interface{} `json:"requestContext,omitempty"`
|
||||
|
||||
@@ -418,9 +424,13 @@ func (s *STSService) AssumeRoleWithWebIdentity(ctx context.Context, request *Ass
|
||||
return nil, fmt.Errorf("invalid request: %w", err)
|
||||
}
|
||||
|
||||
// Check for unsupported session policy
|
||||
sessionPolicy := ""
|
||||
if request.Policy != nil {
|
||||
return nil, fmt.Errorf("session policies are not currently supported - Policy parameter must be omitted")
|
||||
normalized, err := NormalizeSessionPolicy(*request.Policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid session policy: %w", err)
|
||||
}
|
||||
sessionPolicy = normalized
|
||||
}
|
||||
|
||||
// 1. Validate the web identity token with appropriate provider
|
||||
@@ -485,6 +495,9 @@ func (s *STSService) AssumeRoleWithWebIdentity(ctx context.Context, request *Ass
|
||||
WithIdentityProvider(provider.Name(), externalIdentity.UserID, "").
|
||||
WithMaxDuration(sessionDuration).
|
||||
WithRequestContext(requestContext)
|
||||
if sessionPolicy != "" {
|
||||
sessionClaims.WithSessionPolicy(sessionPolicy)
|
||||
}
|
||||
|
||||
// Generate self-contained JWT token with all session information
|
||||
jwtToken, err := s.tokenGenerator.GenerateJWTWithClaims(sessionClaims)
|
||||
@@ -517,6 +530,15 @@ func (s *STSService) AssumeRoleWithCredentials(ctx context.Context, request *Ass
|
||||
return nil, fmt.Errorf("invalid request: %w", err)
|
||||
}
|
||||
|
||||
sessionPolicy := ""
|
||||
if request.Policy != nil {
|
||||
normalized, err := NormalizeSessionPolicy(*request.Policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid session policy: %w", err)
|
||||
}
|
||||
sessionPolicy = normalized
|
||||
}
|
||||
|
||||
// 1. Get the specified provider
|
||||
provider, exists := s.providers[request.ProviderName]
|
||||
if !exists {
|
||||
@@ -565,6 +587,9 @@ func (s *STSService) AssumeRoleWithCredentials(ctx context.Context, request *Ass
|
||||
WithRoleInfo(request.RoleArn, assumedRoleUser.Arn, assumedRoleUser.Arn).
|
||||
WithIdentityProvider(provider.Name(), externalIdentity.UserID, "").
|
||||
WithMaxDuration(sessionDuration)
|
||||
if sessionPolicy != "" {
|
||||
sessionClaims.WithSessionPolicy(sessionPolicy)
|
||||
}
|
||||
|
||||
// Generate self-contained JWT token with all session information
|
||||
jwtToken, err := s.tokenGenerator.GenerateJWTWithClaims(sessionClaims)
|
||||
|
||||
Reference in New Issue
Block a user