lushauth

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 17, 2020 License: Apache-2.0 Imports: 7 Imported by: 0

README

LUSH Core Authentication

This package is used to deal with authenticated requests and responses within the LUSH infrastructure.

Policies

Policies should be used to structure access control inside a project's domain logic.

Roles Policy

Given that you have an action that can only be performed by administrators, you can set up a RolePolicy with the "admin" role. This will permit the consumer access only if they possess one or more of the roles specified in the policy.

policy := lushauth.RolePolicy{"admin", "staff"}
policy.Permit(consumer)
Grants Policy

For more granular access control you can require grants to be set in the consumer. Given that you've got an action to delete a user, you can set up a GrantPolicy with the "users.delete" grant. This will permit the consumer access only if they possess one or more grants specified in the policy.

policy := lushauth.GrantPolicy{"users.delete"}
policy.Permit(consumer)
User Policy

Sometimes actions are bound to only be performed by a very specific user. Given that you have an action for a user to update their own profile, you can set up a UserPolicy with the UUID of the user. This will permit the consumer access only if their UUID match any of the UUIDs specified in the policy.

policy := lushauth.UserPolicy{
    UserID, // UserID: "5d4b32f9-5954-41c3-a470-7d76317635a7"
}
policy.Permit(consumer)
Market Policy

For certain things you need to allow access per market and roles in those markets. Given that you've got an action to set a price for a product in the British market, you can set up a MarketPolicy with the "gb" market id and the "digital_manager" market role. This will permit the consumer access only if they belong to the given market and that they possess one or more of the roles for the given market.

policy := lushauth.MarketPolicy{
    ID: "gb",
    Roles: []string{
        "digital_manager",
    },
}
policy.Permit(consumer)
Any Policy

Sometimes you might have different access criteria for a given action. Given that you have an action to update a page for the Swedish market which can only be done by a digital manager within that market, OR by a global administrator, you can set up multiple policies. This will permit the consumer access only if they're permitted access within any of the policies.

policy := lushauth.AnyPolicy{
    lushauth.MarketPolicy{
        ID: "gb",
        Roles: []string{
            "digital_manager",
        },
    },
    lushauth.RolePolicy{"admin"},
}
policy.Permit(consumer)
All Policy

Sometimes you need more than one criteria for access criteria for a given action. Given that you have an action for going into maintenance mode in the Netherlands where you want to ensure only a specific intersection of people with the global "admin" role and the "digital_manager" role within the market. This will permit the consumer access only if they're permitted by all policies.

policy := lushauth.AllPolicy{
    lushauth.MarketPolicy{
        ID: "nl",
        Roles: []string{
            "digital_manager",
        },
    },
    lushauth.RolePolicy{"admin"},
}
policy.Permit(consumer)

Documentation

Index

Examples

Constants

View Source
const (
	// JWTValidationErrorExpired happens when EXP validation failed
	JWTValidationErrorExpired uint32 = 1 << iota
	// JWTValidationErrorUsedBeforeIssued happens when IAT validation failed
	JWTValidationErrorUsedBeforeIssued
	// JWTValidationErrorNotValidYet happens when NBF validation failed
	JWTValidationErrorNotValidYet
	// JWTValidationErrorIssuer happens when ISS validation failed
	JWTValidationErrorIssuer
	// JWTValidationErrorID happens when JTI validation failed
	JWTValidationErrorID
)

Variables

View Source
var (
	// TimeFunc is a variable with a function to determine the current time.
	// Can be overridden in a test environment to set the current time to whatever you want it to be.
	TimeFunc = time.Now

	// DefaultValidPeriod is the period a set of claims are valid.
	DefaultValidPeriod = 60 * time.Minute
)

Functions

func ContextWithConsumer

func ContextWithConsumer(parent context.Context, consumer Consumer) context.Context

ContextWithConsumer takes a context and a service consumer and returns a new context with the consumer embedded.

Example
package main

import (
	"context"

	"github.com/LUSHDigital/core-lush/lushauth"
)

var ctx context.Context

func main() {
	ctx = lushauth.ContextWithConsumer(context.Background(), lushauth.Consumer{
		ID:     999,
		Grants: []string{"foo"},
	})
}
Output:

func RSAKeyFunc

func RSAKeyFunc(pk crypto.PublicKey) jwt.Keyfunc

RSAKeyFunc is used with the jwt-go library to validate that a token is using the correct signing algorithm.

Types

type AllPolicy added in v0.1.0

type AllPolicy []Permitter

