webauth

package
v0.0.0-...-514cf28 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2024 License: Apache-2.0 Imports: 23 Imported by: 1

Documentation

Overview

Package webauth provides support for web apps that use form authentication.

Index

Constants

View Source
const (
	MsgMissingConfirmToken = "Please provide a token."
	MsgInvalidConfirmToken = "Token is invalid. Request a new token."
	MsgExpiredConfirmToken = "Token is expired. Request a new token."
)
View Source
const (
	ConfirmTokenSize    = 12   // Size of the confirm token
	ConfirmTokenExpires = "5m" // Token expiry time

)

Constants for error and informational messages displayed to the user.

View Source
const (
	MsgMissingEmail    = "Please provide your email."
	MsgMissingAction   = "Please provide an action."
	MsgInvalidAction   = "Please provide a valid action."
	TemplateForgot     = "forgot.html"
	TemplateForgotSent = "forgot_sent.html"
	ResetTokenSize     = 12   // Size of the password reset token; TODO: move to config
	ResetTokenExpires  = "5m" // Token expiry time; TODO: move to config
)

Constants for error and informational messages displayed to the user.

View Source
const (
	MsgMissingUsernameAndPassword = "Missing username and password."
	MsgMissingUsername            = "Missing username."
	MsgMissingPassword            = "Missing password."
	MsgLoginFailed                = "Login failed."
)
View Source
const (
	MsgMissingRequired    = "Please provide required values"
	MsgUsernameExists     = "Username already exists."
	MsgEmailExists        = "Email already registered."
	MsgPasswordsDifferent = "Passwords do not match."
	MsgRegisterFailed     = "Unable to register user."
)
View Source
const ConfirmRequestSentTmpl = "confirm_request_sent.html"
View Source
const ConfirmTmpl = "confirm.html"
View Source
const ConfirmedTmpl = "confirmed.html"
View Source
const LoginPageName = "login.html"

LoginPageName is the name of the login HTML template.

View Source
const LoginTokenCookieName = "login"
View Source
const LoginTokenKind = "login"
View Source
const LoginTokenSize = 32

Variables

View Source
var (
	ErrConfigRead  = errors.New("failed to read config file")
	ErrConfigParse = errors.New("failed to parse config file")
)
View Source
var (
	ErrInitDBOpen = errors.New("db open failed")
	ErrInitDBPing = errors.New("db ping failed")
)
View Source
var (
	ErrRowExistsDBNil       = errors.New("RowExists: db is nil")
	ErrRowExistsQueryFailed = errors.New("RowExists: query failed")
)
View Source
var (
	ErrWriteEventDBNil  = errors.New("WriteEvent: db is nil")
	ErrWriteEventFailed = errors.New("WriteEvent: db write failed")
)
View Source
var (
	ErrGetEventsDBNil = errors.New("GetEvents: db is nil")
	ErrGetEventsQuery = errors.New("GetEvents: query failed")
	ErrGetEventsScan  = errors.New("GetEvents: scan failed")
	ErrGetEventsRows  = errors.New("GetEvents: rows.Err()")
)
View Source
var (
	ErrInvalidDB                 = errors.New("invalid db")
	ErrUserLoginTokenNotFound    = errors.New("user login token not found")
	ErrUserNotFound              = errors.New("user not found")
	ErrUserLoginTokenExpired     = errors.New("user login expired")
	ErrResetPasswordTokenExpired = errors.New("reset password token expired")
	ErrConfirmTokenExpired       = errors.New("confirm token expired")
	ErrUserGetLastLoginFailed    = errors.New("failed to get user last login")
	ErrMissingConfirmToken       = errors.New("empty confirm token")
)

Define command error values.

View Source
var ErrInvalidConfig = errors.New("invalid config")
View Source
var ErrInvalidLength = errors.New("invalid length")
View Source
var ErrInvalidPassword = errors.New("invalid password")
View Source
var ErrRequestNil = errors.New("request is nil")
View Source
var ErrTokenNotFound = errors.New("token not found")

