Documentation ¶
Index ¶
- Variables
- func AuthenticateUser(w http.ResponseWriter, r *http.Request) (AuthStatus, *dt.LoginData, *HTTPError)
- func CheckValidPassword(p1, p2 string) error
- func ComparePassword(u *database.User, pass []byte, clear bool) (err error)
- func DestroySession(w http.ResponseWriter, r *http.Request) bool
- func RemoveSession(id string) (error, error)
- func ValidCSRF(r *http.Request, session *sessions.Session, ws bool) bool
- type AuthStatus
- type HTTPError
- type ServerSession
Constants ¶
This section is empty.
Variables ¶
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.") 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.") )
var ( ErrCantMarshal = errors.New("Cannot marshal ServerSession.") ErrCantUnmarshal = errors.New("Cannot unmarshal byte slice.") )
These need to match the names in the ServerSession struct.
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 ¶
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 ¶
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 ¶
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.
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 ¶
httpError encapsulates an error and an HTTP status code. (E.g, 200 OK, 302 Found)
func CheckSession ¶
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.
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.