diff --git a/auth/auth.go b/auth/auth.go index 3651fa92..07a9ddab 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -27,7 +27,7 @@ type Auth interface { // Generate a new account Generate(id string, opts ...GenerateOption) (*Account, error) // Verify an account has access to a resource using the rules - Verify(acc *Account, res *Resource) error + Verify(acc *Account, res *Resource, opts ...VerifyOption) error // Inspect a token Inspect(token string) (*Account, error) // Token generated using refresh token or credentials diff --git a/auth/default.go b/auth/default.go index 11f9e6ae..ac0ae534 100644 --- a/auth/default.go +++ b/auth/default.go @@ -73,7 +73,7 @@ func (n *noop) Rules() ([]*Rule, error) { } // 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 } diff --git a/auth/jwt/jwt.go b/auth/jwt/jwt.go index 2397586f..4dafc7e3 100644 --- a/auth/jwt/jwt.go +++ b/auth/jwt/jwt.go @@ -99,10 +99,16 @@ func (j *jwt) Revoke(rule *auth.Rule) error { 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() defer j.Unlock() - return rules.Verify(j.options.Namespace, j.rules, acc, res) + + options := auth.VerifyOptions{Scope: j.options.Namespace} + for _, o := range opts { + o(&options) + } + + return rules.Verify(options.Scope, j.rules, acc, res) } func (j *jwt) Rules() ([]*auth.Rule, error) { diff --git a/auth/options.go b/auth/options.go index a498bb37..2dd6cc48 100644 --- a/auth/options.go +++ b/auth/options.go @@ -123,7 +123,7 @@ type GenerateOptions struct { Metadata map[string]string // Roles/scopes associated with the account Roles []string - // Scopes the account hasaccess too + // Scopes the account has access too Scopes []string // Provider of the account, e.g. oauth Provider string @@ -233,3 +233,16 @@ func NewTokenOptions(opts ...TokenOption) TokenOptions { return options } + +type VerifyOptions struct { + Scope string +} + +type VerifyOption func(o *VerifyOptions) + +// WithScope to require when verifying +func WithScope(s string) VerifyOption { + return func(o *VerifyOptions) { + o.Scope = s + } +} diff --git a/auth/rules/rules.go b/auth/rules/rules.go index 35736a8b..c3e96fa9 100644 --- a/auth/rules/rules.go +++ b/auth/rules/rules.go @@ -12,12 +12,6 @@ import ( // access an error will be returned. If there are no rules provided which match the resource, an error // will be returned func Verify(namespace string, rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error { - // ensure the account has the necessary scope. Some rules allow for public access so we don't - // error if the account is nil. - if acc != nil && !acc.HasScope("namespace."+namespace) { - return fmt.Errorf("Missing required scope: %v", "namespace."+namespace) - } - // the rule is only to be applied if the type matches the resource or is catch-all (*) validTypes := []string{"*", res.Type} @@ -37,6 +31,7 @@ func Verify(namespace string, rules []*auth.Rule, acc *auth.Account, res *auth.R // filter the rules to the ones which match the criteria above filteredRules := make([]*auth.Rule, 0) for _, rule := range rules { + fmt.Printf("All rules: %v\n", rule.ID) if !include(validTypes, rule.Resource.Type) { continue } @@ -63,8 +58,8 @@ func Verify(namespace string, rules []*auth.Rule, acc *auth.Account, res *auth.R return nil } - // all furter checks require an account - if acc == nil { + // all further checks require an account within the current scope + if acc == nil || !acc.HasScope("namespace", namespace) { continue } diff --git a/auth/service/service.go b/auth/service/service.go index 7f31b5a4..621e5fb7 100644 --- a/auth/service/service.go +++ b/auth/service/service.go @@ -119,11 +119,17 @@ func (s *svc) Rules() ([]*auth.Rule, error) { } // 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 { + options := auth.VerifyOptions{Scope: s.options.Namespace} + for _, o := range opts { + o(&options) + } + // load the rules if none are loaded s.loadRulesIfEmpty() + // verify the request using the rules - return rules.Verify(s.options.Namespace, s.rules, acc, res) + return rules.Verify(options.Scope, s.rules, acc, res) } // Inspect a token