Functions

func CookieValue

func CookieValue(r *http.Request, name string) (string, error)

CookieValue returns the named cookie value provided in the request or an empty string if not found.

func GenerateRandomString

func GenerateRandomString(n int) (string, error)

GenerateRandomString returns a URL safe base64 encoded string of n random bytes.

func Hash

func Hash(s string) string

Hash returns a hex encoded sha256 Hash of the given string. TODO: should this be a salted Hash to be more secure?

func IsEmpty

func IsEmpty(strs ...string) bool

IsEmpty returns true if any of the strings are empty, otherwise false.

func LoginCookie

func LoginCookie(value string, expires time.Time, remember bool) *http.Cookie

LoginCookie creates and return a login cookie.

Types

type AuthApp

type AuthApp struct {
	*webapp.WebApp         // Embedded WebApp
	DB             *AuthDB // DB is the database connection.
	Cfg            Config
}

AuthApp extends the WebApp to support authentication.

func NewApp

func NewApp(options ...interface{}) (*AuthApp, error)

NewApp creates a new AuthApp with the given options and returns it. These options can be either AuthApp or WebApp Options.

func (*AuthApp) ConfirmHandlerGet

func (app *AuthApp) ConfirmHandlerGet(w http.ResponseWriter, r *http.Request)

ConfirmHandlerGet processes GET requests for the email confirmation page.

This function retrieves the 'ctoken' (confirmation token) from the query parameters of the request URL. If a 'ctoken' is present, it is displayed to the user on the confirmation page. Users may also manually enter a 'ctoken'.

Submission of the token is via a POST request, which is handled by ConfirmHandlerPost, which completes the email confirmation process.

func (*AuthApp) ConfirmHandlerPost

func (app *AuthApp) ConfirmHandlerPost(w http.ResponseWriter, r *http.Request)

ConfirmHandlerPost processes POST requests for user email confirmation.

It extracts the 'ctoken' (confirmation token) from the form data to verify and confirm the associated user. If the token is valid, the user's status is updated to confirmed.

func (*AuthApp) ConfirmRequestHandlerGet

func (app *AuthApp) ConfirmRequestHandlerGet(w http.ResponseWriter, r *http.Request)

ConfirmRequestHandlerGet processes GET requests for the confirmation request page. It allows a user to enter their email to request a confirmation token. Submission of the request with an email is via a POST request, which is handled by ConfirmRequestHandlerPost.

func (*AuthApp) ConfirmRequestHandlerPost

func (app *AuthApp) ConfirmRequestHandlerPost(w http.ResponseWriter, r *http.Request)

ConfirmRequestHandlerPost processes POST rquests that emails a user a confirmation token. It extracts the 'email" from the form data to create the token and then email to the user.

func (*AuthApp) ConfirmRequestSentHandlerGet

func (app *AuthApp) ConfirmRequestSentHandlerGet(w http.ResponseWriter, r *http.Request)

ConfirmRequestSentHandlerGet handles GET requests for confirm request sent success page.

func (*AuthApp) ConfirmedHandlerGet

func (app *AuthApp) ConfirmedHandlerGet(w http.ResponseWriter, r *http.Request)

ConfirmedHandlerGet handles GET requests for the email confirmation success page.

func (*AuthApp) CreateLoginToken

func (app *AuthApp) CreateLoginToken(username string) (Token, error)

CreateLoginToken creates a login token for username.

func (*AuthApp) EventsCSVHandler

func (app *AuthApp) EventsCSVHandler(w http.ResponseWriter, r *http.Request)

EventsCSVHandler provides list of events as a CSV file.

func (*AuthApp) EventsHandler

func (app *AuthApp) EventsHandler(w http.ResponseWriter, r *http.Request)

EventsHandler displays a list of events.

func (*AuthApp) ForgotHandler

func (app *AuthApp) ForgotHandler(w http.ResponseWriter, r *http.Request)

