diff --git a/auth/store/rules.go b/auth/store/rules.go index 29270eeb..c4bf0c49 100644 --- a/auth/store/rules.go +++ b/auth/store/rules.go @@ -14,10 +14,12 @@ type Rule struct { Resource *auth.Resource `json:"resource"` } +var joinKey = ":" + // Key to be used when written to the store func (r *Rule) Key() string { comps := []string{r.Resource.Type, r.Resource.Name, r.Resource.Endpoint, r.Role} - return strings.Join(comps, "/") + return strings.Join(comps, joinKey) } // Bytes returns json encoded bytes @@ -51,7 +53,7 @@ func isValidRule(rule Rule, acc *auth.Account, res *auth.Resource) bool { // prefix matching the filters func (s *Store) listRules(filters ...string) ([]Rule, error) { // get the records from the store - prefix := strings.Join(filters, "/") + prefix := strings.Join(filters, joinKey) recs, err := s.opts.Store.Read(prefix, store.ReadPrefix()) if err != nil { return nil, err diff --git a/auth/store/store.go b/auth/store/store.go index de5d5e75..dad0be00 100644 --- a/auth/store/store.go +++ b/auth/store/store.go @@ -1,6 +1,9 @@ package store import ( + "fmt" + "strings" + "github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth/token" "github.com/micro/go-micro/v2/auth/token/basic" @@ -108,6 +111,15 @@ func (s *Store) Verify(acc *auth.Account, res *auth.Resource) error { {res.Type, res.Name, res.Endpoint}, // check for specific role, e.g. service.foo.ListFoo:admin } + // endpoint is a url which can have wildcard excludes, e.g. + // "/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}) + } + } + for _, q := range queries { rules, err := s.listRules(q...) if err != nil { diff --git a/auth/store/store_test.go b/auth/store/store_test.go index 03381e31..9b1ca0e9 100644 --- a/auth/store/store_test.go +++ b/auth/store/store_test.go @@ -191,6 +191,14 @@ func TestVerify(t *testing.T) { Role: "*", Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.PublicList"}, }, + { + Role: "*", + Resource: &auth.Resource{Type: "service", Name: "go.micro.web", Endpoint: "/foo"}, + }, + { + Role: "*", + Resource: &auth.Resource{Type: "service", Name: "go.micro.web", Endpoint: "/bar/*"}, + }, { Role: "user.*", Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.List"}, @@ -274,6 +282,19 @@ func TestVerify(t *testing.T) { Resource: &auth.Resource{Type: "infra", Name: "go.micro.foo", Endpoint: "Foo.Bar"}, Error: auth.ErrForbidden, }, + { + Name: "Accessing a public web path", + Resource: &auth.Resource{Type: "service", Name: "go.micro.web", Endpoint: "/foo"}, + }, + { + Name: "Accessing a public web path with an invalid wildcard endpoint", + Resource: &auth.Resource{Type: "service", Name: "go.micro.web", Endpoint: "/foo/foo"}, + Error: auth.ErrForbidden, + }, + { + Name: "Accessing a public web path with wildcard endpoint", + Resource: &auth.Resource{Type: "service", Name: "go.micro.web", Endpoint: "/bar/foo"}, + }, } for _, tc := range testTable {