From cc03b58fecd54fa4dd67d21d48d2dcbf57e38fc1 Mon Sep 17 00:00:00 2001 From: kubadz Date: Thu, 8 Aug 2019 14:43:21 +0200 Subject: [PATCH 01/15] add new mutator and provide unit tests for it --- driver/configuration/provider.go | 2 + .../configuration/provider_viper_mutator.go | 6 + driver/registry_memory.go | 1 + go.sum | 2 + pipeline/authn/authenticator.go | 4 +- pipeline/mutate/mutator_enhancer.go | 62 +++++ pipeline/mutate/mutator_enhancer_test.go | 230 ++++++++++++++++++ 7 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 pipeline/mutate/mutator_enhancer.go create mode 100644 pipeline/mutate/mutator_enhancer_test.go diff --git a/driver/configuration/provider.go b/driver/configuration/provider.go index bf2669220d..fb0d0eea73 100644 --- a/driver/configuration/provider.go +++ b/driver/configuration/provider.go @@ -75,6 +75,8 @@ type ProviderMutators interface { MutatorIDTokenTTL() time.Duration MutatorNoopIsEnabled() bool + + MutatorEnhancerIsEnabled() bool } func MustValidate(l logrus.FieldLogger, p Provider) { diff --git a/driver/configuration/provider_viper_mutator.go b/driver/configuration/provider_viper_mutator.go index 257d2fc060..655731169b 100644 --- a/driver/configuration/provider_viper_mutator.go +++ b/driver/configuration/provider_viper_mutator.go @@ -14,6 +14,8 @@ const ( ViperKeyMutatorNoopIsEnabled = "mutators.noop.enabled" + ViperKeyMutatorEnhancerIsEnabled = "mutators.enhancer.enabled" + ViperKeyMutatorIDTokenIsEnabled = "mutators.id_token.enabled" ViperKeyMutatorIDTokenIssuerURL = "mutators.id_token.issuer_url" ViperKeyMutatorIDTokenJWKSURL = "mutators.id_token.jwks_url" @@ -51,3 +53,7 @@ func (v *ViperProvider) MutatorIDTokenTTL() time.Duration { func (v *ViperProvider) MutatorNoopIsEnabled() bool { return viperx.GetBool(v.l, ViperKeyMutatorNoopIsEnabled, false) } + +func (v *ViperProvider) MutatorEnhancerIsEnabled() bool { + return viperx.GetBool(v.l, ViperKeyMutatorEnhancerIsEnabled, false) +} diff --git a/driver/registry_memory.go b/driver/registry_memory.go index fbfd4cbf52..eb8bc291e1 100644 --- a/driver/registry_memory.go +++ b/driver/registry_memory.go @@ -335,6 +335,7 @@ func (r *RegistryMemory) prepareMutators() { mutate.NewMutatorHeader(r.c), mutate.NewMutatorIDToken(r.c, r), mutate.NewMutatorNoop(r.c), + mutate.NewMutatorEnhancer(r.c), } r.mutators = map[string]mutate.Mutator{} diff --git a/go.sum b/go.sum index c852b31951..86b0457f30 100644 --- a/go.sum +++ b/go.sum @@ -264,6 +264,7 @@ github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecU github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0= github.com/gobuffalo/packr v1.22.0 h1:/YVd/GRGsu0QuoCJtlcWSVllobs4q3Xvx3nqxTvPyN0= github.com/gobuffalo/packr v1.22.0/go.mod h1:Qr3Wtxr3+HuQEwWqlLnNW4t1oTvK+7Gc/Rnoi/lDFvA= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes= github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc= github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w= @@ -273,6 +274,7 @@ github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3 github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= github.com/gobuffalo/packr/v2 v2.0.0-rc.15 h1:vSmYcMO6CtuNQvMSbEJeIJlaeZzz2zoxGLTy8HrDh80= github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= +github.com/gobuffalo/packr/v2 v2.5.2 h1:4EvjeIpQLZuRIljwnidYgbRXbr1yIzVRrESiLjqKj6s= github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= diff --git a/pipeline/authn/authenticator.go b/pipeline/authn/authenticator.go index 5ff4ca449c..badaf5e387 100644 --- a/pipeline/authn/authenticator.go +++ b/pipeline/authn/authenticator.go @@ -24,6 +24,6 @@ type Authenticator interface { } type AuthenticationSession struct { - Subject string - Extra map[string]interface{} + Subject string `json:"subject"` + Extra map[string]interface{} `json:"extra"` } diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go new file mode 100644 index 0000000000..cc65a42624 --- /dev/null +++ b/pipeline/mutate/mutator_enhancer.go @@ -0,0 +1,62 @@ +/* + * Copyright © 2017-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2017-2018 Aeneas Rekkas + * @license Apache-2.0 + */ + +package mutate + +import ( + "encoding/json" + "github.com/ory/x/httpx" + "net/http" + + "github.com/pkg/errors" + + "github.com/ory/oathkeeper/driver/configuration" + "github.com/ory/oathkeeper/pipeline" + "github.com/ory/oathkeeper/pipeline/authn" +) + +var ErrMalformedResponseFromUpstreamAPI = errors.New("The call to an external API returned an invalid JSON object") +var ErrMissingAPIURL = errors.New("Missing URL in mutator configuration") +var ErrInvalidAPIURL = errors.New("Invalid URL in mutator configuration") +var ErrNon200ResponseFromAPI = errors.New("The call to an external API returned a non-200 HTTP response") + +type MutatorEnhancer struct { + c configuration.Provider + client *http.Client +} + +func NewMutatorEnhancer(c configuration.Provider) *MutatorEnhancer { + return &MutatorEnhancer{c: c, client: httpx.NewResilientClientLatencyToleranceSmall(nil)} +} + +func (a *MutatorEnhancer) GetID() string { + return "enhancer" +} + +func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) (http.Header, error) { + return nil, nil +} + +func (a *MutatorEnhancer) Validate() error { + if !a.c.MutatorEnhancerIsEnabled() { + return errors.WithStack(ErrMutatorNotEnabled.WithReasonf(`Mutator "%s" is disabled per configuration.`, a.GetID())) + } + return nil +} diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go new file mode 100644 index 0000000000..dee9d2c045 --- /dev/null +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -0,0 +1,230 @@ +package mutate_test + +import ( + "encoding/json" + "fmt" + "github.com/julienschmidt/httprouter" + "github.com/ory/oathkeeper/pipeline/authn" + "github.com/ory/oathkeeper/pipeline/mutate" + "github.com/ory/oathkeeper/rule" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/ory/viper" + + "github.com/ory/oathkeeper/driver/configuration" + "github.com/ory/oathkeeper/internal" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func setExtra(key string, value interface{}) func(a *authn.AuthenticationSession) { + return func(a *authn.AuthenticationSession) { + if a.Extra == nil { + a.Extra = make(map[string]interface{}) + } + a.Extra[key] = value + } +} + +func newAuthenticationSession(modifications ...func(a *authn.AuthenticationSession)) *authn.AuthenticationSession { + a := authn.AuthenticationSession{} + for _, f := range modifications { + f(&a) + } + return &a +} + +func defaultRouterSetup(actions ...func(a *authn.AuthenticationSession)) func(t *testing.T, router *httprouter.Router) { + return func(t *testing.T, router *httprouter.Router) { + router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + body, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + var data authn.AuthenticationSession + err = json.Unmarshal(body, &data) + require.NoError(t, err) + for _, f := range actions { + f(&data) + } + jsonData, err := json.Marshal(data) + require.NoError(t, err) + w.WriteHeader(http.StatusOK) + _, err = w.Write(jsonData) + require.NoError(t, err) + // TODO: Debug only + t.Logf("json response from API: %s", string(jsonData)) + }) + } +} + +func defaultConfigForMutator() func(*httptest.Server) json.RawMessage { + return func(s *httptest.Server) json.RawMessage { + return []byte(fmt.Sprintf(`{"api": {"url": "%s"}}`, s.URL)) + } +} + +func TestMutatorEnhancer(t *testing.T) { + conf := internal.NewConfigurationWithDefaults() + reg := internal.NewRegistry(conf) + + a, err := reg.PipelineMutator("enhancer") + require.NoError(t, err) + assert.Equal(t, "enhancer", a.GetID()) + + t.Run("method=mutate", func(t *testing.T) { + sampleKey := "foo" + sampleValue := "bar" + complexValueKey := "complex" + sampleComplexValue := struct { + foo string + oof int + bar float32 + rab bool + }{"hello", 7, 3.14, true} + + var testMap = map[string]struct { + Setup func(*testing.T, *httprouter.Router) + Session *authn.AuthenticationSession + Rule *rule.Rule + Config func(*httptest.Server) json.RawMessage + Request *http.Request + Match *authn.AuthenticationSession + Err error + }{ + "Extras From API": { + Setup: defaultRouterSetup(setExtra(sampleKey, sampleValue)), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, + "Override Extras": { + Setup: defaultRouterSetup(setExtra(sampleKey, sampleValue)), + Session: newAuthenticationSession(setExtra(sampleKey, "initialValue")), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, + "Multiple Nested Extras": { + Setup: defaultRouterSetup(setExtra(sampleKey, sampleValue), setExtra(complexValueKey, sampleComplexValue)), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue), setExtra(complexValueKey, sampleComplexValue)), + Err: nil, + }, + "No Changes": { + Setup: defaultRouterSetup(), + Session: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, + "Empty Response": { + Setup: func(t *testing.T, router *httprouter.Router) { + router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + w.WriteHeader(http.StatusOK) + _, err = w.Write([]byte(`{}`)) + require.NoError(t, err) + }) + }, + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: mutate.ErrMalformedResponseFromUpstreamAPI, + }, + "Missing API URL": { + Setup: defaultRouterSetup(), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: func(s *httptest.Server) json.RawMessage { + return []byte(`{"api": {"foo": "bar"}}`) + }, + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: mutate.ErrMissingAPIURL, + }, + "Server Error": { + Setup: func(t *testing.T, router *httprouter.Router) { + router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + w.WriteHeader(http.StatusInternalServerError) + }) + }, + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: mutate.ErrNon200ResponseFromAPI, + }, + "Wrong API URL": { + Setup: defaultRouterSetup(), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: func(s *httptest.Server) json.RawMessage { + return []byte(`{"api": {"url": "ZGVmaW5pdGVseU5vdFZhbGlkVXJs"}}`) + }, + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: mutate.ErrInvalidAPIURL, + }, + } + t.Run("caching=off", func(t *testing.T) { + for testName, specs := range testMap { + t.Run(testName, func(t *testing.T) { + router := httprouter.New() + var ts *httptest.Server + if specs.Setup != nil { + specs.Setup(t, router) + } + ts = httptest.NewServer(router) + defer ts.Close() + + _, err := a.Mutate(specs.Request, specs.Session, specs.Config(ts), specs.Rule) + if specs.Err == nil { + // Issuer must run without error + require.NoError(t, err) + } else { + assert.EqualError(t, err, specs.Err.Error()) + } + + assert.Equal(t, specs.Match, specs.Session) + }) + } + }) + // TODO: add tests with caching + }) + + t.Run("method=validate", func(t *testing.T) { + for k, testCase := range []struct { + enabled bool + apiUrl string + shouldPass bool + }{ + {enabled: false, shouldPass: false}, + {enabled: true, shouldPass: true}, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + viper.Set(configuration.ViperKeyMutatorEnhancerIsEnabled, testCase.enabled) + + if testCase.shouldPass { + require.NoError(t, a.Validate()) + } else { + require.Error(t, a.Validate()) + } + }) + } + }) +} From 76a0739a3c24a78c4ff9d3cb749d370e12bd5826 Mon Sep 17 00:00:00 2001 From: kubadz Date: Fri, 9 Aug 2019 11:49:54 +0200 Subject: [PATCH 02/15] add mutator implementation --- pipeline/mutate/mutator_enhancer.go | 67 ++++++++++++++++++++++-- pipeline/mutate/mutator_enhancer_test.go | 37 +++++++------ 2 files changed, 85 insertions(+), 19 deletions(-) diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index cc65a42624..45b47b8a2d 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -21,9 +21,11 @@ package mutate import ( + "bytes" "encoding/json" "github.com/ory/x/httpx" "net/http" + "net/url" "github.com/pkg/errors" @@ -32,16 +34,25 @@ import ( "github.com/ory/oathkeeper/pipeline/authn" ) -var ErrMalformedResponseFromUpstreamAPI = errors.New("The call to an external API returned an invalid JSON object") -var ErrMissingAPIURL = errors.New("Missing URL in mutator configuration") -var ErrInvalidAPIURL = errors.New("Invalid URL in mutator configuration") -var ErrNon200ResponseFromAPI = errors.New("The call to an external API returned a non-200 HTTP response") +var ErrMalformedResponseFromUpstreamAPI = "The call to an external API returned an invalid JSON object" +var ErrMissingAPIURL = "Missing URL in mutator configuration" +var ErrInvalidAPIURL = "Invalid URL in mutator configuration" +var ErrNon200ResponseFromAPI = "The call to an external API returned a non-200 HTTP response" type MutatorEnhancer struct { c configuration.Provider client *http.Client } +type externalAPIConfig struct { + Url string `json:"url"` + // TODO: add retry config +} + +type MutatorEnhancerConfig struct { + Api externalAPIConfig `json:"api"` +} + func NewMutatorEnhancer(c configuration.Provider) *MutatorEnhancer { return &MutatorEnhancer{c: c, client: httpx.NewResilientClientLatencyToleranceSmall(nil)} } @@ -51,6 +62,54 @@ func (a *MutatorEnhancer) GetID() string { } func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) (http.Header, error) { + if len(config) == 0 { + config = []byte("{}") + } + var cfg MutatorEnhancerConfig + d := json.NewDecoder(bytes.NewBuffer(config)) + d.DisallowUnknownFields() + if err := d.Decode(&cfg); err != nil { + return nil, errors.WithStack(err) + } + + var b bytes.Buffer + err := json.NewEncoder(&b).Encode(session) + if err != nil { + return nil, errors.WithStack(err) + } + + if cfg.Api.Url == "" { + return nil, errors.New(ErrMissingAPIURL) + } else if _, err := url.ParseRequestURI(cfg.Api.Url); err != nil { + return nil, errors.New(ErrInvalidAPIURL) + } + req, err := http.NewRequest("POST", cfg.Api.Url, &b) + if err != nil { + return nil, errors.WithStack(err) + } + for key, values := range r.Header { + for _, value := range values { + req.Header.Add(key, value) + } + } + + res, err := a.client.Do(req) + if err != nil { + return nil, errors.WithStack(err) + } + if res.StatusCode != http.StatusOK { + return nil, errors.New(ErrNon200ResponseFromAPI) + } + sessionFromUpstream := authn.AuthenticationSession{} + err = json.NewDecoder(res.Body).Decode(&sessionFromUpstream) + if err != nil { + return nil, errors.WithStack(err) + } + if sessionFromUpstream.Extra == nil || sessionFromUpstream.Subject != session.Subject { // TODO: should API be able to modify subject? + return nil, errors.New(ErrMalformedResponseFromUpstreamAPI) + } + *session = sessionFromUpstream + return nil, nil } diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go index dee9d2c045..902e28b1a2 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -2,6 +2,7 @@ package mutate_test import ( "encoding/json" + "errors" "fmt" "github.com/julienschmidt/httprouter" "github.com/ory/oathkeeper/pipeline/authn" @@ -54,8 +55,6 @@ func defaultRouterSetup(actions ...func(a *authn.AuthenticationSession)) func(t w.WriteHeader(http.StatusOK) _, err = w.Write(jsonData) require.NoError(t, err) - // TODO: Debug only - t.Logf("json response from API: %s", string(jsonData)) }) } } @@ -78,13 +77,10 @@ func TestMutatorEnhancer(t *testing.T) { sampleKey := "foo" sampleValue := "bar" complexValueKey := "complex" - sampleComplexValue := struct { - foo string - oof int - bar float32 - rab bool - }{"hello", 7, 3.14, true} - + sampleComplexValue := map[string]interface{}{ + "foo": "hello", + "bar": 3.14, + } var testMap = map[string]struct { Setup func(*testing.T, *httprouter.Router) Session *authn.AuthenticationSession @@ -143,9 +139,20 @@ func TestMutatorEnhancer(t *testing.T) { Config: defaultConfigForMutator(), Request: &http.Request{}, Match: newAuthenticationSession(), - Err: mutate.ErrMalformedResponseFromUpstreamAPI, + Err: errors.New(mutate.ErrMalformedResponseFromUpstreamAPI), }, "Missing API URL": { + Setup: defaultRouterSetup(), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: func(s *httptest.Server) json.RawMessage { + return []byte(`{"api": {}}`) + }, + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: errors.New(mutate.ErrMissingAPIURL), + }, + "Improper Config": { Setup: defaultRouterSetup(), Session: newAuthenticationSession(), Rule: &rule.Rule{ID: "test-rule"}, @@ -154,12 +161,12 @@ func TestMutatorEnhancer(t *testing.T) { }, Request: &http.Request{}, Match: newAuthenticationSession(), - Err: mutate.ErrMissingAPIURL, + Err: errors.New(`json: unknown field "foo"`), }, - "Server Error": { + "Not Found": { Setup: func(t *testing.T, router *httprouter.Router) { router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusNotFound) }) }, Session: newAuthenticationSession(), @@ -167,7 +174,7 @@ func TestMutatorEnhancer(t *testing.T) { Config: defaultConfigForMutator(), Request: &http.Request{}, Match: newAuthenticationSession(), - Err: mutate.ErrNon200ResponseFromAPI, + Err: errors.New(mutate.ErrNon200ResponseFromAPI), }, "Wrong API URL": { Setup: defaultRouterSetup(), @@ -178,7 +185,7 @@ func TestMutatorEnhancer(t *testing.T) { }, Request: &http.Request{}, Match: newAuthenticationSession(), - Err: mutate.ErrInvalidAPIURL, + Err: errors.New(mutate.ErrInvalidAPIURL), }, } t.Run("caching=off", func(t *testing.T) { From 9f1514d765902a7bcd2ed3039a6cadf2857fdf37 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 07:57:39 +0200 Subject: [PATCH 03/15] add tests and structures for basic auth --- pipeline/mutate/mutator_enhancer.go | 14 ++++- pipeline/mutate/mutator_enhancer_test.go | 72 +++++++++++++++++++++--- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index 45b47b8a2d..44e32ac57f 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -38,14 +38,26 @@ var ErrMalformedResponseFromUpstreamAPI = "The call to an external API returned var ErrMissingAPIURL = "Missing URL in mutator configuration" var ErrInvalidAPIURL = "Invalid URL in mutator configuration" var ErrNon200ResponseFromAPI = "The call to an external API returned a non-200 HTTP response" +var ErrInvalidCredentials = "Invalid credentials were provided in mutator configuration" +var ErrNoCredentialsProvided = "No credentials were provided in mutator configuration" type MutatorEnhancer struct { c configuration.Provider client *http.Client } +type BasicAuthn struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type Authentication struct { + Basic BasicAuthn `json:"basic"` +} + type externalAPIConfig struct { - Url string `json:"url"` + Url string `json:"url"` + Authn Authentication `json:"authn"` // TODO: add retry config } diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go index 902e28b1a2..322affe3c8 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -39,8 +39,11 @@ func newAuthenticationSession(modifications ...func(a *authn.AuthenticationSessi return &a } -func defaultRouterSetup(actions ...func(a *authn.AuthenticationSession)) func(t *testing.T, router *httprouter.Router) { - return func(t *testing.T, router *httprouter.Router) { +type routerSetupFunction func(t *testing.T) http.Handler + +func defaultRouterSetup(actions ...func(a *authn.AuthenticationSession)) routerSetupFunction { + return func(t *testing.T) http.Handler { + router := httprouter.New() router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { body, err := ioutil.ReadAll(r.Body) require.NoError(t, err) @@ -56,6 +59,21 @@ func defaultRouterSetup(actions ...func(a *authn.AuthenticationSession)) func(t _, err = w.Write(jsonData) require.NoError(t, err) }) + return router + } +} + +func withBasicAuth(f routerSetupFunction, user, password string) routerSetupFunction { + return func(t *testing.T) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + u, p, ok := r.BasicAuth() + if !ok || u != user || p != password { + w.WriteHeader(http.StatusUnauthorized) + return + } + h := f(t) + h.ServeHTTP(w, r) + }) } } @@ -65,6 +83,12 @@ func defaultConfigForMutator() func(*httptest.Server) json.RawMessage { } } +func configWithBasicAuthnForMutator(user, password string) func(*httptest.Server) json.RawMessage { + return func(s *httptest.Server) json.RawMessage { + return []byte(fmt.Sprintf(`{"api": {"url": "%s", "authn": {"basic": {"username": "%s", "password": "%s"}}}}`, s.URL, user, password)) + } +} + func TestMutatorEnhancer(t *testing.T) { conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistry(conf) @@ -81,8 +105,11 @@ func TestMutatorEnhancer(t *testing.T) { "foo": "hello", "bar": 3.14, } + sampleUserId := "user" + sampleValidPassword := "passwd1" + sampleNotValidPassword := "passwd7" var testMap = map[string]struct { - Setup func(*testing.T, *httprouter.Router) + Setup func(*testing.T) http.Handler Session *authn.AuthenticationSession Rule *rule.Rule Config func(*httptest.Server) json.RawMessage @@ -127,12 +154,14 @@ func TestMutatorEnhancer(t *testing.T) { Err: nil, }, "Empty Response": { - Setup: func(t *testing.T, router *httprouter.Router) { + Setup: func(t *testing.T) http.Handler { + router := httprouter.New() router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusOK) _, err = w.Write([]byte(`{}`)) require.NoError(t, err) }) + return router }, Session: newAuthenticationSession(), Rule: &rule.Rule{ID: "test-rule"}, @@ -164,10 +193,12 @@ func TestMutatorEnhancer(t *testing.T) { Err: errors.New(`json: unknown field "foo"`), }, "Not Found": { - Setup: func(t *testing.T, router *httprouter.Router) { + Setup: func(t *testing.T) http.Handler { + router := httprouter.New() router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusNotFound) }) + return router }, Session: newAuthenticationSession(), Rule: &rule.Rule{ID: "test-rule"}, @@ -187,14 +218,41 @@ func TestMutatorEnhancer(t *testing.T) { Match: newAuthenticationSession(), Err: errors.New(mutate.ErrInvalidAPIURL), }, + "Successful Basic Authentication": { + Setup: withBasicAuth(defaultRouterSetup(setExtra(sampleKey, sampleValue)), sampleUserId, sampleValidPassword), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: configWithBasicAuthnForMutator(sampleUserId, sampleValidPassword), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, + "Invalid Basic Credentials": { + Setup: withBasicAuth(defaultRouterSetup(setExtra(sampleKey, sampleValue)), sampleUserId, sampleValidPassword), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: configWithBasicAuthnForMutator(sampleUserId, sampleNotValidPassword), + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: errors.New(mutate.ErrInvalidCredentials), + }, + "No Basic Credentials": { + Setup: withBasicAuth(defaultRouterSetup(setExtra(sampleKey, sampleValue)), sampleUserId, sampleValidPassword), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(), + Err: errors.New(mutate.ErrNoCredentialsProvided), + }, } t.Run("caching=off", func(t *testing.T) { for testName, specs := range testMap { t.Run(testName, func(t *testing.T) { - router := httprouter.New() + var router http.Handler var ts *httptest.Server if specs.Setup != nil { - specs.Setup(t, router) + router = specs.Setup(t) } ts = httptest.NewServer(router) defer ts.Close() From 857c4888f912bf1b4317a3f494719d7f617d54e8 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 08:24:15 +0200 Subject: [PATCH 04/15] add basic auth --- pipeline/mutate/mutator_enhancer.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index 44e32ac57f..cc8d6b6a6a 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -56,8 +56,8 @@ type Authentication struct { } type externalAPIConfig struct { - Url string `json:"url"` - Authn Authentication `json:"authn"` + Url string `json:"url"` + Authn *Authentication `json:"authn,omitempty"` // TODO: add retry config } @@ -104,12 +104,25 @@ func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationS req.Header.Add(key, value) } } + if cfg.Api.Authn != nil { + credentials := cfg.Api.Authn.Basic + req.SetBasicAuth(credentials.Username, credentials.Password) + } res, err := a.client.Do(req) if err != nil { return nil, errors.WithStack(err) } - if res.StatusCode != http.StatusOK { + switch res.StatusCode { + case http.StatusOK: + break + case http.StatusUnauthorized: + if cfg.Api.Authn != nil { + return nil, errors.New(ErrInvalidCredentials) + } else { + return nil, errors.New(ErrNoCredentialsProvided) + } + default: return nil, errors.New(ErrNon200ResponseFromAPI) } sessionFromUpstream := authn.AuthenticationSession{} From 75edb07fcbb5f1b4c6f8b9e977d53862e08c7df9 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 10:47:40 +0200 Subject: [PATCH 05/15] add test and structures for retry --- pipeline/mutate/mutator_enhancer.go | 7 +++++- pipeline/mutate/mutator_enhancer_test.go | 30 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index cc8d6b6a6a..f0821fc2e1 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -55,10 +55,15 @@ type Authentication struct { Basic BasicAuthn `json:"basic"` } +type RetryConfig struct { + Number int `json:"number"` + DelayInSeconds int `json:"delayInSeconds"` +} + type externalAPIConfig struct { Url string `json:"url"` Authn *Authentication `json:"authn,omitempty"` - // TODO: add retry config + Retry RetryConfig `json:"retry"` } type MutatorEnhancerConfig struct { diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go index 322affe3c8..957634a874 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -77,6 +77,21 @@ func withBasicAuth(f routerSetupFunction, user, password string) routerSetupFunc } } +func withInitialErrors(f routerSetupFunction, numberOfErrorResponses, httpStatusCode int) routerSetupFunction { + return func(t *testing.T) http.Handler { + counter := 0 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if counter < numberOfErrorResponses { + w.WriteHeader(httpStatusCode) + counter++ + return + } + h := f(t) + h.ServeHTTP(w, r) + }) + } +} + func defaultConfigForMutator() func(*httptest.Server) json.RawMessage { return func(s *httptest.Server) json.RawMessage { return []byte(fmt.Sprintf(`{"api": {"url": "%s"}}`, s.URL)) @@ -89,6 +104,12 @@ func configWithBasicAuthnForMutator(user, password string) func(*httptest.Server } } +func configWithRetriesForMutator(numberOfRetries, retriesDelayInSeconds int) func(*httptest.Server) json.RawMessage { + return func(s *httptest.Server) json.RawMessage { + return []byte(fmt.Sprintf(`{"api": {"url": "%s", "retry": {"number": %d, "delayInSeconds": %d}}}`, s.URL, numberOfRetries, retriesDelayInSeconds)) + } +} + func TestMutatorEnhancer(t *testing.T) { conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistry(conf) @@ -245,6 +266,15 @@ func TestMutatorEnhancer(t *testing.T) { Match: newAuthenticationSession(), Err: errors.New(mutate.ErrNoCredentialsProvided), }, + "Third Time Lucky": { + Setup: withInitialErrors(defaultRouterSetup(setExtra(sampleKey, sampleValue)), 2, http.StatusInternalServerError), + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: configWithRetriesForMutator(3, 1), + Request: &http.Request{}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, } t.Run("caching=off", func(t *testing.T) { for testName, specs := range testMap { From c28ce7f5bd54e469dca4d3bb8c402558257ad6c4 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 11:37:15 +0200 Subject: [PATCH 06/15] add retries + move constants to const section --- go.mod | 1 + pipeline/mutate/mutator_enhancer.go | 61 +++++++++++++++--------- pipeline/mutate/mutator_enhancer_test.go | 6 +-- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index be3593a33f..8012c4b28d 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7 github.com/bxcodec/faker v2.0.1+incompatible + github.com/cenkalti/backoff v2.1.1+incompatible github.com/codegangsta/negroni v1.0.0 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fsnotify/fsnotify v1.4.7 diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index f0821fc2e1..935a5706f1 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -23,9 +23,11 @@ package mutate import ( "bytes" "encoding/json" + "github.com/cenkalti/backoff" "github.com/ory/x/httpx" "net/http" "net/url" + "time" "github.com/pkg/errors" @@ -34,12 +36,16 @@ import ( "github.com/ory/oathkeeper/pipeline/authn" ) -var ErrMalformedResponseFromUpstreamAPI = "The call to an external API returned an invalid JSON object" -var ErrMissingAPIURL = "Missing URL in mutator configuration" -var ErrInvalidAPIURL = "Invalid URL in mutator configuration" -var ErrNon200ResponseFromAPI = "The call to an external API returned a non-200 HTTP response" -var ErrInvalidCredentials = "Invalid credentials were provided in mutator configuration" -var ErrNoCredentialsProvided = "No credentials were provided in mutator configuration" +const ( + ErrMalformedResponseFromUpstreamAPI = "The call to an external API returned an invalid JSON object" + ErrMissingAPIURL = "Missing URL in mutator configuration" + ErrInvalidAPIURL = "Invalid URL in mutator configuration" + ErrNon200ResponseFromAPI = "The call to an external API returned a non-200 HTTP response" + ErrInvalidCredentials = "Invalid credentials were provided in mutator configuration" + ErrNoCredentialsProvided = "No credentials were provided in mutator configuration" + defaultNumberOfRetries = 3 + defaultDelayInMilliseconds = 100 +) type MutatorEnhancer struct { c configuration.Provider @@ -56,14 +62,14 @@ type Authentication struct { } type RetryConfig struct { - Number int `json:"number"` - DelayInSeconds int `json:"delayInSeconds"` + NumberOfRetries int `json:"number"` + DelayInMilliseconds int `json:"delayInMilliseconds"` } type externalAPIConfig struct { Url string `json:"url"` Authn *Authentication `json:"authn,omitempty"` - Retry RetryConfig `json:"retry"` + Retry *RetryConfig `json:"retry,omitempty"` } type MutatorEnhancerConfig struct { @@ -114,22 +120,33 @@ func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationS req.SetBasicAuth(credentials.Username, credentials.Password) } - res, err := a.client.Do(req) - if err != nil { - return nil, errors.WithStack(err) + retryConfig := RetryConfig{defaultNumberOfRetries, defaultDelayInMilliseconds} + if cfg.Api.Retry != nil { + retryConfig = *cfg.Api.Retry } - switch res.StatusCode { - case http.StatusOK: - break - case http.StatusUnauthorized: - if cfg.Api.Authn != nil { - return nil, errors.New(ErrInvalidCredentials) - } else { - return nil, errors.New(ErrNoCredentialsProvided) + var res *http.Response + err = backoff.Retry(func() error { + res, err = a.client.Do(req) + if err != nil { + return errors.WithStack(err) } - default: - return nil, errors.New(ErrNon200ResponseFromAPI) + switch res.StatusCode { + case http.StatusOK: + return nil + case http.StatusUnauthorized: + if cfg.Api.Authn != nil { + return errors.New(ErrInvalidCredentials) + } else { + return errors.New(ErrNoCredentialsProvided) + } + default: + return errors.New(ErrNon200ResponseFromAPI) + } + }, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Millisecond*time.Duration(retryConfig.DelayInMilliseconds)), uint64(retryConfig.NumberOfRetries))) + if err != nil { + return nil, err } + sessionFromUpstream := authn.AuthenticationSession{} err = json.NewDecoder(res.Body).Decode(&sessionFromUpstream) if err != nil { diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go index 957634a874..38119ab892 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -104,9 +104,9 @@ func configWithBasicAuthnForMutator(user, password string) func(*httptest.Server } } -func configWithRetriesForMutator(numberOfRetries, retriesDelayInSeconds int) func(*httptest.Server) json.RawMessage { +func configWithRetriesForMutator(numberOfRetries, retriesDelayInMilliseconds int) func(*httptest.Server) json.RawMessage { return func(s *httptest.Server) json.RawMessage { - return []byte(fmt.Sprintf(`{"api": {"url": "%s", "retry": {"number": %d, "delayInSeconds": %d}}}`, s.URL, numberOfRetries, retriesDelayInSeconds)) + return []byte(fmt.Sprintf(`{"api": {"url": "%s", "retry": {"number": %d, "delayInMilliseconds": %d}}}`, s.URL, numberOfRetries, retriesDelayInMilliseconds)) } } @@ -270,7 +270,7 @@ func TestMutatorEnhancer(t *testing.T) { Setup: withInitialErrors(defaultRouterSetup(setExtra(sampleKey, sampleValue)), 2, http.StatusInternalServerError), Session: newAuthenticationSession(), Rule: &rule.Rule{ID: "test-rule"}, - Config: configWithRetriesForMutator(3, 1), + Config: configWithRetriesForMutator(3, 100), Request: &http.Request{}, Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), Err: nil, From ca0b4575f3a6401c4e0aa89f625cf64f6e3e1d34 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 13:27:13 +0200 Subject: [PATCH 07/15] remove todo comments + add test for authn header override --- pipeline/mutate/mutator_enhancer.go | 2 +- pipeline/mutate/mutator_enhancer_test.go | 65 ++++++++++++++++-------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_enhancer.go index 935a5706f1..06bd9c718b 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_enhancer.go @@ -152,7 +152,7 @@ func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationS if err != nil { return nil, errors.WithStack(err) } - if sessionFromUpstream.Extra == nil || sessionFromUpstream.Subject != session.Subject { // TODO: should API be able to modify subject? + if sessionFromUpstream.Extra == nil || sessionFromUpstream.Subject != session.Subject { return nil, errors.New(ErrMalformedResponseFromUpstreamAPI) } *session = sessionFromUpstream diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_enhancer_test.go index 38119ab892..7a48daeade 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_enhancer_test.go @@ -266,6 +266,28 @@ func TestMutatorEnhancer(t *testing.T) { Match: newAuthenticationSession(), Err: errors.New(mutate.ErrNoCredentialsProvided), }, + "Should Replace Authn Header": { + Setup: func(t *testing.T) http.Handler { + router := httprouter.New() + router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + authnHeaders := r.Header["Authentication"] + assert.Equal(t, len(authnHeaders), 1) + user, passwd, ok := r.BasicAuth() + assert.True(t, ok) + assert.Equal(t, user, sampleUserId) + assert.Equal(t, passwd, sampleValidPassword) + h := defaultRouterSetup(setExtra(sampleKey, sampleValue))(t) + h.ServeHTTP(w, r) + }) + return router + }, + Session: newAuthenticationSession(), + Rule: &rule.Rule{ID: "test-rule"}, + Config: configWithBasicAuthnForMutator(sampleUserId, sampleValidPassword), + Request: &http.Request{Header: http.Header{"Authentication": []string{"Bearer sample"}}}, + Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), + Err: nil, + }, "Third Time Lucky": { Setup: withInitialErrors(defaultRouterSetup(setExtra(sampleKey, sampleValue)), 2, http.StatusInternalServerError), Session: newAuthenticationSession(), @@ -276,30 +298,29 @@ func TestMutatorEnhancer(t *testing.T) { Err: nil, }, } - t.Run("caching=off", func(t *testing.T) { - for testName, specs := range testMap { - t.Run(testName, func(t *testing.T) { - var router http.Handler - var ts *httptest.Server - if specs.Setup != nil { - router = specs.Setup(t) - } - ts = httptest.NewServer(router) - defer ts.Close() - _, err := a.Mutate(specs.Request, specs.Session, specs.Config(ts), specs.Rule) - if specs.Err == nil { - // Issuer must run without error - require.NoError(t, err) - } else { - assert.EqualError(t, err, specs.Err.Error()) - } + for testName, specs := range testMap { + t.Run(testName, func(t *testing.T) { + var router http.Handler + var ts *httptest.Server + if specs.Setup != nil { + router = specs.Setup(t) + } + ts = httptest.NewServer(router) + defer ts.Close() + + _, err := a.Mutate(specs.Request, specs.Session, specs.Config(ts), specs.Rule) + if specs.Err == nil { + // Issuer must run without error + require.NoError(t, err) + } else { + assert.EqualError(t, err, specs.Err.Error()) + } + + assert.Equal(t, specs.Match, specs.Session) + }) + } - assert.Equal(t, specs.Match, specs.Session) - }) - } - }) - // TODO: add tests with caching }) t.Run("method=validate", func(t *testing.T) { From b1e436f44320afe009dd1a8358457e8f8a64ec07 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 14:18:17 +0200 Subject: [PATCH 08/15] rename mutator to 'Hydrator' + update schema --- .schemas/config.schema.json | 12 +++++++++++ docs/.oathkeeper.yaml | 5 +++++ driver/configuration/provider.go | 2 +- driver/configuration/provider_viper.go | 1 + .../configuration/provider_viper_mutator.go | 6 +++--- driver/configuration/provider_viper_test.go | 4 ++++ driver/registry_memory.go | 2 +- ...utator_enhancer.go => mutator_hydrator.go} | 20 +++++++++---------- ...ancer_test.go => mutator_hydrator_test.go} | 8 ++++---- 9 files changed, 41 insertions(+), 19 deletions(-) rename pipeline/mutate/{mutator_enhancer.go => mutator_hydrator.go} (91%) rename pipeline/mutate/{mutator_enhancer_test.go => mutator_hydrator_test.go} (98%) diff --git a/.schemas/config.schema.json b/.schemas/config.schema.json index 281c846ebf..26fd383bd6 100644 --- a/.schemas/config.schema.json +++ b/.schemas/config.schema.json @@ -441,6 +441,18 @@ } } }, + "hydrator": { + "type": "object", + "title": "Hydrator", + "description": "The [`hydrator` mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#hydrator).", + "additionalProperties": false, + "properties": { + "enabled": { + "title": "Enabled", + "type": "boolean" + } + } + }, "id_token": { "type": "object", "title": "ID Token (JSON Web Token)", diff --git a/docs/.oathkeeper.yaml b/docs/.oathkeeper.yaml index 805763f268..84306613a2 100644 --- a/docs/.oathkeeper.yaml +++ b/docs/.oathkeeper.yaml @@ -211,6 +211,11 @@ mutators: # Set enabled to true if the mutator should be enabled and false to disable the mutator. Defaults to false. enabled: true + # Configures the hydrator mutator + hydrator: + # Set enabled to true if the mutator should be enabled and false to disable the mutator. Defaults to false. + enabled: true + # Configures the id_token mutator id_token: # Set enabled to true if the mutator should be enabled and false to disable the mutator. Defaults to false. diff --git a/driver/configuration/provider.go b/driver/configuration/provider.go index fb0d0eea73..28ac7d3f1b 100644 --- a/driver/configuration/provider.go +++ b/driver/configuration/provider.go @@ -76,7 +76,7 @@ type ProviderMutators interface { MutatorNoopIsEnabled() bool - MutatorEnhancerIsEnabled() bool + MutatorHydratorIsEnabled() bool } func MustValidate(l logrus.FieldLogger, p Provider) { diff --git a/driver/configuration/provider_viper.go b/driver/configuration/provider_viper.go index bbfffe218c..db994accfb 100644 --- a/driver/configuration/provider_viper.go +++ b/driver/configuration/provider_viper.go @@ -67,6 +67,7 @@ func BindEnvs() { ViperKeyMutatorCookieIsEnabled, ViperKeyMutatorHeaderIsEnabled, ViperKeyMutatorNoopIsEnabled, + ViperKeyMutatorHydratorIsEnabled, ViperKeyMutatorIDTokenIsEnabled, ViperKeyMutatorIDTokenIssuerURL, ViperKeyMutatorIDTokenJWKSURL, diff --git a/driver/configuration/provider_viper_mutator.go b/driver/configuration/provider_viper_mutator.go index 655731169b..c45eb5a3d1 100644 --- a/driver/configuration/provider_viper_mutator.go +++ b/driver/configuration/provider_viper_mutator.go @@ -14,7 +14,7 @@ const ( ViperKeyMutatorNoopIsEnabled = "mutators.noop.enabled" - ViperKeyMutatorEnhancerIsEnabled = "mutators.enhancer.enabled" + ViperKeyMutatorHydratorIsEnabled = "mutators.Hydrator.enabled" ViperKeyMutatorIDTokenIsEnabled = "mutators.id_token.enabled" ViperKeyMutatorIDTokenIssuerURL = "mutators.id_token.issuer_url" @@ -54,6 +54,6 @@ func (v *ViperProvider) MutatorNoopIsEnabled() bool { return viperx.GetBool(v.l, ViperKeyMutatorNoopIsEnabled, false) } -func (v *ViperProvider) MutatorEnhancerIsEnabled() bool { - return viperx.GetBool(v.l, ViperKeyMutatorEnhancerIsEnabled, false) +func (v *ViperProvider) MutatorHydratorIsEnabled() bool { + return viperx.GetBool(v.l, ViperKeyMutatorHydratorIsEnabled, false) } diff --git a/driver/configuration/provider_viper_test.go b/driver/configuration/provider_viper_test.go index ce87871d14..2478057d28 100644 --- a/driver/configuration/provider_viper_test.go +++ b/driver/configuration/provider_viper_test.go @@ -162,6 +162,10 @@ func TestViperProvider(t *testing.T) { assert.True(t, p.MutatorHeaderIsEnabled()) }) + t.Run("mutator=hydrator", func(t *testing.T) { + assert.True(t, p.MutatorHydratorIsEnabled()) + }) + t.Run("mutator=id_token", func(t *testing.T) { assert.True(t, p.MutatorIDTokenIsEnabled()) assert.EqualValues(t, urlx.ParseOrPanic("https://my-oathkeeper/"), p.MutatorIDTokenIssuerURL()) diff --git a/driver/registry_memory.go b/driver/registry_memory.go index eb8bc291e1..7f14488092 100644 --- a/driver/registry_memory.go +++ b/driver/registry_memory.go @@ -335,7 +335,7 @@ func (r *RegistryMemory) prepareMutators() { mutate.NewMutatorHeader(r.c), mutate.NewMutatorIDToken(r.c, r), mutate.NewMutatorNoop(r.c), - mutate.NewMutatorEnhancer(r.c), + mutate.NewMutatorHydrator(r.c), } r.mutators = map[string]mutate.Mutator{} diff --git a/pipeline/mutate/mutator_enhancer.go b/pipeline/mutate/mutator_hydrator.go similarity index 91% rename from pipeline/mutate/mutator_enhancer.go rename to pipeline/mutate/mutator_hydrator.go index 06bd9c718b..e182ec99c8 100644 --- a/pipeline/mutate/mutator_enhancer.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -47,7 +47,7 @@ const ( defaultDelayInMilliseconds = 100 ) -type MutatorEnhancer struct { +type MutatorHydrator struct { c configuration.Provider client *http.Client } @@ -72,23 +72,23 @@ type externalAPIConfig struct { Retry *RetryConfig `json:"retry,omitempty"` } -type MutatorEnhancerConfig struct { +type MutatorHydratorConfig struct { Api externalAPIConfig `json:"api"` } -func NewMutatorEnhancer(c configuration.Provider) *MutatorEnhancer { - return &MutatorEnhancer{c: c, client: httpx.NewResilientClientLatencyToleranceSmall(nil)} +func NewMutatorHydrator(c configuration.Provider) *MutatorHydrator { + return &MutatorHydrator{c: c, client: httpx.NewResilientClientLatencyToleranceSmall(nil)} } -func (a *MutatorEnhancer) GetID() string { - return "enhancer" +func (a *MutatorHydrator) GetID() string { + return "Hydrator" } -func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) (http.Header, error) { +func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) (http.Header, error) { if len(config) == 0 { config = []byte("{}") } - var cfg MutatorEnhancerConfig + var cfg MutatorHydratorConfig d := json.NewDecoder(bytes.NewBuffer(config)) d.DisallowUnknownFields() if err := d.Decode(&cfg); err != nil { @@ -160,8 +160,8 @@ func (a *MutatorEnhancer) Mutate(r *http.Request, session *authn.AuthenticationS return nil, nil } -func (a *MutatorEnhancer) Validate() error { - if !a.c.MutatorEnhancerIsEnabled() { +func (a *MutatorHydrator) Validate() error { + if !a.c.MutatorHydratorIsEnabled() { return errors.WithStack(ErrMutatorNotEnabled.WithReasonf(`Mutator "%s" is disabled per configuration.`, a.GetID())) } return nil diff --git a/pipeline/mutate/mutator_enhancer_test.go b/pipeline/mutate/mutator_hydrator_test.go similarity index 98% rename from pipeline/mutate/mutator_enhancer_test.go rename to pipeline/mutate/mutator_hydrator_test.go index 7a48daeade..16763b17a8 100644 --- a/pipeline/mutate/mutator_enhancer_test.go +++ b/pipeline/mutate/mutator_hydrator_test.go @@ -110,13 +110,13 @@ func configWithRetriesForMutator(numberOfRetries, retriesDelayInMilliseconds int } } -func TestMutatorEnhancer(t *testing.T) { +func TestMutatorHydrator(t *testing.T) { conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistry(conf) - a, err := reg.PipelineMutator("enhancer") + a, err := reg.PipelineMutator("Hydrator") require.NoError(t, err) - assert.Equal(t, "enhancer", a.GetID()) + assert.Equal(t, "Hydrator", a.GetID()) t.Run("method=mutate", func(t *testing.T) { sampleKey := "foo" @@ -333,7 +333,7 @@ func TestMutatorEnhancer(t *testing.T) { {enabled: true, shouldPass: true}, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - viper.Set(configuration.ViperKeyMutatorEnhancerIsEnabled, testCase.enabled) + viper.Set(configuration.ViperKeyMutatorHydratorIsEnabled, testCase.enabled) if testCase.shouldPass { require.NoError(t, a.Validate()) From 8524f1940277bb77efa6e583e80c1451c056a836 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 14:19:45 +0200 Subject: [PATCH 09/15] fix description of id_token mutator in schema --- .schemas/config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.schemas/config.schema.json b/.schemas/config.schema.json index 26fd383bd6..3f61ce165d 100644 --- a/.schemas/config.schema.json +++ b/.schemas/config.schema.json @@ -456,7 +456,7 @@ "id_token": { "type": "object", "title": "ID Token (JSON Web Token)", - "description": "The [`header` mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#header).", + "description": "The [`id_token` mutator](https://www.ory.sh/docs/oathkeeper/pipeline/mutator#id_token).", "additionalProperties": false, "properties": { "enabled": { From 909c263c74117d666a8dcbd8f659e9adf2b87db2 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 14:35:58 +0200 Subject: [PATCH 10/15] update new mutator to the recent changes in mutator interface --- pipeline/mutate/mutator_hydrator.go | 20 ++++++++++---------- pipeline/mutate/mutator_hydrator_test.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pipeline/mutate/mutator_hydrator.go b/pipeline/mutate/mutator_hydrator.go index e182ec99c8..b8fd5ace1e 100644 --- a/pipeline/mutate/mutator_hydrator.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -84,7 +84,7 @@ func (a *MutatorHydrator) GetID() string { return "Hydrator" } -func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) (http.Header, error) { +func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) error { if len(config) == 0 { config = []byte("{}") } @@ -92,23 +92,23 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS d := json.NewDecoder(bytes.NewBuffer(config)) d.DisallowUnknownFields() if err := d.Decode(&cfg); err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } var b bytes.Buffer err := json.NewEncoder(&b).Encode(session) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } if cfg.Api.Url == "" { - return nil, errors.New(ErrMissingAPIURL) + return errors.New(ErrMissingAPIURL) } else if _, err := url.ParseRequestURI(cfg.Api.Url); err != nil { - return nil, errors.New(ErrInvalidAPIURL) + return errors.New(ErrInvalidAPIURL) } req, err := http.NewRequest("POST", cfg.Api.Url, &b) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } for key, values := range r.Header { for _, value := range values { @@ -144,20 +144,20 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS } }, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Millisecond*time.Duration(retryConfig.DelayInMilliseconds)), uint64(retryConfig.NumberOfRetries))) if err != nil { - return nil, err + return err } sessionFromUpstream := authn.AuthenticationSession{} err = json.NewDecoder(res.Body).Decode(&sessionFromUpstream) if err != nil { - return nil, errors.WithStack(err) + return errors.WithStack(err) } if sessionFromUpstream.Extra == nil || sessionFromUpstream.Subject != session.Subject { - return nil, errors.New(ErrMalformedResponseFromUpstreamAPI) + return errors.New(ErrMalformedResponseFromUpstreamAPI) } *session = sessionFromUpstream - return nil, nil + return nil } func (a *MutatorHydrator) Validate() error { diff --git a/pipeline/mutate/mutator_hydrator_test.go b/pipeline/mutate/mutator_hydrator_test.go index 16763b17a8..6e1b5bab7e 100644 --- a/pipeline/mutate/mutator_hydrator_test.go +++ b/pipeline/mutate/mutator_hydrator_test.go @@ -309,7 +309,7 @@ func TestMutatorHydrator(t *testing.T) { ts = httptest.NewServer(router) defer ts.Close() - _, err := a.Mutate(specs.Request, specs.Session, specs.Config(ts), specs.Rule) + err := a.Mutate(specs.Request, specs.Session, specs.Config(ts), specs.Rule) if specs.Err == nil { // Issuer must run without error require.NoError(t, err) From 8d8990ab675f10154b22080dfaad051342b9d031 Mon Sep 17 00:00:00 2001 From: kubadz Date: Mon, 12 Aug 2019 14:43:44 +0200 Subject: [PATCH 11/15] fix imports formatting --- pipeline/authn/authenticator_test.go | 3 ++- pipeline/mutate/mutator_hydrator.go | 6 ++++-- pipeline/mutate/mutator_hydrator_test.go | 10 ++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pipeline/authn/authenticator_test.go b/pipeline/authn/authenticator_test.go index 31bf0c519a..7f7e1c5168 100644 --- a/pipeline/authn/authenticator_test.go +++ b/pipeline/authn/authenticator_test.go @@ -4,8 +4,9 @@ import ( "fmt" "testing" - "github.com/ory/oathkeeper/pipeline/authn" "github.com/stretchr/testify/assert" + + "github.com/ory/oathkeeper/pipeline/authn" ) const ( diff --git a/pipeline/mutate/mutator_hydrator.go b/pipeline/mutate/mutator_hydrator.go index b8fd5ace1e..b6429a7727 100644 --- a/pipeline/mutate/mutator_hydrator.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -23,12 +23,14 @@ package mutate import ( "bytes" "encoding/json" - "github.com/cenkalti/backoff" - "github.com/ory/x/httpx" "net/http" "net/url" "time" + "github.com/cenkalti/backoff" + + "github.com/ory/x/httpx" + "github.com/pkg/errors" "github.com/ory/oathkeeper/driver/configuration" diff --git a/pipeline/mutate/mutator_hydrator_test.go b/pipeline/mutate/mutator_hydrator_test.go index 6e1b5bab7e..b97db87984 100644 --- a/pipeline/mutate/mutator_hydrator_test.go +++ b/pipeline/mutate/mutator_hydrator_test.go @@ -4,15 +4,17 @@ import ( "encoding/json" "errors" "fmt" - "github.com/julienschmidt/httprouter" - "github.com/ory/oathkeeper/pipeline/authn" - "github.com/ory/oathkeeper/pipeline/mutate" - "github.com/ory/oathkeeper/rule" "io/ioutil" "net/http" "net/http/httptest" "testing" + "github.com/julienschmidt/httprouter" + + "github.com/ory/oathkeeper/pipeline/authn" + "github.com/ory/oathkeeper/pipeline/mutate" + "github.com/ory/oathkeeper/rule" + "github.com/ory/viper" "github.com/ory/oathkeeper/driver/configuration" From 4e2f4a77cfc73b359f1793a7165e5dc7b96ecb82 Mon Sep 17 00:00:00 2001 From: Jakub Dziechciewicz Date: Mon, 12 Aug 2019 16:19:55 +0200 Subject: [PATCH 12/15] Update viper key for hydrator mutator Co-Authored-By: Jakub Kabza --- driver/configuration/provider_viper_mutator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/configuration/provider_viper_mutator.go b/driver/configuration/provider_viper_mutator.go index c45eb5a3d1..08248aaa4c 100644 --- a/driver/configuration/provider_viper_mutator.go +++ b/driver/configuration/provider_viper_mutator.go @@ -14,7 +14,7 @@ const ( ViperKeyMutatorNoopIsEnabled = "mutators.noop.enabled" - ViperKeyMutatorHydratorIsEnabled = "mutators.Hydrator.enabled" + ViperKeyMutatorHydratorIsEnabled = "mutators.hydrator.enabled" ViperKeyMutatorIDTokenIsEnabled = "mutators.id_token.enabled" ViperKeyMutatorIDTokenIssuerURL = "mutators.id_token.issuer_url" From 9a585097e98a37e394228409e72e43b490d51975 Mon Sep 17 00:00:00 2001 From: kubadz Date: Wed, 14 Aug 2019 13:35:24 +0200 Subject: [PATCH 13/15] fix handler ID, set "Content-Type" Header on request to the API and provide a test case for request with empty Extras field --- pipeline/mutate/mutator_hydrator.go | 7 +++++-- pipeline/mutate/mutator_hydrator_test.go | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/pipeline/mutate/mutator_hydrator.go b/pipeline/mutate/mutator_hydrator.go index b6429a7727..c58018c60a 100644 --- a/pipeline/mutate/mutator_hydrator.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -47,6 +47,8 @@ const ( ErrNoCredentialsProvided = "No credentials were provided in mutator configuration" defaultNumberOfRetries = 3 defaultDelayInMilliseconds = 100 + contentTypeHeaderKey = "Content-Type" + contentTypeJSONHeaderValue = "application/json" ) type MutatorHydrator struct { @@ -83,7 +85,7 @@ func NewMutatorHydrator(c configuration.Provider) *MutatorHydrator { } func (a *MutatorHydrator) GetID() string { - return "Hydrator" + return "hydrator" } func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationSession, config json.RawMessage, _ pipeline.Rule) error { @@ -121,6 +123,7 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS credentials := cfg.Api.Authn.Basic req.SetBasicAuth(credentials.Username, credentials.Password) } + req.Header.Set(contentTypeHeaderKey, contentTypeJSONHeaderValue) retryConfig := RetryConfig{defaultNumberOfRetries, defaultDelayInMilliseconds} if cfg.Api.Retry != nil { @@ -154,7 +157,7 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS if err != nil { return errors.WithStack(err) } - if sessionFromUpstream.Extra == nil || sessionFromUpstream.Subject != session.Subject { + if sessionFromUpstream.Subject != session.Subject { return errors.New(ErrMalformedResponseFromUpstreamAPI) } *session = sessionFromUpstream diff --git a/pipeline/mutate/mutator_hydrator_test.go b/pipeline/mutate/mutator_hydrator_test.go index b97db87984..c60bdbd8ae 100644 --- a/pipeline/mutate/mutator_hydrator_test.go +++ b/pipeline/mutate/mutator_hydrator_test.go @@ -33,6 +33,12 @@ func setExtra(key string, value interface{}) func(a *authn.AuthenticationSession } } +func setSubject(subject string) func(a *authn.AuthenticationSession) { + return func(a *authn.AuthenticationSession) { + a.Subject = subject + } +} + func newAuthenticationSession(modifications ...func(a *authn.AuthenticationSession)) *authn.AuthenticationSession { a := authn.AuthenticationSession{} for _, f := range modifications { @@ -116,11 +122,12 @@ func TestMutatorHydrator(t *testing.T) { conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistry(conf) - a, err := reg.PipelineMutator("Hydrator") + a, err := reg.PipelineMutator("hydrator") require.NoError(t, err) - assert.Equal(t, "Hydrator", a.GetID()) + assert.Equal(t, "hydrator", a.GetID()) t.Run("method=mutate", func(t *testing.T) { + sampleSubject := "sub" sampleKey := "foo" sampleValue := "bar" complexValueKey := "complex" @@ -176,6 +183,15 @@ func TestMutatorHydrator(t *testing.T) { Match: newAuthenticationSession(setExtra(sampleKey, sampleValue)), Err: nil, }, + "No Extra Before And After": { + Setup: defaultRouterSetup(), + Session: newAuthenticationSession(setSubject(sampleSubject)), + Rule: &rule.Rule{ID: "test-rule"}, + Config: defaultConfigForMutator(), + Request: &http.Request{}, + Match: newAuthenticationSession(setSubject(sampleSubject)), + Err: nil, + }, "Empty Response": { Setup: func(t *testing.T) http.Handler { router := httprouter.New() @@ -186,11 +202,11 @@ func TestMutatorHydrator(t *testing.T) { }) return router }, - Session: newAuthenticationSession(), + Session: newAuthenticationSession(setSubject(sampleSubject)), Rule: &rule.Rule{ID: "test-rule"}, Config: defaultConfigForMutator(), Request: &http.Request{}, - Match: newAuthenticationSession(), + Match: newAuthenticationSession(setSubject(sampleSubject)), Err: errors.New(mutate.ErrMalformedResponseFromUpstreamAPI), }, "Missing API URL": { From 6fce2123472c4566098587f66a51dc1f40b03c2f Mon Sep 17 00:00:00 2001 From: kubadz Date: Fri, 16 Aug 2019 15:45:25 +0200 Subject: [PATCH 14/15] rename Authentication to Auth as suggested in code review --- pipeline/mutate/mutator_hydrator.go | 20 ++++++++++---------- pipeline/mutate/mutator_hydrator_test.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pipeline/mutate/mutator_hydrator.go b/pipeline/mutate/mutator_hydrator.go index c58018c60a..70a760a8e1 100644 --- a/pipeline/mutate/mutator_hydrator.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -23,6 +23,7 @@ package mutate import ( "bytes" "encoding/json" + "github.com/ory/oathkeeper/pipeline/authn" "net/http" "net/url" "time" @@ -35,7 +36,6 @@ import ( "github.com/ory/oathkeeper/driver/configuration" "github.com/ory/oathkeeper/pipeline" - "github.com/ory/oathkeeper/pipeline/authn" ) const ( @@ -56,13 +56,13 @@ type MutatorHydrator struct { client *http.Client } -type BasicAuthn struct { +type BasicAuth struct { Username string `json:"username"` Password string `json:"password"` } -type Authentication struct { - Basic BasicAuthn `json:"basic"` +type Auth struct { + Basic BasicAuth `json:"basic"` } type RetryConfig struct { @@ -71,9 +71,9 @@ type RetryConfig struct { } type externalAPIConfig struct { - Url string `json:"url"` - Authn *Authentication `json:"authn,omitempty"` - Retry *RetryConfig `json:"retry,omitempty"` + Url string `json:"url"` + Auth *Auth `json:"auth,omitempty"` + Retry *RetryConfig `json:"retry,omitempty"` } type MutatorHydratorConfig struct { @@ -119,8 +119,8 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS req.Header.Add(key, value) } } - if cfg.Api.Authn != nil { - credentials := cfg.Api.Authn.Basic + if cfg.Api.Auth != nil { + credentials := cfg.Api.Auth.Basic req.SetBasicAuth(credentials.Username, credentials.Password) } req.Header.Set(contentTypeHeaderKey, contentTypeJSONHeaderValue) @@ -139,7 +139,7 @@ func (a *MutatorHydrator) Mutate(r *http.Request, session *authn.AuthenticationS case http.StatusOK: return nil case http.StatusUnauthorized: - if cfg.Api.Authn != nil { + if cfg.Api.Auth != nil { return errors.New(ErrInvalidCredentials) } else { return errors.New(ErrNoCredentialsProvided) diff --git a/pipeline/mutate/mutator_hydrator_test.go b/pipeline/mutate/mutator_hydrator_test.go index c60bdbd8ae..01719e3f13 100644 --- a/pipeline/mutate/mutator_hydrator_test.go +++ b/pipeline/mutate/mutator_hydrator_test.go @@ -108,7 +108,7 @@ func defaultConfigForMutator() func(*httptest.Server) json.RawMessage { func configWithBasicAuthnForMutator(user, password string) func(*httptest.Server) json.RawMessage { return func(s *httptest.Server) json.RawMessage { - return []byte(fmt.Sprintf(`{"api": {"url": "%s", "authn": {"basic": {"username": "%s", "password": "%s"}}}}`, s.URL, user, password)) + return []byte(fmt.Sprintf(`{"api": {"url": "%s", "auth": {"basic": {"username": "%s", "password": "%s"}}}}`, s.URL, user, password)) } } From 5119f1ba1bdd49a7319f86d0be148fc30a94a0dd Mon Sep 17 00:00:00 2001 From: kubadz Date: Fri, 16 Aug 2019 15:49:24 +0200 Subject: [PATCH 15/15] fix formatting --- pipeline/mutate/mutator_hydrator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pipeline/mutate/mutator_hydrator.go b/pipeline/mutate/mutator_hydrator.go index 70a760a8e1..0fd3ef7f73 100644 --- a/pipeline/mutate/mutator_hydrator.go +++ b/pipeline/mutate/mutator_hydrator.go @@ -23,11 +23,12 @@ package mutate import ( "bytes" "encoding/json" - "github.com/ory/oathkeeper/pipeline/authn" "net/http" "net/url" "time" + "github.com/ory/oathkeeper/pipeline/authn" + "github.com/cenkalti/backoff" "github.com/ory/x/httpx"