AllPolicy defines a policy made up of multiple other policies where all of them are required for access to be permitted.

Example
policy := lushauth.AllPolicy{
	lushauth.RolePolicy{"staff"},
	lushauth.MarketPolicy{
		ID:    "gb",
		Roles: []string{"manager"},
	},
}
policy.Permit(consumer)
Output:

func (AllPolicy) Permit added in v0.1.0

func (p AllPolicy) Permit(c Consumer) error

Permit a consumer or return an error.

type AnyPolicy added in v0.1.0

type AnyPolicy []Permitter

AnyPolicy defines a policy made up of multiple other policies where any of them will permit access.

Example
policy := lushauth.AnyPolicy{
	lushauth.GrantPolicy{"users.delete"},
	lushauth.RolePolicy{"admin"},
}
policy.Permit(consumer)
Output:

func (AnyPolicy) Permit added in v0.1.0

func (p AnyPolicy) Permit(c Consumer) error

Permit a consumer or return an error.

type Claims

type Claims struct {
	ID       string `json:"jti,omitempty"`
	Issuer   string `json:"iss,omitempty"`
	Audience string `json:"aud,omitempty"`
	Subject  string `json:"sub,omitempty"`

	ExpiresAt int64 `json:"exp,omitempty"`
	IssuedAt  int64 `json:"iat,omitempty"`
	NotBefore int64 `json:"nbf,omitempty"`

	Consumer Consumer `json:"consumer"`
}

Claims hold information of the power exerted by a JWT. A structured version of the Claims section, as referenced at https://tools.ietf.org/html/rfc7519#section-4.1

func NewClaimsForConsumer

func NewClaimsForConsumer(issuer string, consumer Consumer) (Claims, error)

NewClaimsForConsumer spawns new claims for

func (*Claims) Valid

func (c *Claims) Valid() error

Valid validates time based claims (EXP, IAT, NBF) as well as the identifiers (ISS, JTI).

func (*Claims) VerifyExpiresAt

func (c *Claims) VerifyExpiresAt(now time.Time) bool

VerifyExpiresAt compares the exp claim against a timestamp. Will change behaviour depending on the value of corelush.TimeFunc

func (*Claims) VerifyIssuedAt

func (c *Claims) VerifyIssuedAt(now time.Time) bool

VerifyIssuedAt compares the iat claim against a timestamp. Will change behaviour depending on the value of corelush.TimeFunc

func (*Claims) VerifyNotBefore

func (c *Claims) VerifyNotBefore(now time.Time) bool

VerifyNotBefore compares the nbf claim against a timestamp. Will change behaviour depending on the value of corelush.TimeFunc

type Consumer

type Consumer struct {
	// ID is a unique identifier for a user but should not be used in favour of UUID.
	ID int64 `json:"id"`
	// UUID is the unique identifier for a user.
	UUID string `json:"uuid"`
	// FirstName is the given name of a user.
	FirstName string `json:"first_name"`
	// LastName is the surname of a user.
	LastName string `json:"last_name"`
	// Language is the preferred language of a user.
	Language string `json:"language"`
	// Grants are any specific, given permissions for a user.
	// e.g. products.create, pages.read or tills.close
	Grants []string `json:"grants"`
	// Roles are what purpose a user server within the context of LUSH
	// e.g. guest, staff, creator or admin
	Roles []string `json:"roles"`
	// Needs are things that the user needs to do and that a front-end can react to.
	// e.g. password_reset, confirm_email or accept_terms
	Needs []string `json:"needs"`
	// Markets the user belongs to.
	// e.g. "gb", "de", etc...
	Markets []Market `json:"markets"`
}

Consumer represents an API user for the LUSH infrastructure.

func ConsumerFromContext

func ConsumerFromContext(ctx context.Context) Consumer

ConsumerFromContext extracts the consumer from the supplied context.

Example
package main

import (
	"context"

	"github.com/LUSHDigital/core-lush/lushauth"
)

var ctx context.Context

func main() {
	consumer := lushauth.ConsumerFromContext(ctx)
	consumer.IsUser(999)
}
Output:

func (*Consumer) HasAnyGrant

func (c *Consumer) HasAnyGrant(grants ...string) bool

HasAnyGrant checks if a consumer possess any of a given set of grants

func (Consumer) HasAnyMarketRole added in v0.0.2

func (c Consumer) HasAnyMarketRole(id string, roles ...string) bool

HasAnyMarketRole checks if a user has any role in a given market.

func (*Consumer) HasAnyNeed

