mock_provider.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // This file contains mock OIDC provider implementations for testing only.
  2. // These should NOT be used in production environments.
  3. package oidc
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/golang-jwt/jwt/v5"
  10. "github.com/seaweedfs/seaweedfs/weed/iam/providers"
  11. )
  12. // MockOIDCProvider is a mock implementation for testing
  13. type MockOIDCProvider struct {
  14. *OIDCProvider
  15. TestTokens map[string]*providers.TokenClaims
  16. TestUsers map[string]*providers.ExternalIdentity
  17. }
  18. // NewMockOIDCProvider creates a mock OIDC provider for testing
  19. func NewMockOIDCProvider(name string) *MockOIDCProvider {
  20. return &MockOIDCProvider{
  21. OIDCProvider: NewOIDCProvider(name),
  22. TestTokens: make(map[string]*providers.TokenClaims),
  23. TestUsers: make(map[string]*providers.ExternalIdentity),
  24. }
  25. }
  26. // AddTestToken adds a test token with expected claims
  27. func (m *MockOIDCProvider) AddTestToken(token string, claims *providers.TokenClaims) {
  28. m.TestTokens[token] = claims
  29. }
  30. // AddTestUser adds a test user with expected identity
  31. func (m *MockOIDCProvider) AddTestUser(userID string, identity *providers.ExternalIdentity) {
  32. m.TestUsers[userID] = identity
  33. }
  34. // Authenticate overrides the parent Authenticate method to use mock data
  35. func (m *MockOIDCProvider) Authenticate(ctx context.Context, token string) (*providers.ExternalIdentity, error) {
  36. if !m.initialized {
  37. return nil, fmt.Errorf("provider not initialized")
  38. }
  39. if token == "" {
  40. return nil, fmt.Errorf("token cannot be empty")
  41. }
  42. // Validate token using mock validation
  43. claims, err := m.ValidateToken(ctx, token)
  44. if err != nil {
  45. return nil, err
  46. }
  47. // Map claims to external identity
  48. email, _ := claims.GetClaimString("email")
  49. displayName, _ := claims.GetClaimString("name")
  50. groups, _ := claims.GetClaimStringSlice("groups")
  51. return &providers.ExternalIdentity{
  52. UserID: claims.Subject,
  53. Email: email,
  54. DisplayName: displayName,
  55. Groups: groups,
  56. Provider: m.name,
  57. }, nil
  58. }
  59. // ValidateToken validates tokens using test data
  60. func (m *MockOIDCProvider) ValidateToken(ctx context.Context, token string) (*providers.TokenClaims, error) {
  61. if !m.initialized {
  62. return nil, fmt.Errorf("provider not initialized")
  63. }
  64. if token == "" {
  65. return nil, fmt.Errorf("token cannot be empty")
  66. }
  67. // Special test tokens
  68. if token == "expired_token" {
  69. return nil, fmt.Errorf("token has expired")
  70. }
  71. if token == "invalid_token" {
  72. return nil, fmt.Errorf("invalid token")
  73. }
  74. // Try to parse as JWT token first
  75. if len(token) > 20 && strings.Count(token, ".") >= 2 {
  76. parsedToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
  77. if err == nil {
  78. if jwtClaims, ok := parsedToken.Claims.(jwt.MapClaims); ok {
  79. issuer, _ := jwtClaims["iss"].(string)
  80. subject, _ := jwtClaims["sub"].(string)
  81. audience, _ := jwtClaims["aud"].(string)
  82. // Verify the issuer matches our configuration
  83. if issuer == m.config.Issuer && subject != "" {
  84. // Extract expiration and issued at times
  85. var expiresAt, issuedAt time.Time
  86. if exp, ok := jwtClaims["exp"].(float64); ok {
  87. expiresAt = time.Unix(int64(exp), 0)
  88. }
  89. if iat, ok := jwtClaims["iat"].(float64); ok {
  90. issuedAt = time.Unix(int64(iat), 0)
  91. }
  92. return &providers.TokenClaims{
  93. Subject: subject,
  94. Issuer: issuer,
  95. Audience: audience,
  96. ExpiresAt: expiresAt,
  97. IssuedAt: issuedAt,
  98. Claims: map[string]interface{}{
  99. "email": subject + "@test-domain.com",
  100. "name": "Test User " + subject,
  101. },
  102. }, nil
  103. }
  104. }
  105. }
  106. }
  107. // Check test tokens
  108. if claims, exists := m.TestTokens[token]; exists {
  109. return claims, nil
  110. }
  111. // Default test token for basic testing
  112. if token == "valid_test_token" {
  113. return &providers.TokenClaims{
  114. Subject: "test-user-id",
  115. Issuer: m.config.Issuer,
  116. Audience: m.config.ClientID,
  117. ExpiresAt: time.Now().Add(time.Hour),
  118. IssuedAt: time.Now(),
  119. Claims: map[string]interface{}{
  120. "email": "test@example.com",
  121. "name": "Test User",
  122. "groups": []string{"developers", "users"},
  123. },
  124. }, nil
  125. }
  126. return nil, fmt.Errorf("unknown test token: %s", token)
  127. }
  128. // GetUserInfo returns test user info
  129. func (m *MockOIDCProvider) GetUserInfo(ctx context.Context, userID string) (*providers.ExternalIdentity, error) {
  130. if !m.initialized {
  131. return nil, fmt.Errorf("provider not initialized")
  132. }
  133. if userID == "" {
  134. return nil, fmt.Errorf("user ID cannot be empty")
  135. }
  136. // Check test users
  137. if identity, exists := m.TestUsers[userID]; exists {
  138. return identity, nil
  139. }
  140. // Default test user
  141. return &providers.ExternalIdentity{
  142. UserID: userID,
  143. Email: userID + "@example.com",
  144. DisplayName: "Test User " + userID,
  145. Provider: m.name,
  146. }, nil
  147. }
  148. // SetupDefaultTestData configures common test data
  149. func (m *MockOIDCProvider) SetupDefaultTestData() {
  150. // Create default token claims
  151. defaultClaims := &providers.TokenClaims{
  152. Subject: "test-user-123",
  153. Issuer: "https://test-issuer.com",
  154. Audience: "test-client-id",
  155. ExpiresAt: time.Now().Add(time.Hour),
  156. IssuedAt: time.Now(),
  157. Claims: map[string]interface{}{
  158. "email": "testuser@example.com",
  159. "name": "Test User",
  160. "groups": []string{"developers"},
  161. },
  162. }
  163. // Add multiple token variants for compatibility
  164. m.AddTestToken("valid_token", defaultClaims)
  165. m.AddTestToken("valid-oidc-token", defaultClaims) // For integration tests
  166. m.AddTestToken("valid_test_token", defaultClaims) // For STS tests
  167. // Add default test users
  168. m.AddTestUser("test-user-123", &providers.ExternalIdentity{
  169. UserID: "test-user-123",
  170. Email: "testuser@example.com",
  171. DisplayName: "Test User",
  172. Groups: []string{"developers"},
  173. Provider: m.name,
  174. })
  175. }