From 4642de0cfd1fb15bc48c7093be9449abd488755c Mon Sep 17 00:00:00 2001 From: Oleksandra Talalaieva <25621530+sashatalalasha@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:32:50 +0100 Subject: [PATCH] feat: add headers to web hooks (#3849) --- driver/config/config_test.go | 26 ++--- .../config/stub/.kratos.webauthn.invalid.yaml | 26 +++++ .../config/stub/.kratos.webauthn.origin.yaml | 26 +++++ .../config/stub/.kratos.webauthn.origins.yaml | 26 +++++ driver/config/stub/.kratos.yaml | 26 +++++ driver/registry_default_test.go | 110 +++++++++--------- embedx/config.schema.json | 7 ++ 7 files changed, 179 insertions(+), 68 deletions(-) diff --git a/driver/config/config_test.go b/driver/config/config_test.go index 2a8d57e7bebb..6cb37f100850 100644 --- a/driver/config/config_test.go +++ b/driver/config/config_test.go @@ -227,7 +227,7 @@ func TestViperProvider(t *testing.T) { t.Run("hook=before", func(t *testing.T) { expHooks := []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"method":"GET","url":"https://test.kratos.ory.sh/before_registration_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"https://test.kratos.ory.sh/before_registration_hook"}`)}, {Name: "two_step_registration", Config: json.RawMessage(`{}`)}, } @@ -246,7 +246,7 @@ func TestViperProvider(t *testing.T) { strategy: "password", hooks: []config.SelfServiceHook{ {Name: "session", Config: json.RawMessage(`{}`)}, - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_registration_password_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_registration_password_hook"}`)}, // {Name: "verify", Config: json.RawMessage(`{}`)}, // {Name: "redirect", Config: json.RawMessage(`{"allow_user_defined_redirect":false,"default_redirect_url":"http://test.kratos.ory.sh:4000/"}`)}, }, @@ -255,7 +255,7 @@ func TestViperProvider(t *testing.T) { strategy: "oidc", hooks: []config.SelfServiceHook{ // {Name: "verify", Config: json.RawMessage(`{}`)}, - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"GET","url":"https://test.kratos.ory.sh/after_registration_oidc_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"GET","url":"https://test.kratos.ory.sh/after_registration_oidc_hook"}`)}, {Name: "session", Config: json.RawMessage(`{}`)}, // {Name: "redirect", Config: json.RawMessage(`{"allow_user_defined_redirect":false,"default_redirect_url":"http://test.kratos.ory.sh:4000/"}`)}, }, @@ -263,7 +263,7 @@ func TestViperProvider(t *testing.T) { { strategy: config.HookGlobal, hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"auth":{"config":{"in":"header","name":"My-Key","value":"My-Key-Value"},"type":"api_key"},"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_registration_global_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"auth":{"config":{"in":"header","name":"My-Key","value":"My-Key-Value"},"type":"api_key"},"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_registration_global_hook"}`)}, }, }, } { @@ -283,7 +283,7 @@ func TestViperProvider(t *testing.T) { t.Run("hook=before", func(t *testing.T) { expHooks := []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"method":"POST","url":"https://test.kratos.ory.sh/before_login_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/before_login_hook"}`)}, } hooks := p.SelfServiceFlowLoginBeforeHooks(ctx) @@ -303,20 +303,20 @@ func TestViperProvider(t *testing.T) { hooks: []config.SelfServiceHook{ {Name: "revoke_active_sessions", Config: json.RawMessage(`{}`)}, {Name: "require_verified_address", Config: json.RawMessage(`{}`)}, - {Name: "web_hook", Config: json.RawMessage(`{"auth":{"config":{"password":"super-secret","user":"test-user"},"type":"basic_auth"},"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_login_password_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"auth":{"config":{"password":"super-secret","user":"test-user"},"type":"basic_auth"},"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_login_password_hook"}`)}, }, }, { strategy: "oidc", hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"GET","url":"https://test.kratos.ory.sh/after_login_oidc_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"GET","url":"https://test.kratos.ory.sh/after_login_oidc_hook"}`)}, {Name: "revoke_active_sessions", Config: json.RawMessage(`{}`)}, }, }, { strategy: config.HookGlobal, hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_login_global_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_login_global_hook"}`)}, }, }, } { @@ -338,19 +338,19 @@ func TestViperProvider(t *testing.T) { { strategy: "password", hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_settings_password_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_settings_password_hook"}`)}, }, }, { strategy: "profile", hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_settings_profile_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_settings_profile_hook"}`)}, }, }, { strategy: config.HookGlobal, hooks: []config.SelfServiceHook{ - {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"POST","url":"https://test.kratos.ory.sh/after_settings_global_hook"}`)}, + {Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"POST","url":"https://test.kratos.ory.sh/after_settings_global_hook"}`)}, }, }, } { @@ -367,7 +367,7 @@ func TestViperProvider(t *testing.T) { assert.Equal(t, "http://test.kratos.ory.sh/recovery", p.SelfServiceFlowRecoveryUI(ctx).String()) hooks := p.SelfServiceFlowRecoveryAfterHooks(ctx, config.HookGlobal) - assert.Equal(t, []config.SelfServiceHook{{Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"GET","url":"https://test.kratos.ory.sh/after_recovery_hook"}`)}}, hooks) + assert.Equal(t, []config.SelfServiceHook{{Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"GET","url":"https://test.kratos.ory.sh/after_recovery_hook"}`)}}, hooks) }) t.Run("method=verification", func(t *testing.T) { @@ -375,7 +375,7 @@ func TestViperProvider(t *testing.T) { assert.Equal(t, "http://test.kratos.ory.sh/verification", p.SelfServiceFlowVerificationUI(ctx).String()) hooks := p.SelfServiceFlowVerificationAfterHooks(ctx, config.HookGlobal) - assert.Equal(t, []config.SelfServiceHook{{Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","method":"GET","url":"https://test.kratos.ory.sh/after_verification_hook"}`)}}, hooks) + assert.Equal(t, []config.SelfServiceHook{{Name: "web_hook", Config: json.RawMessage(`{"body":"/path/to/template.jsonnet","headers":{"X-Custom-Header":"test"},"method":"GET","url":"https://test.kratos.ory.sh/after_verification_hook"}`)}}, hooks) }) t.Run("group=hashers", func(t *testing.T) { diff --git a/driver/config/stub/.kratos.webauthn.invalid.yaml b/driver/config/stub/.kratos.webauthn.invalid.yaml index 01fc9f5adaad..a1230588c666 100644 --- a/driver/config/stub/.kratos.webauthn.invalid.yaml +++ b/driver/config/stub/.kratos.webauthn.invalid.yaml @@ -104,6 +104,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_recovery_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet verification: @@ -117,6 +119,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_verification_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet settings: @@ -132,6 +136,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet profile: hooks: @@ -139,12 +145,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_profile_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_settings_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet login: @@ -156,6 +166,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_login_hook method: POST + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/login/return_to password: @@ -167,6 +179,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: basic_auth @@ -179,6 +193,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: revoke_active_sessions hooks: @@ -186,6 +202,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet registration: @@ -198,6 +216,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_registration_hook method: GET + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/registration/return_to password: @@ -207,12 +227,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_registration_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: api_key @@ -227,5 +251,7 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: session diff --git a/driver/config/stub/.kratos.webauthn.origin.yaml b/driver/config/stub/.kratos.webauthn.origin.yaml index 1b2ff11e9d8f..95deec00910d 100644 --- a/driver/config/stub/.kratos.webauthn.origin.yaml +++ b/driver/config/stub/.kratos.webauthn.origin.yaml @@ -100,6 +100,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_recovery_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet verification: @@ -113,6 +115,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_verification_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet settings: @@ -128,6 +132,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet profile: hooks: @@ -135,12 +141,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_profile_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_settings_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet login: @@ -152,6 +162,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_login_hook method: POST + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/login/return_to password: @@ -163,6 +175,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: basic_auth @@ -175,6 +189,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: revoke_active_sessions hooks: @@ -182,6 +198,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet registration: @@ -194,6 +212,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_registration_hook method: GET + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/registration/return_to password: @@ -203,12 +223,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_registration_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: api_key @@ -223,5 +247,7 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: session diff --git a/driver/config/stub/.kratos.webauthn.origins.yaml b/driver/config/stub/.kratos.webauthn.origins.yaml index f9349c670ac0..9efeb34e0b02 100644 --- a/driver/config/stub/.kratos.webauthn.origins.yaml +++ b/driver/config/stub/.kratos.webauthn.origins.yaml @@ -103,6 +103,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_recovery_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet verification: @@ -116,6 +118,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_verification_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet settings: @@ -131,6 +135,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet profile: hooks: @@ -138,12 +144,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_profile_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_settings_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet login: @@ -155,6 +165,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_login_hook method: POST + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/login/return_to password: @@ -166,6 +178,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: basic_auth @@ -178,6 +192,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: revoke_active_sessions hooks: @@ -185,6 +201,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet registration: @@ -197,6 +215,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_registration_hook method: GET + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/registration/return_to password: @@ -206,12 +226,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_registration_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: api_key @@ -226,5 +250,7 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: session diff --git a/driver/config/stub/.kratos.yaml b/driver/config/stub/.kratos.yaml index b50341928ad8..bc35439f8a53 100644 --- a/driver/config/stub/.kratos.yaml +++ b/driver/config/stub/.kratos.yaml @@ -99,6 +99,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_recovery_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet verification: @@ -112,6 +114,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_verification_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet settings: @@ -127,6 +131,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet profile: hooks: @@ -134,12 +140,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_settings_profile_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_settings_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet login: @@ -151,6 +161,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_login_hook method: POST + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/login/return_to password: @@ -162,6 +174,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: basic_auth @@ -174,6 +188,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: revoke_active_sessions hooks: @@ -181,6 +197,8 @@ selfservice: config: url: https://test.kratos.ory.sh/after_login_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet registration: @@ -193,6 +211,8 @@ selfservice: config: url: https://test.kratos.ory.sh/before_registration_hook method: GET + headers: + X-Custom-Header: test after: default_browser_return_url: https://self-service/registration/return_to password: @@ -202,12 +222,16 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_password_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet hooks: - hook: web_hook config: url: https://test.kratos.ory.sh/after_registration_global_hook method: POST + headers: + X-Custom-Header: test body: /path/to/template.jsonnet auth: type: api_key @@ -222,5 +246,7 @@ selfservice: config: url: https://test.kratos.ory.sh/after_registration_oidc_hook method: GET + headers: + X-Custom-Header: test body: /path/to/template.jsonnet - hook: session diff --git a/driver/registry_default_test.go b/driver/registry_default_test.go index d1c02490dcb5..009dd76173d8 100644 --- a/driver/registry_default_test.go +++ b/driver/registry_default_test.go @@ -51,14 +51,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceVerificationBeforeHooks, []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []verification.PreHookExecutor { return []verification.PreHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -90,14 +90,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Multiple web_hooks configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceVerificationAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []verification.PostHookExecutor { return []verification.PostHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -132,14 +132,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryBeforeHooks, []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []recovery.PreHookExecutor { return []recovery.PreHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -171,14 +171,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Multiple web_hooks configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceRecoveryAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []recovery.PostHookExecutor { return []recovery.PostHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -217,14 +217,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationBeforeHooks, []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []registration.PreHookExecutor { return []registration.PreHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), hook.NewTwoStepRegistration(reg), } }, @@ -273,14 +273,14 @@ func TestDriverDefault_Hooks(t *testing.T) { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".password.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "body": "bar"}}, + {"hook": "web_hook", "config": map[string]interface{}{"headers": map[string]string{"X-Custom-Header": "test"}, "url": "foo", "method": "POST", "body": "bar"}}, {"hook": "session"}, }) }, expect: func(reg *driver.RegistryDefault) []registration.PostHookPostPersistExecutor { return []registration.PostHookPostPersistExecutor{ hook.NewVerifier(reg), - hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), hook.NewSessionIssuer(reg), } }, @@ -289,14 +289,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured on a global level", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []registration.PostHookPostPersistExecutor { return []registration.PostHookPostPersistExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -304,18 +304,18 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Hooks are configured on a global level, as well as on a strategy level", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".password.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, {"hook": "session"}, }) conf.MustSet(ctx, config.ViperKeySelfServiceRegistrationAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "POST"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) }, expect: func(reg *driver.RegistryDefault) []registration.PostHookPostPersistExecutor { return []registration.PostHookPostPersistExecutor{ hook.NewVerifier(reg), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"foo"}`)), hook.NewSessionIssuer(reg), } }, @@ -364,14 +364,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceLoginBeforeHooks, []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []login.PreHookExecutor { return []login.PreHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -429,14 +429,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "A revoke_active_sessions hook, require_verified_address hook and a web_hook are configured for password strategy", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceLoginAfter+".password.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "body": "bar"}}, + {"hook": "web_hook", "config": map[string]interface{}{"headers": map[string]string{"X-Custom-Header": "test"}, "url": "foo", "method": "POST", "body": "bar"}}, {"hook": "require_verified_address"}, {"hook": "revoke_active_sessions"}, }) }, expect: func(reg *driver.RegistryDefault) []login.PostHookExecutor { return []login.PostHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), hook.NewAddressVerifier(), hook.NewSessionDestroyer(reg), } @@ -446,14 +446,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured on a global level", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceLoginAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []login.PostHookExecutor { return []login.PostHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -461,17 +461,17 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Hooks are configured on a global level, as well as on a strategy level", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceLoginAfter+".password.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, {"hook": "revoke_active_sessions"}, {"hook": "require_verified_address"}, }) conf.MustSet(ctx, config.ViperKeySelfServiceLoginAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []login.PostHookExecutor { return []login.PostHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"foo"}`)), hook.NewSessionDestroyer(reg), hook.NewAddressVerifier(), } @@ -508,14 +508,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsBeforeHooks, []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []settings.PreHookExecutor { return []settings.PreHookExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -561,14 +561,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "A verify hook and a web_hook are configured for profile strategy", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsAfter+".profile.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "body": "bar"}}, + {"hook": "web_hook", "config": map[string]interface{}{"headers": []map[string]string{{"X-Custom-Header": "test"}}, "url": "foo", "method": "POST", "body": "bar"}}, }) conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) }, expect: func(reg *driver.RegistryDefault) []settings.PostHookPostPersistExecutor { return []settings.PostHookPostPersistExecutor{ hook.NewVerifier(reg), - hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"body":"bar","headers":[{"X-Custom-Header":"test"}],"method":"POST","url":"foo"}`)), } }, }, @@ -576,14 +576,14 @@ func TestDriverDefault_Hooks(t *testing.T) { uc: "Two web_hooks are configured on a global level", prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceSettingsAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, - {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "bar", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []settings.PostHookPostPersistExecutor { return []settings.PostHookPostPersistExecutor{ - hook.NewWebHook(reg, json.RawMessage(`{"method":"POST","url":"foo"}`)), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"bar"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"POST","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"bar"}`)), } }, }, @@ -592,16 +592,16 @@ func TestDriverDefault_Hooks(t *testing.T) { prep: func(conf *config.Config) { conf.MustSet(ctx, config.ViperKeySelfServiceVerificationEnabled, true) conf.MustSet(ctx, config.ViperKeySelfServiceSettingsAfter+".profile.hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "GET", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) conf.MustSet(ctx, config.ViperKeySelfServiceSettingsAfter+".hooks", []map[string]interface{}{ - {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST"}}, + {"hook": "web_hook", "config": map[string]interface{}{"url": "foo", "method": "POST", "headers": map[string]string{"X-Custom-Header": "test"}}}, }) }, expect: func(reg *driver.RegistryDefault) []settings.PostHookPostPersistExecutor { return []settings.PostHookPostPersistExecutor{ hook.NewVerifier(reg), - hook.NewWebHook(reg, json.RawMessage(`{"method":"GET","url":"foo"}`)), + hook.NewWebHook(reg, json.RawMessage(`{"headers":{"X-Custom-Header":"test"},"method":"GET","url":"foo"}`)), } }, }, diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 15cc950fbf8e..0b540ea25cd6 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -263,6 +263,13 @@ "type": "string", "description": "The HTTP method to use (GET, POST, etc)." }, + "headers": { + "type": "object", + "description": "The HTTP headers that must be applied to the Web-Hook", + "additionalProperties": { + "type": "string" + } + }, "body": { "type": "string", "oneOf": [