func (c *Consumer) HasAnyNeed(needs ...string) bool

HasAnyNeed checks if a consumer has any of the given needs

func (*Consumer) HasAnyRole

func (c *Consumer) HasAnyRole(roles ...string) bool

HasAnyRole checks if a consumer possess any of a given set of roles

func (*Consumer) HasAnyUUID added in v0.1.0

func (c *Consumer) HasAnyUUID(ids ...string) bool

HasAnyUUID checks if a consumer has the same uuid as a user

func (Consumer) HasNoMatchingGrant

func (c Consumer) HasNoMatchingGrant(grants ...string) bool

HasNoMatchingGrant checks if a consumer is missing any of a given set of grants

func (*Consumer) HasNoMatchingNeed

func (c *Consumer) HasNoMatchingNeed(needs ...string) bool

HasNoMatchingNeed checks if a consumer has any of the given needs

func (*Consumer) HasNoMatchingRole

func (c *Consumer) HasNoMatchingRole(roles ...string) bool

HasNoMatchingRole checks if a consumer is missing any of a given set of roles

func (*Consumer) IsUser

func (c *Consumer) IsUser(id int64) bool

IsUser checks if a consumer has the same ID as a user

type GrantPolicy added in v0.1.0

type GrantPolicy []string

GrantPolicy defines what grants required for access.

Example
policy := lushauth.GrantPolicy{"users.delete"}
policy.Permit(consumer)
Output:

func (GrantPolicy) Error added in v0.1.0

func (p GrantPolicy) Error() string

func (GrantPolicy) Permit added in v0.1.0

func (p GrantPolicy) Permit(c Consumer) error

Permit a consumer or return an error.

type JWTSigningMethodError

type JWTSigningMethodError struct {
	Algorithm interface{}
}

JWTSigningMethodError happens when the RSA

func (JWTSigningMethodError) Error

func (e JWTSigningMethodError) Error() string

type JWTVerificationError

type JWTVerificationError struct {
	Errors uint32
}

JWTVerificationError happens when one or more token fields could not be verified.

func (JWTVerificationError) Error

func (e JWTVerificationError) Error() string

type Market added in v0.0.2

type Market struct {
	ID    string   `json:"id"`
	Roles []string `json:"roles"`
}

Market represents a market attached to an API user.

type MarketPolicy added in v0.1.0

type MarketPolicy struct {
	ID    string
	Roles []string
}

MarketPolicy defines what roles to allow access for in a given market.

Example
policy := lushauth.MarketPolicy{
	ID: "gb",
	Roles: []string{
		"admin",
		"manager",
		"staff",
	},
}
policy.Permit(consumer)
Output:

func (MarketPolicy) Error added in v0.1.0

func (p MarketPolicy) Error() string

func (MarketPolicy) Permit added in v0.1.0

func (p MarketPolicy) Permit(c Consumer) error

Permit a consumer or return an error.

type Permitter added in v0.1.0

type Permitter interface {
	Permit(c Consumer) error
}

Permitter defines the behavior of allowing access.

type RefreshableClaims

type RefreshableClaims struct {
	Claims
}

RefreshableClaims hold information of the power exerted by a JWT. A structured version of the Claims section, as referenced at https://tools.ietf.org/html/rfc7519#section-4.1

The difference between RefreshableClaims and Claims is that this struct will not attempt to validate whether the token is expired.

func (*RefreshableClaims) Valid

func (c *RefreshableClaims) Valid() error

Valid verifies time based claims (IAT, NBF) as well as the identifiers (ISS, JTI).

type RolePolicy added in v0.1.0

type RolePolicy []string

RolePolicy defines what roles to grant access for.

Example
policy := lushauth.RolePolicy{"admin", "staff"}
policy.Permit(consumer)
Output:

func (RolePolicy) Error added in v0.1.0

func (p RolePolicy) Error() string

func (RolePolicy) Permit added in v0.1.0

func (p RolePolicy) Permit(c Consumer) error

Permit a consumer or return an error.

type UserPolicy added in v0.1.0

type UserPolicy []string

UserPolicy defines what users to grant access for.

Example
policy := lushauth.UserPolicy{
	UserID, // UserID: "5d4b32f9-5954-41c3-a470-7d76317635a7"
}
policy.Permit(consumer)
Output:

func (UserPolicy) Error added in v0.1.0

func (p UserPolicy) Error() string

func (UserPolicy) Permit added in v0.1.0

func (p UserPolicy) Permit(c Consumer) error

Permit a consumer or return an error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL