aclcore

package
v1.6.26 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2024 License: AGPL-3.0 Imports: 16 Imported by: 4

Documentation

Overview

Package aclcore manage what an API consumer is granted to do, and issue access tokens to represent it.

This package supports the following use-cases:

1. an admin can create a new owner and administrate the site 2. an owner can back up and retrieve his medias through the API (WEB, CLI and MOBILE) 3. a guest can see albums and medias that have been shared with him 4. an owner can share an album to the rest of the family, and contribute to family albums

Index

Constants

View Source
const (
	ApiScope              ScopeType = "api"               // ApiScope represents a set of API endpoints, like 'admin'
	MainOwnerScope        ScopeType = "owner:main"        // MainOwnerScope is limited to 1 per user, it's the tenant all backups of the user will be stored against
	AlbumVisitorScope     ScopeType = "album:visitor"     // AlbumVisitorScope gives read access to an album and the media it contains FIXME The role is NOT YET MAPPED
	AlbumContributorScope ScopeType = "album:contributor" // AlbumContributorScope gives read access and ability to contribute (add medias) to an album
	MediaVisitorScope     ScopeType = "media:visitor"     // MediaVisitorScope gives read access to medias directly

	JWTScopeOwnerPrefix = "owner:"

	RefreshTokenPurposeWeb RefreshTokenPurpose = "web" // RefreshTokenPurposeWeb is used for WEB sessions
)

Variables

View Source
var (
	InvalidTokenError         = errors.New("authenticated failed")
	InvalidTokenExplicitError = errors.New("authentication failed: token invalid")
	NotPreregisteredError     = errors.New("user must be pre-registered")
	AccessUnauthorisedError   = errors.New("access unauthorised") // AccessUnauthorisedError is used when the request doesn't have valid credentials (no bearer token, or invalid token)
	AccessForbiddenError      = errors.New("access forbidden")    // AccessForbiddenError is used when the request has valid credentials, but the access to the resource has been denied

	ExpiredRefreshTokenError     = errors.New("refresh token has expired")
	InvalidRefreshTokenError     = errors.New("refresh token is not valid")
	IdentityDetailsNotFoundError = errors.New("no identity details stored for this identity") // IdentityDetailsNotFoundError is an internal error between the domain and the repository

	// TrustedIdentityProvider is the default list of trusted identity providers
	TrustedIdentityProvider = []string{
		"https://accounts.google.com/.well-known/openid-configuration",
	}
)
View Source
var TimeFunc = time.Now

Functions

func CreateString added in v1.4.0

func CreateString(input StringParams) ([]byte, error)

Types

type AccessTokenDecoder

type AccessTokenDecoder struct {
	Config OAuthConfig
	Now    func() time.Time // Now is defaulted to time.Now
}

func (*AccessTokenDecoder) Decode

func (a *AccessTokenDecoder) Decode(accessToken string) (Claims, error)

type AccessTokenGenerator added in v1.4.0

type AccessTokenGenerator struct {
	PermissionsReader     ScopesReader
	Config                OAuthConfig
	AccessTokenRepository RefreshTokenRepository
}

AccessTokenGenerator generate an access token pre-authorising consumer to perform most operations

func (*AccessTokenGenerator) GenerateAccessToken added in v1.4.0

func (t *AccessTokenGenerator) GenerateAccessToken(email usermodel.UserId) (*Authentication, error)

type Authentication

type Authentication struct {
	AccessToken  string
	RefreshToken string // RefreshToken is optional
	ExpiryTime   time.Time
	ExpiresIn    int64 // ExpiresIn is the number of seconds before access token expires
}

Authentication is generated upon successful authentication

type Claims

type Claims struct {
	Subject usermodel.UserId       // Subject is the user id (its email)
	Scopes  map[string]interface{} // Scopes is the list of permissions stored eagerly in access token
	Owner   *ownermodel.Owner      // Owner is deviated from Scopes (extract of the MainOwnerScope)
}

func (*Claims) AsCurrentUser added in v1.5.49

func (c *Claims) AsCurrentUser() usermodel.CurrentUser

func (*Claims) OwnerAsDeprecatedString added in v1.5.49

func (c *Claims) OwnerAsDeprecatedString() string

type CoreRules

type CoreRules struct {
	ScopeReader ScopesReader
	Email       usermodel.UserId
}

func (*CoreRules) Owner

func (a *CoreRules) Owner() (*ownermodel.Owner, error)

Owner returns empty if the user own nothing, or the identifier of its owner

type CreateUser

type CreateUser struct {
	ScopesReader ScopesReader
	ScopeWriter  ScopeWriter
}

func (*CreateUser) CreateUser

func (c *CreateUser) CreateUser(email, ownerOptional string) error

CreateUser create a user capable of backup as 'owner', or update an existing owner to be 'owner'

type IAccessTokenGenerator added in v1.4.0

type IAccessTokenGenerator interface {
	GenerateAccessToken(email usermodel.UserId) (*Authentication, error)
}

type IRefreshTokenGenerator added in v1.4.0

