auth/service support for micro clients (rules from mutltiple namespaces

This commit is contained in:
Ben Toogood 2020-05-21 12:25:47 +01:00
parent 8f5ef012ff
commit e876cb917d

View File

@ -6,6 +6,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/micro/go-micro/v2/metadata"
"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/rules"
pb "github.com/micro/go-micro/v2/auth/service/proto" pb "github.com/micro/go-micro/v2/auth/service/proto"
@ -22,7 +24,7 @@ type svc struct {
auth pb.AuthService auth pb.AuthService
rule pb.RulesService rule pb.RulesService
jwt token.Provider jwt token.Provider
rules []*auth.Rule rules map[string][]*auth.Rule
sync.Mutex sync.Mutex
} }
@ -91,7 +93,7 @@ func (s *svc) Grant(rule *auth.Rule) error {
}, },
}, },
}) })
go s.loadRules() go s.loadRules(s.options.Namespace)
return err return err
} }
@ -100,12 +102,12 @@ func (s *svc) Revoke(rule *auth.Rule) error {
_, err := s.rule.Delete(context.TODO(), &pb.DeleteRequest{ _, err := s.rule.Delete(context.TODO(), &pb.DeleteRequest{
Id: rule.ID, Id: rule.ID,
}) })
go s.loadRules() go s.loadRules(s.options.Namespace)
return err return err
} }
func (s *svc) Rules() ([]*auth.Rule, error) { func (s *svc) Rules() ([]*auth.Rule, error) {
return s.rules, nil return s.rules[s.options.Namespace], nil
} }
// Verify an account has access to a resource // Verify an account has access to a resource
@ -116,10 +118,10 @@ func (s *svc) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyO
} }
// load the rules if none are loaded // load the rules if none are loaded
s.loadRulesIfEmpty() s.loadRulesIfEmpty(options.Scope)
// verify the request using the rules // verify the request using the rules
return rules.Verify(options.Scope, s.rules, acc, res) return rules.Verify(options.Scope, s.rules[options.Scope], acc, res)
} }
// Inspect a token // Inspect a token
@ -184,18 +186,17 @@ func accessForRule(rule *pb.Rule, acc *auth.Account, res *auth.Resource) pb.Acce
return pb.Access_UNKNOWN return pb.Access_UNKNOWN
} }
// loadRules retrieves the rules from the auth service // loadRules retrieves the rules from the auth service. Since this implementation is used by micro
func (s *svc) loadRules() { // clients, which support muti-tenancy we may have to persist rules in multiple namespaces.
rsp, err := s.rule.List(context.TODO(), &pb.ListRequest{}) func (s *svc) loadRules(namespace string) {
s.Lock() ctx := metadata.Set(context.TODO(), "Micro-Namespace", namespace)
defer s.Unlock() rsp, err := s.rule.List(ctx, &pb.ListRequest{})
if err != nil { if err != nil {
log.Errorf("Error listing rules: %v", err) log.Errorf("Error listing rules: %v", err)
return return
} }
s.rules = make([]*auth.Rule, 0, len(rsp.Rules)) rules := make([]*auth.Rule, 0, len(rsp.Rules))
for _, r := range rsp.Rules { for _, r := range rsp.Rules {
var access auth.Access var access auth.Access
if r.Access == pb.Access_GRANTED { if r.Access == pb.Access_GRANTED {
@ -204,7 +205,7 @@ func (s *svc) loadRules() {
access = auth.AccessDenied access = auth.AccessDenied
} }
s.rules = append(s.rules, &auth.Rule{ rules = append(rules, &auth.Rule{
ID: r.Id, ID: r.Id,
Role: r.Role, Role: r.Role,
Access: access, Access: access,
@ -216,15 +217,19 @@ func (s *svc) loadRules() {
}, },
}) })
} }
s.Lock()
s.rules[namespace] = rules
s.Unlock()
} }
func (s *svc) loadRulesIfEmpty() { func (s *svc) loadRulesIfEmpty(namespace string) {
s.Lock() s.Lock()
rules := s.rules rules := s.rules
s.Unlock() s.Unlock()
if len(rules) == 0 { if _, ok := rules[namespace]; !ok {
s.loadRules() s.loadRules(namespace)
} }
} }
@ -258,6 +263,7 @@ func NewAuth(opts ...auth.Option) auth.Auth {
service := &svc{ service := &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), rule: pb.NewRulesService("go.micro.auth", options.Client),
rules: make(map[string][]*auth.Rule),
options: options, options: options,
} }
@ -268,7 +274,10 @@ func NewAuth(opts ...auth.Option) auth.Auth {
for { for {
<-ruleTimer.C <-ruleTimer.C
time.Sleep(jitter.Do(time.Second * 5)) time.Sleep(jitter.Do(time.Second * 5))
service.loadRules()
for ns := range service.rules {
service.loadRules(ns)
}
} }
}() }()