Skip to content

Commit

Permalink
Add support for rules in YAML format (#213)
Browse files Browse the repository at this point in the history
This commit adds support for defining access rules in YAML format, in
addition to existing JSON format.
  • Loading branch information
hypnoglow authored and aeneasr committed Jul 1, 2019
1 parent a8afc3b commit 67face6
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 8 deletions.
4 changes: 2 additions & 2 deletions docs/config.yaml
Expand Up @@ -233,13 +233,13 @@ serve:
# Configures Access Rules
access_rules:
# Locations (list of URLs) where access rules should be fetched from on boot.
# It is expected that the documents at those locations return a JSON Array containing ORY Oathkeeper Access Rules.
# It is expected that the documents at those locations return a JSON or YAML Array containing ORY Oathkeeper Access Rules.
repositories:
# If the URL Scheme is `file://`, the access rules (an array of access rules is expected) will be
# fetched from the local file system.
- file://path/to/rules.json
# If the URL Scheme is `inline://`, the access rules (an array of access rules is expected)
# are expected to be a base64 encoded (with padding!) JSON string (base64_encode(`[{"id":"foo-rule","authenticators":[....]}]`)):
# are expected to be a base64 encoded (with padding!) JSON/YAML string (base64_encode(`[{"id":"foo-rule","authenticators":[....]}]`)):
- inline://W3siaWQiOiJmb28tcnVsZSIsImF1dGhlbnRpY2F0b3JzIjpbXX1d
# If the URL Scheme is `http://` or `https://`, the access rules (an array of access rules is expected) will be
# fetched from the provided HTTP(s) location.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -8,6 +8,7 @@ require (
github.com/bxcodec/faker v2.0.1+incompatible
github.com/codegangsta/negroni v1.0.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors v1.0.1
github.com/go-openapi/analysis v0.19.0 // indirect
github.com/go-openapi/errors v0.19.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Expand Up @@ -79,6 +79,7 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
Expand Down
27 changes: 21 additions & 6 deletions rule/fetcher_default.go
Expand Up @@ -5,18 +5,19 @@ import (
"encoding/base64"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"

"github.com/ory/x/httpx"

"github.com/ory/oathkeeper/driver/configuration"
"github.com/ory/oathkeeper/x"
"github.com/ory/x/httpx"

"github.com/ghodss/yaml"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -62,7 +63,7 @@ func (f *FetcherDefault) fetch(source url.URL) ([]Rule, error) {
return f.fetchRemote(source.String())
case "file":
p := strings.Replace(source.String(), "file://", "", 1)
if path.Ext(p) == ".json" {
if path.Ext(p) == ".json" || path.Ext(p) == ".yaml" || path.Ext(p) == ".yml" {
return f.fetchFile(p)
}
return f.fetchDir(p)
Expand Down Expand Up @@ -124,11 +125,25 @@ func (f *FetcherDefault) fetchFile(source string) ([]Rule, error) {
}

func (f *FetcherDefault) decode(r io.Reader) ([]Rule, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return nil, errors.WithStack(err)
}

var ks []Rule
d := json.NewDecoder(r)
d.DisallowUnknownFields()
if err := d.Decode(&ks); err != nil {

if json.Valid(b) {
d := json.NewDecoder(bytes.NewReader(b))
d.DisallowUnknownFields()
if err := d.Decode(&ks); err != nil {
return nil, errors.WithStack(err)
}
return ks, nil
}

if err := yaml.Unmarshal(b, &ks); err != nil {
return nil, errors.WithStack(err)
}

return ks, nil
}
56 changes: 56 additions & 0 deletions rule/fetcher_default_test.go
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/ory/oathkeeper/driver/configuration"
"github.com/ory/oathkeeper/internal"
"github.com/ory/oathkeeper/rule"
)

const testRule = `[{"id":"test-rule-5","upstream":{"preserve_host":true,"strip_path":"/api","url":"mybackend.com/api"},"match":{"url":"myproxy.com/api","methods":["GET","POST"]},"authenticators":[{"handler":"noop"},{"handler":"anonymous"}],"authorizer":{"handler":"allow"},"mutator":{"handler":"noop"}}]`
Expand Down Expand Up @@ -67,3 +68,58 @@ func TestFetcher(t *testing.T) {
})
}
}

func TestFetcherDefaultFetchFormats(t *testing.T) {
expected := []rule.Rule{
{
ID: "test-rule-1",
Match: rule.RuleMatch{
Methods: []string{"GET", "POST"},
URL: "myproxy.com/api",
},
Authenticators: []rule.RuleHandler{
{
Handler: "noop",
},
{
Handler: "anonymous",
},
},
Authorizer: rule.RuleHandler{
Handler: "allow",
},
Mutator: rule.RuleHandler{
Handler: "noop",
},
Upstream: rule.Upstream{
PreserveHost: true,
StripPath: "/api",
URL: "mybackend.com/api",
},
},
}

testCases := map[string]struct {
fpath string
}{
"json file": {
fpath: "testdata/rules.json",
},
"yaml file": {
fpath: "testdata/rules.yaml",
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
conf := internal.NewConfigurationWithDefaults()
viper.Set(configuration.ViperKeyAccessRuleRepositories, []string{"file://" + tc.fpath})

r := internal.NewRegistry(conf)
rules, err := r.RuleFetcher().Fetch()
require.NoError(t, err)

assert.Equal(t, expected, rules)
})
}
}
31 changes: 31 additions & 0 deletions rule/testdata/rules.json
@@ -0,0 +1,31 @@
[
{
"id": "test-rule-1",
"upstream": {
"preserve_host": true,
"strip_path": "/api",
"url": "mybackend.com/api"
},
"match": {
"url": "myproxy.com/api",
"methods": [
"GET",
"POST"
]
},
"authenticators": [
{
"handler": "noop"
},
{
"handler": "anonymous"
}
],
"authorizer": {
"handler": "allow"
},
"mutator": {
"handler": "noop"
}
}
]
17 changes: 17 additions & 0 deletions rule/testdata/rules.yaml
@@ -0,0 +1,17 @@
- id: test-rule-1
upstream:
preserve_host: true
strip_path: /api
url: mybackend.com/api
match:
url: myproxy.com/api
methods:
- GET
- POST
authenticators:
- handler: noop
- handler: anonymous
authorizer:
handler: allow
mutator:
handler: noop

0 comments on commit 67face6

Please sign in to comment.