Esempio n. 1
1
// Middleware sets up the request context so account information can be
// retrieved with auth.GetAccount(ctx). It panics if config.Get(ctx) fails.
func Middleware(ctx context.Context, w http.ResponseWriter, r *http.Request) context.Context {

	var conf config.Global

	if err := config.Get(ctx, &conf); err != nil {
		panic("Could not get AuthSecret: " + err.Error())
	} else if claimSet, err := Decode([]byte(r.Header.Get("Authorization")), []byte(conf.AuthSecret)); err != nil {
		ctx = context.WithValue(ctx, internal.ClaimSetContextKey, err)
		return context.WithValue(ctx, internal.AuthContextKey, err)
	} else if claimSet == SuperClaimSet {
		ctx = context.WithValue(ctx, internal.ClaimSetContextKey, SuperClaimSet)
		return context.WithValue(ctx, internal.AuthContextKey, &account.Super)
	} else if claimSet == NobodyClaimSet {
		ctx = context.WithValue(ctx, internal.ClaimSetContextKey, NobodyClaimSet)
		return context.WithValue(ctx, internal.AuthContextKey, &account.Nobody)
	} else {

		var acct account.Account
		if err := account.Get(ctx, claimSet.Sub, &acct); err != nil {
			rest.WriteJSON(w, &rest.Response{
				Code: http.StatusUnauthorized,
				Body: &rest.Message{"Could not retrieve account with key " + claimSet.Sub + ": " + err.Error()},
			})
			return nil
		} else {
			ctx = context.WithValue(ctx, internal.ClaimSetContextKey, claimSet)
			return context.WithValue(ctx, internal.AuthContextKey, &acct)
		}

	}

}
Esempio n. 2
1
func getConfig(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	conf := config.Config{}
	if err := config.Get(ctx, &conf); err != nil {
		rest.WriteJSON(w, err)
	} else {
		rest.WriteJSON(w, &conf)
	}

}
Esempio n. 3
1
func changeConfig(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	conf := config.Config{}
	if err := config.Get(ctx, &conf); err != nil {
		rest.WriteJSON(w, err)
	} else if err := rest.ReadJSON(r, &conf); err != nil {
		rest.WriteJSON(w, err)
	} else if err := config.Save(ctx, &conf); err != nil {
		rest.WriteJSON(w, err)
	} else {
		rest.WriteJSON(w, &conf)
	}

}
Esempio n. 4
1
func getJwt(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	var acct account.Account
	var email string
	var err error

	conf := config.Global{}
	if err := config.Get(ctx, &conf); err != nil {
		rest.WriteJSON(w, err)
		return
	}

	// read the account ID
	if emailBytes, err := base64.RawURLEncoding.DecodeString(rest.Param(ctx, "id")); err != nil {
		rest.WriteJSON(w, err)
		return
	} else {
		email = string(emailBytes)
	}

	if err = account.Get(ctx, email, &acct); err != nil {
		rest.WriteJSON(w, err)
		return
	}

	// All set. Generate the JWT.
	jwt, err := auth.Encode(&jws.ClaimSet{
		Sub:   acct.Email,
		Scope: strings.Join(acct.Roles, ","),
		Exp:   time.Now().AddDate(1, 0, 0).Unix(),
		PrivateClaims: map[string]interface{}{
			"n": "DEV USER",
		},
	}, []byte(conf.AuthSecret))

	if err != nil {
		rest.WriteJSON(w, errors.New(http.StatusInternalServerError, "Could not generate JWT"))
		return
	} else {
		jwtString := string(jwt)
		rest.WriteJSON(w, &jwtString)
		return
	}

}
Esempio n. 5
1
// Middleware ensures all requests are formatted properly for a REST/JSON API.
// It requires that inbound requests meet all of the following conditions:
//
//	The request accepts application/json.
//	The request's content type is application/json, if it has a body.
//	The request is encoded in UTF-8.
//	The request accepts UTF-8.
//	The request is properly configured for CORS, if it requires it.
//
// If any of these conditions is not met, Rest will respond with an appropriate
// HTTP error code and error message. Otherwise it will pass control down the line.
func Middleware(ctx context.Context, w http.ResponseWriter, r *http.Request) context.Context {

	w.Header().Set("Accept", "application/json")
	w.Header().Set("Accept-Charset", "UTF-8")
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PATCH, DELETE")

	var conf config.Global

	if err := config.Get(ctx, &conf); err != nil {
		panic("Could not retrieve Configuration for Rest middleware: " + err.Error())
	}

	if !AcceptsJson(r) || !AcceptsUtf8(r) {

		// If the requester does not accept JSON in the UTF-8	character set, respond with
		// 406 Not Acceptable

		w.WriteHeader(http.StatusNotAcceptable)
		w.Write([]byte(`{"message": "This API only responds with application/json in UTF-8"}`))
		return nil

	} else if r.Method != "HEAD" && r.Method != "GET" && r.Method != "OPTIONS" && !ContentIsJson(r) {

		// If the requester has sent something other than application/json, respond with
		// 415 Unsupported Media Type

		w.WriteHeader(http.StatusUnsupportedMediaType)
		w.Write([]byte(`{"message": "This API only accepts application/json in UTF-8"}`))
		return nil

	} else if r.Header.Get("Origin") != "" && !HasValidOrigin(r, conf.ValidOriginSuffix) {

		// If the requester has sent Origin and the origin is invalid, respond with
		// 400 Bad Request

		w.Header().Set("Access-Control-Allow-Origin", conf.ValidOriginSuffix)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, `{"message": "Invalid Origin header; this API only accepts %s and its subdomains"}`, conf.ValidOriginSuffix)
		return nil

	} else {

		// The request passes all checks; it can now be processed

		// Since "Access-Control-Allow-Origin" passed, set the request Origin
		// as an allowed origin
		if r.Header.Get("Origin") != "" {
			w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
			w.Header().Set("Access-Control-Allow-Credentials", "true")
		}

		if r.Method == "OPTIONS" {
			// Options call. Intercept and do not forward.
			w.Header().Set("Access-Control-Allow-Headers", "Accept, Accept-Charset, Content-Type, Authorization, X-CORS")
			w.Header().Set("Access-Control-Expose-Headers", "Content-Type, Accept, Accept-Charset, Link, Location, X-CORS")
			w.Header().Set("Access-Control-Max-Age", "3600")
			w.WriteHeader(http.StatusNoContent)
			return nil
		}

		return ctx

	}

}