| @@ -2,8 +2,6 @@ package resolver | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/auth" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // NewOptions returns new initialised options | // NewOptions returns new initialised options | ||||||
| @@ -14,7 +12,7 @@ func NewOptions(opts ...Option) Options { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if options.Namespace == nil { | 	if options.Namespace == nil { | ||||||
| 		options.Namespace = StaticNamespace(auth.DefaultNamespace) | 		options.Namespace = StaticNamespace("go.micro") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return options | 	return options | ||||||
|   | |||||||
							
								
								
									
										118
									
								
								auth/auth.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								auth/auth.go
									
									
									
									
									
								
							| @@ -7,20 +7,23 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | 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 = "*" | ||||||
|  | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// ErrNotFound is returned when a resouce cannot be found | 	// ErrInvalidToken is when the token provided is not valid | ||||||
| 	ErrNotFound = errors.New("not found") |  | ||||||
| 	// ErrEncodingToken is returned when the service encounters an error during encoding |  | ||||||
| 	ErrEncodingToken = errors.New("error encoding the token") |  | ||||||
| 	// ErrInvalidToken is returned when the token provided is not valid |  | ||||||
| 	ErrInvalidToken = errors.New("invalid token provided") | 	ErrInvalidToken = errors.New("invalid token provided") | ||||||
| 	// ErrInvalidRole is returned when the role provided was invalid | 	// ErrForbidden is when a user does not have the necessary scope to access a resource | ||||||
| 	ErrInvalidRole = errors.New("invalid role") |  | ||||||
| 	// ErrForbidden is returned when a user does not have the necessary roles to access a resource |  | ||||||
| 	ErrForbidden = errors.New("resource forbidden") | 	ErrForbidden = errors.New("resource forbidden") | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Auth providers authentication and authorization | // Auth provides authentication and authorization | ||||||
| type Auth interface { | type Auth interface { | ||||||
| 	// Init the auth | 	// Init the auth | ||||||
| 	Init(opts ...Option) | 	Init(opts ...Option) | ||||||
| @@ -28,65 +31,38 @@ type Auth interface { | |||||||
| 	Options() Options | 	Options() Options | ||||||
| 	// Generate a new account | 	// Generate a new account | ||||||
| 	Generate(id string, opts ...GenerateOption) (*Account, error) | 	Generate(id string, opts ...GenerateOption) (*Account, error) | ||||||
| 	// Grant access to a resource | 	// Verify an account has access to a resource using the rules | ||||||
| 	Grant(role string, res *Resource) error | 	Verify(acc *Account, res *Resource, opts ...VerifyOption) error | ||||||
| 	// Revoke access to a resource |  | ||||||
| 	Revoke(role string, res *Resource) error |  | ||||||
| 	// Verify an account has access to a resource |  | ||||||
| 	Verify(acc *Account, res *Resource) error |  | ||||||
| 	// Inspect a token | 	// Inspect a token | ||||||
| 	Inspect(token string) (*Account, error) | 	Inspect(token string) (*Account, error) | ||||||
| 	// Token generated using refresh token | 	// Token generated using refresh token or credentials | ||||||
| 	Token(opts ...TokenOption) (*Token, error) | 	Token(opts ...TokenOption) (*Token, error) | ||||||
|  | 	// 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 | ||||||
|  | 	Rules(...RulesOption) ([]*Rule, error) | ||||||
| 	// String returns the name of the implementation | 	// String returns the name of the implementation | ||||||
| 	String() string | 	String() string | ||||||
| } | } | ||||||
|  |  | ||||||
| // Resource is an entity such as a user or |  | ||||||
| type Resource struct { |  | ||||||
| 	// Name of the resource |  | ||||||
| 	Name string `json:"name"` |  | ||||||
| 	// Type of resource, e.g. |  | ||||||
| 	Type string `json:"type"` |  | ||||||
| 	// Endpoint resource e.g NotesService.Create |  | ||||||
| 	Endpoint string `json:"endpoint"` |  | ||||||
| 	// Namespace the resource belongs to |  | ||||||
| 	Namespace string `json:"namespace"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Account provided by an auth provider | // Account provided by an auth provider | ||||||
| type Account struct { | type Account struct { | ||||||
| 	// ID of the account e.g. email | 	// ID of the account e.g. email | ||||||
| 	ID string `json:"id"` | 	ID string `json:"id"` | ||||||
| 	// Type of the account, e.g. service | 	// Type of the account, e.g. service | ||||||
| 	Type string `json:"type"` | 	Type string `json:"type"` | ||||||
| 	// Provider who issued the account | 	// Issuer of the account | ||||||
| 	Provider string `json:"provider"` | 	Issuer string `json:"issuer"` | ||||||
| 	// Roles associated with the Account |  | ||||||
| 	Roles []string `json:"roles"` |  | ||||||
| 	// Any other associated metadata | 	// Any other associated metadata | ||||||
| 	Metadata map[string]string `json:"metadata"` | 	Metadata map[string]string `json:"metadata"` | ||||||
| 	// Namespace the account belongs to | 	// Scopes the account has access to | ||||||
| 	Namespace string `json:"namespace"` | 	Scopes []string `json:"scopes"` | ||||||
| 	// Secret for the account, e.g. the password | 	// Secret for the account, e.g. the password | ||||||
| 	Secret string `json:"secret"` | 	Secret string `json:"secret"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // HasRole returns a boolean indicating if the account has the given role |  | ||||||
| func (a *Account) HasRole(role string) bool { |  | ||||||
| 	if a.Roles == nil { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, r := range a.Roles { |  | ||||||
| 		if r == role { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Token can be short or long lived | // Token can be short or long lived | ||||||
| type Token struct { | type Token struct { | ||||||
| 	// The token to be used for accessing resources | 	// The token to be used for accessing resources | ||||||
| @@ -99,15 +75,47 @@ type Token struct { | |||||||
| 	Expiry time.Time `json:"expiry"` | 	Expiry time.Time `json:"expiry"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	// DefaultNamespace used for auth | 	// AccessGranted to a resource | ||||||
| 	DefaultNamespace = "go.micro" | 	AccessGranted Access = iota | ||||||
| 	// TokenCookieName is the name of the cookie which stores the auth token | 	// AccessDenied to a resource | ||||||
| 	TokenCookieName = "micro-token" | 	AccessDenied | ||||||
| 	// BearerScheme used for Authorization header |  | ||||||
| 	BearerScheme = "Bearer " |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // Rule is used to verify access to a resource | ||||||
|  | type Rule struct { | ||||||
|  | 	// ID of the rule, e.g. "public" | ||||||
|  | 	ID string | ||||||
|  | 	// Scope the rule requires, a blank scope indicates open to the public and * indicates the rule | ||||||
|  | 	// applies to any valid account | ||||||
|  | 	Scope string | ||||||
|  | 	// Resource the rule applies to | ||||||
|  | 	Resource *Resource | ||||||
|  | 	// Access determines if the rule grants or denies access to the resource | ||||||
|  | 	Access Access | ||||||
|  | 	// Priority the rule should take when verifying a request, the higher the value the sooner the | ||||||
|  | 	// rule will be applied | ||||||
|  | 	Priority int32 | ||||||
|  | } | ||||||
|  |  | ||||||
| type accountKey struct{} | type accountKey struct{} | ||||||
|  |  | ||||||
| // AccountFromContext gets the account from the context, which | // AccountFromContext gets the account from the context, which | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| package auth |  | ||||||
|  |  | ||||||
| import "testing" |  | ||||||
|  |  | ||||||
| func TestHasRole(t *testing.T) { |  | ||||||
| 	if new(Account).HasRole("foo") { |  | ||||||
| 		t.Errorf("Expected the blank account to not have a role") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	acc := Account{Roles: []string{"foo"}} |  | ||||||
| 	if !acc.HasRole("foo") { |  | ||||||
| 		t.Errorf("Expected the account to have the foo role") |  | ||||||
| 	} |  | ||||||
| 	if acc.HasRole("bar") { |  | ||||||
| 		t.Errorf("Expected the account to not have the bar role") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -49,35 +49,37 @@ func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) { | |||||||
| 	options := NewGenerateOptions(opts...) | 	options := NewGenerateOptions(opts...) | ||||||
|  |  | ||||||
| 	return &Account{ | 	return &Account{ | ||||||
| 		ID:        id, | 		ID:       id, | ||||||
| 		Roles:     options.Roles, | 		Secret:   options.Secret, | ||||||
| 		Secret:    options.Secret, | 		Metadata: options.Metadata, | ||||||
| 		Metadata:  options.Metadata, | 		Scopes:   options.Scopes, | ||||||
| 		Namespace: DefaultNamespace, | 		Issuer:   n.Options().Namespace, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // Grant access to a resource | // Grant access to a resource | ||||||
| func (n *noop) Grant(role string, res *Resource) error { | func (n *noop) Grant(rule *Rule) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // Revoke access to a resource | // Revoke access to a resource | ||||||
| func (n *noop) Revoke(role string, res *Resource) error { | func (n *noop) Revoke(rule *Rule) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Rules used to verify requests | ||||||
|  | func (n *noop) Rules(opts ...RulesOption) ([]*Rule, error) { | ||||||
|  | 	return []*Rule{}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // Verify an account has access to a resource | // Verify an account has access to a resource | ||||||
| func (n *noop) Verify(acc *Account, res *Resource) error { | func (n *noop) Verify(acc *Account, res *Resource, opts ...VerifyOption) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // Inspect a token | // Inspect a token | ||||||
| func (n *noop) Inspect(token string) (*Account, error) { | func (n *noop) Inspect(token string) (*Account, error) { | ||||||
| 	return &Account{ | 	return &Account{ID: uuid.New().String(), Issuer: n.Options().Namespace}, nil | ||||||
| 		ID:        uuid.New().String(), |  | ||||||
| 		Namespace: DefaultNamespace, |  | ||||||
| 	}, nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Token generation using an account id and secret | // Token generation using an account id and secret | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/auth" | 	"github.com/micro/go-micro/v2/auth" | ||||||
|  | 	"github.com/micro/go-micro/v2/auth/rules" | ||||||
| 	"github.com/micro/go-micro/v2/auth/token" | 	"github.com/micro/go-micro/v2/auth/token" | ||||||
| 	jwtToken "github.com/micro/go-micro/v2/auth/token/jwt" | 	jwtToken "github.com/micro/go-micro/v2/auth/token/jwt" | ||||||
| ) | ) | ||||||
| @@ -16,15 +17,10 @@ func NewAuth(opts ...auth.Option) auth.Auth { | |||||||
| 	return j | 	return j | ||||||
| } | } | ||||||
|  |  | ||||||
| type rule struct { |  | ||||||
| 	role     string |  | ||||||
| 	resource *auth.Resource |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type jwt struct { | type jwt struct { | ||||||
| 	options auth.Options | 	options auth.Options | ||||||
| 	jwt     token.Provider | 	jwt     token.Provider | ||||||
| 	rules   []*rule | 	rules   []*auth.Rule | ||||||
|  |  | ||||||
| 	sync.Mutex | 	sync.Mutex | ||||||
| } | } | ||||||
| @@ -41,10 +37,6 @@ func (j *jwt) Init(opts ...auth.Option) { | |||||||
| 		o(&j.options) | 		o(&j.options) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(j.options.Namespace) == 0 { |  | ||||||
| 		j.options.Namespace = auth.DefaultNamespace |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	j.jwt = jwtToken.NewTokenProvider( | 	j.jwt = jwtToken.NewTokenProvider( | ||||||
| 		token.WithPrivateKey(j.options.PrivateKey), | 		token.WithPrivateKey(j.options.PrivateKey), | ||||||
| 		token.WithPublicKey(j.options.PublicKey), | 		token.WithPublicKey(j.options.PublicKey), | ||||||
| @@ -60,12 +52,11 @@ func (j *jwt) Options() auth.Options { | |||||||
| func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { | func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { | ||||||
| 	options := auth.NewGenerateOptions(opts...) | 	options := auth.NewGenerateOptions(opts...) | ||||||
| 	account := &auth.Account{ | 	account := &auth.Account{ | ||||||
| 		ID:        id, | 		ID:       id, | ||||||
| 		Type:      options.Type, | 		Type:     options.Type, | ||||||
| 		Roles:     options.Roles, | 		Scopes:   options.Scopes, | ||||||
| 		Provider:  options.Provider, | 		Metadata: options.Metadata, | ||||||
| 		Metadata:  options.Metadata, | 		Issuer:   j.Options().Namespace, | ||||||
| 		Namespace: options.Namespace, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// generate a JWT secret which can be provided to the Token() method | 	// generate a JWT secret which can be provided to the Token() method | ||||||
| @@ -80,84 +71,44 @@ func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e | |||||||
| 	return account, nil | 	return account, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (j *jwt) Grant(role string, res *auth.Resource) error { | func (j *jwt) Grant(rule *auth.Rule) error { | ||||||
| 	j.Lock() | 	j.Lock() | ||||||
| 	defer j.Unlock() | 	defer j.Unlock() | ||||||
| 	j.rules = append(j.rules, &rule{role, res}) | 	j.rules = append(j.rules, rule) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (j *jwt) Revoke(role string, res *auth.Resource) error { | func (j *jwt) Revoke(rule *auth.Rule) error { | ||||||
| 	j.Lock() | 	j.Lock() | ||||||
| 	defer j.Unlock() | 	defer j.Unlock() | ||||||
|  |  | ||||||
| 	rules := make([]*rule, 0, len(j.rules)) | 	rules := []*auth.Rule{} | ||||||
|  |  | ||||||
| 	var ruleFound bool |  | ||||||
| 	for _, r := range rules { | 	for _, r := range rules { | ||||||
| 		if r.role == role && r.resource == res { | 		if r.ID != rule.ID { | ||||||
| 			ruleFound = true |  | ||||||
| 		} else { |  | ||||||
| 			rules = append(rules, r) | 			rules = append(rules, r) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !ruleFound { |  | ||||||
| 		return auth.ErrNotFound |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	j.rules = rules | 	j.rules = rules | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (j *jwt) Verify(acc *auth.Account, res *auth.Resource) error { | func (j *jwt) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error { | ||||||
| 	j.Lock() | 	j.Lock() | ||||||
| 	if len(res.Namespace) == 0 { | 	defer j.Unlock() | ||||||
| 		res.Namespace = j.options.Namespace |  | ||||||
| 	} |  | ||||||
| 	rules := j.rules |  | ||||||
| 	j.Unlock() |  | ||||||
|  |  | ||||||
| 	for _, rule := range rules { | 	var options auth.VerifyOptions | ||||||
| 		// validate the rule applies to the requested resource | 	for _, o := range opts { | ||||||
| 		if rule.resource.Namespace != "*" && rule.resource.Namespace != res.Namespace { | 		o(&options) | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if rule.resource.Type != "*" && rule.resource.Type != res.Type { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if rule.resource.Name != "*" && rule.resource.Name != res.Name { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if rule.resource.Endpoint != "*" && rule.resource.Endpoint != res.Endpoint { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// a blank role indicates anyone can access the resource, even without an account |  | ||||||
| 		if rule.role == "" { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// all furter checks require an account |  | ||||||
| 		if acc == nil { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// this rule allows any account access, allow the request |  | ||||||
| 		if rule.role == "*" { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// if the account has the necessary role, allow the request |  | ||||||
| 		for _, r := range acc.Roles { |  | ||||||
| 			if r == rule.role { |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// no rules matched, forbid the request | 	return rules.Verify(j.rules, acc, res) | ||||||
| 	return auth.ErrForbidden | } | ||||||
|  |  | ||||||
|  | func (j *jwt) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) { | ||||||
|  | 	j.Lock() | ||||||
|  | 	defer j.Unlock() | ||||||
|  | 	return j.rules, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (j *jwt) Inspect(token string) (*auth.Account, error) { | func (j *jwt) Inspect(token string) (*auth.Account, error) { | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package auth | package auth | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/auth/provider" | 	"github.com/micro/go-micro/v2/auth/provider" | ||||||
| @@ -13,9 +14,6 @@ func NewOptions(opts ...Option) Options { | |||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&options) | ||||||
| 	} | 	} | ||||||
| 	if len(options.Namespace) == 0 { |  | ||||||
| 		options.Namespace = DefaultNamespace |  | ||||||
| 	} |  | ||||||
| 	if options.Client == nil { | 	if options.Client == nil { | ||||||
| 		options.Client = client.DefaultClient | 		options.Client = client.DefaultClient | ||||||
| 	} | 	} | ||||||
| @@ -124,10 +122,8 @@ func WithClient(c client.Client) Option { | |||||||
| type GenerateOptions struct { | type GenerateOptions struct { | ||||||
| 	// Metadata associated with the account | 	// Metadata associated with the account | ||||||
| 	Metadata map[string]string | 	Metadata map[string]string | ||||||
| 	// Roles/scopes associated with the account | 	// Scopes the account has access too | ||||||
| 	Roles []string | 	Scopes []string | ||||||
| 	// Namespace the account belongs too |  | ||||||
| 	Namespace string |  | ||||||
| 	// Provider of the account, e.g. oauth | 	// Provider of the account, e.g. oauth | ||||||
| 	Provider string | 	Provider string | ||||||
| 	// Type of the account, e.g. user | 	// Type of the account, e.g. user | ||||||
| @@ -159,20 +155,6 @@ func WithMetadata(md map[string]string) GenerateOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithRoles for the generated account |  | ||||||
| func WithRoles(rs ...string) GenerateOption { |  | ||||||
| 	return func(o *GenerateOptions) { |  | ||||||
| 		o.Roles = rs |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithNamespace for the generated account |  | ||||||
| func WithNamespace(n string) GenerateOption { |  | ||||||
| 	return func(o *GenerateOptions) { |  | ||||||
| 		o.Namespace = n |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithProvider for the generated account | // WithProvider for the generated account | ||||||
| func WithProvider(p string) GenerateOption { | func WithProvider(p string) GenerateOption { | ||||||
| 	return func(o *GenerateOptions) { | 	return func(o *GenerateOptions) { | ||||||
| @@ -180,6 +162,13 @@ func WithProvider(p string) GenerateOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // WithScopes for the generated account | ||||||
|  | func WithScopes(s ...string) GenerateOption { | ||||||
|  | 	return func(o *GenerateOptions) { | ||||||
|  | 		o.Scopes = s | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // NewGenerateOptions from a slice of options | // NewGenerateOptions from a slice of options | ||||||
| func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { | func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { | ||||||
| 	var options GenerateOptions | 	var options GenerateOptions | ||||||
| @@ -236,3 +225,27 @@ func NewTokenOptions(opts ...TokenOption) TokenOptions { | |||||||
|  |  | ||||||
| 	return options | 	return options | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type VerifyOptions struct { | ||||||
|  | 	Context context.Context | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type VerifyOption func(o *VerifyOptions) | ||||||
|  |  | ||||||
|  | func VerifyContext(ctx context.Context) VerifyOption { | ||||||
|  | 	return func(o *VerifyOptions) { | ||||||
|  | 		o.Context = ctx | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type RulesOptions struct { | ||||||
|  | 	Context context.Context | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type RulesOption func(o *RulesOptions) | ||||||
|  |  | ||||||
|  | func RulesContext(ctx context.Context) RulesOption { | ||||||
|  | 	return func(o *RulesOptions) { | ||||||
|  | 		o.Context = ctx | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								auth/rules/rules.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								auth/rules/rules.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | package rules | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"sort" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/v2/auth" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Verify an account has access to a resource using the rules provided. If the account does not have | ||||||
|  | // access an error will be returned. If there are no rules provided which match the resource, an error | ||||||
|  | // will be returned | ||||||
|  | func Verify(rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error { | ||||||
|  | 	// the rule is only to be applied if the type matches the resource or is catch-all (*) | ||||||
|  | 	validTypes := []string{"*", res.Type} | ||||||
|  |  | ||||||
|  | 	// the rule is only to be applied if the name matches the resource or is catch-all (*) | ||||||
|  | 	validNames := []string{"*", res.Name} | ||||||
|  |  | ||||||
|  | 	// rules can have wildcard excludes on endpoints since this can also be a path for web services, | ||||||
|  | 	// e.g. /foo/* would include /foo/bar. We also want to check for wildcards and the exact endpoint | ||||||
|  | 	validEndpoints := []string{"*", res.Endpoint} | ||||||
|  | 	if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 { | ||||||
|  | 		for i := 1; i < len(comps)+1; i++ { | ||||||
|  | 			wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/")) | ||||||
|  | 			validEndpoints = append(validEndpoints, wildcard) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// filter the rules to the ones which match the criteria above | ||||||
|  | 	filteredRules := make([]*auth.Rule, 0) | ||||||
|  | 	for _, rule := range rules { | ||||||
|  | 		if !include(validTypes, rule.Resource.Type) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if !include(validNames, rule.Resource.Name) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if !include(validEndpoints, rule.Resource.Endpoint) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		filteredRules = append(filteredRules, rule) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// sort the filtered rules by priority, highest to lowest | ||||||
|  | 	sort.SliceStable(filteredRules, func(i, j int) bool { | ||||||
|  | 		return filteredRules[i].Priority > filteredRules[j].Priority | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// loop through the rules and check for a rule which applies to this account | ||||||
|  | 	for _, rule := range filteredRules { | ||||||
|  | 		// a blank scope indicates the rule applies to everyone, even nil accounts | ||||||
|  | 		if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessDenied { | ||||||
|  | 			return auth.ErrForbidden | ||||||
|  | 		} else if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessGranted { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// all further checks require an account | ||||||
|  | 		if acc == nil { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// this rule applies to any account | ||||||
|  | 		if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessDenied { | ||||||
|  | 			return auth.ErrForbidden | ||||||
|  | 		} else if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessGranted { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// if the account has the necessary scope | ||||||
|  | 		if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessDenied { | ||||||
|  | 			return auth.ErrForbidden | ||||||
|  | 		} else if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessGranted { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if no rules matched then return forbidden | ||||||
|  | 	return auth.ErrForbidden | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // include is a helper function which checks to see if the slice contains the value. includes is | ||||||
|  | // not case sensitive. | ||||||
|  | func include(slice []string, val string) bool { | ||||||
|  | 	for _, s := range slice { | ||||||
|  | 		if strings.ToLower(s) == strings.ToLower(val) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										290
									
								
								auth/rules/rules_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								auth/rules/rules_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | |||||||
|  | package rules | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/v2/auth" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestVerify(t *testing.T) { | ||||||
|  | 	srvResource := &auth.Resource{ | ||||||
|  | 		Type:     "service", | ||||||
|  | 		Name:     "go.micro.service.foo", | ||||||
|  | 		Endpoint: "Foo.Bar", | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	webResource := &auth.Resource{ | ||||||
|  | 		Type:     "service", | ||||||
|  | 		Name:     "go.micro.web.foo", | ||||||
|  | 		Endpoint: "/foo/bar", | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	catchallResource := &auth.Resource{ | ||||||
|  | 		Type:     "*", | ||||||
|  | 		Name:     "*", | ||||||
|  | 		Endpoint: "*", | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	tt := []struct { | ||||||
|  | 		Name     string | ||||||
|  | 		Rules    []*auth.Rule | ||||||
|  | 		Account  *auth.Account | ||||||
|  | 		Resource *auth.Resource | ||||||
|  | 		Error    error | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			Name:     "NoRules", | ||||||
|  | 			Rules:    []*auth.Rule{}, | ||||||
|  | 			Account:  nil, | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Error:    auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallPublicAccount", | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallPublicNoAccount", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallPrivateAccount", | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallPrivateNoAccount", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallServiceRuleMatch", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     srvResource.Type, | ||||||
|  | 						Name:     srvResource.Name, | ||||||
|  | 						Endpoint: "*", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallServiceRuleNoMatch", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     srvResource.Type, | ||||||
|  | 						Name:     "wrongname", | ||||||
|  | 						Endpoint: "*", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "ExactRuleValidScope", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account: &auth.Account{ | ||||||
|  | 				Scopes: []string{"neededscope"}, | ||||||
|  | 			}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "neededscope", | ||||||
|  | 					Resource: srvResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "ExactRuleInvalidScope", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account: &auth.Account{ | ||||||
|  | 				Scopes: []string{"neededscope"}, | ||||||
|  | 			}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "invalidscope", | ||||||
|  | 					Resource: srvResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallDenyWithAccount", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessDenied, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "CatchallDenyWithNoAccount", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessDenied, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "RulePriorityGrantFirst", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessGranted, | ||||||
|  | 					Priority: 1, | ||||||
|  | 				}, | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessDenied, | ||||||
|  | 					Priority: 0, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "RulePriorityDenyFirst", | ||||||
|  | 			Resource: srvResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessGranted, | ||||||
|  | 					Priority: 0, | ||||||
|  | 				}, | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: catchallResource, | ||||||
|  | 					Access:   auth.AccessDenied, | ||||||
|  | 					Priority: 1, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "WebExactEndpointValid", | ||||||
|  | 			Resource: webResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope:    "*", | ||||||
|  | 					Resource: webResource, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "WebExactEndpointInalid", | ||||||
|  | 			Resource: webResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     webResource.Type, | ||||||
|  | 						Name:     webResource.Name, | ||||||
|  | 						Endpoint: "invalidendpoint", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "WebWildcardEndpoint", | ||||||
|  | 			Resource: webResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     webResource.Type, | ||||||
|  | 						Name:     webResource.Name, | ||||||
|  | 						Endpoint: "*", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "WebWildcardPathEndpointValid", | ||||||
|  | 			Resource: webResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     webResource.Type, | ||||||
|  | 						Name:     webResource.Name, | ||||||
|  | 						Endpoint: "/foo/*", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Name:     "WebWildcardPathEndpointInvalid", | ||||||
|  | 			Resource: webResource, | ||||||
|  | 			Account:  &auth.Account{}, | ||||||
|  | 			Rules: []*auth.Rule{ | ||||||
|  | 				&auth.Rule{ | ||||||
|  | 					Scope: "*", | ||||||
|  | 					Resource: &auth.Resource{ | ||||||
|  | 						Type:     webResource.Type, | ||||||
|  | 						Name:     webResource.Name, | ||||||
|  | 						Endpoint: "/bar/*", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Error: auth.ErrForbidden, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, tc := range tt { | ||||||
|  | 		t.Run(tc.Name, func(t *testing.T) { | ||||||
|  | 			if err := Verify(tc.Rules, tc.Account, tc.Resource); err != tc.Error { | ||||||
|  | 				t.Errorf("Expected %v but got %v", tc.Error, err) | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -188,10 +188,9 @@ func (m *Token) GetExpiry() int64 { | |||||||
| type Account struct { | type Account struct { | ||||||
| 	Id                   string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | 	Id                   string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | ||||||
| 	Type                 string            `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` | 	Type                 string            `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` | ||||||
| 	Roles                []string          `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"` |  | ||||||
| 	Metadata             map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` | 	Metadata             map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` | ||||||
| 	Namespace            string            `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"` | 	Scopes               []string          `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` | ||||||
| 	Provider             string            `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"` | 	Issuer               string            `protobuf:"bytes,6,opt,name=issuer,proto3" json:"issuer,omitempty"` | ||||||
| 	Secret               string            `protobuf:"bytes,7,opt,name=secret,proto3" json:"secret,omitempty"` | 	Secret               string            `protobuf:"bytes,7,opt,name=secret,proto3" json:"secret,omitempty"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}          `json:"-"` | 	XXX_NoUnkeyedLiteral struct{}          `json:"-"` | ||||||
| 	XXX_unrecognized     []byte            `json:"-"` | 	XXX_unrecognized     []byte            `json:"-"` | ||||||
| @@ -237,13 +236,6 @@ func (m *Account) GetType() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *Account) GetRoles() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Roles |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Account) GetMetadata() map[string]string { | func (m *Account) GetMetadata() map[string]string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Metadata | 		return m.Metadata | ||||||
| @@ -251,16 +243,16 @@ func (m *Account) GetMetadata() map[string]string { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *Account) GetNamespace() string { | func (m *Account) GetScopes() []string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Namespace | 		return m.Scopes | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *Account) GetProvider() string { | func (m *Account) GetIssuer() string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Provider | 		return m.Issuer | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
| @@ -276,7 +268,6 @@ type Resource struct { | |||||||
| 	Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` | 	Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` | ||||||
| 	Type                 string   `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` | 	Type                 string   `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` | ||||||
| 	Endpoint             string   `protobuf:"bytes,3,opt,name=endpoint,proto3" json:"endpoint,omitempty"` | 	Endpoint             string   `protobuf:"bytes,3,opt,name=endpoint,proto3" json:"endpoint,omitempty"` | ||||||
| 	Namespace            string   `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -328,18 +319,10 @@ func (m *Resource) GetEndpoint() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *Resource) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type GenerateRequest struct { | type GenerateRequest struct { | ||||||
| 	Id                   string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | 	Id                   string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | ||||||
| 	Roles                []string          `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"` |  | ||||||
| 	Metadata             map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` | 	Metadata             map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` | ||||||
| 	Namespace            string            `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"` | 	Scopes               []string          `protobuf:"bytes,4,rep,name=scopes,proto3" json:"scopes,omitempty"` | ||||||
| 	Secret               string            `protobuf:"bytes,5,opt,name=secret,proto3" json:"secret,omitempty"` | 	Secret               string            `protobuf:"bytes,5,opt,name=secret,proto3" json:"secret,omitempty"` | ||||||
| 	Type                 string            `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"` | 	Type                 string            `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"` | ||||||
| 	Provider             string            `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"` | 	Provider             string            `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"` | ||||||
| @@ -380,13 +363,6 @@ func (m *GenerateRequest) GetId() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *GenerateRequest) GetRoles() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Roles |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *GenerateRequest) GetMetadata() map[string]string { | func (m *GenerateRequest) GetMetadata() map[string]string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Metadata | 		return m.Metadata | ||||||
| @@ -394,11 +370,11 @@ func (m *GenerateRequest) GetMetadata() map[string]string { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *GenerateRequest) GetNamespace() string { | func (m *GenerateRequest) GetScopes() []string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Namespace | 		return m.Scopes | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *GenerateRequest) GetSecret() string { | func (m *GenerateRequest) GetSecret() string { | ||||||
| @@ -462,7 +438,7 @@ func (m *GenerateResponse) GetAccount() *Account { | |||||||
| } | } | ||||||
|  |  | ||||||
| type GrantRequest struct { | type GrantRequest struct { | ||||||
| 	Role                 string    `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` | 	Scope                string    `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` | ||||||
| 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` | 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` | ||||||
| 	XXX_unrecognized     []byte    `json:"-"` | 	XXX_unrecognized     []byte    `json:"-"` | ||||||
| @@ -494,9 +470,9 @@ func (m *GrantRequest) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_GrantRequest proto.InternalMessageInfo | var xxx_messageInfo_GrantRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *GrantRequest) GetRole() string { | func (m *GrantRequest) GetScope() string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Role | 		return m.Scope | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
| @@ -540,7 +516,7 @@ func (m *GrantResponse) XXX_DiscardUnknown() { | |||||||
| var xxx_messageInfo_GrantResponse proto.InternalMessageInfo | var xxx_messageInfo_GrantResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
| type RevokeRequest struct { | type RevokeRequest struct { | ||||||
| 	Role                 string    `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` | 	Scope                string    `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"` | ||||||
| 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` | 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` | ||||||
| 	XXX_unrecognized     []byte    `json:"-"` | 	XXX_unrecognized     []byte    `json:"-"` | ||||||
| @@ -572,9 +548,9 @@ func (m *RevokeRequest) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo | var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *RevokeRequest) GetRole() string { | func (m *RevokeRequest) GetScope() string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Role | 		return m.Scope | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
| @@ -799,7 +775,7 @@ func (m *TokenResponse) GetToken() *Token { | |||||||
|  |  | ||||||
| type Rule struct { | type Rule struct { | ||||||
| 	Id                   string    `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | 	Id                   string    `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | ||||||
| 	Role                 string    `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` | 	Scope                string    `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"` | ||||||
| 	Resource             *Resource `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"` | 	Resource             *Resource `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"` | ||||||
| 	Access               Access    `protobuf:"varint,4,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"` | 	Access               Access    `protobuf:"varint,4,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"` | ||||||
| 	Priority             int32     `protobuf:"varint,5,opt,name=priority,proto3" json:"priority,omitempty"` | 	Priority             int32     `protobuf:"varint,5,opt,name=priority,proto3" json:"priority,omitempty"` | ||||||
| @@ -840,9 +816,9 @@ func (m *Rule) GetId() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *Rule) GetRole() string { | func (m *Rule) GetScope() string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Role | 		return m.Scope | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
| @@ -869,13 +845,10 @@ func (m *Rule) GetPriority() int32 { | |||||||
| } | } | ||||||
|  |  | ||||||
| type CreateRequest struct { | type CreateRequest struct { | ||||||
| 	Role                 string    `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` | 	Rule                 *Rule    `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"` | ||||||
| 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	Access               Access    `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	Priority             int32     `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte    `json:"-"` |  | ||||||
| 	XXX_sizecache        int32     `json:"-"` |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *CreateRequest) Reset()         { *m = CreateRequest{} } | func (m *CreateRequest) Reset()         { *m = CreateRequest{} } | ||||||
| @@ -903,34 +876,13 @@ func (m *CreateRequest) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_CreateRequest proto.InternalMessageInfo | var xxx_messageInfo_CreateRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *CreateRequest) GetRole() string { | func (m *CreateRequest) GetRule() *Rule { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Role | 		return m.Rule | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *CreateRequest) GetResource() *Resource { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Resource |  | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *CreateRequest) GetAccess() Access { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Access |  | ||||||
| 	} |  | ||||||
| 	return Access_UNKNOWN |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *CreateRequest) GetPriority() int32 { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Priority |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type CreateResponse struct { | type CreateResponse struct { | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| @@ -963,13 +915,10 @@ func (m *CreateResponse) XXX_DiscardUnknown() { | |||||||
| var xxx_messageInfo_CreateResponse proto.InternalMessageInfo | var xxx_messageInfo_CreateResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
| type DeleteRequest struct { | type DeleteRequest struct { | ||||||
| 	Role                 string    `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` | 	Id                   string   `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | ||||||
| 	Resource             *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	Access               Access    `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	Priority             int32     `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte    `json:"-"` |  | ||||||
| 	XXX_sizecache        int32     `json:"-"` |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *DeleteRequest) Reset()         { *m = DeleteRequest{} } | func (m *DeleteRequest) Reset()         { *m = DeleteRequest{} } | ||||||
| @@ -997,34 +946,13 @@ func (m *DeleteRequest) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo | var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *DeleteRequest) GetRole() string { | func (m *DeleteRequest) GetId() string { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Role | 		return m.Id | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *DeleteRequest) GetResource() *Resource { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Resource |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *DeleteRequest) GetAccess() Access { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Access |  | ||||||
| 	} |  | ||||||
| 	return Access_UNKNOWN |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *DeleteRequest) GetPriority() int32 { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Priority |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type DeleteResponse struct { | type DeleteResponse struct { | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| @@ -1157,64 +1085,62 @@ func init() { | |||||||
| func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) } | func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) } | ||||||
|  |  | ||||||
| var fileDescriptor_21300bfacc51fc2a = []byte{ | var fileDescriptor_21300bfacc51fc2a = []byte{ | ||||||
| 	// 900 bytes of a gzipped FileDescriptorProto | 	// 872 bytes of a gzipped FileDescriptorProto | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x8e, 0xdb, 0x44, | 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x51, 0x8f, 0xdb, 0x44, | ||||||
| 	0x14, 0x5e, 0xff, 0xc4, 0xc9, 0x9e, 0xfc, 0x6c, 0x34, 0xdd, 0x16, 0x2b, 0xed, 0x96, 0xad, 0x8b, | 	0x10, 0x3e, 0x27, 0xb1, 0x93, 0x9b, 0xc4, 0x77, 0xd1, 0xf6, 0x5a, 0xac, 0x94, 0x6b, 0xaf, 0x2e, | ||||||
| 	0xd0, 0x52, 0x41, 0x16, 0xa5, 0x37, 0x40, 0x6f, 0x58, 0x35, 0x51, 0x68, 0xa1, 0x41, 0x58, 0x45, | 	0x82, 0xa3, 0x82, 0x1c, 0x4a, 0x5f, 0x0a, 0x7d, 0xe1, 0xd4, 0x44, 0xa1, 0x85, 0x06, 0x61, 0x15, | ||||||
| 	0xe5, 0x06, 0x55, 0xc6, 0x39, 0xb0, 0xd6, 0x66, 0x6d, 0x33, 0x33, 0x5e, 0x91, 0x1b, 0x24, 0xde, | 	0x21, 0x90, 0x50, 0x65, 0x9c, 0x81, 0xb3, 0x2e, 0x67, 0x9b, 0xdd, 0xf5, 0x89, 0xbc, 0x20, 0xf1, | ||||||
| 	0x81, 0x37, 0x80, 0x2b, 0x9e, 0x89, 0x7b, 0x5e, 0x03, 0xcd, 0x9f, 0x37, 0x76, 0x9c, 0xaa, 0x40, | 	0xc6, 0x8f, 0xe1, 0x27, 0xf1, 0xce, 0x1f, 0xe0, 0x07, 0x20, 0xef, 0xce, 0xba, 0xb1, 0xe3, 0x54, | ||||||
| 	0x2f, 0xb8, 0x9b, 0x33, 0xe7, 0xf8, 0xcc, 0xf7, 0x7d, 0xe7, 0xcc, 0xf1, 0xc0, 0x51, 0x54, 0xf0, | 	0x15, 0x88, 0x37, 0xcf, 0xec, 0xb7, 0xb3, 0xf3, 0x7d, 0x3b, 0x33, 0x6b, 0x38, 0x0e, 0x73, 0x79, | ||||||
| 	0xf3, 0x53, 0x86, 0xf4, 0x2a, 0x89, 0xf1, 0x34, 0xa7, 0x19, 0xcf, 0x4e, 0xc5, 0xd6, 0x58, 0x2e, | 	0x71, 0x26, 0x90, 0x5f, 0xc7, 0x11, 0x9e, 0x65, 0x3c, 0x95, 0xe9, 0x59, 0xe1, 0x1a, 0xab, 0x4f, | ||||||
| 	0x49, 0xff, 0x87, 0x6c, 0x7c, 0x99, 0xc4, 0x34, 0x1b, 0x8b, 0xcd, 0xe0, 0x26, 0xdc, 0xf8, 0x22, | 	0xe6, 0xfe, 0x94, 0x8e, 0xaf, 0xe2, 0x88, 0xa7, 0xe3, 0xc2, 0xe9, 0xdf, 0x84, 0x1b, 0x5f, 0xc4, | ||||||
| 	0x61, 0xfc, 0x2c, 0x8e, 0xb3, 0x22, 0xe5, 0x2c, 0xc4, 0x1f, 0x0b, 0x64, 0x3c, 0x78, 0x0a, 0x87, | 	0x42, 0x9e, 0x47, 0x51, 0x9a, 0x27, 0x52, 0x04, 0xf8, 0x73, 0x8e, 0x42, 0xfa, 0xcf, 0xe0, 0xa8, | ||||||
| 	0xd5, 0x6d, 0x96, 0x67, 0x29, 0x43, 0x32, 0x81, 0x4e, 0xa4, 0xf7, 0x7c, 0xeb, 0xd8, 0x39, 0xe9, | 	0xea, 0x16, 0x59, 0x9a, 0x08, 0x64, 0x13, 0xe8, 0x85, 0xe4, 0xf3, 0xac, 0x93, 0xf6, 0x69, 0x7f, | ||||||
| 	0x4e, 0x6e, 0x8d, 0x2b, 0x09, 0xc7, 0xfa, 0x93, 0xb0, 0x8c, 0x0b, 0x7e, 0xb1, 0xa0, 0xf5, 0x3c, | 	0x72, 0x6b, 0x5c, 0x09, 0x38, 0xa6, 0x2d, 0x41, 0x89, 0xf3, 0x7f, 0xb3, 0xc0, 0x7e, 0x91, 0x5e, | ||||||
| 	0xbb, 0xc0, 0x94, 0xdc, 0x83, 0x5e, 0x14, 0xc7, 0xc8, 0xd8, 0x4b, 0x2e, 0x6c, 0xdf, 0x3a, 0xb6, | 	0x62, 0xc2, 0xee, 0xc1, 0x20, 0x8c, 0x22, 0x14, 0xe2, 0xa5, 0x2c, 0x6c, 0xcf, 0x3a, 0xb1, 0x4e, | ||||||
| 	0x4e, 0xf6, 0xc3, 0xae, 0xda, 0x53, 0x21, 0xf7, 0xa1, 0x4f, 0xf1, 0x7b, 0x8a, 0xec, 0x5c, 0xc7, | 	0xf7, 0x83, 0xbe, 0xf6, 0x69, 0xc8, 0x7d, 0x70, 0x39, 0xfe, 0xc8, 0x51, 0x5c, 0x10, 0xa6, 0xa5, | ||||||
| 	0xd8, 0x32, 0xa6, 0xa7, 0x37, 0x55, 0x90, 0x0f, 0xed, 0x98, 0x62, 0xc4, 0x71, 0xe9, 0x3b, 0xc7, | 	0x30, 0x03, 0x72, 0x6a, 0x90, 0x07, 0xdd, 0x88, 0x63, 0x28, 0x71, 0xe9, 0xb5, 0x4f, 0xac, 0xd3, | ||||||
| 	0xd6, 0x89, 0x13, 0x1a, 0x93, 0xdc, 0x02, 0x0f, 0x7f, 0xca, 0x13, 0xba, 0xf6, 0x5d, 0xe9, 0xd0, | 	0x76, 0x60, 0x4c, 0x76, 0x0b, 0x1c, 0xfc, 0x25, 0x8b, 0xf9, 0xda, 0xeb, 0xa8, 0x05, 0xb2, 0xfc, | ||||||
| 	0x56, 0xf0, 0xab, 0x0d, 0x6d, 0x8d, 0x8c, 0x0c, 0xc0, 0x4e, 0x96, 0xfa, 0x6c, 0x3b, 0x59, 0x12, | 	0xbf, 0x2d, 0xe8, 0x52, 0x66, 0xec, 0x00, 0x5a, 0xf1, 0x92, 0xce, 0x6e, 0xc5, 0x4b, 0xc6, 0xa0, | ||||||
| 	0x02, 0x2e, 0x5f, 0xe7, 0xa8, 0x4f, 0x92, 0x6b, 0x72, 0x08, 0x2d, 0x9a, 0xad, 0x90, 0xf9, 0xce, | 	0x23, 0xd7, 0x19, 0xd2, 0x49, 0xea, 0x9b, 0x7d, 0x0a, 0xbd, 0x2b, 0x94, 0xe1, 0x32, 0x94, 0xa1, | ||||||
| 	0xb1, 0x73, 0xb2, 0x1f, 0x2a, 0x83, 0x7c, 0x0a, 0x9d, 0x4b, 0xe4, 0xd1, 0x32, 0xe2, 0x91, 0xef, | 	0xd7, 0x51, 0x3c, 0xdf, 0x69, 0xe6, 0x39, 0x7e, 0x4e, 0xb0, 0x59, 0x22, 0xf9, 0x3a, 0x28, 0x77, | ||||||
| 	0x4a, 0xf6, 0xef, 0x34, 0xb3, 0x1f, 0x3f, 0xd3, 0x61, 0xb3, 0x94, 0xd3, 0x75, 0x58, 0x7e, 0x45, | 	0x15, 0x99, 0x88, 0x28, 0xcd, 0x50, 0x78, 0xf6, 0x49, 0xfb, 0x74, 0x3f, 0x20, 0xab, 0xf0, 0xc7, | ||||||
| 	0xee, 0xc0, 0x7e, 0x1a, 0x5d, 0x22, 0xcb, 0xa3, 0x18, 0xfd, 0x96, 0x3c, 0xf0, 0x7a, 0x83, 0x8c, | 	0x42, 0xe4, 0xc8, 0x3d, 0x47, 0x9d, 0x47, 0x96, 0xc2, 0x63, 0xc4, 0x51, 0x7a, 0x5d, 0xed, 0xd7, | ||||||
| 	0xa0, 0x93, 0xd3, 0xec, 0x2a, 0x59, 0x22, 0xf5, 0x3d, 0xe9, 0x2c, 0x6d, 0xc1, 0x8c, 0x61, 0x4c, | 	0xd6, 0xe8, 0x31, 0xb8, 0x95, 0x23, 0xd8, 0x10, 0xda, 0x97, 0xb8, 0xa6, 0xfc, 0x8b, 0x4f, 0x76, | ||||||
| 	0x91, 0xfb, 0x6d, 0xe9, 0xd1, 0xd6, 0xe8, 0x11, 0xf4, 0x2b, 0x87, 0x91, 0x21, 0x38, 0x17, 0xb8, | 	0x04, 0xf6, 0x75, 0xb8, 0xca, 0x0d, 0x03, 0x6d, 0x7c, 0xd2, 0x7a, 0x64, 0xf9, 0x0b, 0xe8, 0x05, | ||||||
| 	0xd6, 0xfc, 0xc4, 0x52, 0x90, 0xb9, 0x8a, 0x56, 0x85, 0x61, 0xa8, 0x8c, 0x4f, 0xec, 0x8f, 0xac, | 	0x28, 0xd2, 0x9c, 0x47, 0x58, 0xd0, 0x4c, 0xc2, 0x2b, 0xa4, 0x8d, 0xea, 0xbb, 0x91, 0xfa, 0x08, | ||||||
| 	0x60, 0x05, 0x9d, 0x10, 0x59, 0x56, 0xd0, 0x18, 0x85, 0x0c, 0x02, 0x89, 0xfe, 0x50, 0xae, 0x1b, | 	0x7a, 0x98, 0x2c, 0xb3, 0x34, 0x4e, 0xa4, 0x52, 0x77, 0x3f, 0x28, 0x6d, 0xff, 0xf7, 0x16, 0x1c, | ||||||
| 	0xa5, 0x19, 0x41, 0x07, 0xd3, 0x65, 0x9e, 0x25, 0x29, 0x97, 0xea, 0xef, 0x87, 0xa5, 0x5d, 0xa5, | 	0xce, 0x31, 0x41, 0x1e, 0x4a, 0xa4, 0x52, 0xd9, 0x92, 0xf3, 0xb3, 0x0d, 0xe9, 0xda, 0x4a, 0xba, | ||||||
| 	0xe7, 0xd6, 0xe8, 0x05, 0xbf, 0xdb, 0x70, 0x30, 0xc7, 0x14, 0x69, 0xc4, 0x51, 0x37, 0xda, 0x56, | 	0x0f, 0x6a, 0xd2, 0xd5, 0x22, 0xbc, 0x81, 0x84, 0x9d, 0xba, 0x84, 0x24, 0x95, 0xbd, 0x29, 0x55, | ||||||
| 	0x31, 0x4a, 0xe1, 0xed, 0x4d, 0xe1, 0x3f, 0xdb, 0x10, 0xde, 0x91, 0xc2, 0xbf, 0x5f, 0x13, 0xbe, | 	0xc9, 0xc6, 0xa9, 0xb2, 0xc9, 0x78, 0x7a, 0x1d, 0x2f, 0x91, 0x93, 0xb0, 0xa5, 0xfd, 0xdf, 0xa4, | ||||||
| 	0x96, 0xf7, 0xf5, 0x0a, 0x50, 0x47, 0xb8, 0x21, 0x72, 0x6b, 0x53, 0xe4, 0x52, 0x07, 0xaf, 0xaa, | 	0x9d, 0xc2, 0xf0, 0x15, 0x0f, 0xea, 0x8e, 0x8f, 0xa0, 0x4b, 0x55, 0xaf, 0x62, 0xec, 0x6e, 0x0e, | ||||||
| 	0x43, 0x59, 0xac, 0x76, 0xb5, 0x58, 0xff, 0xad, 0x28, 0x53, 0x18, 0x5e, 0xb3, 0xd1, 0xf7, 0xee, | 	0x03, 0xf3, 0xbf, 0x85, 0xc1, 0x9c, 0x87, 0x89, 0x34, 0x62, 0x1e, 0x81, 0xad, 0x48, 0x52, 0x0e, | ||||||
| 	0x43, 0x68, 0xeb, 0xfb, 0x24, 0x73, 0xec, 0xbe, 0x76, 0x26, 0x2c, 0x78, 0x01, 0xbd, 0x39, 0x8d, | 	0xda, 0x60, 0x0f, 0xa1, 0xc7, 0xe9, 0x1a, 0x55, 0x22, 0xfd, 0xc9, 0x5b, 0xb5, 0xc0, 0xe6, 0x96, | ||||||
| 	0x52, 0x6e, 0x84, 0x26, 0xe0, 0x0a, 0x2d, 0x4d, 0x79, 0xc5, 0x9a, 0x3c, 0x84, 0x0e, 0xd5, 0xe5, | 	0x83, 0x12, 0xe8, 0x1f, 0x82, 0x4b, 0xa1, 0x75, 0x76, 0xfe, 0x77, 0xe0, 0x06, 0x78, 0x9d, 0x5e, | ||||||
| 	0x97, 0x30, 0xba, 0x93, 0xb7, 0x6a, 0x69, 0x4d, 0x77, 0x84, 0x65, 0x60, 0x70, 0x00, 0x7d, 0x9d, | 	0xe2, 0xff, 0x70, 0xd8, 0x10, 0x0e, 0x4c, 0x6c, 0x3a, 0xed, 0x5d, 0x38, 0x78, 0x9a, 0x88, 0x0c, | ||||||
| 	0x58, 0x61, 0x0b, 0xbe, 0x81, 0x7e, 0x88, 0x57, 0xd9, 0x05, 0xbe, 0xf1, 0xa3, 0x86, 0x30, 0x30, | 	0xa3, 0x4d, 0x6e, 0x9b, 0x6d, 0xaf, 0x0d, 0xff, 0x09, 0x1c, 0x96, 0xb8, 0x7f, 0x2d, 0xe3, 0xaf, | ||||||
| 	0x99, 0xf5, 0x59, 0xef, 0xc2, 0xe0, 0x49, 0xca, 0x72, 0x8c, 0x4b, 0x5e, 0x87, 0xd0, 0xda, 0x1c, | 	0x30, 0x50, 0x93, 0x61, 0x57, 0x4d, 0xbe, 0xaa, 0x98, 0x56, 0xa5, 0x62, 0xb6, 0xa6, 0x4d, 0xbb, | ||||||
| 	0x26, 0xca, 0x08, 0x1e, 0xc3, 0x41, 0x19, 0xf7, 0xaf, 0x25, 0xfc, 0x19, 0x7a, 0x72, 0xde, 0xec, | 	0x61, 0xda, 0xdc, 0x83, 0x81, 0x5a, 0x7c, 0x59, 0x99, 0x2c, 0x7d, 0xe5, 0x9b, 0xe9, 0xf1, 0xf2, | ||||||
| 	0xea, 0xd5, 0xeb, 0x6e, 0xb1, 0x2b, 0xdd, 0xb2, 0x35, 0xc3, 0x9c, 0x86, 0x19, 0x76, 0x0f, 0x7a, | 	0x18, 0x5c, 0x3a, 0x9f, 0x28, 0x3c, 0xd8, 0xe4, 0xda, 0x9f, 0x1c, 0xd5, 0x08, 0x68, 0x30, 0x29, | ||||||
| 	0xd2, 0xf9, 0xb2, 0x32, 0xaf, 0xba, 0x72, 0x6f, 0xa6, 0x86, 0xd6, 0x23, 0xe8, 0xeb, 0xf3, 0x35, | 	0xf0, 0x87, 0x05, 0x9d, 0x20, 0x5f, 0xe1, 0x56, 0xd6, 0xe5, 0xfd, 0xb4, 0x76, 0xdd, 0x4f, 0xfb, | ||||||
| 	0x85, 0x07, 0x9b, 0x5c, 0xbb, 0x93, 0xc3, 0x1a, 0x01, 0x15, 0xac, 0x15, 0xf8, 0xc3, 0x02, 0x37, | 	0x0d, 0xef, 0x87, 0x7d, 0x08, 0x8e, 0x9e, 0xb2, 0x2a, 0xfb, 0x83, 0xc9, 0xcd, 0x6d, 0x45, 0x51, | ||||||
| 	0x2c, 0x56, 0xd8, 0x34, 0xee, 0x64, 0x75, 0xec, 0x1d, 0xd5, 0x71, 0x5e, 0xb3, 0x3a, 0xe4, 0x03, | 	0x88, 0x80, 0x40, 0xba, 0x6b, 0xe2, 0x94, 0xc7, 0x72, 0xad, 0x7a, 0xcc, 0x0e, 0x4a, 0xdb, 0x7f, | ||||||
| 	0xf0, 0xd4, 0xe4, 0x96, 0xd8, 0x07, 0x93, 0x9b, 0xdb, 0x7a, 0x22, 0x63, 0xa1, 0x0e, 0x52, 0xf7, | 	0x04, 0xee, 0x13, 0x35, 0x6d, 0x8d, 0xd8, 0xef, 0x41, 0x87, 0xe7, 0x2b, 0x24, 0xaa, 0x37, 0xea, | ||||||
| 	0x25, 0xc9, 0x68, 0xc2, 0xd7, 0xf2, 0x76, 0xb5, 0xc2, 0xd2, 0x0e, 0x7e, 0xb3, 0xa0, 0xff, 0x58, | 	0xc9, 0xe4, 0x2b, 0x0c, 0x14, 0xa0, 0x28, 0x12, 0xb3, 0x93, 0x8a, 0xe4, 0x2e, 0xb8, 0x53, 0x5c, | ||||||
| 	0x8e, 0xf0, 0x37, 0xdd, 0x43, 0x1b, 0x28, 0x9d, 0x7f, 0x8a, 0xd2, 0xad, 0xa1, 0x1c, 0xc2, 0xc0, | 	0xe1, 0xce, 0x61, 0x52, 0x6c, 0x31, 0x00, 0xda, 0xe2, 0x42, 0xbf, 0x78, 0x99, 0xcc, 0x43, 0xf5, | ||||||
| 	0x80, 0xd4, 0xed, 0x28, 0x70, 0x4f, 0x71, 0x85, 0xff, 0x7b, 0xdc, 0x06, 0xa4, 0xc6, 0xdd, 0x87, | 	0x31, 0x0c, 0xb4, 0x49, 0xc2, 0xbf, 0x0f, 0x76, 0x71, 0x96, 0x79, 0x9d, 0x1a, 0xb3, 0xd1, 0x88, | ||||||
| 	0xae, 0xf8, 0xbd, 0x9b, 0xbf, 0xfd, 0xc7, 0xd0, 0x53, 0xa6, 0xee, 0xb3, 0xf7, 0xa0, 0x45, 0x0b, | 	0x07, 0x63, 0x70, 0x34, 0x6d, 0xd6, 0x87, 0xee, 0xd7, 0x8b, 0xcf, 0x17, 0x5f, 0x7e, 0xb3, 0x18, | ||||||
| 	0x31, 0x84, 0xd5, 0x2f, 0xfe, 0x46, 0x1d, 0x6d, 0xb1, 0xc2, 0x50, 0x45, 0x3c, 0x18, 0x83, 0xa7, | 	0xee, 0x15, 0xc6, 0x3c, 0x38, 0x5f, 0xbc, 0x98, 0x4d, 0x87, 0x16, 0x03, 0x70, 0xa6, 0xb3, 0xc5, | ||||||
| 	0x90, 0x90, 0x2e, 0xb4, 0xbf, 0x5e, 0x7c, 0xbe, 0xf8, 0xf2, 0xc5, 0x62, 0xb8, 0x27, 0x8c, 0x79, | 	0xd3, 0xd9, 0x74, 0xd8, 0x9a, 0xfc, 0x65, 0x41, 0xe7, 0x3c, 0x97, 0x17, 0xec, 0x39, 0xf4, 0x4c, | ||||||
| 	0x78, 0xb6, 0x78, 0x3e, 0x9b, 0x0e, 0x2d, 0x02, 0xe0, 0x4d, 0x67, 0x8b, 0x27, 0xb3, 0xe9, 0xd0, | 	0xeb, 0xb3, 0x3b, 0xaf, 0x9f, 0x6d, 0xa3, 0xbb, 0x3b, 0xd7, 0x89, 0xcf, 0x1e, 0x7b, 0x06, 0x5d, | ||||||
| 	0x9e, 0xfc, 0x65, 0x81, 0x7b, 0x56, 0xf0, 0x73, 0xf2, 0x0c, 0x3a, 0x66, 0xca, 0x91, 0xbb, 0xaf, | 	0xea, 0x00, 0x76, 0x5c, 0x43, 0x57, 0x3b, 0x68, 0x74, 0x67, 0xd7, 0x72, 0x19, 0x6b, 0x6a, 0x9e, | ||||||
| 	0x1e, 0xe6, 0xa3, 0xb7, 0x77, 0xfa, 0x35, 0x9f, 0x3d, 0xf2, 0x14, 0xda, 0xfa, 0xc2, 0x93, 0xa3, | 	0xda, 0xdb, 0x8d, 0x15, 0x47, 0x71, 0xde, 0x6e, 0x5e, 0x34, 0x51, 0x26, 0xdf, 0x43, 0xcf, 0xbc, | ||||||
| 	0x5a, 0x74, 0x75, 0x60, 0x8c, 0xee, 0xee, 0x72, 0x97, 0xb9, 0xa6, 0xe6, 0xbd, 0x72, 0xbb, 0xf1, | 	0xfc, 0xec, 0x2b, 0xe8, 0x14, 0x02, 0x33, 0xbf, 0xb6, 0xa7, 0xe1, 0xaf, 0x61, 0x74, 0xff, 0xb5, | ||||||
| 	0x82, 0xe9, 0x3c, 0x77, 0x9a, 0x9d, 0x26, 0xcb, 0xe4, 0x5b, 0xe8, 0x98, 0xe7, 0x13, 0xf9, 0x0a, | 	0x98, 0x32, 0xfc, 0x9f, 0x16, 0xd8, 0xc5, 0x45, 0x08, 0x36, 0x07, 0x47, 0x57, 0x04, 0xab, 0xa7, | ||||||
| 	0x5c, 0x21, 0x30, 0x09, 0x6a, 0xdf, 0x34, 0x3c, 0xbd, 0x46, 0xf7, 0x5f, 0x19, 0x53, 0xa6, 0xff, | 	0x54, 0x29, 0xb1, 0xd1, 0xf1, 0x8e, 0xd5, 0x92, 0xf7, 0x1c, 0x1c, 0x5d, 0x27, 0x5b, 0x81, 0x2a, | ||||||
| 	0xd3, 0x82, 0x96, 0x28, 0x04, 0x23, 0x73, 0xf0, 0x54, 0x5b, 0x92, 0x3a, 0xa4, 0xca, 0x95, 0x1a, | 	0xf5, 0xb5, 0x15, 0xa8, 0x56, 0x5c, 0x7b, 0xec, 0x9c, 0xe8, 0x8e, 0x1a, 0xa8, 0x98, 0x20, 0xb7, | ||||||
| 	0x1d, 0xed, 0xf0, 0x96, 0xbc, 0xe7, 0xe0, 0xa9, 0x3e, 0xd9, 0x4a, 0x54, 0xe9, 0xf1, 0xad, 0x44, | 	0x1b, 0xd7, 0x4c, 0x88, 0x1f, 0x1c, 0xf5, 0xa3, 0xf5, 0xf0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, | ||||||
| 	0xb5, 0xe6, 0xda, 0x23, 0x67, 0x9a, 0xee, 0xa8, 0x81, 0x8a, 0x49, 0x72, 0xbb, 0xd1, 0x67, 0x52, | 	0x52, 0x12, 0xc2, 0xdb, 0x89, 0x09, 0x00, 0x00, | ||||||
| 	0x7c, 0xe7, 0xc9, 0xd7, 0xea, 0xc3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x67, 0x3c, 0x6e, |  | ||||||
| 	0xce, 0x0a, 0x00, 0x00, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Reference imports to suppress errors if they are not otherwise used. | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|   | |||||||
| @@ -35,10 +35,9 @@ message Token { | |||||||
| message Account { | message Account { | ||||||
| 	string id = 1; | 	string id = 1; | ||||||
| 	string type = 2; | 	string type = 2; | ||||||
| 	repeated string roles = 3; |  | ||||||
| 	map<string, string> metadata = 4; | 	map<string, string> metadata = 4; | ||||||
| 	string namespace = 5; | 	repeated string scopes = 5; | ||||||
| 	string provider = 6; | 	string issuer = 6; | ||||||
| 	string secret = 7; | 	string secret = 7; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -46,14 +45,12 @@ message Resource{ | |||||||
| 	string name = 1; | 	string name = 1; | ||||||
| 	string type = 2; | 	string type = 2; | ||||||
| 	string endpoint = 3; | 	string endpoint = 3; | ||||||
| 	string namespace = 4; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message GenerateRequest { | message GenerateRequest { | ||||||
| 	string id = 1; | 	string id = 1; | ||||||
| 	repeated string roles = 2; |  | ||||||
| 	map<string, string> metadata = 3; | 	map<string, string> metadata = 3; | ||||||
| 	string namespace = 4; | 	repeated string scopes = 4; | ||||||
| 	string secret = 5; | 	string secret = 5; | ||||||
| 	string type = 6; | 	string type = 6; | ||||||
| 	string provider = 7; | 	string provider = 7; | ||||||
| @@ -64,14 +61,14 @@ message GenerateResponse { | |||||||
| } | } | ||||||
|  |  | ||||||
| message GrantRequest { | message GrantRequest { | ||||||
| 	string role = 1; | 	string scope = 1; | ||||||
| 	Resource resource = 2; | 	Resource resource = 2; | ||||||
| } | } | ||||||
|  |  | ||||||
| message GrantResponse {} | message GrantResponse {} | ||||||
|  |  | ||||||
| message RevokeRequest { | message RevokeRequest { | ||||||
| 	string role = 1; | 	string scope = 1; | ||||||
| 	Resource resource = 2; | 	Resource resource = 2; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -104,26 +101,20 @@ enum Access { | |||||||
|  |  | ||||||
| message Rule { | message Rule { | ||||||
| 	string id = 1; | 	string id = 1; | ||||||
| 	string role = 2; | 	string scope = 2; | ||||||
| 	Resource resource = 3; | 	Resource resource = 3; | ||||||
| 	Access access = 4; | 	Access access = 4; | ||||||
| 	int32 priority = 5; | 	int32 priority = 5; | ||||||
| } | } | ||||||
|  |  | ||||||
| message CreateRequest { | message CreateRequest { | ||||||
| 	string role = 1; | 	Rule rule = 1; | ||||||
| 	Resource resource = 2; |  | ||||||
| 	Access access = 3; |  | ||||||
| 	int32 priority = 4; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message CreateResponse {} | message CreateResponse {} | ||||||
|  |  | ||||||
| message DeleteRequest { | message DeleteRequest { | ||||||
| 	string role = 1; | 	string id = 1; | ||||||
| 	Resource resource = 2; |  | ||||||
| 	Access access = 3; |  | ||||||
| 	int32 priority = 4; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message DeleteResponse {} | message DeleteResponse {} | ||||||
|   | |||||||
| @@ -2,25 +2,22 @@ package service | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" |  | ||||||
| 	"sort" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/auth" | 	"github.com/micro/go-micro/v2/auth" | ||||||
|  | 	"github.com/micro/go-micro/v2/auth/rules" | ||||||
| 	pb "github.com/micro/go-micro/v2/auth/service/proto" | 	pb "github.com/micro/go-micro/v2/auth/service/proto" | ||||||
| 	"github.com/micro/go-micro/v2/auth/token" | 	"github.com/micro/go-micro/v2/auth/token" | ||||||
| 	"github.com/micro/go-micro/v2/auth/token/jwt" | 	"github.com/micro/go-micro/v2/auth/token/jwt" | ||||||
| 	"github.com/micro/go-micro/v2/client" | 	"github.com/micro/go-micro/v2/client" | ||||||
| 	log "github.com/micro/go-micro/v2/logger" |  | ||||||
| 	"github.com/micro/go-micro/v2/util/jitter" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // svc is the service implementation of the Auth interface | // svc is the service implementation of the Auth interface | ||||||
| type svc struct { | type svc struct { | ||||||
| 	options auth.Options | 	options auth.Options | ||||||
| 	auth    pb.AuthService | 	auth    pb.AuthService | ||||||
| 	rule    pb.RulesService | 	rules   pb.RulesService | ||||||
| 	jwt     token.Provider | 	jwt     token.Provider | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -38,7 +35,7 @@ func (s *svc) Init(opts ...auth.Option) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	s.auth = pb.NewAuthService("go.micro.auth", s.options.Client) | 	s.auth = pb.NewAuthService("go.micro.auth", s.options.Client) | ||||||
| 	s.rule = pb.NewRulesService("go.micro.auth", s.options.Client) | 	s.rules = pb.NewRulesService("go.micro.auth", s.options.Client) | ||||||
|  |  | ||||||
| 	// if we have a JWT public key passed as an option, | 	// if we have a JWT public key passed as an option, | ||||||
| 	// we can decode tokens with the type "JWT" locally | 	// we can decode tokens with the type "JWT" locally | ||||||
| @@ -57,13 +54,12 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e | |||||||
| 	options := auth.NewGenerateOptions(opts...) | 	options := auth.NewGenerateOptions(opts...) | ||||||
|  |  | ||||||
| 	rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{ | 	rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{ | ||||||
| 		Id:        id, | 		Id:       id, | ||||||
| 		Type:      options.Type, | 		Type:     options.Type, | ||||||
| 		Secret:    options.Secret, | 		Secret:   options.Secret, | ||||||
| 		Roles:     options.Roles, | 		Scopes:   options.Scopes, | ||||||
| 		Metadata:  options.Metadata, | 		Metadata: options.Metadata, | ||||||
| 		Provider:  options.Provider, | 		Provider: options.Provider, | ||||||
| 		Namespace: options.Namespace, |  | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -73,87 +69,75 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e | |||||||
| } | } | ||||||
|  |  | ||||||
| // Grant access to a resource | // Grant access to a resource | ||||||
| func (s *svc) Grant(role string, res *auth.Resource) error { | func (s *svc) Grant(rule *auth.Rule) error { | ||||||
| 	_, err := s.rule.Create(context.TODO(), &pb.CreateRequest{ | 	access := pb.Access_UNKNOWN | ||||||
| 		Role:   role, | 	if rule.Access == auth.AccessGranted { | ||||||
| 		Access: pb.Access_GRANTED, | 		access = pb.Access_GRANTED | ||||||
| 		Resource: &pb.Resource{ | 	} else if rule.Access == auth.AccessDenied { | ||||||
| 			Namespace: res.Namespace, | 		access = pb.Access_DENIED | ||||||
| 			Type:      res.Type, | 	} | ||||||
| 			Name:      res.Name, |  | ||||||
| 			Endpoint:  res.Endpoint, | 	_, err := s.rules.Create(context.TODO(), &pb.CreateRequest{ | ||||||
|  | 		Rule: &pb.Rule{ | ||||||
|  | 			Id:       rule.ID, | ||||||
|  | 			Scope:    rule.Scope, | ||||||
|  | 			Priority: rule.Priority, | ||||||
|  | 			Access:   access, | ||||||
|  | 			Resource: &pb.Resource{ | ||||||
|  | 				Type:     rule.Resource.Type, | ||||||
|  | 				Name:     rule.Resource.Name, | ||||||
|  | 				Endpoint: rule.Resource.Endpoint, | ||||||
|  | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| // Revoke access to a resource | // Revoke access to a resource | ||||||
| func (s *svc) Revoke(role string, res *auth.Resource) error { | func (s *svc) Revoke(rule *auth.Rule) error { | ||||||
| 	_, err := s.rule.Delete(context.TODO(), &pb.DeleteRequest{ | 	_, err := s.rules.Delete(context.TODO(), &pb.DeleteRequest{ | ||||||
| 		Role:   role, | 		Id: rule.ID, | ||||||
| 		Access: pb.Access_GRANTED, |  | ||||||
| 		Resource: &pb.Resource{ |  | ||||||
| 			Namespace: res.Namespace, |  | ||||||
| 			Type:      res.Type, |  | ||||||
| 			Name:      res.Name, |  | ||||||
| 			Endpoint:  res.Endpoint, |  | ||||||
| 		}, |  | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (s *svc) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) { | ||||||
|  | 	var options auth.RulesOptions | ||||||
|  | 	for _, o := range opts { | ||||||
|  | 		o(&options) | ||||||
|  | 	} | ||||||
|  | 	if options.Context == nil { | ||||||
|  | 		options.Context = context.TODO() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rsp, err := s.rules.List(options.Context, &pb.ListRequest{}, client.WithCache(time.Second*30)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rules := make([]*auth.Rule, len(rsp.Rules)) | ||||||
|  | 	for i, r := range rsp.Rules { | ||||||
|  | 		rules[i] = serializeRule(r) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return rules, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // Verify an account has access to a resource | // Verify an account has access to a resource | ||||||
| func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error { | func (s *svc) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error { | ||||||
| 	// set the namespace on the resource | 	var options auth.VerifyOptions | ||||||
| 	if len(res.Namespace) == 0 { | 	for _, o := range opts { | ||||||
| 		res.Namespace = s.Options().Namespace | 		o(&options) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	queries := [][]string{ | 	rs, err := s.Rules(auth.RulesContext(options.Context)) | ||||||
| 		{res.Namespace, res.Type, res.Name, res.Endpoint}, // check for specific role, e.g. service.foo.ListFoo:admin (role is checked in accessForRule) | 	if err != nil { | ||||||
| 		{res.Namespace, res.Type, res.Name, "*"},          // check for wildcard endpoint, e.g. service.foo* | 		return err | ||||||
| 		{res.Namespace, res.Type, "*"},                    // check for wildcard name, e.g. service.* |  | ||||||
| 		{res.Namespace, "*"},                              // check for wildcard type, e.g. * |  | ||||||
| 		{"*"},                                             // check for wildcard namespace |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// endpoint is a url which can have wildcard excludes, e.g. | 	return rules.Verify(rs, acc, res) | ||||||
| 	// "/foo/*" will allow "/foo/bar" |  | ||||||
| 	if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 { |  | ||||||
| 		for i := 1; i < len(comps); i++ { |  | ||||||
| 			wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/")) |  | ||||||
| 			queries = append(queries, []string{res.Type, res.Name, wildcard}) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// set a default account id / namespace to log |  | ||||||
| 	logID := acc.ID |  | ||||||
| 	if len(logID) == 0 { |  | ||||||
| 		logID = "[no account]" |  | ||||||
| 	} |  | ||||||
| 	logNamespace := acc.Namespace |  | ||||||
| 	if len(logNamespace) == 0 { |  | ||||||
| 		logNamespace = "[no namespace]" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, q := range queries { |  | ||||||
| 		for _, rule := range s.listRules(q...) { |  | ||||||
| 			switch accessForRule(rule, acc, res) { |  | ||||||
| 			case pb.Access_UNKNOWN: |  | ||||||
| 				continue // rule did not specify access, check the next rule |  | ||||||
| 			case pb.Access_GRANTED: |  | ||||||
| 				log.Tracef("%v:%v granted access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id) |  | ||||||
| 				return nil // rule grants the account access to the resource |  | ||||||
| 			case pb.Access_DENIED: |  | ||||||
| 				log.Tracef("%v:%v denied access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id) |  | ||||||
| 				return auth.ErrForbidden // rule denies access to the resource |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// no rules were found for the resource, default to denying access |  | ||||||
| 	log.Tracef("%v:%v denied access to %v:%v:%v:%v by lack of rule (%v rules found for namespace)", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, len(s.listRules(res.Namespace))) |  | ||||||
| 	return auth.ErrForbidden |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Inspect a token | // Inspect a token | ||||||
| @@ -189,82 +173,6 @@ func (s *svc) Token(opts ...auth.TokenOption) (*auth.Token, error) { | |||||||
| 	return serializeToken(rsp.Token), nil | 	return serializeToken(rsp.Token), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| var ruleJoinKey = ":" |  | ||||||
|  |  | ||||||
| // accessForRule returns a rule status, indicating if a rule permits access to a |  | ||||||
| // resource for a given account |  | ||||||
| func accessForRule(rule *pb.Rule, acc *auth.Account, res *auth.Resource) pb.Access { |  | ||||||
| 	// a blank role permits access to the public |  | ||||||
| 	if rule.Role == "" { |  | ||||||
| 		return rule.Access |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// a * role permits access to any user |  | ||||||
| 	if rule.Role == "*" && acc != nil { |  | ||||||
| 		return rule.Access |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, role := range acc.Roles { |  | ||||||
| 		if rule.Role == role { |  | ||||||
| 			return rule.Access |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// allow user.anything if role is user.* |  | ||||||
| 		if strings.HasSuffix(rule.Role, ".*") && strings.HasPrefix(rule.Role, role+".") { |  | ||||||
| 			return rule.Access |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return pb.Access_UNKNOWN |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // listRules gets all the rules from the store which match the filters. |  | ||||||
| // filters are namespace, type, name and then endpoint. |  | ||||||
| func (s *svc) listRules(filters ...string) []*pb.Rule { |  | ||||||
| 	// load rules using the client cache |  | ||||||
| 	allRules, err := s.loadRules() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return []*pb.Rule{} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var rules []*pb.Rule |  | ||||||
| 	for _, r := range allRules { |  | ||||||
| 		if len(filters) > 0 && r.Resource.Namespace != filters[0] { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if len(filters) > 1 && r.Resource.Type != filters[1] { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if len(filters) > 2 && r.Resource.Name != filters[2] { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if len(filters) > 3 && r.Resource.Endpoint != filters[3] { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		rules = append(rules, r) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// sort rules by priority |  | ||||||
| 	sort.Slice(rules, func(i, j int) bool { |  | ||||||
| 		return rules[i].Priority < rules[j].Priority |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	return rules |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // loadRules retrieves the rules from the auth service |  | ||||||
| func (s *svc) loadRules() ([]*pb.Rule, error) { |  | ||||||
| 	rsp, err := s.rule.List(context.TODO(), &pb.ListRequest{}, client.WithCache(time.Minute)) |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Debugf("Error listing rules: %v", err) |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return rsp.Rules, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func serializeToken(t *pb.Token) *auth.Token { | func serializeToken(t *pb.Token) *auth.Token { | ||||||
| 	return &auth.Token{ | 	return &auth.Token{ | ||||||
| 		AccessToken:  t.AccessToken, | 		AccessToken:  t.AccessToken, | ||||||
| @@ -276,12 +184,32 @@ func serializeToken(t *pb.Token) *auth.Token { | |||||||
|  |  | ||||||
| func serializeAccount(a *pb.Account) *auth.Account { | func serializeAccount(a *pb.Account) *auth.Account { | ||||||
| 	return &auth.Account{ | 	return &auth.Account{ | ||||||
| 		ID:        a.Id, | 		ID:       a.Id, | ||||||
| 		Roles:     a.Roles, | 		Secret:   a.Secret, | ||||||
| 		Secret:    a.Secret, | 		Issuer:   a.Issuer, | ||||||
| 		Metadata:  a.Metadata, | 		Metadata: a.Metadata, | ||||||
| 		Provider:  a.Provider, | 		Scopes:   a.Scopes, | ||||||
| 		Namespace: a.Namespace, | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func serializeRule(r *pb.Rule) *auth.Rule { | ||||||
|  | 	var access auth.Access | ||||||
|  | 	if r.Access == pb.Access_GRANTED { | ||||||
|  | 		access = auth.AccessGranted | ||||||
|  | 	} else { | ||||||
|  | 		access = auth.AccessDenied | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &auth.Rule{ | ||||||
|  | 		ID:       r.Id, | ||||||
|  | 		Scope:    r.Scope, | ||||||
|  | 		Access:   access, | ||||||
|  | 		Priority: r.Priority, | ||||||
|  | 		Resource: &auth.Resource{ | ||||||
|  | 			Type:     r.Resource.Type, | ||||||
|  | 			Name:     r.Resource.Name, | ||||||
|  | 			Endpoint: r.Resource.Endpoint, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -292,22 +220,9 @@ func NewAuth(opts ...auth.Option) auth.Auth { | |||||||
| 		options.Client = client.DefaultClient | 		options.Client = client.DefaultClient | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	service := &svc{ | 	return &svc{ | ||||||
| 		auth:    pb.NewAuthService("go.micro.auth", options.Client), | 		auth:    pb.NewAuthService("go.micro.auth", options.Client), | ||||||
| 		rule:    pb.NewRulesService("go.micro.auth", options.Client), | 		rules:   pb.NewRulesService("go.micro.auth", options.Client), | ||||||
| 		options: options, | 		options: options, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// load rules periodically from the auth service |  | ||||||
| 	go func() { |  | ||||||
| 		ruleTimer := time.NewTicker(time.Second * 30) |  | ||||||
|  |  | ||||||
| 		for { |  | ||||||
| 			<-ruleTimer.C |  | ||||||
| 			time.Sleep(jitter.Do(time.Second * 5)) |  | ||||||
| 			service.loadRules() |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	return service |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -32,10 +32,10 @@ func TestInspect(t *testing.T) { | |||||||
|  |  | ||||||
| 	t.Run("Valid token", func(t *testing.T) { | 	t.Run("Valid token", func(t *testing.T) { | ||||||
| 		md := map[string]string{"foo": "bar"} | 		md := map[string]string{"foo": "bar"} | ||||||
| 		roles := []string{"admin"} | 		scopes := []string{"admin"} | ||||||
| 		subject := "test" | 		subject := "test" | ||||||
|  |  | ||||||
| 		tok, err := b.Generate(&auth.Account{ID: subject, Roles: roles, Metadata: md}) | 		tok, err := b.Generate(&auth.Account{ID: subject, Scopes: scopes, Metadata: md}) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatalf("Generate returned %v error, expected nil", err) | 			t.Fatalf("Generate returned %v error, expected nil", err) | ||||||
| 		} | 		} | ||||||
| @@ -47,8 +47,8 @@ func TestInspect(t *testing.T) { | |||||||
| 		if tok2.ID != subject { | 		if tok2.ID != subject { | ||||||
| 			t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject) | 			t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject) | ||||||
| 		} | 		} | ||||||
| 		if len(tok2.Roles) != len(roles) { | 		if len(tok2.Scopes) != len(scopes) { | ||||||
| 			t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles)) | 			t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes)) | ||||||
| 		} | 		} | ||||||
| 		if len(tok2.Metadata) != len(md) { | 		if len(tok2.Metadata) != len(md) { | ||||||
| 			t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md) | 			t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md) | ||||||
|   | |||||||
| @@ -11,11 +11,9 @@ import ( | |||||||
|  |  | ||||||
| // authClaims to be encoded in the JWT | // authClaims to be encoded in the JWT | ||||||
| type authClaims struct { | type authClaims struct { | ||||||
| 	Type      string            `json:"type"` | 	Type     string            `json:"type"` | ||||||
| 	Roles     []string          `json:"roles"` | 	Scopes   []string          `json:"scopes"` | ||||||
| 	Provider  string            `json:"provider"` | 	Metadata map[string]string `json:"metadata"` | ||||||
| 	Metadata  map[string]string `json:"metadata"` |  | ||||||
| 	Namespace string            `json:"namespace"` |  | ||||||
|  |  | ||||||
| 	jwt.StandardClaims | 	jwt.StandardClaims | ||||||
| } | } | ||||||
| @@ -52,8 +50,9 @@ func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token. | |||||||
| 	// generate the JWT | 	// generate the JWT | ||||||
| 	expiry := time.Now().Add(options.Expiry) | 	expiry := time.Now().Add(options.Expiry) | ||||||
| 	t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{ | 	t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{ | ||||||
| 		acc.Type, acc.Roles, acc.Provider, acc.Metadata, acc.Namespace, jwt.StandardClaims{ | 		acc.Type, acc.Scopes, acc.Metadata, jwt.StandardClaims{ | ||||||
| 			Subject:   acc.ID, | 			Subject:   acc.ID, | ||||||
|  | 			Issuer:    acc.Issuer, | ||||||
| 			ExpiresAt: expiry.Unix(), | 			ExpiresAt: expiry.Unix(), | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
| @@ -97,12 +96,11 @@ func (j *JWT) Inspect(t string) (*auth.Account, error) { | |||||||
|  |  | ||||||
| 	// return the token | 	// return the token | ||||||
| 	return &auth.Account{ | 	return &auth.Account{ | ||||||
| 		ID:        claims.Subject, | 		ID:       claims.Subject, | ||||||
| 		Type:      claims.Type, | 		Issuer:   claims.Issuer, | ||||||
| 		Roles:     claims.Roles, | 		Type:     claims.Type, | ||||||
| 		Provider:  claims.Provider, | 		Scopes:   claims.Scopes, | ||||||
| 		Metadata:  claims.Metadata, | 		Metadata: claims.Metadata, | ||||||
| 		Namespace: claims.Namespace, |  | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,10 +42,10 @@ func TestInspect(t *testing.T) { | |||||||
|  |  | ||||||
| 	t.Run("Valid token", func(t *testing.T) { | 	t.Run("Valid token", func(t *testing.T) { | ||||||
| 		md := map[string]string{"foo": "bar"} | 		md := map[string]string{"foo": "bar"} | ||||||
| 		roles := []string{"admin"} | 		scopes := []string{"admin"} | ||||||
| 		subject := "test" | 		subject := "test" | ||||||
|  |  | ||||||
| 		acc := &auth.Account{ID: subject, Roles: roles, Metadata: md} | 		acc := &auth.Account{ID: subject, Scopes: scopes, Metadata: md} | ||||||
| 		tok, err := j.Generate(acc) | 		tok, err := j.Generate(acc) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatalf("Generate returned %v error, expected nil", err) | 			t.Fatalf("Generate returned %v error, expected nil", err) | ||||||
| @@ -58,8 +58,8 @@ func TestInspect(t *testing.T) { | |||||||
| 		if acc.ID != subject { | 		if acc.ID != subject { | ||||||
| 			t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject) | 			t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject) | ||||||
| 		} | 		} | ||||||
| 		if len(tok2.Roles) != len(roles) { | 		if len(tok2.Scopes) != len(scopes) { | ||||||
| 			t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles)) | 			t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes)) | ||||||
| 		} | 		} | ||||||
| 		if len(tok2.Metadata) != len(md) { | 		if len(tok2.Metadata) != len(md) { | ||||||
| 			t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md) | 			t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md) | ||||||
|   | |||||||
| @@ -48,10 +48,10 @@ func (c *Cache) List() map[string]string { | |||||||
|  |  | ||||||
| // key returns a hash for the context and request | // key returns a hash for the context and request | ||||||
| func key(ctx context.Context, req *Request) string { | func key(ctx context.Context, req *Request) string { | ||||||
| 	md, _ := metadata.FromContext(ctx) | 	ns, _ := metadata.Get(ctx, "Micro-Namespace") | ||||||
|  |  | ||||||
| 	bytes, _ := json.Marshal(map[string]interface{}{ | 	bytes, _ := json.Marshal(map[string]interface{}{ | ||||||
| 		"metadata": md, | 		"namespace": ns, | ||||||
| 		"request": map[string]interface{}{ | 		"request": map[string]interface{}{ | ||||||
| 			"service":  (*req).Service(), | 			"service":  (*req).Service(), | ||||||
| 			"endpoint": (*req).Endpoint(), | 			"endpoint": (*req).Endpoint(), | ||||||
|   | |||||||
| @@ -65,7 +65,7 @@ func TestCacheKey(t *testing.T) { | |||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	t.Run("DifferentMetadata", func(t *testing.T) { | 	t.Run("DifferentMetadata", func(t *testing.T) { | ||||||
| 		mdCtx := metadata.Set(context.TODO(), "foo", "bar") | 		mdCtx := metadata.Set(context.TODO(), "Micro-Namespace", "bar") | ||||||
| 		key1 := key(mdCtx, &req1) | 		key1 := key(mdCtx, &req1) | ||||||
| 		key2 := key(ctx, &req1) | 		key2 := key(ctx, &req1) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -278,6 +278,7 @@ var ( | |||||||
| 			Name:    "auth_namespace", | 			Name:    "auth_namespace", | ||||||
| 			EnvVars: []string{"MICRO_AUTH_NAMESPACE"}, | 			EnvVars: []string{"MICRO_AUTH_NAMESPACE"}, | ||||||
| 			Usage:   "Namespace for the services auth account", | 			Usage:   "Namespace for the services auth account", | ||||||
|  | 			Value:   "go.micro", | ||||||
| 		}, | 		}, | ||||||
| 		&cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:    "auth_public_key", | 			Name:    "auth_public_key", | ||||||
|   | |||||||
| @@ -166,9 +166,7 @@ type CreateOptions struct { | |||||||
| 	// create type of service | 	// create type of service | ||||||
| 	Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` | 	Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` | ||||||
| 	// image to use | 	// image to use | ||||||
| 	Image string `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"` | 	Image                string   `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"` | ||||||
| 	// namespace to use |  | ||||||
| 	Namespace            string   `protobuf:"bytes,7,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -241,13 +239,6 @@ func (m *CreateOptions) GetImage() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *CreateOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type CreateRequest struct { | type CreateRequest struct { | ||||||
| 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | ||||||
| 	Options              *CreateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | 	Options              *CreateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | ||||||
| @@ -332,9 +323,7 @@ type ReadOptions struct { | |||||||
| 	// version of the service | 	// version of the service | ||||||
| 	Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` | 	Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` | ||||||
| 	// type of service | 	// type of service | ||||||
| 	Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` | 	Type                 string   `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` | ||||||
| 	// namespace of service |  | ||||||
| 	Namespace            string   `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -386,13 +375,6 @@ func (m *ReadOptions) GetType() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *ReadOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ReadRequest struct { | type ReadRequest struct { | ||||||
| 	Options              *ReadOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` | 	Options              *ReadOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}     `json:"-"` | 	XXX_NoUnkeyedLiteral struct{}     `json:"-"` | ||||||
| @@ -472,8 +454,6 @@ func (m *ReadResponse) GetServices() []*Service { | |||||||
| } | } | ||||||
|  |  | ||||||
| type DeleteOptions struct { | type DeleteOptions struct { | ||||||
| 	// namespace of the service |  | ||||||
| 	Namespace            string   `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -504,13 +484,6 @@ func (m *DeleteOptions) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo | var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *DeleteOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type DeleteRequest struct { | type DeleteRequest struct { | ||||||
| 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | ||||||
| 	Options              *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | 	Options              *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | ||||||
| @@ -590,8 +563,6 @@ func (m *DeleteResponse) XXX_DiscardUnknown() { | |||||||
| var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo | var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
| type UpdateOptions struct { | type UpdateOptions struct { | ||||||
| 	// namespace of the service |  | ||||||
| 	Namespace            string   `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -622,13 +593,6 @@ func (m *UpdateOptions) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_UpdateOptions proto.InternalMessageInfo | var xxx_messageInfo_UpdateOptions proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *UpdateOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type UpdateRequest struct { | type UpdateRequest struct { | ||||||
| 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | 	Service              *Service       `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | ||||||
| 	Options              *UpdateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | 	Options              *UpdateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` | ||||||
| @@ -708,8 +672,6 @@ func (m *UpdateResponse) XXX_DiscardUnknown() { | |||||||
| var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo | var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
| type ListOptions struct { | type ListOptions struct { | ||||||
| 	// namespace to list from |  | ||||||
| 	Namespace            string   `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -740,13 +702,6 @@ func (m *ListOptions) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_ListOptions proto.InternalMessageInfo | var xxx_messageInfo_ListOptions proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *ListOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ListRequest struct { | type ListRequest struct { | ||||||
| 	Options              *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` | 	Options              *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` | ||||||
| 	XXX_NoUnkeyedLiteral struct{}     `json:"-"` | 	XXX_NoUnkeyedLiteral struct{}     `json:"-"` | ||||||
| @@ -826,8 +781,6 @@ func (m *ListResponse) GetServices() []*Service { | |||||||
| } | } | ||||||
|  |  | ||||||
| type LogsOptions struct { | type LogsOptions struct { | ||||||
| 	// namespace of the service |  | ||||||
| 	Namespace            string   `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
| 	XXX_sizecache        int32    `json:"-"` | 	XXX_sizecache        int32    `json:"-"` | ||||||
| @@ -858,13 +811,6 @@ func (m *LogsOptions) XXX_DiscardUnknown() { | |||||||
|  |  | ||||||
| var xxx_messageInfo_LogsOptions proto.InternalMessageInfo | var xxx_messageInfo_LogsOptions proto.InternalMessageInfo | ||||||
|  |  | ||||||
| func (m *LogsOptions) GetNamespace() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Namespace |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type LogsRequest struct { | type LogsRequest struct { | ||||||
| 	// service to request logs for | 	// service to request logs for | ||||||
| 	Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | 	Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` | ||||||
| @@ -1031,52 +977,50 @@ func init() { | |||||||
| } | } | ||||||
|  |  | ||||||
| var fileDescriptor_2434d8152598889b = []byte{ | var fileDescriptor_2434d8152598889b = []byte{ | ||||||
| 	// 711 bytes of a gzipped FileDescriptorProto | 	// 683 bytes of a gzipped FileDescriptorProto | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4d, 0x6f, 0xd3, 0x4c, | 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6e, 0xd3, 0x40, | ||||||
| 	0x10, 0xae, 0x63, 0x27, 0x69, 0x27, 0x6f, 0x5e, 0x55, 0xab, 0x0a, 0x99, 0xf2, 0x15, 0x99, 0x03, | 	0x14, 0xad, 0xe3, 0x3c, 0xda, 0x1b, 0x42, 0xab, 0x51, 0x85, 0x4c, 0x79, 0x45, 0x66, 0x41, 0xd9, | ||||||
| 	0x45, 0xa8, 0x2e, 0x4a, 0x85, 0xf8, 0x3a, 0x96, 0x94, 0x4b, 0x2b, 0x24, 0x23, 0x7e, 0xc0, 0xe2, | 	0x38, 0x28, 0x15, 0xe2, 0xb5, 0x2c, 0x09, 0x9b, 0x46, 0x48, 0x46, 0xfd, 0x80, 0xc1, 0xb9, 0x8a, | ||||||
| 	0x8c, 0x22, 0x8b, 0xda, 0x6b, 0xbc, 0xeb, 0x48, 0x3d, 0x71, 0xe4, 0x8f, 0x70, 0xe7, 0x67, 0x70, | 	0x2c, 0x6a, 0x8f, 0xf1, 0x8c, 0x23, 0x65, 0xc5, 0x92, 0x35, 0xff, 0xc0, 0xbf, 0xb0, 0xe6, 0x8f, | ||||||
| 	0xe6, 0x1f, 0xa1, 0xfd, 0x8a, 0x3f, 0x1a, 0x47, 0xad, 0xaa, 0xde, 0x76, 0xc6, 0xb3, 0xb3, 0xcf, | 	0xd0, 0xbc, 0xfc, 0x48, 0xeb, 0x48, 0xa8, 0xea, 0x6e, 0xce, 0xf5, 0xcc, 0x9d, 0x73, 0xce, 0x9d, | ||||||
| 	0xf3, 0xcc, 0xec, 0xac, 0xe1, 0x69, 0x51, 0x66, 0x22, 0x49, 0xf1, 0x88, 0x63, 0xb1, 0x4c, 0x62, | 	0x7b, 0x65, 0x78, 0x9e, 0x17, 0xa9, 0x88, 0x13, 0x9c, 0x70, 0xcc, 0xd7, 0x71, 0x84, 0x93, 0x2c, | ||||||
| 	0x3c, 0xca, 0x0b, 0x26, 0xd8, 0x91, 0xf1, 0x86, 0xca, 0x22, 0xbb, 0x0b, 0x16, 0xa6, 0x49, 0x5c, | 	0x67, 0x82, 0x4d, 0x4c, 0x34, 0x50, 0x88, 0x1c, 0xad, 0x58, 0x90, 0xc4, 0x51, 0xce, 0x02, 0x13, | ||||||
| 	0xb0, 0xd0, 0xf8, 0x83, 0xbf, 0x0e, 0x0c, 0x3f, 0xeb, 0x1d, 0x84, 0x80, 0x97, 0xd1, 0x14, 0x7d, | 	0xf7, 0xff, 0x3a, 0x30, 0xf8, 0xa2, 0x4f, 0x10, 0x02, 0xdd, 0x94, 0x26, 0xe8, 0x39, 0x63, 0xe7, | ||||||
| 	0x67, 0xe2, 0x1c, 0xec, 0x44, 0x6a, 0x4d, 0x7c, 0x18, 0x2e, 0xb1, 0xe0, 0x09, 0xcb, 0xfc, 0x9e, | 	0xf4, 0x20, 0x54, 0x6b, 0xe2, 0xc1, 0x60, 0x8d, 0x39, 0x8f, 0x59, 0xea, 0x75, 0x54, 0xd8, 0x42, | ||||||
| 	0x72, 0x5b, 0x93, 0xdc, 0x83, 0x01, 0x67, 0x65, 0x11, 0xa3, 0xef, 0xaa, 0x0f, 0xc6, 0x22, 0x27, | 	0xf2, 0x00, 0xfa, 0x9c, 0x15, 0x79, 0x84, 0x9e, 0xab, 0x3e, 0x18, 0x44, 0xce, 0x61, 0x3f, 0x41, | ||||||
| 	0xb0, 0x9d, 0xa2, 0xa0, 0x73, 0x2a, 0xa8, 0xef, 0x4d, 0xdc, 0x83, 0xd1, 0xf4, 0x59, 0xd8, 0x3e, | 	0x41, 0x97, 0x54, 0x50, 0xaf, 0x3b, 0x76, 0x4f, 0x87, 0xd3, 0x17, 0xc1, 0xf6, 0xb5, 0x81, 0xb9, | ||||||
| 	0x36, 0x34, 0x47, 0x86, 0xe7, 0x26, 0x72, 0x96, 0x89, 0xe2, 0x32, 0x5a, 0x6d, 0xdc, 0x7f, 0x0f, | 	0x32, 0x58, 0x98, 0x9d, 0xb3, 0x54, 0xe4, 0x9b, 0xb0, 0x3c, 0x78, 0xf2, 0x01, 0x46, 0x8d, 0x4f, | ||||||
| 	0xe3, 0xc6, 0x27, 0xb2, 0x0b, 0xee, 0x37, 0xbc, 0x34, 0xd0, 0xe4, 0x92, 0xec, 0x41, 0x7f, 0x49, | 	0xe4, 0x08, 0xdc, 0x6f, 0xb8, 0x31, 0xd4, 0xe4, 0x92, 0x1c, 0x43, 0x6f, 0x4d, 0xaf, 0x0a, 0x34, | ||||||
| 	0x2f, 0x4a, 0x34, 0xb8, 0xb4, 0xf1, 0xae, 0xf7, 0xc6, 0x09, 0x52, 0xe8, 0xcf, 0x96, 0x98, 0x09, | 	0xbc, 0x34, 0x78, 0xdf, 0x79, 0xeb, 0xf8, 0x09, 0xf4, 0x66, 0x6b, 0x4c, 0x85, 0x14, 0x24, 0x36, | ||||||
| 	0x49, 0x48, 0x5c, 0xe6, 0x2b, 0x42, 0x72, 0x4d, 0x1e, 0xc2, 0x8e, 0x44, 0xc0, 0x05, 0x4d, 0x73, | 	0x59, 0x29, 0x48, 0xae, 0xc9, 0x63, 0x38, 0x90, 0x0c, 0xb8, 0xa0, 0x49, 0xa6, 0x8e, 0xba, 0x61, | ||||||
| 	0xb5, 0xd5, 0x8d, 0x2a, 0x87, 0xa4, 0x6b, 0xf4, 0x33, 0xac, 0xac, 0x59, 0x17, 0xc2, 0x6b, 0x08, | 	0x15, 0x90, 0x72, 0x8d, 0x7f, 0x46, 0x95, 0x85, 0x75, 0x23, 0xba, 0x0d, 0x23, 0xfc, 0x5f, 0x0e, | ||||||
| 	0x11, 0xfc, 0x76, 0x60, 0x7c, 0x52, 0x20, 0x15, 0xf8, 0x29, 0x17, 0x09, 0xcb, 0xb8, 0x8c, 0x8d, | 	0x8c, 0xce, 0x73, 0xa4, 0x02, 0x3f, 0x67, 0x22, 0x66, 0x29, 0x97, 0x7b, 0x23, 0x96, 0x24, 0x34, | ||||||
| 	0x59, 0x9a, 0xd2, 0x6c, 0xee, 0x3b, 0x13, 0x57, 0xc6, 0x1a, 0x53, 0x22, 0xa2, 0xc5, 0x82, 0xfb, | 	0x5d, 0x7a, 0xce, 0xd8, 0x95, 0x7b, 0x0d, 0x94, 0x8c, 0x68, 0xbe, 0xe2, 0x5e, 0x47, 0x85, 0xd5, | ||||||
| 	0x3d, 0xe5, 0x56, 0x6b, 0x49, 0x0d, 0xb3, 0xa5, 0xef, 0x2a, 0x97, 0x5c, 0x4a, 0x69, 0x59, 0x29, | 	0x5a, 0x4a, 0xc3, 0x74, 0xed, 0xb9, 0x2a, 0x24, 0x97, 0xd2, 0x5a, 0x56, 0x88, 0xac, 0x10, 0xe6, | ||||||
| 	0xf2, 0x52, 0x98, 0xa3, 0x8c, 0xb5, 0xe2, 0xd3, 0xaf, 0xf1, 0xd9, 0x83, 0x7e, 0x92, 0xd2, 0x05, | 	0x2a, 0x83, 0x4a, 0x3d, 0xbd, 0x9a, 0x9e, 0x63, 0xe8, 0xc5, 0x09, 0x5d, 0xa1, 0xd7, 0xd7, 0x36, | ||||||
| 	0xfa, 0x03, 0x2d, 0x83, 0x32, 0x24, 0x4b, 0x59, 0x3e, 0x9e, 0xd3, 0x18, 0xfd, 0xa1, 0xfa, 0x52, | 	0x28, 0xe0, 0xff, 0xb0, 0x94, 0x42, 0xfc, 0x5e, 0x20, 0x17, 0xe4, 0xac, 0x12, 0x26, 0xdd, 0x18, | ||||||
| 	0x39, 0x82, 0x1f, 0x16, 0x70, 0x84, 0xdf, 0x4b, 0xe4, 0x82, 0x1c, 0x57, 0xb4, 0xa5, 0x56, 0xa3, | 	0x4e, 0x1f, 0xb6, 0x16, 0xa5, 0xd2, 0xfc, 0x0e, 0x06, 0x4c, 0x4b, 0x52, 0x4e, 0x0d, 0xa7, 0xcf, | ||||||
| 	0xe9, 0xfd, 0xce, 0x92, 0x55, 0x8a, 0xbc, 0x85, 0x21, 0xd3, 0x84, 0x95, 0x8e, 0xa3, 0xe9, 0x93, | 	0xae, 0x1f, 0x6a, 0x28, 0x0f, 0xed, 0x7e, 0xff, 0x08, 0xee, 0x5b, 0x02, 0x3c, 0x63, 0x29, 0x47, | ||||||
| 	0xab, 0x9b, 0x1a, 0xba, 0x44, 0x36, 0x3e, 0xd8, 0x85, 0xff, 0x2d, 0x00, 0x9e, 0xb3, 0x8c, 0x63, | 	0xff, 0x12, 0x86, 0x21, 0xd2, 0x65, 0xcd, 0xa3, 0x3a, 0xa1, 0x9b, 0x9d, 0xde, 0x7a, 0x72, 0x56, | ||||||
| 	0xc0, 0x61, 0x14, 0x21, 0x9d, 0xd7, 0x14, 0xac, 0x03, 0x5a, 0x5f, 0x87, 0x56, 0x43, 0x5a, 0x75, | 	0xbf, 0x5b, 0xe9, 0xf7, 0xe7, 0x3a, 0xad, 0xd5, 0xf9, 0xa6, 0xa2, 0xac, 0x75, 0x3e, 0xb9, 0x4e, | ||||||
| 	0xdc, 0x66, 0xb5, 0x2b, 0x1d, 0xbc, 0xb6, 0x0e, 0xa7, 0xfa, 0x50, 0xab, 0xc2, 0xeb, 0x8a, 0x90, | 	0xb9, 0x46, 0xa3, 0x22, 0x3c, 0x83, 0x7b, 0x3a, 0x8f, 0xa6, 0x4b, 0x5e, 0xc3, 0xbe, 0x21, 0xc4, | ||||||
| 	0x56, 0xe1, 0xd1, 0x55, 0x42, 0x35, 0x90, 0x15, 0x9d, 0x19, 0xfc, 0xa7, 0xf3, 0x68, 0x32, 0xe4, | 	0x55, 0x11, 0x77, 0x3a, 0x56, 0x6e, 0xf5, 0x0f, 0x61, 0xf4, 0x11, 0xaf, 0xb0, 0x74, 0x44, 0x56, | ||||||
| 	0x15, 0x6c, 0x1b, 0xb8, 0x5c, 0x35, 0xc0, 0x46, 0x3d, 0x57, 0xa1, 0xc1, 0x21, 0x8c, 0x3f, 0xe0, | 	0x42, 0x07, 0xee, 0xbc, 0x12, 0x8d, 0x7b, 0x1b, 0x95, 0xb0, 0x04, 0x4c, 0x25, 0x0e, 0x61, 0x74, | ||||||
| 	0x05, 0x56, 0x7d, 0xd4, 0x40, 0xef, 0xac, 0xa9, 0xa2, 0x0e, 0xbf, 0xf3, 0x2a, 0x36, 0x50, 0x35, | 	0x99, 0x2d, 0x69, 0x83, 0xa3, 0x0e, 0xdc, 0x39, 0xc7, 0xc6, 0xbd, 0x0d, 0x8e, 0x96, 0x80, 0xe1, | ||||||
| 	0xaa, 0x68, 0x01, 0x98, 0x2a, 0x1e, 0xc2, 0xf8, 0x4b, 0x3e, 0xa7, 0x37, 0x60, 0xa0, 0xc3, 0xef, | 	0x38, 0x82, 0xe1, 0x45, 0xcc, 0x85, 0x65, 0x38, 0xd7, 0xf0, 0x7f, 0xaa, 0x5c, 0x3b, 0xde, 0xa8, | ||||||
| 	0x9c, 0x41, 0x03, 0x55, 0x83, 0x81, 0x05, 0x60, 0x18, 0xbc, 0x80, 0xd1, 0x59, 0xc2, 0xc5, 0xf5, | 	0xb2, 0xce, 0x73, 0xbb, 0x2a, 0x4b, 0x76, 0x6c, 0xc5, 0x2d, 0xbb, 0xdf, 0x8e, 0xc6, 0x96, 0x5e, | ||||||
| 	0xf0, 0x9f, 0xea, 0xe0, 0x9b, 0xf4, 0x4f, 0x2d, 0x79, 0xa3, 0x7f, 0x74, 0x9e, 0xdb, 0xf5, 0x8f, | 	0xfb, 0xdb, 0x96, 0x43, 0x53, 0xe4, 0x48, 0x13, 0x65, 0xd1, 0x7e, 0x68, 0x90, 0xec, 0xe2, 0x88, | ||||||
| 	0xc4, 0xce, 0x16, 0xfc, 0x7a, 0xd8, 0x7f, 0x39, 0x3a, 0xda, 0x82, 0xef, 0xbe, 0x71, 0x72, 0xd0, | 	0x15, 0xa9, 0x50, 0x4f, 0xdb, 0x0d, 0x35, 0x90, 0x51, 0x1e, 0xa7, 0x11, 0xaa, 0x31, 0xe0, 0x86, | ||||||
| 	0x8b, 0x02, 0x69, 0xaa, 0xe4, 0xdd, 0x8e, 0x8c, 0x25, 0x27, 0x4f, 0xcc, 0xca, 0x4c, 0xa8, 0x0b, | 	0x1a, 0xd4, 0xc5, 0xf7, 0x5a, 0xc5, 0x57, 0xec, 0x2a, 0xf1, 0x7f, 0x1c, 0x38, 0xb8, 0x60, 0xab, | ||||||
| 	0xe7, 0x46, 0xda, 0x90, 0x5e, 0x9e, 0x64, 0xe6, 0xb6, 0xb9, 0x91, 0x36, 0xea, 0xd2, 0xf4, 0x3b, | 	0x10, 0x23, 0x96, 0x2f, 0x9b, 0x83, 0xd0, 0xd9, 0x1e, 0x84, 0xb3, 0xda, 0x14, 0xef, 0x28, 0x63, | ||||||
| 	0xa5, 0xa9, 0xb0, 0x57, 0xd2, 0xfc, 0x71, 0x60, 0xe7, 0x8c, 0x2d, 0x22, 0x8c, 0x59, 0x31, 0x6f, | 	0x5e, 0xde, 0x78, 0x8b, 0x4e, 0xd6, 0x36, 0xc7, 0xa5, 0x13, 0x09, 0x72, 0x2e, 0xe7, 0x93, 0x99, | ||||||
| 	0x0e, 0x6f, 0xa7, 0x3d, 0xbc, 0x67, 0xb5, 0x97, 0xa7, 0xa7, 0x64, 0x7b, 0xbe, 0xf6, 0x14, 0x9d, | 	0xa7, 0x06, 0xde, 0x6a, 0xc2, 0x4f, 0x7f, 0xba, 0x30, 0x08, 0x35, 0x09, 0xb2, 0x80, 0xbe, 0x9e, | ||||||
| 	0xac, 0xeb, 0xed, 0x91, 0x4a, 0xa4, 0xc8, 0xb9, 0x9c, 0xa9, 0xe6, 0x0d, 0x30, 0xe6, 0xad, 0x5e, | 	0x34, 0xa4, 0x75, 0x3a, 0x99, 0xba, 0x9c, 0x8c, 0xdb, 0x37, 0x98, 0x67, 0xb7, 0x47, 0x3e, 0x41, | ||||||
| 	0xa5, 0xe9, 0x4f, 0x17, 0x86, 0x91, 0x06, 0x41, 0xce, 0x61, 0xa0, 0xe7, 0x1f, 0xe9, 0x9c, 0x99, | 	0x57, 0xce, 0x01, 0xd2, 0x32, 0x37, 0x6c, 0xaa, 0xa7, 0x6d, 0x9f, 0xcb, 0x44, 0x0b, 0xe8, 0xeb, | ||||||
| 	0xa6, 0x2e, 0xfb, 0x93, 0xee, 0x00, 0xd3, 0xb2, 0x5b, 0xe4, 0x23, 0x78, 0x72, 0xfe, 0x90, 0x8e, | 	0xbe, 0x23, 0xad, 0xbd, 0xba, 0x83, 0xd7, 0x56, 0xcb, 0xaa, 0x74, 0xba, 0x45, 0x48, 0x6b, 0x5b, | ||||||
| 	0x79, 0x65, 0x53, 0x3d, 0xee, 0xfa, 0xbc, 0x4a, 0x74, 0x0e, 0x03, 0x7d, 0xa3, 0x49, 0xe7, 0x14, | 	0xed, 0x48, 0xb7, 0xd5, 0x5d, 0x7b, 0x64, 0x0e, 0x5d, 0xf9, 0x46, 0x48, 0xcb, 0xdb, 0xb1, 0xa9, | ||||||
| 	0xd8, 0x80, 0xab, 0x35, 0x0c, 0x54, 0x3a, 0x7d, 0xbd, 0x48, 0xe7, 0x95, 0xdc, 0x90, 0xae, 0x75, | 	0x1e, 0xed, 0x28, 0xba, 0xbf, 0xf7, 0xca, 0xf9, 0xda, 0x57, 0x3f, 0x16, 0x67, 0xff, 0x02, 0x00, | ||||||
| 	0x33, 0xb7, 0xc8, 0x29, 0x78, 0xb2, 0x47, 0x48, 0x47, 0xef, 0xd8, 0x54, 0x0f, 0x36, 0x14, 0x3d, | 	0x00, 0xff, 0xff, 0xe1, 0x5b, 0x52, 0x93, 0x7f, 0x08, 0x00, 0x00, | ||||||
| 	0xd8, 0x7a, 0xe9, 0x7c, 0x1d, 0xa8, 0x9f, 0xa1, 0xe3, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8e, |  | ||||||
| 	0x6c, 0x03, 0x59, 0x33, 0x09, 0x00, 0x00, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Reference imports to suppress errors if they are not otherwise used. | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|   | |||||||
| @@ -41,8 +41,6 @@ message CreateOptions { | |||||||
| 	string type = 5; | 	string type = 5; | ||||||
| 	// image to use | 	// image to use | ||||||
| 	string image = 6; | 	string image = 6; | ||||||
| 	// namespace to use |  | ||||||
| 	string namespace = 7; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message CreateRequest { | message CreateRequest { | ||||||
| @@ -59,8 +57,6 @@ message ReadOptions { | |||||||
| 	string version = 2; | 	string version = 2; | ||||||
| 	// type of service | 	// type of service | ||||||
| 	string type = 3; | 	string type = 3; | ||||||
| 	// namespace of service |  | ||||||
| 	string namespace = 4; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message ReadRequest { | message ReadRequest { | ||||||
| @@ -72,8 +68,6 @@ message ReadResponse { | |||||||
| } | } | ||||||
|  |  | ||||||
| message DeleteOptions { | message DeleteOptions { | ||||||
| 	// namespace of the service |  | ||||||
| 	string namespace = 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message DeleteRequest { | message DeleteRequest { | ||||||
| @@ -84,8 +78,6 @@ message DeleteRequest { | |||||||
| message DeleteResponse {} | message DeleteResponse {} | ||||||
|  |  | ||||||
| message UpdateOptions { | message UpdateOptions { | ||||||
| 	// namespace of the service |  | ||||||
| 	string namespace = 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message UpdateRequest { | message UpdateRequest { | ||||||
| @@ -96,8 +88,6 @@ message UpdateRequest { | |||||||
| message UpdateResponse {} | message UpdateResponse {} | ||||||
|  |  | ||||||
| message ListOptions { | message ListOptions { | ||||||
| 	// namespace to list from |  | ||||||
| 	string namespace = 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message ListRequest { | message ListRequest { | ||||||
| @@ -109,8 +99,6 @@ message ListResponse { | |||||||
| } | } | ||||||
|  |  | ||||||
| message LogsOptions { | message LogsOptions { | ||||||
| 	// namespace of the service |  | ||||||
| 	string namespace = 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| message LogsRequest{ | message LogsRequest{ | ||||||
|   | |||||||
| @@ -54,12 +54,11 @@ func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error { | |||||||
| 			Metadata: svc.Metadata, | 			Metadata: svc.Metadata, | ||||||
| 		}, | 		}, | ||||||
| 		Options: &pb.CreateOptions{ | 		Options: &pb.CreateOptions{ | ||||||
| 			Command:   options.Command, | 			Command: options.Command, | ||||||
| 			Args:      options.Args, | 			Args:    options.Args, | ||||||
| 			Env:       options.Env, | 			Env:     options.Env, | ||||||
| 			Type:      options.Type, | 			Type:    options.Type, | ||||||
| 			Image:     options.Image, | 			Image:   options.Image, | ||||||
| 			Namespace: options.Namespace, |  | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -84,9 +83,6 @@ func (s *svc) Logs(service *runtime.Service, opts ...runtime.LogsOption) (runtim | |||||||
| 		Service: service.Name, | 		Service: service.Name, | ||||||
| 		Stream:  options.Stream, | 		Stream:  options.Stream, | ||||||
| 		Count:   options.Count, | 		Count:   options.Count, | ||||||
| 		Options: &pb.LogsOptions{ |  | ||||||
| 			Namespace: options.Namespace, |  | ||||||
| 		}, |  | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -176,10 +172,9 @@ func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) { | |||||||
| 	// runtime service create request | 	// runtime service create request | ||||||
| 	req := &pb.ReadRequest{ | 	req := &pb.ReadRequest{ | ||||||
| 		Options: &pb.ReadOptions{ | 		Options: &pb.ReadOptions{ | ||||||
| 			Service:   options.Service, | 			Service: options.Service, | ||||||
| 			Version:   options.Version, | 			Version: options.Version, | ||||||
| 			Type:      options.Type, | 			Type:    options.Type, | ||||||
| 			Namespace: options.Namespace, |  | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -220,9 +215,6 @@ func (s *svc) Update(svc *runtime.Service, opts ...runtime.UpdateOption) error { | |||||||
| 			Source:   svc.Source, | 			Source:   svc.Source, | ||||||
| 			Metadata: svc.Metadata, | 			Metadata: svc.Metadata, | ||||||
| 		}, | 		}, | ||||||
| 		Options: &pb.UpdateOptions{ |  | ||||||
| 			Namespace: options.Namespace, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, err := s.runtime.Update(options.Context, req); err != nil { | 	if _, err := s.runtime.Update(options.Context, req); err != nil { | ||||||
| @@ -250,9 +242,6 @@ func (s *svc) Delete(svc *runtime.Service, opts ...runtime.DeleteOption) error { | |||||||
| 			Source:   svc.Source, | 			Source:   svc.Source, | ||||||
| 			Metadata: svc.Metadata, | 			Metadata: svc.Metadata, | ||||||
| 		}, | 		}, | ||||||
| 		Options: &pb.DeleteOptions{ |  | ||||||
| 			Namespace: options.Namespace, |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, err := s.runtime.Delete(options.Context, req); err != nil { | 	if _, err := s.runtime.Delete(options.Context, req); err != nil { | ||||||
|   | |||||||
| @@ -18,17 +18,17 @@ func Generate(id string, name string, a auth.Auth) error { | |||||||
| 	// if no credentials were provided, generate an account | 	// if no credentials were provided, generate an account | ||||||
| 	if len(accID) == 0 || len(accSecret) == 0 { | 	if len(accID) == 0 || len(accSecret) == 0 { | ||||||
| 		name := fmt.Sprintf("%v-%v", name, id) | 		name := fmt.Sprintf("%v-%v", name, id) | ||||||
|  |  | ||||||
| 		opts := []auth.GenerateOption{ | 		opts := []auth.GenerateOption{ | ||||||
| 			auth.WithType("service"), | 			auth.WithType("service"), | ||||||
| 			auth.WithRoles("service"), | 			auth.WithScopes("service"), | ||||||
| 			auth.WithNamespace(a.Options().Namespace), |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		acc, err := a.Generate(name, opts...) | 		acc, err := a.Generate(name, opts...) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		logger.Infof("Auth [%v] Authenticated as %v in the %v namespace", a, name, acc.Namespace) | 		logger.Infof("Auth [%v] Authenticated as %v issued by %v", a, name, acc.Issuer) | ||||||
|  |  | ||||||
| 		accID = acc.ID | 		accID = acc.ID | ||||||
| 		accSecret = acc.Secret | 		accSecret = acc.Secret | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/auth" | 	"github.com/micro/go-micro/v2/auth" | ||||||
| 	"github.com/micro/go-micro/v2/client" | 	"github.com/micro/go-micro/v2/client" | ||||||
| @@ -157,9 +156,14 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac | |||||||
| 		return a.Client.Call(ctx, req, rsp, opts...) | 		return a.Client.Call(ctx, req, rsp, opts...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// set the namespace header if it has not been set (e.g. on a service to service request) | ||||||
|  | 	if _, ok := metadata.Get(ctx, "Micro-Namespace"); !ok { | ||||||
|  | 		ctx = metadata.Set(ctx, "Micro-Namespace", aa.Options().Namespace) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// check to see if we have a valid access token | 	// check to see if we have a valid access token | ||||||
| 	aaOpts := aa.Options() | 	aaOpts := aa.Options() | ||||||
| 	if aaOpts.Token != nil && aaOpts.Token.Expiry.Unix() > time.Now().Unix() { | 	if aaOpts.Token != nil && !aaOpts.Token.Expired() { | ||||||
| 		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken) | 		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken) | ||||||
| 		return a.Client.Call(ctx, req, rsp, opts...) | 		return a.Client.Call(ctx, req, rsp, opts...) | ||||||
| 	} | 	} | ||||||
| @@ -187,20 +191,28 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper { | |||||||
|  |  | ||||||
| 			// Extract the token if present. Note: if noop is being used | 			// Extract the token if present. Note: if noop is being used | ||||||
| 			// then the token can be blank without erroring | 			// then the token can be blank without erroring | ||||||
| 			var token string | 			var account *auth.Account | ||||||
| 			if header, ok := metadata.Get(ctx, "Authorization"); ok { | 			if header, ok := metadata.Get(ctx, "Authorization"); ok { | ||||||
| 				// Ensure the correct scheme is being used | 				// Ensure the correct scheme is being used | ||||||
| 				if !strings.HasPrefix(header, auth.BearerScheme) { | 				if !strings.HasPrefix(header, auth.BearerScheme) { | ||||||
| 					return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema") | 					return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema") | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				token = header[len(auth.BearerScheme):] | 				// Strip the prefix and inspect the resulting token | ||||||
|  | 				account, _ = a.Inspect(strings.TrimPrefix(header, auth.BearerScheme)) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// Inspect the token and get the account | 			// Extract the namespace header | ||||||
| 			account, err := a.Inspect(token) | 			ns, ok := metadata.Get(ctx, "Micro-Namespace") | ||||||
| 			if err != nil { | 			if !ok { | ||||||
| 				account = &auth.Account{Namespace: a.Options().Namespace} | 				ns = a.Options().Namespace | ||||||
|  | 				ctx = metadata.Set(ctx, "Micro-Namespace", ns) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check the issuer matches the services namespace. TODO: Stop allowing go.micro to access | ||||||
|  | 			// any namespace and instead check for the server issuer. | ||||||
|  | 			if account != nil && account.Issuer != ns && account.Issuer != "go.micro" { | ||||||
|  | 				return errors.Forbidden(req.Service(), "Account was not issued by %v", ns) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// construct the resource | 			// construct the resource | ||||||
| @@ -211,15 +223,15 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// Verify the caller has access to the resource | 			// Verify the caller has access to the resource | ||||||
| 			err = a.Verify(account, res) | 			err := a.Verify(account, res, auth.VerifyContext(ctx)) | ||||||
| 			if err != nil && len(account.ID) > 0 { | 			if err != nil && account != nil { | ||||||
| 				return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID) | 				return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID) | ||||||
| 			} else if err != nil { | 			} else if err != nil { | ||||||
| 				return errors.Unauthorized(req.Service(), "Unauthorised call made to %v:%v", req.Service(), req.Endpoint()) | 				return errors.Unauthorized(req.Service(), "Unauthorised call made to %v:%v", req.Service(), req.Endpoint()) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// There is an account, set it in the context | 			// There is an account, set it in the context | ||||||
| 			if len(account.ID) > 0 { | 			if account != nil { | ||||||
| 				ctx = auth.ContextWithAccount(ctx, account) | 				ctx = auth.ContextWithAccount(ctx, account) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,12 +2,16 @@ package wrapper | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"net/http" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/v2/auth" | ||||||
| 	"github.com/micro/go-micro/v2/client" | 	"github.com/micro/go-micro/v2/client" | ||||||
|  | 	"github.com/micro/go-micro/v2/errors" | ||||||
| 	"github.com/micro/go-micro/v2/metadata" | 	"github.com/micro/go-micro/v2/metadata" | ||||||
|  | 	"github.com/micro/go-micro/v2/server" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestWrapper(t *testing.T) { | func TestWrapper(t *testing.T) { | ||||||
| @@ -54,6 +58,313 @@ func TestWrapper(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type testAuth struct { | ||||||
|  | 	verifyCount    int | ||||||
|  | 	inspectCount   int | ||||||
|  | 	namespace      string | ||||||
|  | 	inspectAccount *auth.Account | ||||||
|  | 	verifyError    error | ||||||
|  |  | ||||||
|  | 	auth.Auth | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (a *testAuth) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error { | ||||||
|  | 	a.verifyCount = a.verifyCount + 1 | ||||||
|  | 	return a.verifyError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (a *testAuth) Inspect(token string) (*auth.Account, error) { | ||||||
|  | 	a.inspectCount = a.inspectCount + 1 | ||||||
|  | 	return a.inspectAccount, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (a *testAuth) Options() auth.Options { | ||||||
|  | 	return auth.Options{Namespace: a.namespace} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type testRequest struct { | ||||||
|  | 	service  string | ||||||
|  | 	endpoint string | ||||||
|  |  | ||||||
|  | 	server.Request | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r testRequest) Service() string { | ||||||
|  | 	return r.service | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r testRequest) Endpoint() string { | ||||||
|  | 	return r.endpoint | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestAuthHandler(t *testing.T) { | ||||||
|  | 	h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	debugReq := testRequest{service: "go.micro.service.foo", endpoint: "Debug.Foo"} | ||||||
|  | 	serviceReq := testRequest{service: "go.micro.service.foo", endpoint: "Foo.Bar"} | ||||||
|  |  | ||||||
|  | 	// Debug endpoints should be excluded from auth so auth.Verify should never get called | ||||||
|  | 	t.Run("DebugEndpoint", func(t *testing.T) { | ||||||
|  | 		a := testAuth{} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		err := handler(h)(context.TODO(), debugReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if a.verifyCount != 0 { | ||||||
|  | 			t.Errorf("Did not expect verify to be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the Authorization header is blank, no error should be returned and verify not called | ||||||
|  | 	t.Run("BlankAuthorizationHeader", func(t *testing.T) { | ||||||
|  | 		a := testAuth{} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		err := handler(h)(context.TODO(), serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if a.inspectCount != 0 { | ||||||
|  | 			t.Errorf("Did not expect inspect to be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the Authorization header is invalid, an error should be returned and verify not called | ||||||
|  | 	t.Run("InvalidAuthorizationHeader", func(t *testing.T) { | ||||||
|  | 		a := testAuth{} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", "Invalid") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized { | ||||||
|  | 			t.Errorf("Expected unauthorized error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if a.inspectCount != 0 { | ||||||
|  | 			t.Errorf("Did not expect inspect to be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the Authorization header is valid, no error should be returned and verify should called | ||||||
|  | 	t.Run("ValidAuthorizationHeader", func(t *testing.T) { | ||||||
|  | 		a := testAuth{} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if a.inspectCount != 1 { | ||||||
|  | 			t.Errorf("Expected inspect to be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the namespace header was not set on the request, the wrapper should set it to the auths | ||||||
|  | 	// own namespace | ||||||
|  | 	t.Run("BlankNamespaceHeader", func(t *testing.T) { | ||||||
|  | 		a := testAuth{namespace: "mynamespace"} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		inCtx := context.TODO() | ||||||
|  | 		h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 			inCtx = ctx | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err := handler(h)(inCtx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if ns, _ := metadata.Get(inCtx, "Micro-Namespace"); ns != a.namespace { | ||||||
|  | 			t.Errorf("Expected namespace to be set to %v but was %v", a.namespace, ns) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	t.Run("ValidNamespaceHeader", func(t *testing.T) { | ||||||
|  | 		a := testAuth{namespace: "mynamespace"} | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		inNs := "reqnamespace" | ||||||
|  | 		inCtx := metadata.Set(context.TODO(), "Micro-Namespace", inNs) | ||||||
|  | 		h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 			inCtx = ctx | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err := handler(h)(inCtx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if ns, _ := metadata.Get(inCtx, "Micro-Namespace"); ns != inNs { | ||||||
|  | 			t.Errorf("Expected namespace to remain as %v but was set to %v", inNs, ns) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the callers account was set but the issuer didn't match that of the request, the request | ||||||
|  | 	// should be forbidden | ||||||
|  | 	t.Run("InvalidAccountIssuer", func(t *testing.T) { | ||||||
|  | 		a := testAuth{ | ||||||
|  | 			namespace:      "validnamespace", | ||||||
|  | 			inspectAccount: &auth.Account{Issuer: "invalidnamespace"}, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusForbidden { | ||||||
|  | 			t.Errorf("Expected forbidden error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	t.Run("ValidAccountIssuer", func(t *testing.T) { | ||||||
|  | 		a := testAuth{ | ||||||
|  | 			namespace:      "validnamespace", | ||||||
|  | 			inspectAccount: &auth.Account{Issuer: "validnamespace"}, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If the caller had a nil account and verify returns an error, the request should be unauthorised | ||||||
|  | 	t.Run("NilAccountUnauthorized", func(t *testing.T) { | ||||||
|  | 		a := testAuth{verifyError: auth.ErrForbidden} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		err := handler(h)(context.TODO(), serviceReq, nil) | ||||||
|  | 		if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized { | ||||||
|  | 			t.Errorf("Expected unauthorizard error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	t.Run("AccountForbidden", func(t *testing.T) { | ||||||
|  | 		a := testAuth{verifyError: auth.ErrForbidden, inspectAccount: &auth.Account{}} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusForbidden { | ||||||
|  | 			t.Errorf("Expected forbidden error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	t.Run("AccountValid", func(t *testing.T) { | ||||||
|  | 		a := testAuth{inspectAccount: &auth.Account{}} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If an account is returned from inspecting the token, it should be set in the context | ||||||
|  | 	t.Run("ContextWithAccount", func(t *testing.T) { | ||||||
|  | 		accID := "myaccountid" | ||||||
|  | 		a := testAuth{inspectAccount: &auth.Account{ID: accID}} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		inCtx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 			inCtx = ctx | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err := handler(h)(inCtx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if acc, ok := auth.AccountFromContext(inCtx); !ok { | ||||||
|  | 			t.Errorf("Expected an account to be set in the context") | ||||||
|  | 		} else if acc.ID != accID { | ||||||
|  | 			t.Errorf("Expected the account in the context to have the ID %v but it actually had %v", accID, acc.ID) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If verify returns an error the handler should not be called | ||||||
|  | 	t.Run("HandlerNotCalled", func(t *testing.T) { | ||||||
|  | 		a := testAuth{verifyError: auth.ErrForbidden} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		var handlerCalled bool | ||||||
|  | 		h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 			handlerCalled = true | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized { | ||||||
|  | 			t.Errorf("Expected unauthorizard error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if handlerCalled { | ||||||
|  | 			t.Errorf("Expected the handler to not be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// If verify does not return an error the handler should be called | ||||||
|  | 	t.Run("HandlerNotCalled", func(t *testing.T) { | ||||||
|  | 		a := testAuth{} | ||||||
|  |  | ||||||
|  | 		handler := AuthHandler(func() auth.Auth { | ||||||
|  | 			return &a | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 		var handlerCalled bool | ||||||
|  | 		h := func(ctx context.Context, req server.Request, rsp interface{}) error { | ||||||
|  | 			handlerCalled = true | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token") | ||||||
|  | 		err := handler(h)(ctx, serviceReq, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Expected nil error but got %v", err) | ||||||
|  | 		} | ||||||
|  | 		if !handlerCalled { | ||||||
|  | 			t.Errorf("Expected the handler be called") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
| type testClient struct { | type testClient struct { | ||||||
| 	callCount int | 	callCount int | ||||||
| 	callRsp   interface{} | 	callRsp   interface{} | ||||||
|   | |||||||
| @@ -444,7 +444,7 @@ func (s *service) Init(opts ...Option) error { | |||||||
| func (s *service) Run() error { | func (s *service) Run() error { | ||||||
| 	// generate an auth account | 	// generate an auth account | ||||||
| 	srvID := s.opts.Service.Server().Options().Id | 	srvID := s.opts.Service.Server().Options().Id | ||||||
| 	srvName := s.opts.Service.Name() | 	srvName := s.Options().Name | ||||||
| 	if err := authutil.Generate(srvID, srvName, s.opts.Service.Options().Auth); err != nil { | 	if err := authutil.Generate(srvID, srvName, s.opts.Service.Options().Auth); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user