api/http/basic_auth.go
package http
import (
"net/http"
"github.com/18F/e-QIP-prototype/api"
"github.com/18F/e-QIP-prototype/api/simplestore"
)
// BasicAuthHandler is the handler for basic authentication.
type BasicAuthHandler struct {
Env api.Settings
Log api.LogService
Database api.DatabaseService
Store api.StorageService
Session api.SessionService
Cookie SessionCookieService
}
// ServeHTTP processes a users request to login with a Username and Password
func (service BasicAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !service.Env.True(api.BasicEnabled) {
service.Log.Warn(api.BasicAuthNotImplemented, api.LogFields{})
RespondWithStructuredError(w, api.BasicAuthNotImplemented, http.StatusInternalServerError)
return
}
var respBody struct {
Username string
Password string
}
if err := DecodeJSON(r.Body, &respBody); err != nil {
service.Log.WarnError(api.BasicAuthError, err, api.LogFields{})
RespondWithStructuredError(w, api.BasicAuthError, http.StatusInternalServerError)
return
}
errors := structuredErrors{}
if respBody.Username == "" {
service.Log.Warn(api.BasicAuthMissingUsername, api.LogFields{})
errors.addError("USERNAME_MISSING", api.BasicAuthMissingUsername)
}
if respBody.Password == "" {
service.Log.Warn(api.BasicAuthMissingPassword, api.LogFields{})
errors.addError("PASSWORD_MISSING", api.BasicAuthMissingPassword)
}
if errors.hasErrors() {
RespondWithErrors(w, errors, http.StatusBadRequest)
return
}
account := &api.Account{
Username: respBody.Username,
}
// Associate with a database context.
if _, err := account.Get(service.Database, 0); err != nil {
service.Log.WarnError(api.AccountUpdateError, err, api.LogFields{"username": account.Username})
RespondWithStructuredError(w, api.AccountUpdateError, http.StatusInternalServerError)
return
}
// Validate the user name and password combination
if err := account.BasicAuthentication(service.Database, respBody.Password); err != nil {
service.Log.WarnError(api.BasicAuthInvalid, err, api.LogFields{"account": account.ID})
RespondWithStructuredError(w, api.BasicAuthInvalid, http.StatusUnauthorized)
return
}
sessionKey, authErr := service.Session.UserDidAuthenticate(account.ID, simplestore.NullString())
if authErr != nil {
service.Log.WarnError("bad session get", authErr, api.LogFields{"account": account.ID})
RespondWithStructuredError(w, "bad session get", http.StatusInternalServerError)
return
}
service.Cookie.AddSessionKeyToResponse(w, sessionKey)
// If we need to flush the storage first then do so now.
if service.Env.True(api.FlushStorage) {
service.Log.Info(api.PurgeAccountData, api.LogFields{"account": account.ID})
delErr := service.Store.DeleteApplication(account.ID)
if delErr != nil {
service.Log.Warn("Unable to purge the application data on login", api.LogFields{"account": account.ID})
}
}
service.Log.Info(api.BasicAuthValid, api.LogFields{"account": account.ID})
}