Browse Source

validateExternalOIDCToken() - delegates to STS service's secure issuer-based lookup

pull/7160/head
chrislu 2 months ago
parent
commit
801f8d98e1
  1. 6
      weed/iam/sts/sts_service.go
  2. 100
      weed/s3api/s3_iam_middleware.go

6
weed/iam/sts/sts_service.go

@ -581,6 +581,12 @@ func (s *STSService) validateWebIdentityToken(ctx context.Context, token string)
return identity, provider, nil
}
// ValidateWebIdentityToken is a public method that exposes secure token validation for external use
// This method uses issuer-based lookup to select the correct provider, ensuring security and efficiency
func (s *STSService) ValidateWebIdentityToken(ctx context.Context, token string) (*providers.ExternalIdentity, providers.IdentityProvider, error) {
return s.validateWebIdentityToken(ctx, token)
}
// validateWithAllProviders is a fallback for non-JWT tokens (e.g., LDAP credentials, test tokens)
// This should only be used when the token is not a valid JWT
func (s *STSService) validateWithAllProviders(ctx context.Context, token string) (*providers.ExternalIdentity, providers.IdentityProvider, error) {

100
weed/s3api/s3_iam_middleware.go

@ -97,7 +97,7 @@ func (s3iam *S3IAMIntegration) AuthenticateJWT(ctx context.Context, r *http.Requ
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
identity, err := s3iam.validateOIDCToken(ctx, sessionToken)
identity, err := s3iam.validateExternalOIDCToken(ctx, sessionToken)
elapsed := time.Since(start)
if err != nil {
@ -729,77 +729,71 @@ type OIDCIdentity struct {
Provider string
}
// validateOIDCToken validates an OIDC token using registered identity providers
func (s3iam *S3IAMIntegration) validateOIDCToken(ctx context.Context, token string) (*OIDCIdentity, error) {
glog.V(0).Infof("🔍 validateOIDCToken: Starting OIDC token validation")
// validateExternalOIDCToken validates an external OIDC token using the STS service's secure issuer-based lookup
// This method delegates to the STS service's validateWebIdentityToken for better security and efficiency
func (s3iam *S3IAMIntegration) validateExternalOIDCToken(ctx context.Context, token string) (*OIDCIdentity, error) {
glog.V(0).Infof("🔍 validateExternalOIDCToken: Starting secure OIDC token validation via STS service")
if s3iam.iamManager == nil {
glog.V(0).Infof("🔍 validateOIDCToken: IAM manager not available")
glog.V(0).Infof("🔍 validateExternalOIDCToken: IAM manager not available")
return nil, fmt.Errorf("IAM manager not available")
}
// Get STS service to access identity providers
// Get STS service for secure token validation
stsService := s3iam.iamManager.GetSTSService()
if stsService == nil {
glog.V(0).Infof("🔍 validateOIDCToken: STS service not available")
glog.V(0).Infof("🔍 validateExternalOIDCToken: STS service not available")
return nil, fmt.Errorf("STS service not available")
}
// Try to validate token with each registered OIDC provider
providers := stsService.GetProviders()
glog.V(0).Infof("🔍 validateOIDCToken: Found %d providers to try", len(providers))
for providerName, provider := range providers {
glog.V(0).Infof("🔍 validateOIDCToken: Trying provider '%s'...", providerName)
start := time.Now()
// Try to authenticate with this provider
externalIdentity, err := provider.Authenticate(ctx, token)
elapsed := time.Since(start)
if err != nil {
glog.V(0).Infof("🔍 validateOIDCToken: Provider '%s' FAILED after %v: %v", providerName, elapsed, err)
continue
}
// Use the STS service's secure validateWebIdentityToken method
// This method uses issuer-based lookup to select the correct provider, which is more secure and efficient
externalIdentity, provider, err := stsService.ValidateWebIdentityToken(ctx, token)
if err != nil {
glog.V(0).Infof("🔍 validateExternalOIDCToken: STS validation failed: %v", err)
return nil, fmt.Errorf("token validation failed: %w", err)
}
glog.V(0).Infof("🔍 validateOIDCToken: Provider '%s' SUCCEEDED after %v", providerName, elapsed)
if externalIdentity == nil {
glog.V(0).Infof("🔍 validateExternalOIDCToken: STS validation succeeded but no identity returned")
return nil, fmt.Errorf("authentication succeeded but no identity returned")
}
// Extract role from external identity attributes
rolesAttr, exists := externalIdentity.Attributes["roles"]
if !exists || rolesAttr == "" {
glog.V(3).Infof("No roles found in external identity from provider %s", providerName)
continue
}
glog.V(0).Infof("🔍 validateExternalOIDCToken: STS validation succeeded with provider type: %T", provider)
// Parse roles (stored as comma-separated string)
rolesStr := strings.TrimSpace(rolesAttr)
roles := strings.Split(rolesStr, ",")
// Extract role from external identity attributes
rolesAttr, exists := externalIdentity.Attributes["roles"]
if !exists || rolesAttr == "" {
glog.V(3).Infof("No roles found in external identity")
return nil, fmt.Errorf("no roles found in external identity")
}
// Clean up role names
var cleanRoles []string
for _, role := range roles {
cleanRole := strings.TrimSpace(role)
if cleanRole != "" {
cleanRoles = append(cleanRoles, cleanRole)
}
}
// Parse roles (stored as comma-separated string)
rolesStr := strings.TrimSpace(rolesAttr)
roles := strings.Split(rolesStr, ",")
if len(cleanRoles) == 0 {
glog.V(3).Infof("Empty roles list from provider %s", providerName)
continue
// Clean up role names
var cleanRoles []string
for _, role := range roles {
cleanRole := strings.TrimSpace(role)
if cleanRole != "" {
cleanRoles = append(cleanRoles, cleanRole)
}
}
// Determine the primary role using intelligent selection
roleArn := s3iam.selectPrimaryRole(cleanRoles, externalIdentity)
return &OIDCIdentity{
UserID: externalIdentity.UserID,
RoleArn: roleArn,
Provider: providerName,
}, nil
if len(cleanRoles) == 0 {
glog.V(3).Infof("Empty roles list after parsing")
return nil, fmt.Errorf("no valid roles found in token")
}
return nil, fmt.Errorf("token not valid for any registered OIDC provider")
// Determine the primary role using intelligent selection
roleArn := s3iam.selectPrimaryRole(cleanRoles, externalIdentity)
return &OIDCIdentity{
UserID: externalIdentity.UserID,
RoleArn: roleArn,
Provider: fmt.Sprintf("%T", provider), // Use provider type as identifier
}, nil
}
// selectPrimaryRole simply picks the first role from the list

Loading…
Cancel
Save