Beispiel #1
1
// HasRole returns an AuthCheck that grants access under the following conditions:
//	- The account specified by the token has the specified role.
//	- The token itself has that role in scope.
//	- The token is not used up.
func HasRole(role string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

		var acct account.Account
		var claimSet jws.ClaimSet

		if err := GetAccount(ctx, &acct); err != nil {
			// we can't get the user, so we can't check authentication status.
			log.Errorf(ctx, "Error getting account for authentication: %s", err.Error())
			return ErrCannotGetAccount
		} else if err := GetClaimSet(ctx, &claimSet); err != nil {
			log.Errorf(ctx, "Error getting claim set for authentication: %s", err.Error())
			return ErrCannotGetClaimSet
		} else if !acct.HasRole(role) {
			// the account making the request does not have the specified role.
			return ErrRoleMissing
		} else if !roleInScope(ctx, role) {
			// the JWT claimset for this request does not have the specified role in its scope.
			return ErrRoleNotInScope
		} else if err = UseClaimSet(ctx, &claimSet); err == ErrClaimSetUsedUp {
			// The claimset for this request has been all used up.
			return err
		} else if err != nil {
			return errors.New(http.StatusBadRequest, err.Error())
		} else {
			// All ok; this request's account may access the resource.
			return nil
		}

	}

}
Beispiel #2
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
	}

}
Beispiel #3
1
package config

import (
	"encoding/json"
	"github.com/qedus/nds"
	"github.com/the-information/ori/errors"
	"github.com/the-information/ori/internal"
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"net/http"
)

var ErrNotInConfigContext = errors.New(http.StatusInternalServerError, "That context was not run through the ori/config middleware")
var ErrConflict = errors.New(http.StatusConflict, "There was a conflict between versions of the object being saved")

// Entity is the string name for the Entity used to store the configuration
// in the App Engine Datastore. Think of it like a table name.
const Entity = "Config"

// Global describes some configuration parameters that are required for the API to function.
type Global struct {
	// AuthSecret is the secret key by which all JWTs are signed using a SHA-256 HMAC.
	AuthSecret string `json:",omitempty"`
	// ValidOriginSuffix is the suffix for which CORS requests are valid for this app.
	ValidOriginSuffix string `json:",omitempty"`
}

// Config is a type that can represent the full state of the application at any time.
// It's quite slow because it has to rely on reflection. Use config.Get to pull config
// into your own struct instead.
type Config datastore.PropertyList
Beispiel #4
0
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"net/http"
	"reflect"
	"sync"
	"time"
)

var xgTransaction = &datastore.TransactionOptions{
	XG: true,
}

// Entity is the name of the Datastore entity used to store API accounts.
var Entity = "APIAccount"

var ErrConflict = errors.New(http.StatusConflict, "A competing change to the account has already been made")
var ErrAccountExists = errors.New(http.StatusConflict, "An account with that email already exists")
var ErrPasswordTooShort = errors.New(http.StatusBadRequest, "Password is too short")
var ErrUnsaveableAccount = errors.New(http.StatusBadRequest, "This is a special account that cannot be saved")

// Account represents an account to access the API. It handles
// all logic to do with authentication and password checking.
type Account struct {
	flag int

	// CreatedAt stores the time at which this account was originally created.
	CreatedAt time.Time `json:"createdAt,omitempty"`

	// LastUpdatedAt represents the last time at which this account was modified.
	LastUpdatedAt time.Time `json:"lastUpdatedAt,omitempty"`
Beispiel #5
0
	"github.com/guregu/kami"
	"github.com/the-information/ori/account"
	"github.com/the-information/ori/config"
	"github.com/the-information/ori/errors"
	"github.com/the-information/ori/internal"
	"github.com/the-information/ori/rest"
	"github.com/the-information/ori/shard"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/jws"
	"google.golang.org/appengine/log"
	"net/http"
	"strings"
)

var (
	ErrForbidden                 = errors.New(http.StatusForbidden, "The account does not have permission to read the specified resource")
	ErrCannotGetAccount          = errors.New(http.StatusUnauthorized, "There was an error retrieving the account to be authenticated. Please try again.")
	ErrCannotGetClaimSet         = errors.New(http.StatusUnauthorized, "There was an error retrieving the claim set to be authenticated. Please try again.")
	ErrRoleMissing               = errors.New(http.StatusForbidden, "The specified account does not have the specified role")
	ErrRoleNotInScope            = errors.New(http.StatusUnauthorized, "The authentication token does not have the specified role in scope")
	ErrNotInAuthContext          = errors.New(http.StatusInternalServerError, "That context object was not run through auth.Middleware!")
	ErrAccountIDDoesNotMatch     = errors.New(http.StatusForbidden, "Account ID does not match route parameter")
	ErrInvalidConsumableClaimSet = errors.New(http.StatusForbidden, "Claimset has a u claim but not a jti claim")
	ErrClaimSetUsedUp            = errors.New(http.StatusUnauthorized, "Claimset has been used up")
)

// 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