auth

package
v0.0.0-...-9fb3cb1 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2015 License: MIT Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBadUsername      = errors.New("Incorrect username.")
	ErrBadPassword      = errors.New("Incorrect password.")
	ErrInvalidTFACode   = errors.New("Invalid Two-Factor Authentication code.")
	ErrInvalidCSRFToken = errors.New("Invalid CSRF token.")

	// Generic error for when a user isn't logged in.
	ErrUnauthorized = errors.New("Unauthorized access.")

	// Means email/username was too long.
	ErrInvalidLogin = errors.New("Invalid login submitted.")

	ErrTooManyRequests = errors.New("Too many invalid login attempts.")
	ErrUnableToLogOut  = errors.New("Unable to destroy tokens.")

	ErrPassDoesntMatch = errors.New("Provided passwords do not match.")
	ErrCommonPassword  = errors.New("Password is too common.")
	ErrPassTooShort    = errors.New("Password is too short.")

	ErrNoReferer = errors.New("Referer header is empty.")
)
View Source
var (
	ErrCantMarshal   = errors.New("Cannot marshal ServerSession.")
	ErrCantUnmarshal = errors.New("Cannot unmarshal byte slice.")
)

These need to match the names in the ServerSession struct.

View Source
var ErrNoSession = errors.New("No sessions")

Functions

func AuthenticateUser

func AuthenticateUser(w http.ResponseWriter, r *http.Request) (AuthStatus, *dt.LoginData, *HTTPError)

AuthenticateUser attempts to authenticate a user from the login page.

It returns:

  • An an enum indicating the user's authentication status.
  • A pointer to dt.LoginData which holds information to be displayed.
  • An HTTPError if applicable.

Errors displayed to the user _must_ use proper punctuation.

func CheckValidPassword

func CheckValidPassword(p1, p2 string) error

CheckValidPassword will check to see if the password meets the minimum password requirements. It'll return an error if applicable. Nil implies a valid password.

func ComparePassword

func ComparePassword(u *database.User, pass []byte, clear bool) (err error)

ComparePassword compares a *User's password with the given password. It uses bcrypt's constant time comparison to securely compare the passwords.

func DestroySession

func DestroySession(w http.ResponseWriter, r *http.Request) bool

DestroySession terminates a session for a given user. It returns a boolean indicating whether or not the termination of the cookie was successful.

func RemoveSession

func RemoveSession(id string) (error, error)

RemoveSession removes a ServerSession from the database. It checks memcached/redis first, and even if the session does not exist in memcached/redis, it still removes it from the database. It returns two errors, one for removing the session from redis and one from removing the session from PostgreSQL. The errors are nil if nothing went wrong.

func ValidCSRF

func ValidCSRF(r *http.Request, session *sessions.Session, ws bool) bool

ValidCSRF returns true if the given CSRF token matches the CSRF token for a specific session.

Types

type AuthStatus

type AuthStatus uint8

Enum for AuthenticateUser's return values.

const (
	InvalidAuth AuthStatus = iota // Bad user/password.
	ValidAuth                     // Auth is 100% valid; proceed.
)

type HTTPError

type HTTPError struct {
	Status int
	Err    error
}

httpError encapsulates an error and an HTTP status code. (E.g, 200 OK, 302 Found)

func CheckSession

func CheckSession(r *http.Request) (*sessions.Session, bool, *HTTPError)

CheckSession checks to see if a session exists for a user. It returns three values:

  • A pointer to a session if available
  • A bool which indicates whether the session is authenticated or not
  • An error if store.Get fails

The structure is this: First, we check the user's cookies for our cookie. If store.Get gives us an error, we return a nil session, false for authentication, and the error.

Theoretically that should never happen because store.Get will return a new session if the user did not provide a valid cookie, but we need to check for it anyway.

We then test the session to see if it's new. If it is, we jump to our error label and return the new session and return false for authentication.

We then test the user's cookie for the authToken and the authDate. If neither exist, or they cannot be cast to their proper types, []byte and int64 respectively, then we jump to our error label.

We then query database (usually memcache/redis, falling back to PostgreSQL) for the session that matches 'session.ID' (the unique ID attached to each session that's inside our cookie).

The session's values are compared to those provided by the user. If -- and only if -- the session's values match those provided by the user, we then return the session, true for authentication, and nil for any errors.

func (*HTTPError) Error

func (err *HTTPError) Error() string

type ServerSession

type ServerSession struct {
	ID        []byte `redis:"-"` // Session ID
	AuthToken []byte `redis:"auth_token"`
	CSRFToken []byte `redis:"csrf_token"`
	Email     string `redis:"email"`  // User's email
	School    string `redis:"school"` // User's school
	Date      int64  `redis:"date"`   // Session expiry date
}

ServerSession is the data-view of a user's session found both in redis and our database.

func GetSession

func GetSession(id string) (*ServerSession, error)

GetSession returns a SeverSession from the database. It checks memcached/redis first, and then falls back on the database.

func GetSetSession

func GetSetSession(w http.ResponseWriter, r *http.Request, session *sessions.Session) *ServerSession

GetSetSession will either get or set a ServerSession depending on whether or not the session exists in the database.

If a session cannot be successfully retrieved, one will be created. However, until properly authenticated, the

func (*ServerSession) MarshalJSON

func (s *ServerSession) MarshalJSON() (buf []byte, err error)

MarshalJSON implements the Marshaler interface for expedient JSON marshalling. We implement it ourself, as ugly and as brittle as it is, because of the speedup we receive. As long as this is updated whenever the ServerSession struct is updated, we shouldn't have any issues.

See https://play.golang.org/p/FWubrFGNx2 for the benchmark code. The results of the benchmark on my laptop were:

eric@archbox ~/sermodigital/sermocrm/test $ go test marshal_test.go -bench=. testing: warning: no tests to run PASS BenchmarkMarshal 300000 4460 ns/op BenchmarkCustomMarshal 2000000 889 ns/op ok command-line-arguments 43.620s

func (*ServerSession) StoreSession

func (s *ServerSession) StoreSession(id string) error

StoreSession stores a ServerSession in both memcached/redis and the backing PostgreSQL database.

func (*ServerSession) UnmarshalJSON

func (s *ServerSession) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON implements the Marshaler interface for expedient JSON unmarshalling of ServerSession structures. See ServerSession.MarshalJSON for more information on why it's done by hand.

An additional note is that the standard library's json.Unmarshal base64-encodes byte slices, and we don't want to waste the time un-encoding those when we get the cached ServerSession from redis.

Jump to

Keyboard shortcuts

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