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.
		
		
		
		
		
			
		
			
				
					
					
						
							203 lines
						
					
					
						
							5.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							203 lines
						
					
					
						
							5.5 KiB
						
					
					
				
								//go:build test
							 | 
						|
								// +build test
							 | 
						|
								
							 | 
						|
								package oidc
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"context"
							 | 
						|
									"fmt"
							 | 
						|
									"strings"
							 | 
						|
									"time"
							 | 
						|
								
							 | 
						|
									"github.com/golang-jwt/jwt/v5"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/iam/providers"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// MockOIDCProvider is a mock implementation for testing
							 | 
						|
								type MockOIDCProvider struct {
							 | 
						|
									*OIDCProvider
							 | 
						|
									TestTokens map[string]*providers.TokenClaims
							 | 
						|
									TestUsers  map[string]*providers.ExternalIdentity
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// NewMockOIDCProvider creates a mock OIDC provider for testing
							 | 
						|
								func NewMockOIDCProvider(name string) *MockOIDCProvider {
							 | 
						|
									return &MockOIDCProvider{
							 | 
						|
										OIDCProvider: NewOIDCProvider(name),
							 | 
						|
										TestTokens:   make(map[string]*providers.TokenClaims),
							 | 
						|
										TestUsers:    make(map[string]*providers.ExternalIdentity),
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// AddTestToken adds a test token with expected claims
							 | 
						|
								func (m *MockOIDCProvider) AddTestToken(token string, claims *providers.TokenClaims) {
							 | 
						|
									m.TestTokens[token] = claims
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// AddTestUser adds a test user with expected identity
							 | 
						|
								func (m *MockOIDCProvider) AddTestUser(userID string, identity *providers.ExternalIdentity) {
							 | 
						|
									m.TestUsers[userID] = identity
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Authenticate overrides the parent Authenticate method to use mock data
							 | 
						|
								func (m *MockOIDCProvider) Authenticate(ctx context.Context, token string) (*providers.ExternalIdentity, error) {
							 | 
						|
									if !m.initialized {
							 | 
						|
										return nil, fmt.Errorf("provider not initialized")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if token == "" {
							 | 
						|
										return nil, fmt.Errorf("token cannot be empty")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Validate token using mock validation
							 | 
						|
									claims, err := m.ValidateToken(ctx, token)
							 | 
						|
									if err != nil {
							 | 
						|
										return nil, err
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Map claims to external identity
							 | 
						|
									email, _ := claims.GetClaimString("email")
							 | 
						|
									displayName, _ := claims.GetClaimString("name")
							 | 
						|
									groups, _ := claims.GetClaimStringSlice("groups")
							 | 
						|
								
							 | 
						|
									return &providers.ExternalIdentity{
							 | 
						|
										UserID:      claims.Subject,
							 | 
						|
										Email:       email,
							 | 
						|
										DisplayName: displayName,
							 | 
						|
										Groups:      groups,
							 | 
						|
										Provider:    m.name,
							 | 
						|
									}, nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// ValidateToken validates tokens using test data
							 | 
						|
								func (m *MockOIDCProvider) ValidateToken(ctx context.Context, token string) (*providers.TokenClaims, error) {
							 | 
						|
									if !m.initialized {
							 | 
						|
										return nil, fmt.Errorf("provider not initialized")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if token == "" {
							 | 
						|
										return nil, fmt.Errorf("token cannot be empty")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Special test tokens
							 | 
						|
									if token == "expired_token" {
							 | 
						|
										return nil, fmt.Errorf("token has expired")
							 | 
						|
									}
							 | 
						|
									if token == "invalid_token" {
							 | 
						|
										return nil, fmt.Errorf("invalid token")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Try to parse as JWT token first
							 | 
						|
									if len(token) > 20 && strings.Count(token, ".") >= 2 {
							 | 
						|
										parsedToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
							 | 
						|
										if err == nil {
							 | 
						|
											if jwtClaims, ok := parsedToken.Claims.(jwt.MapClaims); ok {
							 | 
						|
												issuer, _ := jwtClaims["iss"].(string)
							 | 
						|
												subject, _ := jwtClaims["sub"].(string)
							 | 
						|
												audience, _ := jwtClaims["aud"].(string)
							 | 
						|
								
							 | 
						|
												// Verify the issuer matches our configuration
							 | 
						|
												if issuer == m.config.Issuer && subject != "" {
							 | 
						|
													// Extract expiration and issued at times
							 | 
						|
													var expiresAt, issuedAt time.Time
							 | 
						|
													if exp, ok := jwtClaims["exp"].(float64); ok {
							 | 
						|
														expiresAt = time.Unix(int64(exp), 0)
							 | 
						|
													}
							 | 
						|
													if iat, ok := jwtClaims["iat"].(float64); ok {
							 | 
						|
														issuedAt = time.Unix(int64(iat), 0)
							 | 
						|
													}
							 | 
						|
								
							 | 
						|
													return &providers.TokenClaims{
							 | 
						|
														Subject:   subject,
							 | 
						|
														Issuer:    issuer,
							 | 
						|
														Audience:  audience,
							 | 
						|
														ExpiresAt: expiresAt,
							 | 
						|
														IssuedAt:  issuedAt,
							 | 
						|
														Claims: map[string]interface{}{
							 | 
						|
															"email": subject + "@test-domain.com",
							 | 
						|
															"name":  "Test User " + subject,
							 | 
						|
														},
							 | 
						|
													}, nil
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Check test tokens
							 | 
						|
									if claims, exists := m.TestTokens[token]; exists {
							 | 
						|
										return claims, nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Default test token for basic testing
							 | 
						|
									if token == "valid_test_token" {
							 | 
						|
										return &providers.TokenClaims{
							 | 
						|
											Subject:   "test-user-id",
							 | 
						|
											Issuer:    m.config.Issuer,
							 | 
						|
											Audience:  m.config.ClientID,
							 | 
						|
											ExpiresAt: time.Now().Add(time.Hour),
							 | 
						|
											IssuedAt:  time.Now(),
							 | 
						|
											Claims: map[string]interface{}{
							 | 
						|
												"email":  "test@example.com",
							 | 
						|
												"name":   "Test User",
							 | 
						|
												"groups": []string{"developers", "users"},
							 | 
						|
											},
							 | 
						|
										}, nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return nil, fmt.Errorf("unknown test token: %s", token)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// GetUserInfo returns test user info
							 | 
						|
								func (m *MockOIDCProvider) GetUserInfo(ctx context.Context, userID string) (*providers.ExternalIdentity, error) {
							 | 
						|
									if !m.initialized {
							 | 
						|
										return nil, fmt.Errorf("provider not initialized")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if userID == "" {
							 | 
						|
										return nil, fmt.Errorf("user ID cannot be empty")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Check test users
							 | 
						|
									if identity, exists := m.TestUsers[userID]; exists {
							 | 
						|
										return identity, nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Default test user
							 | 
						|
									return &providers.ExternalIdentity{
							 | 
						|
										UserID:      userID,
							 | 
						|
										Email:       userID + "@example.com",
							 | 
						|
										DisplayName: "Test User " + userID,
							 | 
						|
										Provider:    m.name,
							 | 
						|
									}, nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// SetupDefaultTestData configures common test data
							 | 
						|
								func (m *MockOIDCProvider) SetupDefaultTestData() {
							 | 
						|
									// Create default token claims
							 | 
						|
									defaultClaims := &providers.TokenClaims{
							 | 
						|
										Subject:   "test-user-123",
							 | 
						|
										Issuer:    "https://test-issuer.com",
							 | 
						|
										Audience:  "test-client-id",
							 | 
						|
										ExpiresAt: time.Now().Add(time.Hour),
							 | 
						|
										IssuedAt:  time.Now(),
							 | 
						|
										Claims: map[string]interface{}{
							 | 
						|
											"email":  "testuser@example.com",
							 | 
						|
											"name":   "Test User",
							 | 
						|
											"groups": []string{"developers"},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Add multiple token variants for compatibility
							 | 
						|
									m.AddTestToken("valid_token", defaultClaims)
							 | 
						|
									m.AddTestToken("valid-oidc-token", defaultClaims) // For integration tests
							 | 
						|
									m.AddTestToken("valid_test_token", defaultClaims) // For STS tests
							 | 
						|
								
							 | 
						|
									// Add default test users
							 | 
						|
									m.AddTestUser("test-user-123", &providers.ExternalIdentity{
							 | 
						|
										UserID:      "test-user-123",
							 | 
						|
										Email:       "testuser@example.com",
							 | 
						|
										DisplayName: "Test User",
							 | 
						|
										Groups:      []string{"developers"},
							 | 
						|
										Provider:    m.name,
							 | 
						|
									})
							 | 
						|
								}
							 |