diff --git a/cmd/cognito_test/cognito.auth.harness/main.go b/cmd/cognito_test/cognito.auth.harness/main.go index b918eb13..30e0ce9f 100644 --- a/cmd/cognito_test/cognito.auth.harness/main.go +++ b/cmd/cognito_test/cognito.auth.harness/main.go @@ -8,6 +8,7 @@ import ( "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" + "queryorchestration/internal/cognitoauth" // Replace with your actual package import path ) diff --git a/cmd/cognito_test/jwtstuff/main.go b/cmd/cognito_test/jwtstuff/main.go.save similarity index 100% rename from cmd/cognito_test/jwtstuff/main.go rename to cmd/cognito_test/jwtstuff/main.go.save diff --git a/cmd/queryAPI/main.go b/cmd/queryAPI/main.go index b9d94106..b534a9ab 100644 --- a/cmd/queryAPI/main.go +++ b/cmd/queryAPI/main.go @@ -34,7 +34,6 @@ import ( "queryorchestration/internal/server/api" "queryorchestration/internal/serviceconfig/queue/clientsync" "queryorchestration/internal/serviceconfig/queue/queryversionsync" - "queryorchestration/internal/serviceconfig/rbac" "github.com/getkin/kin-openapi/openapi3" _ "github.com/lib/pq" @@ -106,12 +105,13 @@ func main() { os.Exit(1) } + // note initialize cognito config here // Initialize the rbac config here since only the API service needs it - errorGettingAuthProvider := rbac.InitializeAuthProvider(&cfg.AuthConfig) - if errorGettingAuthProvider != nil { - slog.Error(errorGettingAuthProvider.Error()) - os.Exit(1) - } + //errorGettingAuthProvider := rbac.InitializeAuthProvider(&cfg.AuthConfig) + //if errorGettingAuthProvider != nil { + // slog.Error(errorGettingAuthProvider.Error()) + // os.Exit(1) + //} server, err := api.New(ctx, cfg) if err != nil { diff --git a/internal/cognitoauth/auth.go b/internal/cognitoauth/auth.go index 1b442d9b..ef2969a2 100644 --- a/internal/cognitoauth/auth.go +++ b/internal/cognitoauth/auth.go @@ -11,7 +11,7 @@ import ( ) // RegisterRoutes registers all authentication-related routes to the Echo engine -func RegisterRoutes(e *echo.Echo, config *Config) { +func RegisterRoutes(e *echo.Echo, config *CognitoConfig) { // Register the login route - the middleware will handle this e.GET(config.LoginPath, func(c echo.Context) error { // This is handled by the middleware @@ -53,7 +53,7 @@ func RegisterRoutes(e *echo.Echo, config *Config) { } // HomeHandler implements a simple home page that shows auth status and available endpoints -func HomeHandler(c echo.Context, config *Config) error { +func HomeHandler(c echo.Context, config *CognitoConfig) error { // Create a list of all registered routes var endpoints []string diff --git a/internal/cognitoauth/config.go b/internal/cognitoauth/config.go index d03e9f71..08053a32 100644 --- a/internal/cognitoauth/config.go +++ b/internal/cognitoauth/config.go @@ -8,27 +8,30 @@ import ( "strings" ) -// Config holds the configuration for AWS Cognito +// CognitoConfig holds the configuration for AWS Cognito // Contains all necessary parameters to interact with Cognito endpoints -type Config struct { - ClientID string // OAuth2 client ID registered with Cognito +type CognitoConfig struct { RedirectURI string // URL where Cognito redirects after authentication TokenURL string // Cognito endpoint for token operations JwksURL string // URL for JSON Web Key Set (for token verification) - UserPoolID string // Cognito User Pool ID AuthURL string // Cognito authorization endpoint for initiating login - ClientSecret string // Client secret for authenticated clients - Region string // AWS region where the Cognito User Pool is located LoginPath string // Path for initiating login CallbackPath string // Path for OAuth callback HomePath string // Path for home page LogoutPath string // Path for logout Logger *slog.Logger // Logger instance RoutePermissions map[string][]string // Map of routes to required permissions + + // annotated vars + Region string `env:"COGNITO_REGION" envDefault:"us-east-2"` + UserPoolID string `env:"COGNITO_USER_POOL_ID" required:"true"` + ClientSecret string `env:"COGNITO_CLIENT_SECRET" required:"true"` + Domain string `env:"COGNITO_DOMAIN" required:"true"` + ClientID string `env:"COGNITO_CLIENT_ID" required:"true"` } -// NewConfigFromEnv creates a new Config from environment variables -func NewConfigFromEnv(baseURL string, logger *slog.Logger) *Config { +// NewConfigFromEnv creates a new CognitoConfig from environment variables +func NewConfigFromEnv(baseURL string, logger *slog.Logger) *CognitoConfig { // Set default logger if not provided if logger == nil { var logLevel slog.Level @@ -94,7 +97,7 @@ func NewConfigFromEnv(baseURL string, logger *slog.Logger) *Config { // Sanitize base URL (remove trailing slash) baseURL = strings.TrimSuffix(baseURL, "/") - config := &Config{ + config := &CognitoConfig{ ClientID: os.Getenv("COGNITO_CLIENT_ID"), ClientSecret: os.Getenv("COGNITO_CLIENT_SECRET"), RedirectURI: baseURL + callbackPath, @@ -115,8 +118,8 @@ func NewConfigFromEnv(baseURL string, logger *slog.Logger) *Config { return config } -func (c *Config) PrettyPrint() { - fmt.Printf("Config:\n") +func (c *CognitoConfig) PrettyPrint() { + fmt.Printf("CognitoConfig:\n") fmt.Printf(" ClientID: %s\n", c.ClientID) fmt.Printf(" ClientSecret: %s\n", c.ClientSecret) fmt.Printf(" RedirectURI: %s\n", c.RedirectURI) @@ -138,6 +141,6 @@ func (c *Config) PrettyPrint() { } // SetRoutePermissions sets the route permissions map -func (c *Config) SetRoutePermissions(permissions map[string][]string) { +func (c *CognitoConfig) SetRoutePermissions(permissions map[string][]string) { c.RoutePermissions = permissions } diff --git a/internal/cognitoauth/handler.go b/internal/cognitoauth/handler.go index f267ec24..a1114855 100644 --- a/internal/cognitoauth/handler.go +++ b/internal/cognitoauth/handler.go @@ -15,7 +15,7 @@ import ( // initiateLoginWithPKCE generates PKCE code challenge and redirects to Cognito // This function starts the OAuth authorization flow with PKCE -func initiateLoginWithPKCE(c echo.Context, config *Config) error { +func initiateLoginWithPKCE(c echo.Context, config *CognitoConfig) error { // Generate random state parameter to prevent CSRF state, err := generateRandomString(32) if err != nil { @@ -63,7 +63,7 @@ func initiateLoginWithPKCE(c echo.Context, config *Config) error { // exchangeCodeForTokensWithPKCE exchanges the authorization code for tokens using PKCE // Called during the OAuth callback flow to get tokens from the authorization code // Makes an HTTP request to Cognito's token endpoint to perform this exchange -func exchangeCodeForTokensWithPKCE(authCode, codeVerifier string, config Config) (*TokenResponse, error) { +func exchangeCodeForTokensWithPKCE(authCode, codeVerifier string, config CognitoConfig) (*TokenResponse, error) { data := url.Values{} data.Set("grant_type", "authorization_code") data.Set("client_id", config.ClientID) @@ -118,7 +118,7 @@ func exchangeCodeForTokensWithPKCE(authCode, codeVerifier string, config Config) // handleOAuthCallback handles the OAuth 2.0 authorization code flow callback with PKCE // Called when Cognito redirects back to our application with an authorization code // Exchanges the code for tokens, verifies them, and redirects to home page with token in cookie -func handleOAuthCallback(c echo.Context, config *Config) error { +func handleOAuthCallback(c echo.Context, config *CognitoConfig) error { // Extract the authorization code and state code := c.QueryParam("code") if code == "" { @@ -228,7 +228,7 @@ func handleOAuthCallback(c echo.Context, config *Config) error { } // LogoutHandler handles the logout process by clearing the auth cookie -func LogoutHandler(c echo.Context, config *Config) error { +func LogoutHandler(c echo.Context, config *CognitoConfig) error { // Clear the token cookie cookie := new(http.Cookie) cookie.Name = "auth_token" diff --git a/internal/cognitoauth/middleware.go b/internal/cognitoauth/middleware.go index 0e6b5dfa..555f4e41 100644 --- a/internal/cognitoauth/middleware.go +++ b/internal/cognitoauth/middleware.go @@ -10,7 +10,7 @@ import ( // TokenValidationMiddleware verifies JWT tokens efficiently // This is the primary middleware that handles both authentication and authorization // Applied to all routes to enforce security requirements -func TokenValidationMiddleware(config *Config) echo.MiddlewareFunc { +func TokenValidationMiddleware(config *CognitoConfig) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { requestPath := c.Request().URL.Path @@ -106,7 +106,7 @@ func TokenValidationMiddleware(config *Config) echo.MiddlewareFunc { } // JWTAuthMiddleware checks for JWT token in cookies and adds it to the Authorization header -func JWTAuthMiddleware(config *Config) echo.MiddlewareFunc { +func JWTAuthMiddleware(config *CognitoConfig) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // Skip for login and callback paths diff --git a/internal/cognitoauth/token.go b/internal/cognitoauth/token.go index bfce4974..002767d1 100644 --- a/internal/cognitoauth/token.go +++ b/internal/cognitoauth/token.go @@ -17,7 +17,7 @@ import ( // verifyToken verifies the JWT token and returns its claims // Used during both OAuth callback and subsequent API requests with bearer token // Verifies signature, expiration, issuer, and other JWT claims -func verifyToken(tokenString string, keySet jwk.Set, config Config) (map[string]interface{}, error) { +func verifyToken(tokenString string, keySet jwk.Set, config CognitoConfig) (map[string]interface{}, error) { region := config.Region issuer := fmt.Sprintf("https://cognito-idp.%s.amazonaws.com/%s", region, config.UserPoolID) diff --git a/internal/cognitoauth/utils.go b/internal/cognitoauth/utils.go index 980316ad..8740f9a1 100644 --- a/internal/cognitoauth/utils.go +++ b/internal/cognitoauth/utils.go @@ -84,14 +84,14 @@ func checkPermissions(path string, userGroups []string, routePermissions map[str return false, requiredGroups } -// Helper function to mask sensitive values -// Used for logging sensitive information like client IDs -func maskString(s string) string { - if s == "" { - return "" - } - if len(s) <= 8 { - return "****" - } - return s[:4] + "..." + s[len(s)-4:] -} +//// Helper function to mask sensitive values +//// Used for logging sensitive information like client IDs +//func maskString(s string) string { +// if s == "" { +// return "" +// } +// if len(s) <= 8 { +// return "****" +// } +// return s[:4] + "..." + s[len(s)-4:] +//} diff --git a/internal/serviceconfig/cognitoauth/config.go b/internal/serviceconfig/cognitoauth/config.go new file mode 100644 index 00000000..4000b10e --- /dev/null +++ b/internal/serviceconfig/cognitoauth/config.go @@ -0,0 +1,147 @@ +package cognitoauth + +import ( + "fmt" + "log" + "log/slog" + "os" + "strings" +) + +// CognitoConfig holds the configuration for AWS Cognito +// Contains all necessary parameters to interact with Cognito endpoints +type CognitoConfig struct { + // annotated vars + Region string `env:"COGNITO_REGION" envDefault:"us-east-2"` + UserPoolID string `env:"COGNITO_USER_POOL_ID,required,notEmpty"` + ClientSecret string `env:"COGNITO_CLIENT_SECRET,required,notEmpty"` + Domain string `env:"COGNITO_DOMAIN,required,notEmpty"` + ClientID string `env:"COGNITO_CLIENT_ID,required,notEmpty"` + + RedirectURI string // URL where Cognito redirects after authentication + TokenURL string // Cognito endpoint for token operations + JwksURL string // URL for JSON Web Key Set (for token verification) + AuthURL string // Cognito authorization endpoint for initiating login + LoginPath string // Path for initiating login + CallbackPath string // Path for OAuth callback + HomePath string // Path for home page + LogoutPath string // Path for logout + AuthLogger *slog.Logger // Logger instance ( normally just the same logger as main) + RoutePermissions map[string][]string // Map of routes to required permissions +} + +// InitializeConfig creates a new CognitoConfig from environment variables +// and sets the values that are computed from other values +func InitializeConfig(baseURL string, logger *slog.Logger) *CognitoConfig { + // Set default logger if not provided + if logger == nil { + var logLevel slog.Level + if os.Getenv("DEBUG") == "true" { + logLevel = slog.LevelDebug + } else { + logLevel = slog.LevelInfo + } + + logHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + Level: logLevel, + }) + logger = slog.New(logHandler) + } + + // Set paths with defaults + loginPath := os.Getenv("COGNITO_LOGIN_PATH") + if loginPath == "" { + loginPath = "/login" + } + + callbackPath := os.Getenv("COGNITO_CALLBACK_PATH") + if callbackPath == "" { + callbackPath = "/login-callback" + } + + homePath := os.Getenv("COGNITO_HOME_PATH") + if homePath == "" { + homePath = "/home" + } + + logoutPath := os.Getenv("COGNITO_LOGOUT_PATH") + if logoutPath == "" { + logoutPath = "/logout" + } + + // Get AWS region with fallback + region := os.Getenv("AWS_REGION") + if region == "" { + region = "us-east-2" // Fallback to default value + } + + // Get User Pool ID with fallback + userPoolID := os.Getenv("COGNITO_USER_POOL_ID") + if userPoolID == "" { + userPoolID = "" // No default, will need to be provided + logger.Warn("COGNITO_USER_POOL_ID environment variable is not set") + } + + // Get Cognito domain + domain := os.Getenv("COGNITO_DOMAIN") + if domain == "" { + //logger.Warn("COGNITO_DOMAIN environment variable is not set, using default") + //// Use the user pool ID directly as part of the domain + //domain = fmt.Sprintf("%s.auth.%s.amazoncognito.com", userPoolID, region) + log.Fatalf("COGNITO_DOMAIN environment variable is not set") + } + + // Ensure domain format is correct (no protocol prefix) + domain = strings.TrimPrefix(domain, "https://") + domain = strings.TrimPrefix(domain, "http://") + + // Sanitize base URL (remove trailing slash) + baseURL = strings.TrimSuffix(baseURL, "/") + + config := &CognitoConfig{ + ClientID: os.Getenv("COGNITO_CLIENT_ID"), + ClientSecret: os.Getenv("COGNITO_CLIENT_SECRET"), + RedirectURI: baseURL + callbackPath, + TokenURL: fmt.Sprintf("https://%s/oauth2/token", domain), + AuthURL: fmt.Sprintf("https://%s/oauth2/authorize", domain), + JwksURL: fmt.Sprintf("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", region, userPoolID), + UserPoolID: userPoolID, + Region: region, + LoginPath: loginPath, + CallbackPath: callbackPath, + HomePath: homePath, + LogoutPath: logoutPath, + AuthLogger: logger, + RoutePermissions: make(map[string][]string), + } + + config.PrettyPrint() + return config +} + +func (c *CognitoConfig) PrettyPrint() { + fmt.Printf("CognitoConfig:\n") + fmt.Printf(" ClientID: %s\n", c.ClientID) + fmt.Printf(" ClientSecret: %s\n", c.ClientSecret) + fmt.Printf(" RedirectURI: %s\n", c.RedirectURI) + fmt.Printf(" TokenURL: %s\n", c.TokenURL) + fmt.Printf(" AuthURL: %s\n", c.AuthURL) + fmt.Printf(" JwksURL: %s\n", c.JwksURL) + fmt.Printf(" UserPoolID: %s\n", c.UserPoolID) + fmt.Printf(" Region: %s\n", c.Region) + fmt.Printf(" LoginPath: %s\n", c.LoginPath) + fmt.Printf(" CallbackPath: %s\n", c.CallbackPath) + fmt.Printf(" HomePath: %s\n", c.HomePath) + fmt.Printf(" LogoutPath: %s\n", c.LogoutPath) + + // pretty print the route permissions map + for route, permissions := range c.RoutePermissions { + fmt.Printf(" Route: %s, Permissions: %v\n", route, permissions) + } + +} + +// SetRoutePermissions sets the route permissions map +func (c *CognitoConfig) SetRoutePermissions(permissions map[string][]string) { + c.RoutePermissions = permissions +} diff --git a/internal/serviceconfig/common.go b/internal/serviceconfig/common.go index 6d03cee3..60d35acc 100644 --- a/internal/serviceconfig/common.go +++ b/internal/serviceconfig/common.go @@ -4,12 +4,11 @@ import ( "errors" "fmt" "log/slog" + "queryorchestration/internal/serviceconfig/cognitoauth" "reflect" "strings" "sync" - "queryorchestration/internal/serviceconfig/rbac" - "queryorchestration/internal/serviceconfig/aws" "queryorchestration/internal/serviceconfig/database" "queryorchestration/internal/serviceconfig/logger" @@ -33,7 +32,8 @@ type BaseConfig struct { Pwd string `env:"PWD,required,notEmpty"` - rbac.AuthConfig + //rbac.AuthConfig + cognitoauth.CognitoConfig logger.LogConfig observability.ObsConfig database.DBConfig @@ -52,7 +52,7 @@ type ConfigProvider interface { logger.ConfigProvider aws.ConfigProvider queue.ConfigProvider - rbac.ConfigProvider + //rbac.ConfigProvider } // Configuration Methods diff --git a/internal/serviceconfig/rbac/config.go b/internal/serviceconfig/rbac/config.go deleted file mode 100644 index 4f83c75f..00000000 --- a/internal/serviceconfig/rbac/config.go +++ /dev/null @@ -1,92 +0,0 @@ -package rbac - -import ( - "fmt" - "log/slog" - - "queryorchestration/internal/rbac" -) - -// AuthConfig holds the RBAC configuration and KeyProvider -type AuthConfig struct { - // cognito or local - AuthType string `env:"RBAC_PROVIDER" envDefault:"local"` - // Cognito Config - CognitoRegion string `env:"COGNITO_REGION" envDefault:"us-east-1"` - CognitoUserPoolID string `env:"COGNITO_USER_POOL_ID"` - // Local Key Config - PrivateKeyPath string `env:"RBAC_PRIVATE_KEY_PATH" envDefault:"./public_key.pem"` - PublicKeyPath string `env:"RBAC_PUBLIC_KEY_PATH" envDefault:"./private_key.pem"` - - // Actual provider - can be either local or cognito - AuthProvider rbac.KeyProvider -} - -// ConfigProvider interface defines the methods required for RBAC configuration -type ConfigProvider interface { - //Initialize() error - GetKeyProvider() rbac.KeyProvider - PrintAuthConfig() -} - -// GetKeyProvider returns the configured KeyProvider -func (r *AuthConfig) GetKeyProvider() rbac.KeyProvider { - return r.AuthProvider -} - -func InitializeAuthProvider(config *AuthConfig) error { - return config.InitializeAuthProvider() -} - -// InitializeAuthProvider initializes the appropriate KeyProvider based on configuration -func (r *AuthConfig) InitializeAuthProvider() error { - switch r.AuthType { - case "local": - if r.PrivateKeyPath == "" || r.PublicKeyPath == "" { - return fmt.Errorf("local key provider requires both private and public key paths") - } - r.AuthProvider = rbac.NewLocalKeyProvider(r.PrivateKeyPath, r.PublicKeyPath) - slog.Info("RBAC initialized with local key provider") - - case "cognito": - if r.CognitoUserPoolID == "" { - return fmt.Errorf("cognito provider requires user pool ID") - } - r.AuthProvider = rbac.NewCognitoKeyProvider(r.CognitoRegion, r.CognitoUserPoolID) - slog.Info("RBAC initialized with Cognito key provider") - - default: - return fmt.Errorf("unknown RBAC provider type: %s", r.AuthType) - } - r.PrintAuthConfig() - - return nil -} - -// PrintAuthConfig logs the current configuration, masking sensitive values -func (r *AuthConfig) PrintAuthConfig() { - slog.Info("RBAC AuthConfig:", - "provider_type", r.AuthType, - "region", r.CognitoRegion, - "user_pool_id", r.CognitoUserPoolID, - "private_key_path", r.PrivateKeyPath, - "public_key_path", r.PublicKeyPath, - ) -} - -// Validate checks if the configuration is valid -func (r *AuthConfig) Validate() error { - switch r.AuthType { - case "local": - if r.PrivateKeyPath == "" || r.PublicKeyPath == "" { - return fmt.Errorf("local key provider requires both private and public key paths") - } - case "cognito": - if r.CognitoUserPoolID == "" { - return fmt.Errorf("cognito provider requires user pool ID") - } - default: - return fmt.Errorf("invalid provider type: %s", r.AuthType) - } - return nil -} diff --git a/internal/serviceconfig/rbac/config_test.go b/internal/serviceconfig/rbac/config_test.go deleted file mode 100644 index 02a21b92..00000000 --- a/internal/serviceconfig/rbac/config_test.go +++ /dev/null @@ -1,311 +0,0 @@ -package rbac_test - -import ( - "crypto/rsa" - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "queryorchestration/internal/serviceconfig/rbac" -) - -// TestGetKeyProvider tests the GetKeyProvider method -func TestGetKeyProvider(t *testing.T) { - // Create a temporary directory for test key files - tmpDir, err := os.MkdirTemp("", "rbac-test") - if err != nil { - t.Fatalf("Failed to create temp dir: %v", err) - } - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Failed to remove temp dir: %v", err) - } - }(tmpDir) - - // Create temporary key files with minimal PEM format - privateKeyPath := tmpDir + "/private_key.pem" - publicKeyPath := tmpDir + "/public_key.pem" - - // Write minimal PEM content to the key files - // These are not valid RSA keys, but that doesn't matter for this test - // as we're just testing that the config passes the paths correctly - err = os.WriteFile(privateKeyPath, []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0Gzk05Pbnb12O7O+vCrwY9oMsEsKkJZ1hnMvP4JXOa0beJAw -DgYKAAAAAAAAAAA= ------END RSA PRIVATE KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write private key: %v", err) - } - - err = os.WriteFile(publicKeyPath, []byte(`-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Gzk05Pbnb12O7O+vCrw -Y9oMsEsKkJZ1hnMvP4JXOa0beJAwOJosFh5kAAs= ------END PUBLIC KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write public key: %v", err) - } - - // Create an AuthConfig with local provider - config := &rbac.AuthConfig{ - AuthType: "local", - PrivateKeyPath: privateKeyPath, - PublicKeyPath: publicKeyPath, - } - - // Since we can't successfully load invalid keys, we'll just test the GetKeyProvider method directly - // without initializing the provider - config.AuthProvider = &mockKeyProvider{} // Use our mock key provider - - // Test GetKeyProvider - provider := config.GetKeyProvider() - assert.NotNil(t, provider, "GetKeyProvider should return a non-nil provider") - assert.Equal(t, &mockKeyProvider{}, provider, "Provider should match what we set") -} - -// TestInitializeAuthProvider tests the InitializeAuthProvider function -func TestInitializeAuthProvider(t *testing.T) { - // Create a temporary directory for test key files - tmpDir, err := os.MkdirTemp("", "rbac-test") - if err != nil { - t.Fatalf("Failed to create temp dir: %v", err) - } - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Failed to remove temp dir: %v", err) - } - }(tmpDir) - - // Create temporary key files - privateKeyPath := tmpDir + "/private_key.pem" - publicKeyPath := tmpDir + "/public_key.pem" - - // Write some dummy content to the key files - these are NOT valid keys - err = os.WriteFile(privateKeyPath, []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0Gzk05Pbnb12O7O+vCrwY9oMsEsKkJZ1hnMvP4JXOa0beJAw -DgYKAAAAAAAAAAA= ------END RSA PRIVATE KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write private key: %v", err) - } - - err = os.WriteFile(publicKeyPath, []byte(`-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Gzk05Pbnb12O7O+vCrw -Y9oMsEsKkJZ1hnMvP4JXOa0beJAwOJosFh5kAAs= ------END PUBLIC KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write public key: %v", err) - } - - // Test cases for InitializeAuthProvider - testCases := []struct { - name string - config *rbac.AuthConfig - expectError bool - }{ - { - name: "Missing local key paths", - config: &rbac.AuthConfig{ - AuthType: "local", - }, - expectError: true, - }, - { - name: "Missing Cognito user pool ID", - config: &rbac.AuthConfig{ - AuthType: "cognito", - CognitoRegion: "us-east-1", - // Missing user pool ID - }, - expectError: true, - }, - { - name: "Invalid auth type", - config: &rbac.AuthConfig{ - AuthType: "invalid", - }, - expectError: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := rbac.InitializeAuthProvider(tc.config) - - if tc.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// TestAuthConfigInitializeAuthProvider tests the AuthConfig method version of InitializeAuthProvider -func TestAuthConfigInitializeAuthProvider(t *testing.T) { - // Create a temporary directory for test key files - tmpDir, err := os.MkdirTemp("", "rbac-test") - if err != nil { - t.Fatalf("Failed to create temp dir: %v", err) - } - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - t.Fatalf("Failed to remove temp dir: %v", err) - } - }(tmpDir) - - // Create temporary key files - privateKeyPath := tmpDir + "/private_key.pem" - publicKeyPath := tmpDir + "/public_key.pem" - - // Write dummy PEM content to the key files - err = os.WriteFile(privateKeyPath, []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0Gzk05Pbnb12O7O+vCrwY9oMsEsKkJZ1hnMvP4JXOa0beJAw -DgYKAAAAAAAAAAA= ------END RSA PRIVATE KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write private key: %v", err) - } - - err = os.WriteFile(publicKeyPath, []byte(`-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Gzk05Pbnb12O7O+vCrw -Y9oMsEsKkJZ1hnMvP4JXOa0beJAwOJosFh5kAAs= ------END PUBLIC KEY-----`), 0600) - if err != nil { - t.Fatalf("Failed to write public key: %v", err) - } - - testCases := []struct { - name string - config *rbac.AuthConfig - expectError bool - }{ - { - name: "Supplied local key paths", - config: &rbac.AuthConfig{ - AuthType: "local", - // Missing key paths - PublicKeyPath: publicKeyPath, - PrivateKeyPath: privateKeyPath, - }, - expectError: false, - }, - { - name: "Missing Cognito user pool ID", - config: &rbac.AuthConfig{ - AuthType: "cognito", - CognitoRegion: "us-east-1", - // Missing user pool ID - }, - expectError: true, - }, - { - name: "Invalid auth type", - config: &rbac.AuthConfig{ - AuthType: "invalid", - }, - expectError: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.config.InitializeAuthProvider() - - if tc.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// TestPrintAuthConfig tests the PrintAuthConfig method -func TestPrintAuthConfig(t *testing.T) { - // Create an AuthConfig with some test values - config := &rbac.AuthConfig{ - AuthType: "cognito", - CognitoRegion: "us-east-1", - CognitoUserPoolID: "us-east-1_TestPool", - PrivateKeyPath: "/path/to/private.pem", - PublicKeyPath: "/path/to/public.pem", - } - - // Call PrintAuthConfig - there's no return value, so we're just ensuring it doesn't panic - config.PrintAuthConfig() -} - -// TestValidate tests the Validate method -func TestValidate(t *testing.T) { - testCases := []struct { - name string - config *rbac.AuthConfig - expectError bool - }{ - { - name: "Valid local config", - config: &rbac.AuthConfig{ - AuthType: "local", - PrivateKeyPath: "/path/to/private.pem", - PublicKeyPath: "/path/to/public.pem", - }, - expectError: false, - }, - { - name: "Valid Cognito config", - config: &rbac.AuthConfig{ - AuthType: "cognito", - CognitoRegion: "us-east-1", - CognitoUserPoolID: "us-east-1_TestPool", - }, - expectError: false, - }, - { - name: "Invalid auth type", - config: &rbac.AuthConfig{ - AuthType: "invalid", - }, - expectError: true, - }, - { - name: "Missing local key paths", - config: &rbac.AuthConfig{ - AuthType: "local", - // Missing key paths - }, - expectError: true, - }, - { - name: "Missing Cognito user pool ID", - config: &rbac.AuthConfig{ - AuthType: "cognito", - CognitoRegion: "us-east-1", - // Missing user pool ID - }, - expectError: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.config.Validate() - - if tc.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Mock key provider for testing -type mockKeyProvider struct{} - -func (m *mockKeyProvider) GetPublicKey(kid string) (*rsa.PublicKey, error) { - return nil, nil -}