type IRefreshTokenGenerator interface {
	GenerateRefreshToken(spec RefreshTokenSpec) (string, error)
}

type Identity

type Identity struct {
	Email   usermodel.UserId
	Name    string
	Picture string
}

Identity is read from token created by the Identity Provider (google, ...)

type IdentityDetailsStore added in v1.4.0

type IdentityDetailsStore interface {
	StoreIdentity(identity Identity) error
	FindIdentity(email usermodel.UserId) (*Identity, error)
}

type IdentityQueries added in v1.4.0

type IdentityQueries struct {
	IdentityRepository IdentityQueriesIdentityRepository
	ScopeRepository    IdentityQueriesScopeRepository
}

func (*IdentityQueries) FindIdentities added in v1.4.0

func (i *IdentityQueries) FindIdentities(emails []usermodel.UserId) ([]*Identity, error)

func (*IdentityQueries) FindOwnerIdentities added in v1.4.0

func (i *IdentityQueries) FindOwnerIdentities(owners []ownermodel.Owner) (map[ownermodel.Owner][]*Identity, error)

type IdentityQueriesIdentityRepository added in v1.4.0

type IdentityQueriesIdentityRepository interface {
	FindIdentities(emails []usermodel.UserId) ([]*Identity, error)
}

type IdentityQueriesScopeRepository added in v1.4.0

type IdentityQueriesScopeRepository interface {
	ListScopesByOwners(ctx context.Context, owners []ownermodel.Owner, types ...ScopeType) ([]*Scope, error)
}

type Logout added in v1.4.0

type Logout struct {
	RevokeAccessTokenAdapter RevokeAccessTokenAdapter
}

func (*Logout) RevokeSession added in v1.4.0

func (l *Logout) RevokeSession(refreshToken string) error

type OAuth2IssuerConfig

type OAuth2IssuerConfig struct {
	ConfigSource     string
	PublicKeysLookup func(method OAuthTokenMethod) (interface{}, error)
}

func (*OAuth2IssuerConfig) String

func (i *OAuth2IssuerConfig) String() string

type OAuthConfig

type OAuthConfig struct {
	AccessDuration  time.Duration                         // AccessDuration for generated access tokens
	RefreshDuration map[RefreshTokenPurpose]time.Duration // RefreshDuration for generated refresh token (based on the purpose)
	Issuer          string                                // Issuer is the application instance ID, used in both 'iss' and 'aud'
	SecretJwtKey    []byte                                // SecretJwtKey is the key used to sign and validate DPhoto JWT
}

type OAuthTokenMethod

type OAuthTokenMethod struct {
	Algorithm string
	Kid       string
}

func (*OAuthTokenMethod) String

func (t *OAuthTokenMethod) String() string

type RefreshTokenAuthenticator added in v1.4.0

type RefreshTokenAuthenticator struct {
	AccessTokenGenerator   IAccessTokenGenerator
	RefreshTokenGenerator  IRefreshTokenGenerator
	RefreshTokenRepository RefreshTokenRepository
	IdentityDetailsStore   IdentityDetailsStore
}

RefreshTokenAuthenticator use a known identity token issued by a known and trusted identity provider (google, facebook, ...) to create an access token

func (*RefreshTokenAuthenticator) AuthenticateFromRefreshToken added in v1.4.0

func (s *RefreshTokenAuthenticator) AuthenticateFromRefreshToken(refreshToken string) (*Authentication, *Identity, error)

type RefreshTokenGenerator added in v1.4.0

type RefreshTokenGenerator struct {
	RefreshTokenRepository RefreshTokenRepository
	RefreshDuration        map[RefreshTokenPurpose]time.Duration
}

func (*RefreshTokenGenerator) GenerateRefreshToken added in v1.4.0

func (t *RefreshTokenGenerator) GenerateRefreshToken(spec RefreshTokenSpec) (string, error)

type RefreshTokenPurpose added in v1.4.0

type RefreshTokenPurpose string

type RefreshTokenRepository added in v1.4.0

type RefreshTokenRepository interface {
	StoreRefreshToken(token string, spec RefreshTokenSpec) error

	FindRefreshToken(token string) (*RefreshTokenSpec, error)
	DeleteRefreshToken(token string) error

	// HouseKeepRefreshToken removes any token that have expired
	HouseKeepRefreshToken() (int, error)
}

type RefreshTokenSpec added in v1.4.0

type RefreshTokenSpec struct {
	Email               usermodel.UserId
	RefreshTokenPurpose RefreshTokenPurpose // RefreshTokenPurpose is mandatory
	AbsoluteExpiryTime  time.Time           // AbsoluteExpiryTime will be generated from RefreshTokenPurpose if not defined
	Scopes              []string            // Scopes is the list of scopes for which an access token can be generated
}

type ReverseScopesReader

type ReverseScopesReader interface {
	// ListOwnerScopes is a reverse query to find to whom has been shared owner resources.
	ListScopesByOwner(ctx context.Context, owner ownermodel.Owner, types ...ScopeType) ([]*Scope, error)
}

type RevokeAccessTokenAdapter added in v1.4.0

type RevokeAccessTokenAdapter interface {
	DeleteRefreshToken(token string) error
}

type SSOAuthenticator

type SSOAuthenticator struct {
	AccessTokenGenerator
	RefreshTokenGenerator  IRefreshTokenGenerator
	IdentityDetailsStore   IdentityDetailsStore
	TrustedIdentityIssuers map[string]OAuth2IssuerConfig // TrustedIdentityIssuers is the list of accepted 'iss', and their public key
}

SSOAuthenticator use a known identity token issued by a known and trusted identity provider (google, facebook, ...) to create an access token

func (*SSOAuthenticator) AuthenticateFromExternalIDProvider

func (s *SSOAuthenticator) AuthenticateFromExternalIDProvider(identityJWT string, refreshTokenPurpose RefreshTokenPurpose) (*Authentication, *Identity, error)

type Scope

type Scope struct {
	Type          ScopeType        // Type is mandatory, it defines what fields on this structure is used and allow to filter the results
	GrantedAt     time.Time        // GrantedAt is the date the scope has been granted to the user for the first time
	GrantedTo     usermodel.UserId // GrantedTo is the consumer, usually an email address
	ResourceOwner ownermodel.Owner // ResourceOwner (optional) is used has part of the ID of the catalog resources
	ResourceId    string           // ResourceId if a unique identifier of the resource (in conjunction of the ResourceOwner for most catalog resources) ; ex: 'admin' (for 'api' type)
	ResourceName  string           // ResourceName (optional) used for user-friendly display of the shared albums // TODO is it necessary ?
}

Scope is attached to a user (a consumer of the API) and define the role it has on resource basis

func (Scope) Id added in v1.6.4

func (s Scope) Id() ScopeId

type ScopeId

type ScopeId struct {
	Type          ScopeType        // Type is mandatory, it defines what fields on this structure is used and allow to filter the results
	GrantedTo     usermodel.UserId // GrantedTo is the consumer, usually an email address
	ResourceOwner ownermodel.Owner // ResourceOwner (optional) is used has part of the ID of the catalog resources
	ResourceId    string           // ResourceId if a unique identifier of the resource (in conjunction of the ResourceOwner for most catalog resources) ; ex: 'admin' (for 'api' type)
}

ScopeId are the properties of a Scope that identity it

type ScopeQueries added in v1.5.49

type ScopeQueries struct {
	ScopeReadRepository
}

ScopeQueries is a read-only repository to query scopes

type ScopeReadRepository added in v1.5.49

type ScopeReadRepository interface {
	ListScopesByUser(ctx context.Context, email usermodel.UserId, types ...ScopeType) ([]*Scope, error)
	ListScopesByOwner(ctx context.Context, owner ownermodel.Owner, types ...ScopeType) ([]*Scope, error)
	FindScopesByIdCtx(ctx context.Context, ids ...ScopeId) ([]*Scope, error)
}

type ScopeReadRepositoryInMemory added in v1.6.4

type ScopeReadRepositoryInMemory struct {
	Scopes []*Scope
}

ScopeReadRepositoryInMemory implements ScopeReadRepository and is used for testing and stubbing.

func (*ScopeReadRepositoryInMemory) FindScopesByIdCtx added in v1.6.4

func (s *ScopeReadRepositoryInMemory) FindScopesByIdCtx(ctx context.Context, ids ...ScopeId) ([]*Scope, error)

func (*ScopeReadRepositoryInMemory) ListScopesByOwner added in v1.6.4

func (s *ScopeReadRepositoryInMemory) ListScopesByOwner(ctx context.Context, owner ownermodel.Owner, types ...ScopeType) ([]*Scope, error)

func (*ScopeReadRepositoryInMemory) ListScopesByUser added in v1.6.4

func (s *ScopeReadRepositoryInMemory) ListScopesByUser(ctx context.Context, userId usermodel.UserId, types ...ScopeType) ([]*Scope, error)

type ScopeType

type ScopeType string

ScopeType is a type of API (admin) or a catalog resource (owner, album, ...)

type ScopeWriter

type ScopeWriter interface {
	// DeleteScopes deletes the scope(s) if it exists, do nothing otherwise
	DeleteScopes(id ...ScopeId) error

	// SaveIfNewScope persists the scope if it doesn't exist yet, no error is returned if it already exists
	SaveIfNewScope(scope Scope) error
}

type ScopesReader

type ScopesReader interface {
	// ListUserScopes returns all access of a certain type that have been granted to a user
	ListScopesByUser(ctx context.Context, email usermodel.UserId, types ...ScopeType) ([]*Scope, error)

	// FindScopesById returns scopes that have been granted (exists in DB)
	FindScopesById(ids ...ScopeId) ([]*Scope, error)
}

type StringParams added in v1.4.0

type StringParams struct {
	Length          int64
	Upper           bool
	MinUpper        int64
	Lower           bool
	MinLower        int64
	Numeric         bool
	MinNumeric      int64
	Special         bool
	MinSpecial      int64
	OverrideSpecial string
}

Jump to

Keyboard shortcuts

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