ForgotHandler handles HTTP requests for forgot user or password.

func (*AuthApp) LoginGetHandler

func (app *AuthApp) LoginGetHandler(w http.ResponseWriter, r *http.Request)

LoginGetHandler handles login GET requests.

func (*AuthApp) LoginPostHandler

func (app *AuthApp) LoginPostHandler(w http.ResponseWriter, r *http.Request)

LoginPostHandler handles login POST requests.

func (*AuthApp) LoginUser

func (app *AuthApp) LoginUser(username, password string) (Token, error)

LoginUser returns a login token if the username and password are correct.

func (*AuthApp) LogoutHandler

func (app *AuthApp) LogoutHandler(w http.ResponseWriter, r *http.Request)

LogoutHandler handles /logout requests.

func (*AuthApp) RegisterHandler

func (app *AuthApp) RegisterHandler(w http.ResponseWriter, r *http.Request)

RegisterHandler handles requests to register a user.

func (*AuthApp) RenderPage

func (app *AuthApp) RenderPage(w http.ResponseWriter, logger *slog.Logger, templateName string, data PageData)

RenderPage renders a web page using the specified template and data.

If the page cannot be rendered, http.StatusInternalServerError is set and the caller should ensure no further writes are done to w.

func (*AuthApp) ResetHandler

func (app *AuthApp) ResetHandler(w http.ResponseWriter, r *http.Request)

ResetHandler handles /reset requests.

func (*AuthApp) String

func (a *AuthApp) String() string

String returns a string representation of the AuthApp instance.

func (*AuthApp) UserGetHandler

func (app *AuthApp) UserGetHandler(w http.ResponseWriter, r *http.Request)

UserGetHandler shows user information.

func (*AuthApp) UsersCSVHandler

func (app *AuthApp) UsersCSVHandler(w http.ResponseWriter, r *http.Request)

UsersCSVHandler provides list of the current users as a CSV file.

func (*AuthApp) UsersHandler

func (app *AuthApp) UsersHandler(w http.ResponseWriter, r *http.Request)

UsersHandler shows a list of the current users.

type AuthDB

type AuthDB struct {
	*sql.DB
}

func InitDB

func InitDB(driverName, dataSourceName string) (*AuthDB, error)

InitDB initializes a db connection and verifies with a Ping().

func (*AuthDB) CheckPassword

func (db *AuthDB) CheckPassword(username, password string) error

CheckPassword validates the password for a user.

func (*AuthDB) ConfirmUser

func (db *AuthDB) ConfirmUser(username, ctoken string) error

ConfirmUser updates database to indicate user confirmed their email.

func (*AuthDB) CreateConfirmEmailToken

func (db *AuthDB) CreateConfirmEmailToken(username string) (Token, error)

CreateConfirmEmailToken generates a new token to confirm a user's email.

func (*AuthDB) CreateToken

func (db *AuthDB) CreateToken(kind, username string, size int, duration string) (Token, error)

CreateToken creates and saves a token for user of size that expires in duration.

func (*AuthDB) EmailExists

func (db *AuthDB) EmailExists(email string) (bool, error)

EmailExists returns true if the given email already exists.

func (*AuthDB) GetEvents

func (db *AuthDB) GetEvents() ([]Event, error)

GetEvents returns a list of all events.

func (*AuthDB) HashedPassword

func (db *AuthDB) HashedPassword(username string) (string, error)

HashedPassword retrieves the hashed password for a given username.

func (*AuthDB) LastLoginForUser

func (db *AuthDB) LastLoginForUser(username string) (time.Time, string, error)

LastLoginForUser retrieves the last login time and result for a given username. It returns zero values in case of no previous login.

func (*AuthDB) RegisterUser

func (db *AuthDB) RegisterUser(username, fullName, email, password string) error

RegisterUser registers a user with the given values. Returns nil on success or an error on failure.

func (*AuthDB) RemoveToken

func (db *AuthDB) RemoveToken(kind, value string) error

RemoveToken removes the token with kind and value.

