diff --git a/cmd/root.go b/cmd/root.go index 0ec6f12..3c3ec1c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,9 +1,12 @@ package cmd import ( + "os" "strings" + "time" cmd "tinyauth/cmd/user" "tinyauth/internal/api" + "tinyauth/internal/assets" "tinyauth/internal/auth" "tinyauth/internal/hooks" "tinyauth/internal/providers" @@ -22,29 +25,28 @@ var rootCmd = &cobra.Command{ Short: "The simplest way to protect your apps with a login screen.", Long: `Tinyauth is a simple authentication middleware that adds simple username/password login or OAuth with Google, Github and any generic OAuth provider to all of your docker apps.`, Run: func(cmd *cobra.Command, args []string) { + // Logger + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Logger().Level(zerolog.FatalLevel) + // Get config - log.Info().Msg("Parsing config") var config types.Config parseErr := viper.Unmarshal(&config) HandleError(parseErr, "Failed to parse config") // Secrets - log.Info().Msg("Parsing secrets") - config.Secret = utils.GetSecret(config.Secret, config.SecretFile) config.GithubClientSecret = utils.GetSecret(config.GithubClientSecret, config.GithubClientSecretFile) config.GoogleClientSecret = utils.GetSecret(config.GoogleClientSecret, config.GoogleClientSecretFile) config.GenericClientSecret = utils.GetSecret(config.GenericClientSecret, config.GenericClientSecretFile) // Validate config - log.Info().Msg("Validating config") validator := validator.New() validateErr := validator.Struct(config) - HandleError(validateErr, "Invalid config") + HandleError(validateErr, "Failed to validate config") - // Set log level - log.Info().Int8("log_level", config.LogLevel).Msg("Setting log level") - log.Logger = log.Logger.Level(zerolog.Level(config.LogLevel)) + // Logger + log.Logger = log.Level(zerolog.Level(config.LogLevel)) + log.Info().Str("version", assets.Version).Msg("Starting tinyauth") // Users log.Info().Msg("Parsing users") @@ -56,7 +58,7 @@ var rootCmd = &cobra.Command{ // Create oauth whitelist oauthWhitelist := strings.Split(config.OAuthWhitelist, ",") - log.Debug().Strs("oauth_whitelist", oauthWhitelist).Msg("Parsed OAuth whitelist") + log.Debug().Msg("Parsed OAuth whitelist") // Create OAuth config oauthConfig := types.OAuthConfig{ @@ -72,7 +74,8 @@ var rootCmd = &cobra.Command{ GenericUserURL: config.GenericUserURL, AppURL: config.AppURL, } - log.Debug().Interface("oauth_config", oauthConfig).Msg("Parsed OAuth config") + + log.Debug().Msg("Parsed OAuth config") // Create auth service auth := auth.NewAuth(users, oauthWhitelist) diff --git a/cmd/user/create/create.go b/cmd/user/create/create.go index 3d55329..7dcbfcb 100644 --- a/cmd/user/create/create.go +++ b/cmd/user/create/create.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/charmbracelet/huh" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "golang.org/x/crypto/bcrypt" @@ -21,6 +22,8 @@ var CreateCmd = &cobra.Command{ Short: "Create a user", Long: `Create a user either interactively or by passing flags.`, Run: func(cmd *cobra.Command, args []string) { + log.Logger = log.Level(zerolog.InfoLevel) + if interactive { form := huh.NewForm( huh.NewGroup( diff --git a/cmd/user/user.go b/cmd/user/user.go index b35328d..02d1a63 100644 --- a/cmd/user/user.go +++ b/cmd/user/user.go @@ -8,12 +8,17 @@ import ( ) func UserCmd() *cobra.Command { + // Create the user command userCmd := &cobra.Command{ - Use: "user", + Use: "user", Short: "User utilities", - Long: `Utilities for creating and verifying tinyauth compatible users.`, + Long: `Utilities for creating and verifying tinyauth compatible users.`, } + + // Add subcommands userCmd.AddCommand(create.CreateCmd) userCmd.AddCommand(verify.VerifyCmd) + + // Return the user command return userCmd -} \ No newline at end of file +} diff --git a/cmd/user/verify/verify.go b/cmd/user/verify/verify.go index 967bf9c..ace1609 100644 --- a/cmd/user/verify/verify.go +++ b/cmd/user/verify/verify.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/charmbracelet/huh" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "golang.org/x/crypto/bcrypt" @@ -21,6 +22,8 @@ var VerifyCmd = &cobra.Command{ Short: "Verify a user is set up correctly", Long: `Verify a user is set up correctly meaning that it has a correct username and password.`, Run: func(cmd *cobra.Command, args []string) { + log.Logger = log.Level(zerolog.InfoLevel) + if interactive { form := huh.NewForm( huh.NewGroup( diff --git a/internal/api/api.go b/internal/api/api.go index b4456c0..6088bc9 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -114,7 +114,7 @@ func (api *API) SetupRoutes() { RedirectURI: fmt.Sprintf("%s://%s%s", proto, host, uri), }) - log.Debug().Interface("queries", queries).Msg("Redirecting to login") + log.Debug().Interface("redirect_uri", fmt.Sprintf("%s://%s%s", proto, host, uri)).Msg("Redirecting to login") if queryErr != nil { log.Error().Err(queryErr).Msg("Failed to build query") @@ -142,7 +142,7 @@ func (api *API) SetupRoutes() { return } - log.Debug().Interface("login", login).Msg("Got login request") + log.Debug().Msg("Got login request") user := api.Auth.GetUser(login.Username) @@ -250,7 +250,7 @@ func (api *API) SetupRoutes() { return } - log.Debug().Interface("request", request).Msg("Got OAuth request") + log.Debug().Msg("Got OAuth request") provider := api.Providers.GetProvider(request.Provider) @@ -266,7 +266,7 @@ func (api *API) SetupRoutes() { authURL := provider.GetAuthURL() - log.Debug().Str("authURL", authURL).Msg("Got auth URL") + log.Debug().Msg("Got auth URL") redirectURI := c.Query("redirect_uri") @@ -291,7 +291,7 @@ func (api *API) SetupRoutes() { return } - log.Debug().Interface("providerName", providerName).Msg("Got provider name") + log.Debug().Interface("provider", providerName.Provider).Msg("Got provider name") code := c.Query("code") @@ -301,7 +301,7 @@ func (api *API) SetupRoutes() { return } - log.Debug().Str("code", code).Msg("Got code") + log.Debug().Msg("Got code") provider := api.Providers.GetProvider(providerName.Provider) @@ -312,9 +312,9 @@ func (api *API) SetupRoutes() { return } - token, tokenErr := provider.ExchangeToken(code) + _, tokenErr := provider.ExchangeToken(code) - log.Debug().Str("token", token).Msg("Got token") + log.Debug().Msg("Got token") if handleApiError(c, "Failed to exchange token", tokenErr) { return @@ -363,7 +363,7 @@ func (api *API) SetupRoutes() { RedirectURI: redirectURI, }) - log.Debug().Interface("redirectQuery", redirectQuery).Msg("Got redirect query") + log.Debug().Msg("Got redirect query") if handleApiError(c, "Failed to build query", redirectQueryErr) { return diff --git a/internal/auth/auth.go b/internal/auth/auth.go index d87a7ef..6ed71a5 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -50,7 +50,7 @@ func (auth *Auth) EmailWhitelisted(emailSrc string) bool { func (auth *Auth) CreateSessionCookie(c *gin.Context, data *types.SessionCookie) { log.Debug().Msg("Creating session cookie") sessions := sessions.Default(c) - log.Debug().Interface("data", data).Msg("Setting session cookie") + log.Debug().Msg("Setting session cookie") sessions.Set("username", data.Username) sessions.Set("provider", data.Provider) sessions.Save() @@ -70,13 +70,10 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error) cookieUsername := sessions.Get("username") cookieProvider := sessions.Get("provider") - log.Debug().Interface("cookieUsername", cookieUsername).Msg("Got username") - log.Debug().Interface("cookieProvider", cookieProvider).Msg("Got provider") - username, usernameOk := cookieUsername.(string) provider, providerOk := cookieProvider.(string) - log.Debug().Str("username", username).Bool("usernameOk", usernameOk).Str("provider", provider).Bool("providerOk", providerOk).Msg("Parsed cookie") + log.Debug().Str("username", username).Str("provider", provider).Msg("Parsed cookie") if !usernameOk || !providerOk { log.Warn().Msg("Session cookie invalid") diff --git a/internal/hooks/hooks.go b/internal/hooks/hooks.go index 58d1feb..9a1a6db 100644 --- a/internal/hooks/hooks.go +++ b/internal/hooks/hooks.go @@ -34,8 +34,6 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext { } } - log.Debug().Interface("cookie", cookie).Msg("Got session cookie") - if cookie.Provider == "username" { log.Debug().Msg("Provider is username") if hooks.Auth.GetUser(cookie.Username) != nil { @@ -55,7 +53,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext { if provider != nil { log.Debug().Msg("Provider exists") if !hooks.Auth.EmailWhitelisted(cookie.Username) { - log.Error().Msgf("Email %s not whitelisted", cookie.Username) + log.Error().Str("email", cookie.Username).Msg("Email is not whitelisted") hooks.Auth.DeleteSessionCookie(c) return types.UserContext{ Username: "", diff --git a/internal/providers/generic.go b/internal/providers/generic.go index 4654bb7..2dbcf4e 100644 --- a/internal/providers/generic.go +++ b/internal/providers/generic.go @@ -37,7 +37,7 @@ func GetGenericEmail(client *http.Client, url string) (string, error) { return "", jsonErr } - log.Debug().Interface("user", user).Msg("Parsed user from generic provider") + log.Debug().Msg("Parsed user from generic provider") return user.Email, nil } diff --git a/internal/providers/github.go b/internal/providers/github.go index 356fe14..515652d 100644 --- a/internal/providers/github.go +++ b/internal/providers/github.go @@ -43,7 +43,7 @@ func GetGithubEmail(client *http.Client) (string, error) { return "", jsonErr } - log.Debug().Interface("emails", emails).Msg("Parsed emails from github") + log.Debug().Msg("Parsed emails from github") for _, email := range emails { if email.Primary { diff --git a/internal/providers/google.go b/internal/providers/google.go index 15cfed6..d3554fd 100644 --- a/internal/providers/google.go +++ b/internal/providers/google.go @@ -41,7 +41,7 @@ func GetGoogleEmail(client *http.Client) (string, error) { return "", jsonErr } - log.Debug().Interface("user", user).Msg("Parsed user from google") + log.Debug().Msg("Parsed user from google") return user.Email, nil } diff --git a/internal/types/types.go b/internal/types/types.go index bfd0782..692d326 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -19,9 +19,9 @@ type User struct { type Users []User type Config struct { - Port int `mapstructure:"port"` - Address string `validate:"ip4_addr" mapstructure:"address"` - Secret string `validate:"len=32" mapstructure:"secret"` + Port int `mapstructure:"port" validate:"required"` + Address string `validate:"required,ip4_addr" mapstructure:"address"` + Secret string `validate:"required,len=32" mapstructure:"secret"` SecretFile string `mapstructure:"secret-file"` AppURL string `validate:"required,url" mapstructure:"app-url"` Users string `mapstructure:"users"` @@ -43,7 +43,7 @@ type Config struct { DisableContinue bool `mapstructure:"disable-continue"` OAuthWhitelist string `mapstructure:"oauth-whitelist"` CookieExpiry int `mapstructure:"cookie-expiry"` - LogLevel int8 `mapstructure:"log-level"` + LogLevel int8 `mapstructure:"log-level" validate:"min=-1,max=5"` } type UserContext struct { diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 7941460..06b2b70 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -15,15 +15,12 @@ func ParseUsers(users string) (types.Users, error) { var usersParsed types.Users userList := strings.Split(users, ",") - log.Debug().Strs("users", userList).Msg("Splitted users") - if len(userList) == 0 { return types.Users{}, errors.New("invalid user format") } for _, user := range userList { userSplit := strings.Split(user, ":") - log.Debug().Strs("user", userSplit).Msg("Splitting user") if len(userSplit) != 2 { return types.Users{}, errors.New("invalid user format") } @@ -33,7 +30,7 @@ func ParseUsers(users string) (types.Users, error) { }) } - log.Debug().Interface("users", usersParsed).Msg("Parsed users") + log.Debug().Msg("Parsed users") return usersParsed, nil } @@ -83,15 +80,13 @@ func ParseFileToLine(content string) string { return strings.Join(users, ",") } -func GetSecret(env string, file string) string { - if env == "" && file == "" { - log.Debug().Msg("No secret provided") +func GetSecret(conf string, file string) string { + if conf == "" && file == "" { return "" } - if env != "" { - log.Debug().Str("secret", env).Msg("Using secret from env") - return env + if conf != "" { + return conf } contents, err := ReadFile(file) @@ -100,28 +95,26 @@ func GetSecret(env string, file string) string { return "" } - log.Debug().Str("secret", contents).Msg("Using secret from file") - return contents } -func GetUsers(env string, file string) (types.Users, error) { +func GetUsers(conf string, file string) (types.Users, error) { var users string - if env == "" && file == "" { + if conf == "" && file == "" { return types.Users{}, errors.New("no users provided") } - if env != "" { - log.Debug().Str("users", env).Msg("Using users from env") - users += env + if conf != "" { + log.Debug().Msg("Using users from config") + users += conf } if file != "" { fileContents, fileErr := ReadFile(file) if fileErr == nil { - log.Debug().Str("users", ParseFileToLine(fileContents)).Msg("Using users from file") + log.Debug().Msg("Using users from file") if users != "" { users += "," } diff --git a/main.go b/main.go index 72b3d91..ad87e90 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "os" "time" "tinyauth/cmd" - "tinyauth/internal/assets" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -12,8 +11,7 @@ import ( func main() { // Logger - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Logger() - log.Info().Str("version", assets.Version).Msg("Starting tinyauth") + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Logger().Level(zerolog.FatalLevel) // Run cmd cmd.Execute()