Skip to content

Commit

Permalink
feat: handle HTTP config locations
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl committed Oct 5, 2022
1 parent 26944e9 commit 6571bae
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 40 deletions.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module github.com/ory/keto

replace (
github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.0.0
github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.10
github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1
Expand All @@ -13,6 +12,7 @@ require (
github.com/cenkalti/backoff/v3 v3.2.2
github.com/ghodss/yaml v1.0.0
github.com/go-sql-driver/mysql v1.6.0
github.com/gobuffalo/httptest v1.0.2
github.com/gobuffalo/pop/v6 v6.0.7-0.20220726152515-770e0c458f7b
github.com/gofrs/uuid v4.3.0+incompatible
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
Expand Down Expand Up @@ -53,6 +53,7 @@ require (
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f // indirect
github.com/avast/retry-go/v4 v4.1.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down Expand Up @@ -117,6 +118,7 @@ require (
github.com/knadh/koanf v1.4.3 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/markbates/hmax v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f h1:zvClvFQwU++UpIUBGC8YmDlfhUrweEy1R1Fj1gu5iIM=
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down Expand Up @@ -241,6 +242,7 @@ github.com/gobuffalo/helpers v0.6.6 h1:h7cnk9WNdvDtK4VVz/p4itkYPVTP2tr3NwRrxb8Qw
github.com/gobuffalo/helpers v0.6.6/go.mod h1:O+QsL1S4hoR3Pgn6OYSjztYdQbUebRW13xxzYYI8kos=
github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
github.com/gobuffalo/httptest v1.0.2 h1:LWp2khlgA697h4BIYWW2aRxvB93jMnBrbakQ/r2KLzs=
github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E=
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
github.com/gobuffalo/nulls v0.4.1/go.mod h1:pp8e1hWTRJZFpMl4fj/CVbSMlaxjeGKkFq4RuBZi3w8=
github.com/gobuffalo/nulls v0.4.2 h1:GAqBR29R3oPY+WCC7JL9KKk9erchaNuV6unsOSZGQkw=
Expand Down Expand Up @@ -347,10 +349,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
Expand Down Expand Up @@ -552,6 +558,7 @@ github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/markbates/hmax v1.0.0 h1:yo2N0gBoCnUMKhV/VRLHomT6Y9wUm+oQQENuWJqCdlM=
github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c=
github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
Expand Down
40 changes: 20 additions & 20 deletions internal/driver/config/namespace_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,11 @@ func (nw *NamespaceWatcher) readNamespaceFile(r io.Reader, source string) *Names
return &NamespaceFile{Name: source, Contents: raw, Parser: parse, namespace: &n}
}

func (n *NamespaceWatcher) GetNamespaceByName(_ context.Context, name string) (*namespace.Namespace, error) {
n.RLock()
defer n.RUnlock()
func (nw *NamespaceWatcher) GetNamespaceByName(_ context.Context, name string) (*namespace.Namespace, error) {
nw.RLock()
defer nw.RUnlock()

for _, nsf := range n.namespaces {
for _, nsf := range nw.namespaces {
if nsf.namespace != nil && nsf.namespace.Name == name {
return nsf.namespace, nil
}
Expand All @@ -221,11 +221,11 @@ func (n *NamespaceWatcher) GetNamespaceByName(_ context.Context, name string) (*
"Unknown namespace with name %s", name))
}

func (n *NamespaceWatcher) GetNamespaceByConfigID(_ context.Context, id int32) (*namespace.Namespace, error) {
n.RLock()
defer n.RUnlock()
func (nw *NamespaceWatcher) GetNamespaceByConfigID(_ context.Context, id int32) (*namespace.Namespace, error) {
nw.RLock()
defer nw.RUnlock()

for _, nspace := range n.namespaces {
for _, nspace := range nw.namespaces {
if nspace.namespace.ID == id { // nolint ignore deprecated ID
return nspace.namespace, nil
}
Expand All @@ -235,38 +235,38 @@ func (n *NamespaceWatcher) GetNamespaceByConfigID(_ context.Context, id int32) (
"Unknown namespace with ID %d", id))
}

func (n *NamespaceWatcher) Namespaces(_ context.Context) ([]*namespace.Namespace, error) {
n.RLock()
defer n.RUnlock()
func (nw *NamespaceWatcher) Namespaces(_ context.Context) ([]*namespace.Namespace, error) {
nw.RLock()
defer nw.RUnlock()

nspaces := make([]*namespace.Namespace, 0, len(n.namespaces))
for _, nsf := range n.namespaces {
nspaces := make([]*namespace.Namespace, 0, len(nw.namespaces))
for _, nsf := range nw.namespaces {
if nsf.namespace != nil {
nspaces = append(nspaces, nsf.namespace)
}
}
return nspaces, nil
}

func (n *NamespaceWatcher) NamespaceFiles() []*NamespaceFile {
n.RLock()
defer n.RUnlock()
func (nw *NamespaceWatcher) NamespaceFiles() []*NamespaceFile {
nw.RLock()
defer nw.RUnlock()

nsfs := make([]*NamespaceFile, 0, len(n.namespaces))
for _, nsf := range n.namespaces {
nsfs := make([]*NamespaceFile, 0, len(nw.namespaces))
for _, nsf := range nw.namespaces {
nsfs = append(nsfs, nsf)
}
return nsfs
}

func (n *NamespaceWatcher) ShouldReload(newValue interface{}) bool {
func (nw *NamespaceWatcher) ShouldReload(newValue interface{}) bool {
v, ok := newValue.(string)
if !ok {
// the manager type changed
return true
}
// reload if target changed
return v != n.target
return v != nw.target
}

func GetParser(fn string) (Parser, error) {
Expand Down
39 changes: 37 additions & 2 deletions internal/driver/config/opl_config_namespace_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package config

import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"sync"

"github.com/ory/x/logrusx"
"github.com/ory/x/urlx"
"github.com/ory/x/watcherx"
"github.com/pkg/errors"

"github.com/ory/keto/internal/namespace"
"github.com/ory/keto/internal/schema"
Expand All @@ -30,15 +35,45 @@ type (
var _ namespace.Manager = (*oplConfigWatcher)(nil)

func newOPLConfigWatcher(ctx context.Context, l *logrusx.Logger, target string) (*oplConfigWatcher, error) {

nw := &oplConfigWatcher{
logger: l,
target: target,
files: configFiles{byPath: make(map[string]io.Reader)},
memoryNamespaceManager: *NewMemoryNamespaceManager(),
}

return nw, watchTarget(ctx, target, nw, l)
targetUrl, err := urlx.Parse(target)
if err != nil {
return nil, errors.WithStack(err)
}

switch targetUrl.Scheme {
case "file":
return nw, watchTarget(ctx, target, nw, l)
case "http", "https":
file, err := download(ctx, targetUrl)
if err != nil {
return nil, err
}
defer file.Close()
nw.files.byPath[targetUrl.String()] = file
nw.parseFiles()
return nw, err
default:
return nil, fmt.Errorf("unexpected url scheme: %q", targetUrl.Scheme)
}
}

func download(ctx context.Context, url *url.URL) (io.ReadCloser, error) {
req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil)
if err != nil {
return nil, errors.WithStack(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.WithStack(err)
}
return resp.Body, nil
}

func (nw *oplConfigWatcher) handleChange(e *watcherx.ChangeEvent) {
Expand Down
59 changes: 42 additions & 17 deletions internal/driver/config/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"testing"

"github.com/gobuffalo/httptest"
"github.com/ory/x/configx"
"github.com/ory/x/logrusx"
"github.com/sirupsen/logrus/hooks/test"
Expand All @@ -28,7 +30,7 @@ func createFile(t *testing.T, content string) (path string) {
t.Fatal(err)
}

t.Cleanup(func() { os.Remove(f.Name()) })
t.Cleanup(func() { _ = os.Remove(f.Name()) })

n, err := f.WriteString(content)
if err != nil {
Expand Down Expand Up @@ -163,8 +165,7 @@ namespaces: file://%s`,
// Test that the namespaces can be configured through the Ory Permission
// Language.
func TestRewritesNamespaceConfig(t *testing.T) {
t.Run("case=one file", func(t *testing.T) {
oplConfig := createFile(t, `
oplContent := `
class User implements Namespace {
related: {
manager: User[]
Expand All @@ -175,23 +176,47 @@ class Group implements Namespace {
related: {
members: (User | Group)[]
}
}
`)
config := createFileF(t, `
}`

oplConfigFile := createFile(t, oplContent)

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, err := w.Write([]byte(oplContent))
if err != nil {
t.Fatal(err)
}
}))
t.Cleanup(func() { srv.Close() })

cases := []struct {
name string
location string
}{{
name: "local file",
location: "file://" + oplConfigFile,
}, {
name: "HTTP url",
location: srv.URL,
}}

for _, tc := range cases {
t.Run("case="+tc.name, func(t *testing.T) {
config := createFileF(t, `
dsn: memory
namespaces:
location: file://%s`, oplConfig)
location: %s`, tc.location)

_, p := setup(t, config)
nm, err := p.NamespaceManager()
require.NoError(t, err)
namespaces, err := nm.Namespaces(context.Background())
require.NoError(t, err)
require.Len(t, namespaces, 2)
_, p := setup(t, config)
nm, err := p.NamespaceManager()
require.NoError(t, err)
namespaces, err := nm.Namespaces(context.Background())
require.NoError(t, err)
require.Len(t, namespaces, 2)

names, relationNames := []string{namespaces[0].Name, namespaces[1].Name}, []string{namespaces[0].Relations[0].Name, namespaces[1].Relations[0].Name}
names, relationNames := []string{namespaces[0].Name, namespaces[1].Name}, []string{namespaces[0].Relations[0].Name, namespaces[1].Relations[0].Name}

assert.ElementsMatch(t, names, []string{"User", "Group"})
assert.ElementsMatch(t, relationNames, []string{"manager", "members"})
})
assert.ElementsMatch(t, names, []string{"User", "Group"})
assert.ElementsMatch(t, relationNames, []string{"manager", "members"})
})
}
}

0 comments on commit 6571bae

Please sign in to comment.