Files
query-orchestration/internal/serviceconfig/auth/config.go
T
2025-04-14 13:39:13 -07:00

337 lines
9.5 KiB
Go

package auth
import (
"fmt"
"log"
"log/slog"
"os"
"reflect"
"strings"
)
// CognitoConfig holds the configuration for AWS Cognito
// Contains all necessary parameters to interact with Cognito endpoints
type CognitoConfig struct {
// annotated vars
AuthRegion string `env:"COGNITO_REGION" envDefault:"us-east-2"`
AuthUserPoolID string `env:"COGNITO_USER_POOL_ID,required,notEmpty"`
AuthClientSecret string `env:"COGNITO_CLIENT_SECRET,required,notEmpty"`
AuthDomain string `env:"COGNITO_DOMAIN,required,notEmpty"`
AuthClientID string `env:"COGNITO_CLIENT_ID,required,notEmpty"`
AuthRedirectURI string // URL where Cognito redirects after authentication
AuthTokenURL string // Cognito endpoint for token operations
AuthJwksURL string // URL for JSON Web Key Set (for token verification)
AuthURL string // Cognito authorization endpoint for initiating login
AuthLoginPath string // Path for initiating login
AuthCallbackPath string // Path for OAuth callback
AuthHomePath string // Path for home page
AuthLogoutPath string // Path for logout
AuthLogger *slog.Logger // Logger instance ( normally just the same logger as main)
AuthRoutePermissions map[string][]string // Map of routes to required permissions
}
type ConfigProvider interface {
// Env annotated fields
GetAuthRegion() string
SetAuthRegion(string)
GetAuthUserPoolID() string
SetAuthUserPoolID(string)
GetAuthClientSecret() string
SetAuthClientSecret(string)
GetAuthDomain() string
SetAuthDomain(string)
GetAuthClientID() string
SetAuthClientID(string)
// Non-env fields
GetAuthRedirectURI() string
SetAuthRedirectURI(string)
GetAuthTokenURL() string
SetAuthTokenURL(string)
GetAuthJwksURL() string
SetAuthJwksURL(string)
GetAuthURL() string
SetAuthURL(string)
GetAuthLoginPath() string
SetAuthLoginPath(string)
GetAuthCallbackPath() string
SetAuthCallbackPath(string)
GetAuthHomePath() string
SetAuthHomePath(string)
GetAuthLogoutPath() string
SetAuthLogoutPath(string)
GetAuthLogger() *slog.Logger
SetAuthLogger(*slog.Logger)
GetAuthRoutePermissions() map[string][]string
SetAuthRoutePermissions(map[string][]string)
// Initialize method
InitializeAuthConfig(baseURL string, logger *slog.Logger) error
}
// InitializeAuthConfig initializes the receiver CognitoConfig instance with values from a newly created config.
// It takes a baseURL string used for redirect URI construction and a logger instance for logging operations.
// The function creates a temporary config using InitializeConfig() and copies all fields to the receiver using reflection.
// Returns an error if initialization fails, nil otherwise.
func (c *CognitoConfig) InitializeAuthConfig(baseURL string, logger *slog.Logger) error {
tempConfig := InitializeConfig(baseURL, logger)
if tempConfig == nil {
return fmt.Errorf("could not initialize auth config")
}
// Use reflection to copy all fields
dst := reflect.ValueOf(c).Elem()
src := reflect.ValueOf(tempConfig).Elem()
for i := 0; i < src.NumField(); i++ {
dstField := dst.Field(i)
srcField := src.Field(i)
if dstField.CanSet() {
dstField.Set(srcField)
}
}
return nil
}
// InitializeConfig creates a new CognitoConfig from environment variables
// and sets the values that are computed from other values and
// sets all default values for fields that will infrequently change.
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{
AuthClientID: os.Getenv("COGNITO_CLIENT_ID"),
AuthClientSecret: os.Getenv("COGNITO_CLIENT_SECRET"),
AuthRedirectURI: baseURL + callbackPath,
AuthTokenURL: fmt.Sprintf("https://%s/oauth2/token", domain),
AuthURL: fmt.Sprintf("https://%s/oauth2/authorize", domain),
AuthJwksURL: fmt.Sprintf("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", region, userPoolID),
AuthUserPoolID: userPoolID,
AuthDomain: domain,
AuthRegion: region,
AuthLoginPath: loginPath,
AuthCallbackPath: callbackPath,
AuthHomePath: homePath,
AuthLogoutPath: logoutPath,
AuthLogger: logger,
AuthRoutePermissions: make(map[string][]string),
}
config.PrettyPrintDebugOnly()
return config
}
func (c *CognitoConfig) PrettyPrintDebugOnly() {
if os.Getenv("DEBUG") == "true" {
fmt.Printf("CognitoConfig (debug on):\n")
fmt.Printf(" AuthClientID: %s\n", c.AuthClientID)
fmt.Printf(" AuthClientSecret: %s\n", c.AuthClientSecret)
fmt.Printf(" AuthRedirectURI: %s\n", c.AuthRedirectURI)
fmt.Printf(" AuthTokenURL: %s\n", c.AuthTokenURL)
fmt.Printf(" AuthURL: %s\n", c.AuthURL)
fmt.Printf(" AuthJwksURL: %s\n", c.AuthJwksURL)
fmt.Printf(" AuthUserPoolID: %s\n", c.AuthUserPoolID)
fmt.Printf(" AuthRegion: %s\n", c.AuthRegion)
fmt.Printf(" AuthLoginPath: %s\n", c.AuthLoginPath)
fmt.Printf(" AuthCallbackPath: %s\n", c.AuthCallbackPath)
fmt.Printf(" AuthHomePath: %s\n", c.AuthHomePath)
fmt.Printf(" AuthLogoutPath: %s\n", c.AuthLogoutPath)
// pretty print the route permissions map
for route, permissions := range c.AuthRoutePermissions {
fmt.Printf(" Route: %s, Permissions: %v\n", route, permissions)
}
}
}
//// SetRoutePermissions sets the route permissions map
//func (c *CognitoConfig) SetRoutePermissions(permissions map[string][]string) {
// c.AuthRoutePermissions = permissions
//}
func (c *CognitoConfig) GetAuthRegion() string {
return c.AuthRegion
}
func (c *CognitoConfig) SetAuthRegion(val string) {
c.AuthRegion = val
}
func (c *CognitoConfig) GetAuthUserPoolID() string {
return c.AuthUserPoolID
}
func (c *CognitoConfig) SetAuthUserPoolID(val string) {
c.AuthUserPoolID = val
}
func (c *CognitoConfig) GetAuthClientSecret() string {
return c.AuthClientSecret
}
func (c *CognitoConfig) SetAuthClientSecret(val string) {
c.AuthClientSecret = val
}
func (c *CognitoConfig) GetAuthDomain() string {
return c.AuthDomain
}
func (c *CognitoConfig) SetAuthDomain(val string) {
c.AuthDomain = val
}
func (c *CognitoConfig) GetAuthClientID() string {
return c.AuthClientID
}
func (c *CognitoConfig) SetAuthClientID(val string) {
c.AuthClientID = val
}
func (c *CognitoConfig) GetAuthRedirectURI() string {
return c.AuthRedirectURI
}
func (c *CognitoConfig) SetAuthRedirectURI(val string) {
c.AuthRedirectURI = val
}
func (c *CognitoConfig) GetAuthTokenURL() string {
return c.AuthTokenURL
}
func (c *CognitoConfig) SetAuthTokenURL(val string) {
c.AuthTokenURL = val
}
func (c *CognitoConfig) GetAuthJwksURL() string {
return c.AuthJwksURL
}
func (c *CognitoConfig) SetAuthJwksURL(val string) {
c.AuthJwksURL = val
}
func (c *CognitoConfig) GetAuthURL() string {
return c.AuthURL
}
func (c *CognitoConfig) SetAuthURL(val string) {
c.AuthURL = val
}
func (c *CognitoConfig) GetAuthLoginPath() string {
return c.AuthLoginPath
}
func (c *CognitoConfig) SetAuthLoginPath(val string) {
c.AuthLoginPath = val
}
func (c *CognitoConfig) GetAuthCallbackPath() string {
return c.AuthCallbackPath
}
func (c *CognitoConfig) SetAuthCallbackPath(val string) {
c.AuthCallbackPath = val
}
func (c *CognitoConfig) GetAuthHomePath() string {
return c.AuthHomePath
}
func (c *CognitoConfig) SetAuthHomePath(val string) {
c.AuthHomePath = val
}
func (c *CognitoConfig) GetAuthLogoutPath() string {
return c.AuthLogoutPath
}
func (c *CognitoConfig) SetAuthLogoutPath(val string) {
c.AuthLogoutPath = val
}
func (c *CognitoConfig) GetAuthLogger() *slog.Logger {
return c.AuthLogger
}
func (c *CognitoConfig) SetAuthLogger(val *slog.Logger) {
c.AuthLogger = val
}
func (c *CognitoConfig) GetAuthRoutePermissions() map[string][]string {
return c.AuthRoutePermissions
}
func (c *CognitoConfig) SetAuthRoutePermissions(val map[string][]string) {
c.AuthRoutePermissions = val
}