You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
9.6 KiB
317 lines
9.6 KiB
package sts
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/iam/providers"
|
|
)
|
|
|
|
// STSService provides Security Token Service functionality
|
|
type STSService struct {
|
|
config *STSConfig
|
|
initialized bool
|
|
providers map[string]providers.IdentityProvider
|
|
sessionStore SessionStore
|
|
}
|
|
|
|
// STSConfig holds STS service configuration
|
|
type STSConfig struct {
|
|
// TokenDuration is the default duration for issued tokens
|
|
TokenDuration time.Duration `json:"tokenDuration"`
|
|
|
|
// MaxSessionLength is the maximum duration for any session
|
|
MaxSessionLength time.Duration `json:"maxSessionLength"`
|
|
|
|
// Issuer is the STS issuer identifier
|
|
Issuer string `json:"issuer"`
|
|
|
|
// SigningKey is used to sign session tokens
|
|
SigningKey []byte `json:"signingKey"`
|
|
|
|
// SessionStore configuration
|
|
SessionStoreType string `json:"sessionStoreType"` // memory, filer, redis
|
|
SessionStoreConfig map[string]interface{} `json:"sessionStoreConfig,omitempty"`
|
|
}
|
|
|
|
// AssumeRoleWithWebIdentityRequest represents a request to assume role with web identity
|
|
type AssumeRoleWithWebIdentityRequest struct {
|
|
// RoleArn is the ARN of the role to assume
|
|
RoleArn string `json:"RoleArn"`
|
|
|
|
// WebIdentityToken is the OIDC token from the identity provider
|
|
WebIdentityToken string `json:"WebIdentityToken"`
|
|
|
|
// RoleSessionName is a name for the assumed role session
|
|
RoleSessionName string `json:"RoleSessionName"`
|
|
|
|
// 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"`
|
|
}
|
|
|
|
// AssumeRoleWithCredentialsRequest represents a request to assume role with username/password
|
|
type AssumeRoleWithCredentialsRequest struct {
|
|
// RoleArn is the ARN of the role to assume
|
|
RoleArn string `json:"RoleArn"`
|
|
|
|
// Username is the username for authentication
|
|
Username string `json:"Username"`
|
|
|
|
// Password is the password for authentication
|
|
Password string `json:"Password"`
|
|
|
|
// RoleSessionName is a name for the assumed role session
|
|
RoleSessionName string `json:"RoleSessionName"`
|
|
|
|
// ProviderName is the name of the identity provider to use
|
|
ProviderName string `json:"ProviderName"`
|
|
|
|
// DurationSeconds is the duration of the role session (optional)
|
|
DurationSeconds *int64 `json:"DurationSeconds,omitempty"`
|
|
}
|
|
|
|
// AssumeRoleResponse represents the response from assume role operations
|
|
type AssumeRoleResponse struct {
|
|
// Credentials contains the temporary security credentials
|
|
Credentials *Credentials `json:"Credentials"`
|
|
|
|
// AssumedRoleUser contains information about the assumed role user
|
|
AssumedRoleUser *AssumedRoleUser `json:"AssumedRoleUser"`
|
|
|
|
// PackedPolicySize is the percentage of max policy size used (AWS compatibility)
|
|
PackedPolicySize *int64 `json:"PackedPolicySize,omitempty"`
|
|
}
|
|
|
|
// Credentials represents temporary security credentials
|
|
type Credentials struct {
|
|
// AccessKeyId is the access key ID
|
|
AccessKeyId string `json:"AccessKeyId"`
|
|
|
|
// SecretAccessKey is the secret access key
|
|
SecretAccessKey string `json:"SecretAccessKey"`
|
|
|
|
// SessionToken is the session token
|
|
SessionToken string `json:"SessionToken"`
|
|
|
|
// Expiration is when the credentials expire
|
|
Expiration time.Time `json:"Expiration"`
|
|
}
|
|
|
|
// AssumedRoleUser contains information about the assumed role user
|
|
type AssumedRoleUser struct {
|
|
// AssumedRoleId is the unique identifier of the assumed role
|
|
AssumedRoleId string `json:"AssumedRoleId"`
|
|
|
|
// Arn is the ARN of the assumed role user
|
|
Arn string `json:"Arn"`
|
|
|
|
// Subject is the subject identifier from the identity provider
|
|
Subject string `json:"Subject,omitempty"`
|
|
}
|
|
|
|
// SessionInfo represents information about an active session
|
|
type SessionInfo struct {
|
|
// SessionId is the unique identifier for the session
|
|
SessionId string `json:"sessionId"`
|
|
|
|
// SessionName is the name of the role session
|
|
SessionName string `json:"sessionName"`
|
|
|
|
// RoleArn is the ARN of the assumed role
|
|
RoleArn string `json:"roleArn"`
|
|
|
|
// Subject is the subject identifier from the identity provider
|
|
Subject string `json:"subject"`
|
|
|
|
// Provider is the identity provider used
|
|
Provider string `json:"provider"`
|
|
|
|
// CreatedAt is when the session was created
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
|
|
// ExpiresAt is when the session expires
|
|
ExpiresAt time.Time `json:"expiresAt"`
|
|
|
|
// Credentials are the temporary credentials for this session
|
|
Credentials *Credentials `json:"credentials"`
|
|
}
|
|
|
|
// SessionStore defines the interface for storing session information
|
|
type SessionStore interface {
|
|
// StoreSession stores session information
|
|
StoreSession(ctx context.Context, sessionId string, session *SessionInfo) error
|
|
|
|
// GetSession retrieves session information
|
|
GetSession(ctx context.Context, sessionId string) (*SessionInfo, error)
|
|
|
|
// RevokeSession revokes a session
|
|
RevokeSession(ctx context.Context, sessionId string) error
|
|
|
|
// CleanupExpiredSessions removes expired sessions
|
|
CleanupExpiredSessions(ctx context.Context) error
|
|
}
|
|
|
|
// NewSTSService creates a new STS service
|
|
func NewSTSService() *STSService {
|
|
return &STSService{
|
|
providers: make(map[string]providers.IdentityProvider),
|
|
}
|
|
}
|
|
|
|
// Initialize initializes the STS service with configuration
|
|
func (s *STSService) Initialize(config *STSConfig) error {
|
|
if config == nil {
|
|
return fmt.Errorf("config cannot be nil")
|
|
}
|
|
|
|
if err := s.validateConfig(config); err != nil {
|
|
return fmt.Errorf("invalid STS configuration: %w", err)
|
|
}
|
|
|
|
s.config = config
|
|
|
|
// Initialize session store
|
|
sessionStore, err := s.createSessionStore(config)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to initialize session store: %w", err)
|
|
}
|
|
s.sessionStore = sessionStore
|
|
|
|
s.initialized = true
|
|
return nil
|
|
}
|
|
|
|
// validateConfig validates the STS configuration
|
|
func (s *STSService) validateConfig(config *STSConfig) error {
|
|
if config.TokenDuration <= 0 {
|
|
return fmt.Errorf("token duration must be positive")
|
|
}
|
|
|
|
if config.MaxSessionLength <= 0 {
|
|
return fmt.Errorf("max session length must be positive")
|
|
}
|
|
|
|
if config.Issuer == "" {
|
|
return fmt.Errorf("issuer is required")
|
|
}
|
|
|
|
if len(config.SigningKey) < 16 {
|
|
return fmt.Errorf("signing key must be at least 16 bytes")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createSessionStore creates a session store based on configuration
|
|
func (s *STSService) createSessionStore(config *STSConfig) (SessionStore, error) {
|
|
switch config.SessionStoreType {
|
|
case "", "memory":
|
|
return NewMemorySessionStore(), nil
|
|
case "filer":
|
|
return NewFilerSessionStore(config.SessionStoreConfig)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported session store type: %s", config.SessionStoreType)
|
|
}
|
|
}
|
|
|
|
// IsInitialized returns whether the service is initialized
|
|
func (s *STSService) IsInitialized() bool {
|
|
return s.initialized
|
|
}
|
|
|
|
// RegisterProvider registers an identity provider
|
|
func (s *STSService) RegisterProvider(provider providers.IdentityProvider) error {
|
|
if provider == nil {
|
|
return fmt.Errorf("provider cannot be nil")
|
|
}
|
|
|
|
name := provider.Name()
|
|
if name == "" {
|
|
return fmt.Errorf("provider name cannot be empty")
|
|
}
|
|
|
|
s.providers[name] = provider
|
|
return nil
|
|
}
|
|
|
|
// AssumeRoleWithWebIdentity assumes a role using a web identity token (OIDC)
|
|
func (s *STSService) AssumeRoleWithWebIdentity(ctx context.Context, request *AssumeRoleWithWebIdentityRequest) (*AssumeRoleResponse, error) {
|
|
if !s.initialized {
|
|
return nil, fmt.Errorf("STS service not initialized")
|
|
}
|
|
|
|
if request == nil {
|
|
return nil, fmt.Errorf("request cannot be nil")
|
|
}
|
|
|
|
// TODO: Implement AssumeRoleWithWebIdentity
|
|
// 1. Validate the web identity token with appropriate provider
|
|
// 2. Check if the role exists and can be assumed
|
|
// 3. Generate temporary credentials
|
|
// 4. Create and store session information
|
|
// 5. Return response with credentials
|
|
|
|
return nil, fmt.Errorf("AssumeRoleWithWebIdentity not implemented yet")
|
|
}
|
|
|
|
// AssumeRoleWithCredentials assumes a role using username/password credentials
|
|
func (s *STSService) AssumeRoleWithCredentials(ctx context.Context, request *AssumeRoleWithCredentialsRequest) (*AssumeRoleResponse, error) {
|
|
if !s.initialized {
|
|
return nil, fmt.Errorf("STS service not initialized")
|
|
}
|
|
|
|
if request == nil {
|
|
return nil, fmt.Errorf("request cannot be nil")
|
|
}
|
|
|
|
// TODO: Implement AssumeRoleWithCredentials
|
|
// 1. Validate credentials with the specified provider
|
|
// 2. Check if the role exists and can be assumed
|
|
// 3. Generate temporary credentials
|
|
// 4. Create and store session information
|
|
// 5. Return response with credentials
|
|
|
|
return nil, fmt.Errorf("AssumeRoleWithCredentials not implemented yet")
|
|
}
|
|
|
|
// ValidateSessionToken validates a session token and returns session information
|
|
func (s *STSService) ValidateSessionToken(ctx context.Context, sessionToken string) (*SessionInfo, error) {
|
|
if !s.initialized {
|
|
return nil, fmt.Errorf("STS service not initialized")
|
|
}
|
|
|
|
if sessionToken == "" {
|
|
return nil, fmt.Errorf("session token cannot be empty")
|
|
}
|
|
|
|
// TODO: Implement session token validation
|
|
// 1. Parse and verify the session token
|
|
// 2. Extract session ID from token
|
|
// 3. Retrieve session from store
|
|
// 4. Validate expiration and other claims
|
|
// 5. Return session information
|
|
|
|
return nil, fmt.Errorf("session token validation not implemented yet")
|
|
}
|
|
|
|
// RevokeSession revokes an active session
|
|
func (s *STSService) RevokeSession(ctx context.Context, sessionToken string) error {
|
|
if !s.initialized {
|
|
return fmt.Errorf("STS service not initialized")
|
|
}
|
|
|
|
if sessionToken == "" {
|
|
return fmt.Errorf("session token cannot be empty")
|
|
}
|
|
|
|
// TODO: Implement session revocation
|
|
// 1. Parse session token to extract session ID
|
|
// 2. Remove session from store
|
|
// 3. Add token to revocation list
|
|
|
|
return fmt.Errorf("session revocation not implemented yet")
|
|
}
|