func (*AuthDB) RowExists

func (db *AuthDB) RowExists(qry string, args ...interface{}) (bool, error)

RowExists checks if the given SQL query returns at least one row. The query should be in the form "SELECT 1 FROM ... WHERE ... LIMIT 1".

func (*AuthDB) UserExists

func (db *AuthDB) UserExists(username string) (bool, error)

UserExists returns true if the given username already exists in db.

func (*AuthDB) UserForLoginToken

func (db *AuthDB) UserForLoginToken(loginToken string) (User, error)

UserForLoginToken returns a user for the given loginToken.

func (*AuthDB) UserForName

func (db *AuthDB) UserForName(username string) (User, error)

UserForName returns a user for the given username.

func (*AuthDB) UserFromRequest

func (db *AuthDB) UserFromRequest(w http.ResponseWriter, r *http.Request) (User, error)

UserFromRequest returns the user for the login token cookie in the request. If the login token is invalid or expired, the cookie is removed and an empty user returned.

func (*AuthDB) UsernameForConfirmToken

func (db *AuthDB) UsernameForConfirmToken(tokenValue string) (string, error)

UsernameForConfirmToken returns the username for a given confirm token.

If token is not found, ErrUserNotFound is returned.

If token is expired, ErrConfirmTokenExpired is returned and token is removed.

If a SQL error occurs, it will be returned, except ErrNoRows.

func (*AuthDB) UsernameForEmail

func (db *AuthDB) UsernameForEmail(email string) (string, error)

UsernameForEmail looks up a username based on their email address.

If not found, ErrUserNotFound is returned.

If a SQL error occurs, other than ErrNoRows, it is returned.

func (*AuthDB) UsernameForResetToken

func (db *AuthDB) UsernameForResetToken(tokenValue string) (string, error)

UsernameForResetToken returns the username for a given reset token.

func (*AuthDB) WriteEvent

func (db *AuthDB) WriteEvent(name EventName, succeeded bool, username, message string) error

WriteEvent saves an event to database.

type CommonData

type CommonData struct {
	Title string
}

CommonData holds common fields for page data.

func (*CommonData) SetDefaultTitle

func (c *CommonData) SetDefaultTitle(appName string)

SetDefaultTitle ensures that the Title of CommonPageData is not empty. If Title is empty, this method sets it to the value of appName.

type Config

type Config struct {
	webapp.Config                  // Inherit webapp.Config
	Auth          ConfigAuth       // Auth app configuration.
	SQL           ConfigSQL        // SQL Database configuration.
	SMTP          email.SMTPConfig // SMTP server configuration.
	EmailFrom     string           `required:"true"` // From address for emails.
}

Config represents the overall application configuration.

func LoadConfigFromJSON

func LoadConfigFromJSON(filepath string) (*Config, error)

LoadConfigFromJSON loads configuration settings from a JSON file.

func (*Config) MarshalJSON

func (c *Config) MarshalJSON() ([]byte, error)

MarshalJSON customizes JSON marshalling to redact sensitive Config data.

func (*Config) MissingFields

func (c *Config) MissingFields() ([]string, error)

MissingFields identifies which required fields are absent in Config. It returns a slice of missing fields. If an error occurs during the check, an empty slice and the error are returned.

func (*Config) String

func (c *Config) String() string

String returns string representation of Config with sensitive data redacted.

type ConfigAuth

type ConfigAuth struct {
	BaseURL      string `required:"true"` // Base URL of the application.
	LoginExpires string `required:"true"` // Duration string for expiry.
}

ConfigAuth holds settings specific to the auth app.

type ConfigSQL

type ConfigSQL struct {
	DriverName     string `required:"true"` // Database driver name.
	DataSourceName string `required:"true"` // Database connection string.
}

ConfigSQL hold SQL database connection settings.

type ConfirmData

type ConfirmData struct {
	CommonData
	Message      string
	ConfirmToken string
}

ConfirmData contains data to render the confirm template.

type ConfirmRequestPageData

type ConfirmRequestPageData struct {
	CommonData
	Message string // An message to display to the user.
}

ConfirmRequestPageData contains data to render the confirm request template.

type ConfirmRequestSentData

type ConfirmRequestSentData struct {
	CommonData
	EmailFrom string // The email address that sends the confirm message.
}

ConfirmRequestSentData contains data to render the confirm template.

type ConfirmedData

type ConfirmedData struct {
	CommonData
}

ConfirmedData contains data to render the confirm template.

type Event

type Event struct {
	Name      EventName // Name of the event.
	Succeeded bool      // Indicates if the event was successful.
	Username  string    // Username associated with the event.
	Message   string    // Message or details about the event.
	Created   time.Time // Timestamp of event, set by db when inserted.
}

Event represents a system event, such as a user login or registration.

func (Event) LogValue

func (e Event) LogValue() slog.Value

LogValue implements slog.LogValuer. It returns a group containing the fields of Event, so that they appear together in the log output.

type EventName

type EventName string

EventName represents possible event types within the system.

const (
	EventLogin     EventName = "login"
	EventLogout    EventName = "logout"
	EventRegister  EventName = "register"
	EventSaveToken EventName = "save_token"
	EventResetPass EventName = "reset_pass"
	EventConfirmed EventName = "confirmed"
	EventMaxName   EventName = "1234567890" // Event defined as varchar(10).
)

type EventsPageData

type EventsPageData struct {
	CommonData
	User   User
	Events []Event
}

EventsPageData contains data passed to the HTML template.

type ForgotPageData

type ForgotPageData struct {
	CommonData
	Message   string // An informational or error message to display to the user.
	EmailFrom string // The email address from which the reset or reminder email will be sent.
}

ForgotPageData contains data required to render the forgot templates.

type LoginPageData

type LoginPageData struct {
	CommonData
	Message string
}

LoginPageData contains data passed to the login HTML template.

type LogoutPageData

type LogoutPageData struct {
	CommonData
	Message string
}

LogoutPageData contains data passed to the HTML template.

type Option

type Option func(*AuthApp)

Option is a function type used to apply configuration options to a AuthApp. This follows the Option pattern from https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html and elsewhere.

func WithConfig

func WithConfig(cfg Config) Option

WithConfig returns an Option to set the Config for a AuthApp.

func WithDB

func WithDB(db *AuthDB) Option

WithDB returns an Option to set the DB for a AuthApp.

type PageData

type PageData interface {
	SetDefaultTitle(appName string)
}

PageData is an interface that all page data structs must implement.

type RedactedConfig

type RedactedConfig Config

RedactedConfig provides a redacted copy of Config for secure logging.

type RegisterPageData

type RegisterPageData struct {
	CommonData
	Message string
}

RegisterPageData contains data passed to the HTML template.

type ResetPageData

type ResetPageData struct {
	Title      string
	Message    string
	ResetToken string
}

ResetPageData contains data passed to the HTML template.

type Token

type Token struct {
	Value   string
	Expires time.Time
	Kind    string
}

Token represent a token for the user.

type User

type User struct {
	Username        string
	FullName        string
	Email           string
	IsAdmin         bool
	Confirmed       bool
	Created         time.Time
	LastLoginTime   time.Time
	LastLoginResult string // TODO: implement as bool?
}

User represents in the application.

var EmptyUser User // EmptyUser is a empty User used when returning a error.

func GetUsers

func GetUsers(db *AuthDB) ([]User, error)

GetUsers returns a list of all users.

func (User) LogValue

func (u User) LogValue() slog.Value

LogValue implements slog.LogValuer to group User fields in log output.

type UserPageData

type UserPageData struct {
	Title   string
	Message string
	User    User
}

UserPageData contains data passed to the HTML template.

type UsersPageData

type UsersPageData struct {
	Title   string
	Message string
	User    User
	Users   []User
}

UsersPageData contains data passed to the HTML template.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL