2019-11-25 09:30:26 +00:00
|
|
|
// Package auth provides authentication and authorization capability
|
|
|
|
package auth
|
|
|
|
|
2019-11-25 09:33:30 +00:00
|
|
|
import (
|
2020-03-04 09:54:52 +00:00
|
|
|
"context"
|
2020-03-23 16:19:30 +00:00
|
|
|
"errors"
|
2019-11-25 09:33:30 +00:00
|
|
|
"time"
|
2020-11-18 16:50:41 +03:00
|
|
|
|
|
|
|
"github.com/unistack-org/micro/v3/metadata"
|
2019-11-25 09:33:30 +00:00
|
|
|
)
|
|
|
|
|
2020-05-22 11:37:12 +01:00
|
|
|
const (
|
|
|
|
// BearerScheme used for Authorization header
|
|
|
|
BearerScheme = "Bearer "
|
|
|
|
// ScopePublic is the scope applied to a rule to allow access to the public
|
|
|
|
ScopePublic = ""
|
|
|
|
// ScopeAccount is the scope applied to a rule to limit to users with any valid account
|
|
|
|
ScopeAccount = "*"
|
|
|
|
)
|
2020-05-20 11:59:01 +01:00
|
|
|
|
2020-03-23 16:19:30 +00:00
|
|
|
var (
|
2021-02-14 16:16:01 +03:00
|
|
|
// DefaultAuth holds default auth implementation
|
2020-12-08 00:38:37 +03:00
|
|
|
DefaultAuth Auth = NewAuth()
|
2020-05-20 11:59:01 +01:00
|
|
|
// ErrInvalidToken is when the token provided is not valid
|
2020-03-23 16:19:30 +00:00
|
|
|
ErrInvalidToken = errors.New("invalid token provided")
|
2020-05-21 14:56:17 +01:00
|
|
|
// ErrForbidden is when a user does not have the necessary scope to access a resource
|
2020-03-23 16:19:30 +00:00
|
|
|
ErrForbidden = errors.New("resource forbidden")
|
|
|
|
)
|
|
|
|
|
2020-05-21 16:41:55 +01:00
|
|
|
// Auth provides authentication and authorization
|
2019-11-25 09:30:26 +00:00
|
|
|
type Auth interface {
|
2020-03-23 16:19:30 +00:00
|
|
|
// Init the auth
|
2021-03-24 13:12:03 +03:00
|
|
|
Init(opts ...Option) error
|
2020-03-23 16:19:30 +00:00
|
|
|
// Options set for auth
|
2020-02-10 08:26:28 +00:00
|
|
|
Options() Options
|
2020-03-23 16:19:30 +00:00
|
|
|
// Generate a new account
|
2020-04-01 17:20:02 +01:00
|
|
|
Generate(id string, opts ...GenerateOption) (*Account, error)
|
2020-05-20 11:59:01 +01:00
|
|
|
// Verify an account has access to a resource using the rules
|
2020-05-20 16:49:52 +01:00
|
|
|
Verify(acc *Account, res *Resource, opts ...VerifyOption) error
|
2020-03-23 16:19:30 +00:00
|
|
|
// Inspect a token
|
|
|
|
Inspect(token string) (*Account, error)
|
2020-05-20 11:59:01 +01:00
|
|
|
// Token generated using refresh token or credentials
|
2020-04-01 14:25:00 +01:00
|
|
|
Token(opts ...TokenOption) (*Token, error)
|
2020-05-20 11:59:01 +01:00
|
|
|
// Grant access to a resource
|
|
|
|
Grant(rule *Rule) error
|
|
|
|
// Revoke access to a resource
|
|
|
|
Revoke(rule *Rule) error
|
|
|
|
// Rules returns all the rules used to verify requests
|
2020-05-26 15:52:21 +01:00
|
|
|
Rules(...RulesOption) ([]*Rule, error)
|
2020-03-23 16:19:30 +00:00
|
|
|
// String returns the name of the implementation
|
2020-02-16 19:36:45 +00:00
|
|
|
String() string
|
2019-12-17 21:27:05 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 08:16:02 +00:00
|
|
|
// Account provided by an auth provider
|
|
|
|
type Account struct {
|
2021-03-06 19:45:13 +03:00
|
|
|
// Metadata any other associated metadata
|
|
|
|
Metadata metadata.Metadata `json:"metadata"`
|
|
|
|
// ID of the account e.g. email or uuid
|
2020-03-23 16:19:30 +00:00
|
|
|
ID string `json:"id"`
|
2020-03-31 19:01:43 +01:00
|
|
|
// Type of the account, e.g. service
|
|
|
|
Type string `json:"type"`
|
2020-05-21 16:41:55 +01:00
|
|
|
// Issuer of the account
|
|
|
|
Issuer string `json:"issuer"`
|
2020-03-31 18:17:01 +01:00
|
|
|
// Secret for the account, e.g. the password
|
|
|
|
Secret string `json:"secret"`
|
2021-03-06 19:45:13 +03:00
|
|
|
// Scopes the account has access to
|
|
|
|
Scopes []string `json:"scopes"`
|
2020-03-23 16:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Token can be short or long lived
|
|
|
|
type Token struct {
|
|
|
|
// Time of token creation
|
2019-11-25 09:30:26 +00:00
|
|
|
Created time.Time `json:"created"`
|
2020-03-23 16:19:30 +00:00
|
|
|
// Time of token expiry
|
2019-11-25 09:30:26 +00:00
|
|
|
Expiry time.Time `json:"expiry"`
|
2021-03-06 19:45:13 +03:00
|
|
|
// The token to be used for accessing resources
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
// RefreshToken to be used to generate a new token
|
|
|
|
RefreshToken string `json:"refresh_token"`
|
2019-11-25 09:30:26 +00:00
|
|
|
}
|
2020-03-04 09:54:52 +00:00
|
|
|
|
2020-05-20 11:59:01 +01:00
|
|
|
// Expired returns a boolean indicating if the token needs to be refreshed
|
|
|
|
func (t *Token) Expired() bool {
|
|
|
|
return t.Expiry.Unix() < time.Now().Unix()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resource is an entity such as a user or
|
|
|
|
type Resource struct {
|
|
|
|
// Name of the resource, e.g. go.micro.service.notes
|
|
|
|
Name string `json:"name"`
|
|
|
|
// Type of resource, e.g. service
|
|
|
|
Type string `json:"type"`
|
|
|
|
// Endpoint resource e.g NotesService.Create
|
|
|
|
Endpoint string `json:"endpoint"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access defines the type of access a rule grants
|
|
|
|
type Access int
|
|
|
|
|
2020-03-04 09:54:52 +00:00
|
|
|
const (
|
2020-05-20 11:59:01 +01:00
|
|
|
// AccessGranted to a resource
|
|
|
|
AccessGranted Access = iota
|
|
|
|
// AccessDenied to a resource
|
|
|
|
AccessDenied
|
2020-03-04 09:54:52 +00:00
|
|
|
)
|
|
|
|
|
2020-05-20 11:59:01 +01:00
|
|
|
// Rule is used to verify access to a resource
|
|
|
|
type Rule struct {
|
2021-03-06 19:45:13 +03:00
|
|
|
// Resource that rule belongs to
|
|
|
|
Resource *Resource
|
|
|
|
// ID of the rule
|
2020-05-20 11:59:01 +01:00
|
|
|
ID string
|
2021-03-06 19:45:13 +03:00
|
|
|
// Scope of the rule
|
2020-05-21 14:56:17 +01:00
|
|
|
Scope string
|
2021-03-06 19:45:13 +03:00
|
|
|
// Access flag allow/deny
|
2020-05-20 11:59:01 +01:00
|
|
|
Access Access
|
2021-03-06 19:45:13 +03:00
|
|
|
// Priority holds the rule priority
|
2020-05-20 11:59:01 +01:00
|
|
|
Priority int32
|
|
|
|
}
|
|
|
|
|
2020-04-28 17:35:18 +01:00
|
|
|
type accountKey struct{}
|
|
|
|
|
2020-03-04 09:54:52 +00:00
|
|
|
// AccountFromContext gets the account from the context, which
|
|
|
|
// is set by the auth wrapper at the start of a call. If the account
|
|
|
|
// is not set, a nil account will be returned. The error is only returned
|
|
|
|
// when there was a problem retrieving an account
|
2020-04-28 17:35:18 +01:00
|
|
|
func AccountFromContext(ctx context.Context) (*Account, bool) {
|
2020-12-17 22:52:00 +03:00
|
|
|
if ctx == nil {
|
|
|
|
return nil, false
|
|
|
|
}
|
2020-04-28 17:35:18 +01:00
|
|
|
acc, ok := ctx.Value(accountKey{}).(*Account)
|
|
|
|
return acc, ok
|
2020-03-04 09:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ContextWithAccount sets the account in the context
|
2020-04-28 17:35:18 +01:00
|
|
|
func ContextWithAccount(ctx context.Context, account *Account) context.Context {
|
2020-12-17 22:52:00 +03:00
|
|
|
if ctx == nil {
|
|
|
|
ctx = context.Background()
|
|
|
|
}
|
2020-04-28 17:35:18 +01:00
|
|
|
return context.WithValue(ctx, accountKey{}, account)
|
2020-03-04 09:54:52 +00:00
|
|
|
}
|