Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homogenize configuration management #258

Merged
merged 17 commits into from
Sep 23, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
u
aeneasr committed Sep 22, 2019
commit d80efadbe9d6d8591a235094007b3c9881b35917
3 changes: 0 additions & 3 deletions .schemas/authenticators.anonymous.schema.json
Original file line number Diff line number Diff line change
@@ -18,8 +18,5 @@
"description": "Sets the anonymous username."
}
},
"required": [
"subject"
],
"additionalProperties": false
}
22 changes: 2 additions & 20 deletions .schemas/config.schema.json
Original file line number Diff line number Diff line change
@@ -176,26 +176,7 @@
},
"config": {
"$ref": "https://raw.githubusercontent.com/ory/oathkeeper/fix-255/.schemas/authenticators.anonymous.schema.json#"
},
"anyOf": [
{
"properties": {
"enabled": {
"const": true
}
},
"required": [
"config"
]
},
{
"properties": {
"enabled": {
"const": false
}
}
}
]
}
},
"noop": {
"title": "No Operation (noop)",
@@ -425,6 +406,7 @@
}
},
"required": [
"config"
]
},
{
1 change: 1 addition & 0 deletions .schemas/mutators.cookie.schema.json
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
"type": "object",
"title": "Cookie Mutator Configuration",
"description": "This section is optional when the mutator is disabled.",
"required": ["cookies"],
"properties": {
"cookies": {
"type": "object",
1 change: 1 addition & 0 deletions .schemas/mutators.header.schema.json
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
"type": "object",
"title": "Header Mutator Configuration",
"description": "This section is optional when the mutator is disabled.",
"required": ["headers"],
"properties": {
"headers": {
"type": "object",
2 changes: 1 addition & 1 deletion .schemas/mutators.hydrator.schema.json
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@
"type": "object",
"additionalProperties": false,
"properties": {
"number": {
"number_of_retries": {
"type": "number",
"minimum": 0,
"default": 100
2 changes: 1 addition & 1 deletion .schemas/mutators.id_token.schema.json
Original file line number Diff line number Diff line change
@@ -4,13 +4,13 @@
"type": "object",
"title": "ID Token Mutator Configuration",
"description": "This section is optional when the mutator is disabled.",
"required": ["jwks_url","issuer_url"],
"properties": {
"claims": {
"type": "string"
},
"issuer_url": {
"type": "string",
"format": "uri",
"title": "Issuer URL",
"description": "Sets the \"iss\" value of the ID Token.\n\n>If this mutator is enabled, this value is required."
},
3 changes: 1 addition & 2 deletions api/decision_test.go
Original file line number Diff line number Diff line change
@@ -28,10 +28,9 @@ import (

"github.com/ory/viper"

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

"github.com/urfave/negroni"

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

"github.com/julienschmidt/httprouter"
12 changes: 11 additions & 1 deletion docs/.oathkeeper.yaml
Original file line number Diff line number Diff line change
@@ -209,14 +209,24 @@ authorizers:
config:
# REQUIRED IF ENABLED - The base URL of ORY Keto, typically something like http(s)://<host>[:<port>]/
base_url: http://my-keto/

required_action: unknown
required_resource: unknown

# All mutators can be configured under this configuration key
mutators:
header:
enabled: true
config:
headers:
foo: bar

# Configures the cookie mutator
cookie:
# Set enabled to true if the mutator should be enabled and false to disable the mutator. Defaults to false.
enabled: true
config:
cookies:
foo: bar

# Configures the hydrator mutator
hydrator:
89 changes: 65 additions & 24 deletions driver/configuration/provider_viper.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (

"github.com/imdario/mergo"
"github.com/ory/gojsonschema"
"github.com/ory/x/jsonx"
"github.com/pkg/errors"
"github.com/rs/cors"
"github.com/sirupsen/logrus"
@@ -20,6 +21,8 @@ import (
"github.com/ory/x/corsx"
"github.com/ory/x/urlx"
"github.com/ory/x/viperx"

"github.com/ory/oathkeeper/x"
)

var _ Provider = new(ViperProvider)
@@ -35,6 +38,53 @@ const (
ViperKeyAccessRuleRepositories = "access_rules.repositories"
)

// Authorizers
const (
ViperKeyAuthorizerAllowIsEnabled = "authorizers.allow.enabled"

ViperKeyAuthorizerDenyIsEnabled = "authorizers.deny.enabled"

ViperKeyAuthorizerKetoEngineACPORYIsEnabled = "authorizers.keto_engine_acp_ory.enabled"
)

// Mutators
const (
ViperKeyMutatorCookieIsEnabled = "mutators.cookie.enabled"

ViperKeyMutatorHeaderIsEnabled = "mutators.header.enabled"

ViperKeyMutatorNoopIsEnabled = "mutators.noop.enabled"

ViperKeyMutatorHydratorIsEnabled = "mutators.hydrator.enabled"

ViperKeyMutatorIDTokenIsEnabled = "mutators.id_token.enabled"
ViperKeyMutatorIDTokenJWKSURL = "mutators.id_token.jwks_url"
)

// Authenticators
const (
// anonymous
ViperKeyAuthenticatorAnonymousIsEnabled = "authenticators.anonymous.enabled"

// noop
ViperKeyAuthenticatorNoopIsEnabled = "authenticators.noop.enabled"

// cookie session
ViperKeyAuthenticatorCookieSessionIsEnabled = "authenticators.cookie_session.enabled"

// jwt
ViperKeyAuthenticatorJWTIsEnabled = "authenticators.jwt.enabled"

// oauth2_client_credentials
ViperKeyAuthenticatorOAuth2ClientCredentialsIsEnabled = "authenticators.oauth2_client_credentials.enabled"

// oauth2_token_introspection
ViperKeyAuthenticatorOAuth2TokenIntrospectionIsEnabled = "authenticators.oauth2_introspection.enabled"

// unauthorized
ViperKeyAuthenticatorUnauthorizedIsEnabled = "authenticators.unauthorized.enabled"
)

func BindEnvs() {
if err := viper.BindEnv(
ViperKeyProxyReadTimeout,
@@ -148,9 +198,10 @@ func (v *ViperProvider) pipelineIsEnabled(prefix, id string) bool {
}

func (v *ViperProvider) PipelineConfig(prefix, id string, override json.RawMessage, dest interface{}) error {
config := viper.GetStringMap(fmt.Sprintf("%s.%s.config", prefix, id))
if len(config) == 0 {
return nil
// we need to create a copy for config otherwise we will accidentally override values
config, err := x.Deepcopy(viper.GetStringMap(fmt.Sprintf("%s.%s.config", prefix, id)))
if err != nil {
return errors.WithStack(err)
}

if len(override) != 0 {
@@ -159,47 +210,37 @@ func (v *ViperProvider) PipelineConfig(prefix, id string, override json.RawMessa
return errors.WithStack(err)
}

// we need to create a copy for config otherwise merge will override the viper values
tc := make(map[string]interface{})
for k, v := range config {
tc[k] = v
}

if err := mergo.Merge(&tc, &overrideMap, mergo.WithOverride); err != nil {
if err := mergo.Merge(&config, &overrideMap, mergo.WithOverride); err != nil {
return errors.WithStack(err)
}

config = tc

fmt.Printf("\n\n%+v\n\n", config)
}

var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(config); err != nil {
marshalled, err := json.Marshal(config)
if err != nil {
return errors.WithStack(err)
}

if dest != nil {
if err := jsonx.NewStrictDecoder(bytes.NewBuffer(marshalled)).Decode(dest); err != nil {
return errors.WithStack(err)
}
}

schema, err := schemas.Find(fmt.Sprintf("%s.%s.schema.json", prefix, id))
if err != nil {
return errors.WithStack(err)
}

if result, err := gojsonschema.Validate(
gojsonschema.NewBytesLoader(schema),
gojsonschema.NewBytesLoader(b.Bytes()),
gojsonschema.NewBytesLoader(marshalled),
); err != nil {
return errors.WithStack(err)
} else if !result.Valid() {
return errors.WithStack(result.Errors())
}

if dest == nil {
return nil
}

dec := json.NewDecoder(&b)
dec.DisallowUnknownFields()
return errors.WithStack(dec.Decode(dest))
return nil
}

func (v *ViperProvider) AuthenticatorIsEnabled(id string) bool {
31 changes: 21 additions & 10 deletions driver/configuration/provider_viper_public_test.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"net/url"
"reflect"
"testing"

"github.com/rs/cors"
@@ -42,18 +41,24 @@ func TestPipelineConfig(t *testing.T) {
p := NewViperProvider(logrus.New())

t.Run("case=should fail when invalid value is used in override", func(t *testing.T) {
require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"not-api":"invalid"}`), nil))
require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"this-key-does-not-exist":true}}`), nil))
require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"url":"not-a-url"}}`), nil))
res := json.RawMessage{}
require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"not-api":"invalid"}`), &res))
assert.JSONEq(t, `{"api":{"url":"https://some-url/"},"not-api":"invalid"}`, string(res))

require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"this-key-does-not-exist":true}}`), &res))
assert.JSONEq(t, `{"api":{"url":"https://some-url/","this-key-does-not-exist":true}}`, string(res))

require.Error(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"url":"not-a-url"}}`), &res))
assert.JSONEq(t, `{"api":{"url":"not-a-url"}}`, string(res))
})

t.Run("case=should pass and override values", func(t *testing.T) {
var dec mutate.MutatorHydratorConfig
require.NoError(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(``), &dec))
assert.Equal(t, "https://some-url/", dec.Api.URL)

require.NoError(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"url":"http://override-url/foo","retry":{"number":15}}}`), &dec))
assert.Equal(t, "https://override-url/foo", dec.Api.URL)
require.NoError(t, p.PipelineConfig("mutators", "hydrator", json.RawMessage(`{"api":{"url":"http://override-url/foo","retry":{"number_of_retries":15}}}`), &dec))
assert.Equal(t, "http://override-url/foo", dec.Api.URL)
assert.Equal(t, 15, dec.Api.Retry.NumberOfRetries)
})
}
@@ -67,7 +72,10 @@ func TestViperProvider(t *testing.T) {
logrus.New(),
)

require.NoError(t, viperx.Validate(gojsonschema.NewReferenceLoader("file://../../.schemas/config.schema.json")))
err := viperx.Validate(gojsonschema.NewReferenceLoader("file://../../.schemas/config.schema.json"))
if err != nil {
viperx.LoggerWithValidationErrorFields(logrus.New(), err).Error("unable to validate")
}
p := NewViperProvider(logrus.New())

t.Run("group=serve", func(t *testing.T) {
@@ -159,7 +167,7 @@ func TestViperProvider(t *testing.T) {
config, err := a.Config(nil)
require.NoError(t, err)

assert.Equal(t, "wildcard", reflect.ValueOf(config.ScopeStrategy).Pointer())
assert.Equal(t, "wildcard", config.ScopeStrategy)
assert.Equal(t, []string{
"https://my-website.com/.well-known/jwks.json",
"https://my-other-website.com/.well-known/jwks.json",
@@ -191,6 +199,7 @@ func TestViperProvider(t *testing.T) {
ClientSecret: "some_secret",
TokenURL: "https://my-website.com/oauth2/token",
Scope: []string{"foo", "bar"},
Enabled: true,
}, config.PreAuth)
})

@@ -278,6 +287,8 @@ func TestToScopeStrategy(t *testing.T) {
func TestAuthenticatorOAuth2TokenIntrospectionPreAuthorization(t *testing.T) {
viper.Reset()
v := NewViperProvider(logrus.New())
viper.Set("authenticators.oauth2_introspection.enabled", true)
viper.Set("authenticators.oauth2_introspection.config.introspection_url", "http://some-url/")

for k, tc := range []struct {
enabled bool
@@ -299,14 +310,14 @@ func TestAuthenticatorOAuth2TokenIntrospectionPreAuthorization(t *testing.T) {
t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
a := authn.NewAuthenticatorOAuth2Introspection(v)

config, err := a.Config(json.RawMessage(`{
config, err := a.Config(json.RawMessage(fmt.Sprintf(`{
"pre_authorization": {
"enabled": %v,
"client_id": "%v",
"client_secret": "%v",
"token_url": "%v"
}
}`))
}`, tc.enabled, tc.id, tc.secret, tc.turl)))

if tc.err {
assert.Error(t, err, "%+v", config)
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fsnotify/fsnotify v1.4.7
github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-openapi/analysis v0.19.0 // indirect
github.com/go-openapi/errors v0.19.0
github.com/go-openapi/inflect v0.19.0 // indirect
@@ -58,6 +57,8 @@ require (
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518
github.com/square/go-jose v2.3.1+incompatible
github.com/stretchr/testify v1.3.0
github.com/tidwall/gjson v1.3.2 // indirect
github.com/tidwall/sjson v1.0.4
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
github.com/toqueteos/webbrowser v1.1.0 // indirect
github.com/urfave/negroni v1.0.0
Loading