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, | |
| 	}) | |
| }
 |