From e791a01ea202663a03f1d198dc77a0aac9747f45 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Fri, 3 May 2024 20:20:06 -0600 Subject: [PATCH] Added environment variables support (WIP) --- cmd/root.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++-- cmd/serve.go | 5 +++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 2d3e916..5e5b3e7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,6 +4,8 @@ import ( opaal "davidallendj/opaal/internal" "fmt" "os" + "strconv" + "strings" "github.com/davidallendj/go-utils/pathx" "github.com/spf13/cobra" @@ -17,11 +19,19 @@ var rootCmd = &cobra.Command{ Use: "opaal", Short: "An experimental OIDC helper tool for handling logins", Run: func(cmd *cobra.Command, args []string) { - + // print help and exit + if len(args) <= 0 { + err := cmd.Help() + if err != nil { + fmt.Printf("failed to print help message: %v\n", err) + } + os.Exit(0) + } }, } func Execute() { + initialize() if err := rootCmd.Execute(); err != nil { fmt.Fprintf(os.Stderr, "failed to start CLI: %s", err) os.Exit(1) @@ -29,11 +39,16 @@ func Execute() { } func init() { - cobra.OnInitialize(initConfig) + rootCmd.PersistentFlags().BoolVarP(&config.Options.Verbose, "verbose", "v", false, "set the verbose flag") rootCmd.PersistentFlags().StringVarP(&confPath, "config", "c", "", "set the config path") rootCmd.PersistentFlags().StringVar(&config.Options.CachePath, "cache", "", "set the cache path") } +func initialize() { + initConfig() + initEnv() +} + func initConfig() { // load config if found or create a new one if confPath != "" { @@ -48,3 +63,81 @@ func initConfig() { } } } + +func initEnv() { + // set environment variables before by CLI, but after config + err := parseEnv("OPAAL_LOGIN_HOST", &config.Server.Host) + _ = err + err = parseEnv("OPAAL_LOGIN_PORT", &config.Server.Port) + err = parseEnv("OPAAL_IDP_HOST", &config.Server.Issuer.Host) + err = parseEnv("OPAAL_IDP_PORT", &config.Server.Issuer.Port) + + // authentication env vars + err = parseEnv("OPAAL_IDP_REGISTERED_CLIENTS", &config.Server.Issuer.Clients) + err = parseEnv("OPAAL_AUTHN_CLIENTS", &config.Authentication.Clients) + + // authorization token env vars + err = parseEnv("OPAAL_AUTHZ_TOKEN_FORWARDING", &config.Authorization) + err = parseEnv("OPAAL_AUTHZ_TOKEN_REFRESH", &config.Authorization.Token.Refresh) + err = parseEnv("OPAAL_AUTHZ_TOKEN_DURATION", &config.Authorization.Token.Duration) + err = parseEnv("OPAAL_AUTHZ_TOKEN_SCOPE", &config.Authorization.Token.Scope) + + // authorization endpoint env vars + err = parseEnv("OPAAL_AUTHZ_KEY_PATH", &config.Authorization.KeyPath) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_ISSUER", &config.Authorization.Endpoints.Issuer) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_CONFIG", &config.Authorization.Endpoints.Config) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_JWKS", &config.Authorization.Endpoints.JwksUri) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_TRUSTED_ISSUER", &config.Authorization.Endpoints.TrustedIssuers) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_CLIENTS", &config.Authorization.Endpoints.Clients) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_AUTHORIZE", &config.Authorization.Endpoints.Authorize) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_REGISTER", &config.Authorization.Endpoints.Register) + err = parseEnv("OPAAL_AUTHZ_ENDPOINT_TOKEN", &config.Authorization.Endpoints.Token) + + // other miscellaneous option env vars + err = parseEnv("OPAAL_OPT_VERBOSE", &config.Options.Verbose) + err = parseEnv("OPAAL_OPT_RUN_ONCE", &config.Options.RunOnce) + err = parseEnv("OPAAL_OPT_OPEN_BROWSER", &config.Options.OpenBrowser) + err = parseEnv("OPAAL_OPT_CACHE_ONLY", &config.Options.CacheOnly) + err = parseEnv("OPAAL_OPT_CACHE_PATH", &config.Options.CachePath) + +} + +func parseEnv(evar string, v interface{}) error { + if val := os.Getenv(evar); val != "" { + switch vp := v.(type) { + case *int: + var temp int64 + temp, err := strconv.ParseInt(val, 0, 64) + if err == nil { + *vp = int(temp) + } + case *uint: + var temp uint64 + temp, err := strconv.ParseUint(val, 0, 64) + if err == nil { + *vp = uint(temp) + } + case *string: + *vp = val + case *bool: + switch strings.ToLower(val) { + case "0", "off", "no", "false": + *vp = false + case "1", "on", "yes", "true": + *vp = true + default: + return fmt.Errorf("unrecognized bool value: '%s'", val) + } + case *[]string: + *vp = strings.Split(val, ",") + default: + // try unmarshaling into an object using JSON + // err := json.Unmarshal([]byte(val), &v) + // if err != nil { + // return fmt.Errorf("invalid type for receiving ENV variable value %T", v) + // } + return fmt.Errorf("invalid type for receiving ENV variable value %T", v) + } + } + return nil +} diff --git a/cmd/serve.go b/cmd/serve.go index b68b814..2f35d18 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -22,6 +22,9 @@ var serveCmd = &cobra.Command{ s := opaal.NewServerWithConfig(&config) // FIXME: change how the server address is set with `NewServerWithConfig` s.Server.Addr = fmt.Sprintf("%s:%d", s.Issuer.Host, s.Issuer.Port) + if config.Options.Verbose { + fmt.Printf("Identity provider listening on %s\n", s.Server.Addr) + } err := s.StartIdentityProvider() if errors.Is(err, http.ErrServerClosed) { fmt.Printf("Identity provider server closed.\n") @@ -32,6 +35,8 @@ var serveCmd = &cobra.Command{ } func init() { + serveCmd.Flags().StringVar(&config.Server.Issuer.Host, "host", "127.0.0.1", "set the identity provider host") + serveCmd.Flags().IntVar(&config.Server.Issuer.Port, "port", 3332, "set the identity provider port") serveCmd.Flags().StringVar(&endpoints.Authorization, "endpoints.authorization", "", "set the authorization endpoint for the identity provider") serveCmd.Flags().StringVar(&endpoints.Token, "endpoints.token", "", "set the token endpoint for the identity provider") serveCmd.Flags().StringVar(&endpoints.JwksUri, "endpoints.jwks_uri", "", "set the JWKS endpoints for the identity provider")