Exemple #1
0
// Authenticate checks a request's basic authentication, and associates a *models.User with the context
// if so. Otherwise it handles responding to and closing the request.
//
//		contextWithUser, authWasSuccessful := routes.Authenticate(ctx, w, r, logger, db)
//
// Use for any requests which expect to act on behalf of a user (which is most)
func Authenticate(ctx context.Context, w http.ResponseWriter, r *http.Request, l services.Logger, db services.DB) (context.Context, bool) {
	l = l.WithPrefix("routes.Authenticate: ")
	var (
		c   *models.Credential
		u   *models.User
		err error
	)

	public, private, ok := r.BasicAuth()
	if !ok {
		l.Printf("authentication reverting from basic auth to session")
		// assume std lib didn't make a mistake, and the BasicAuth simply wasn't given
		// fall back to cookie

		if sesh, err := session(r, db); err != nil {
			switch err {
			case http.ErrNoCookie:
				l.Printf("no session cookie")
			case data.ErrNotFound:
				l.Printf("session token not found")
			default:
				l.Printf("session(r, db) error: %s", err)
			}

			l.Printf("authentication reverting from cookie to form values")
			public, private = r.FormValue(publicParam), r.FormValue(privateParam)
		} else if sesh.Valid() {
			if u, err := sesh.Owner(db); err != nil {
				l.Printf("sesh.Owner(db) error: %s", err)
				public, private = r.FormValue(publicParam), r.FormValue(privateParam)
			} else {
				return user.NewContext(ctx, u), true
			}
		} else {
			l.Printf("session no longer valid")
			public, private = r.FormValue(publicParam), r.FormValue(privateParam)
		}
	}

	if c, err = access.Authenticate(db, public, private); err != nil {
		l.Printf("authentication of (%s, %s) failed: couldn't find credential: %s", public, private, err)
		goto unauthorized // this error is on us, but it manifests as a failure to authenticate
	}

	if u, err = c.Owner(db); err != nil {
		l.Printf("authentication failed: couldn't load user's owner: %s", err)
		goto unauthorized // this error is also on us, but also manifests as a failure to authenticate
	}

	// successful authentications
	return user.NewContext(ctx, u), true

	// rejection
unauthorized:
	http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	return nil, false
}
Exemple #2
0
// basic logging
func logRequest(handle http.HandlerFunc, logger services.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logger.Printf("%s %s", r.Method, r.URL)
		handle(w, r)
	}
}
Exemple #3
0
func MobileLocationPOST(ctx context.Context, w http.ResponseWriter, r *http.Request, l services.Logger, db data.DB) {
	// Parse the form value
	if err := r.ParseForm(); err != nil {
		l.Printf("MobileLocationPOST Error: %s", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Altitude
	alt := r.FormValue(altitudeParam)
	if alt == "" {
		http.Error(w, "You must specify an altitude", http.StatusBadRequest)
		return
	}
	altitude, err := strconv.ParseFloat(alt, 64)
	if err != nil {
		http.Error(w, "Parsing altitude", http.StatusBadRequest)
		return
	}

	// Latitude
	lat := r.FormValue(latitudeParam)
	if lat == "" {
		http.Error(w, "You must specify a latitude", http.StatusBadRequest)
		return
	}
	latitude, err := strconv.ParseFloat(lat, 64)
	if err != nil {
		http.Error(w, "Parsing latitude", http.StatusBadRequest)
		return
	}

	// Longitude
	lon := r.FormValue(longitudeParam)
	if lon == "" {
		http.Error(w, "You must specify an longitude", http.StatusBadRequest)
		return
	}
	longitude, err := strconv.ParseFloat(lon, 64)
	if err != nil {
		http.Error(w, "Parsing longitude", http.StatusBadRequest)
		return
	}

	// Retrieve the user this request was authenticated as
	u, ok := user.FromContext(ctx)
	if !ok { // This is certainly an issue, and should _never_ happen
		l.Print("MobileLocationPOST Error: failed to retrieve user from context")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Create location
	loc := location.NewCoords(altitude, latitude, longitude)
	loc.SetID(db.NewID())
	loc.SetOwner(u)

	now := loc.CreatedAt

	e := models.NewEvent()
	e.CreatedAt = now
	e.SetID(db.NewID())
	e.SetOwner(u)
	e.Name = "Location Update"
	e.SetLocation(loc)
	e.Time = now
	e.UpdatedAt = now

	locationTag, err1 := tag.ForName(db, u, tag.Location)
	updateTag, err2 := tag.ForName(db, u, tag.Update)
	mobileTag, err3 := tag.ForName(db, u, tag.Mobile)
	if err1 != nil || err2 != nil || err3 != nil {
		l.Printf("MobileLocationPOST Error: %s", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	e.IncludeTag(locationTag)
	e.IncludeTag(updateTag)
	e.IncludeTag(mobileTag)

	if err = db.Save(loc); err != nil {
		l.Printf("MobileLocationPOST Error: %s", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	if err = db.Save(e); err != nil {
		l.Printf("MobileLocationPOST Error: %s", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	bytes, err := json.MarshalIndent(e, "", "	")
	if err != nil {
		l.Printf("MobileLocationPOST Error: while marshalling json %s", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
	w.Header().Set("Content-Type", "application/json")
	w.Write(bytes)
}