From d54e39d3cd365b234e38ae49a193abfa4a347c99 Mon Sep 17 00:00:00 2001 From: Dimitrij Drus Date: Fri, 6 Oct 2023 13:24:34 +0200 Subject: [PATCH] refactor!: `unifier` renamed to `finalizer` (#956) --- DockerHub-README.md | 12 +- README.md | 4 +- charts/heimdall/templates/demo/configmap.yaml | 6 +- charts/heimdall/templates/demo/test-rule.yaml | 2 +- cmd/validate/test_data/config.yaml | 4 +- .../invalid-ruleset-for-proxy-usage.yaml | 6 +- cmd/validate/test_data/valid-ruleset.yaml | 6 +- .../configuration/cryptographic_material.adoc | 2 +- .../configuration/reference/reference.adoc | 7 +- .../configuration/rules/configuration.adoc | 26 +- .../docs/configuration/rules/default.adoc | 8 +- .../pipeline_mechanisms/error_handlers.adoc | 2 +- .../rules/pipeline_mechanisms/finalizers.adoc | 124 ++ .../rules/pipeline_mechanisms/overview.adoc | 10 +- .../rules/pipeline_mechanisms/unifiers.adoc | 123 -- .../docs/getting_started/concepts.adoc | 10 +- .../configuration_introduction.adoc | 10 +- .../decision_service_quickstart.adoc | 12 +- .../proxy_service_quickstart.adoc | 10 +- docs/content/docs/guides/envoy.adoc | 2 +- docs/content/docs/guides/haproxy.adoc | 2 +- docs/content/docs/guides/nginx.adoc | 6 +- docs/content/docs/guides/opa.adoc | 2 +- docs/content/docs/guides/traefik.adoc | 2 +- .../docs/operations/observability.adoc | 4 +- docs/content/docs/welcome.adoc | 2 +- docs/package-lock.json | 1064 +++++------------ example_config.yaml | 4 +- example_rules.yaml | 6 +- .../quickstarts/heimdall-config.yaml | 4 +- .../quickstarts/upstream-rules.yaml | 2 +- .../quickstarts/demo-app/base/rules.yaml | 2 +- .../quickstarts/heimdall/config.yaml | 6 +- .../quickstarts/proxy-demo/deployment.yaml | 66 + .../proxy-demo/heimdall-config.yaml | 59 + .../proxy-demo/heimdall-rules.yaml | 43 + .../quickstarts/proxy-demo/ingress.yaml | 24 + .../quickstarts/proxy-demo/kustomization.yaml | 9 + .../quickstarts/proxy-demo/namespace.yaml | 4 + .../quickstarts/proxy-demo/service.yaml | 14 + internal/config/mechanism_prototypes.go | 2 +- internal/config/test_data/test_config.yaml | 4 +- internal/handler/decision/request_context.go | 5 +- .../envoyextauth/grpcv3/request_context.go | 4 +- internal/handler/proxy/request_context.go | 1 - internal/rules/mechanisms/factory.go | 6 +- internal/rules/mechanisms/factory_impl.go | 16 +- internal/rules/mechanisms/factory_test.go | 54 +- .../config_decoder.go | 2 +- .../{unifiers => finalizers}/constants.go | 10 +- .../cookie_finalizer.go} | 34 +- .../cookie_finalizer_test.go} | 56 +- .../unifier.go => finalizers/finalizer.go} | 8 +- .../finalizer_type_registry.go} | 18 +- .../finalizer_type_registry_test.go} | 22 +- .../header_finalizer.go} | 34 +- .../header_finalizer_test.go} | 54 +- .../jwt_finalizer.go} | 40 +- .../jwt_finalizer_test.go} | 166 +-- .../mechanisms/finalizers/mocks/finalizer.go | 219 ++++ .../noop_finalizer.go} | 24 +- .../noop_finalizer_test.go} | 24 +- internal/rules/mechanisms/mocks/factory.go | 32 +- .../rules/mechanisms/prototype_repository.go | 22 +- .../mechanisms/unifiers/mocks/unifier.go | 219 ---- internal/rules/rule_factory_impl.go | 40 +- internal/rules/rule_factory_impl_test.go | 156 +-- internal/rules/rule_impl.go | 6 +- internal/rules/rule_impl_test.go | 44 +- schema/config.schema.json | 41 +- 70 files changed, 1406 insertions(+), 1668 deletions(-) create mode 100644 docs/content/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc delete mode 100644 docs/content/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc create mode 100644 examples/kubernetes/quickstarts/proxy-demo/deployment.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/heimdall-config.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/heimdall-rules.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/ingress.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/kustomization.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/namespace.yaml create mode 100644 examples/kubernetes/quickstarts/proxy-demo/service.yaml rename internal/rules/mechanisms/{unifiers => finalizers}/config_decoder.go (98%) rename internal/rules/mechanisms/{unifiers => finalizers}/constants.go (83%) rename internal/rules/mechanisms/{unifiers/cookie_unifier.go => finalizers/cookie_finalizer.go} (71%) rename internal/rules/mechanisms/{unifiers/cookie_unifier_test.go => finalizers/cookie_finalizer_test.go} (80%) rename internal/rules/mechanisms/{unifiers/unifier.go => finalizers/finalizer.go} (84%) rename internal/rules/mechanisms/{unifiers/unifier_type_registry.go => finalizers/finalizer_type_registry.go} (65%) rename internal/rules/mechanisms/{unifiers/unifier_type_registry_test.go => finalizers/finalizer_type_registry_test.go} (68%) rename internal/rules/mechanisms/{unifiers/header_unifier.go => finalizers/header_finalizer.go} (72%) rename internal/rules/mechanisms/{unifiers/header_unifier_test.go => finalizers/header_finalizer_test.go} (81%) rename internal/rules/mechanisms/{unifiers/jwt_unifier.go => finalizers/jwt_finalizer.go} (84%) rename internal/rules/mechanisms/{unifiers/jwt_unifier_test.go => finalizers/jwt_finalizer_test.go} (76%) create mode 100644 internal/rules/mechanisms/finalizers/mocks/finalizer.go rename internal/rules/mechanisms/{unifiers/noop_unifier.go => finalizers/noop_finalizer.go} (60%) rename internal/rules/mechanisms/{unifiers/noop_unifier_test.go => finalizers/noop_finalizer_test.go} (68%) delete mode 100644 internal/rules/mechanisms/unifiers/mocks/unifier.go diff --git a/DockerHub-README.md b/DockerHub-README.md index 802093cf7..1124c58c5 100644 --- a/DockerHub-README.md +++ b/DockerHub-README.md @@ -25,7 +25,7 @@ rules: authenticators: - id: anonymous_authenticator type: anonymous - unifiers: + finalizers: - id: create_jwt type: jwt @@ -35,7 +35,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: create_jwt + - finalizer: create_jwt ``` Start heimdall: @@ -104,7 +104,7 @@ rules: type: deny - id: allow_all_requests type: allow - unifiers: + finalizers: - id: create_jwt type: jwt @@ -115,7 +115,7 @@ rules: execute: - authenticator: anonymous_authenticator - authorizer: deny_all_requests - - unifier: create_jwt + - finalizer: create_jwt providers: file_system: @@ -210,8 +210,8 @@ X-Forwarded-For: 172.22.0.1 What did you actually do? ;) -* You've created a very simple configuration with a default rule, with preconfigured defaults. The used authenticator instructs heimdall to create an anonymous subject for every request on every URL for the HTTP methods GET and POST. The default authenticator rejects any request and the default unifier creates a JWT from the subject mentioned above. -* You've created a very simple rule, which reuses the default authenticator and unifier and configures an authorizer, which allows any request to pass through. +* You've created a very simple configuration with a default rule, with preconfigured defaults. The used authenticator instructs heimdall to create an anonymous subject for every request on every URL for the HTTP methods GET and POST. The default authenticator rejects any request and the default finalizer creates a JWT from the subject mentioned above. +* You've created a very simple rule, which reuses the default authenticator and finalizer and configures an authorizer, which allows any request to pass through. * You've created and started a docker compose environment with heimdall operated in proxy mode and a "upstream" service, which responds with everything it receives. * And sent an HTTP GET request to an imaginary `foobar` endpoint. * Heimdall run the request through its pipeline and forwarded the enriched (`Authorization` header) request to the "upstream" service, which just returned all it has received to the caller. diff --git a/README.md b/README.md index 511577f7a..7272d63f5 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,13 @@ The above said decision and transformation process happens via rules, respective That way, these rule sets can not only be managed centrally, but be deployed together with each particular upstream service as well without the need to restart or redeploy heimdall. Indeed, these rule sets are optional first class citizens of the upstream service and allow: * implementation of secure defaults. If no rule matches the incoming request, a default decision and transformation, if configured, is applied. This is the reason for "optional first class citizens" above. -* configuration of as many authentication (e.g. OpenID Connect), authorization (e.g. via CEL expressions, or via OPA, or OpenFGA), contextualization (by e.g. communicating to some specific endpoint) and unification mechanisms, supported by heimdall, as required for the particular system. So, if your system requires integration with multiple authentication providers, or you want to migrate from one to another - it is just a matter of configuring them in heimdall. +* configuration of as many authentication (e.g. OpenID Connect), authorization (e.g. via CEL expressions, or via OPA, or OpenFGA), contextualization (by e.g. communicating to some specific endpoint) and finalization mechanisms (e.g. creation of a JWT out of the available subject information), supported by heimdall, as required for the particular system. So, if your system requires integration with multiple authentication providers, or you want to migrate from one to another - it is just a matter of configuring them in heimdall. * reuse and combination of these mechanisms in as many rules, as required for the particular system. * partial reconfiguration of a particular mechanism in a rule if required by the upstream service. * authentication mechanism fallbacks * implementation of different decision process schemes by combining e.g. authentication mechanisms with error handlers to drive authentication mechanism specific error handling strategies. * execution of authorization and contextualization mechanisms in any order; that way, if the information about your subject, available from the authentication system, is not sufficient to make proper authorization decisions, you can let heimdall call other services to retrieve that additional information. -* conditional execution of authorization, contextualization and unification mechanisms is possible, e.g. if depending on the available information about the subject you would like heimdall to either block the request, or let the upstream return different representations of the requested resource. +* conditional execution of authorization, contextualization and finalization mechanisms is possible, e.g. if depending on the available information about the subject you would like heimdall to either block the request, or let the upstream return different representations of the requested resource. ## Beyond the functionality diff --git a/charts/heimdall/templates/demo/configmap.yaml b/charts/heimdall/templates/demo/configmap.yaml index d83e27951..48ca04196 100644 --- a/charts/heimdall/templates/demo/configmap.yaml +++ b/charts/heimdall/templates/demo/configmap.yaml @@ -70,10 +70,10 @@ data: type: deny - id: allow_all_requests type: allow - unifiers: + finalizers: - id: create_jwt type: jwt - - id: noop_unifier + - id: noop_finalizer type: noop default: @@ -83,7 +83,7 @@ data: execute: - authenticator: anonymous_authenticator - authorizer: deny_all_requests - - unifier: create_jwt + - finalizer: create_jwt providers: kubernetes: {} diff --git a/charts/heimdall/templates/demo/test-rule.yaml b/charts/heimdall/templates/demo/test-rule.yaml index 14fe92892..a66aabb0b 100644 --- a/charts/heimdall/templates/demo/test-rule.yaml +++ b/charts/heimdall/templates/demo/test-rule.yaml @@ -32,7 +32,7 @@ spec: execute: - authenticator: noop_authenticator - authorizer: allow_all_requests - - unifier: noop_unifier + - finalizer: noop_finalizer - id: anonymous-access match: url: http://<**>/anon/<**> diff --git a/cmd/validate/test_data/config.yaml b/cmd/validate/test_data/config.yaml index df6255cb6..1a5e9c651 100644 --- a/cmd/validate/test_data/config.yaml +++ b/cmd/validate/test_data/config.yaml @@ -143,7 +143,7 @@ rules: url: http://profile headers: foo: bar - unifiers: + finalizers: - id: jwt type: jwt config: @@ -182,7 +182,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: jwt + - finalizer: jwt on_error: - error_handler: authenticate_with_kratos diff --git a/cmd/validate/test_data/invalid-ruleset-for-proxy-usage.yaml b/cmd/validate/test_data/invalid-ruleset-for-proxy-usage.yaml index 7350e143b..c841814f7 100644 --- a/cmd/validate/test_data/invalid-ruleset-for-proxy-usage.yaml +++ b/cmd/validate/test_data/invalid-ruleset-for-proxy-usage.yaml @@ -22,13 +22,13 @@ rules: - authenticator: hydra_authenticator - contextualizer: subscription_contextualizer - authorizer: allow_all_authorizer - - unifier: jwt + - finalizer: jwt config: claims: | {"foo": "bar"} - - unifier: bla + - finalizer: bla config: headers: foo-bar: bla - - unifier: blabla + - finalizer: blabla # no on_error (reuses default) \ No newline at end of file diff --git a/cmd/validate/test_data/valid-ruleset.yaml b/cmd/validate/test_data/valid-ruleset.yaml index 92eb3ad35..909890103 100644 --- a/cmd/validate/test_data/valid-ruleset.yaml +++ b/cmd/validate/test_data/valid-ruleset.yaml @@ -28,13 +28,13 @@ rules: - authenticator: hydra_authenticator - contextualizer: subscription_contextualizer - authorizer: allow_all_authorizer - - unifier: jwt + - finalizer: jwt config: claims: | {"foo": "bar"} - - unifier: bla + - finalizer: bla config: headers: foo-bar: bla - - unifier: blabla + - finalizer: blabla # no on_error (reuses default) \ No newline at end of file diff --git a/docs/content/docs/configuration/cryptographic_material.adoc b/docs/content/docs/configuration/cryptographic_material.adoc index f7f8c7977..2f0407833 100644 --- a/docs/content/docs/configuration/cryptographic_material.adoc +++ b/docs/content/docs/configuration/cryptographic_material.adoc @@ -9,7 +9,7 @@ menu: parent: "Configuration" --- -Some link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers], which finalize the successful execution of the pipeline, can generated signed objects, like a JWT, to be forwarded to the upstream services. In such cases Heimdall acts as an issuer of such objects and needs at least corresponding key material. +Some link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers], which, as the name implies, finalize the successful execution of the pipeline, can generated signed objects, like a JWT, to be forwarded to the upstream services. In such cases Heimdall acts as an issuer of such objects and needs at least corresponding key material. == Configuration diff --git a/docs/content/docs/configuration/reference/reference.adoc b/docs/content/docs/configuration/reference/reference.adoc index 111dc93c8..a9367510c 100644 --- a/docs/content/docs/configuration/reference/reference.adoc +++ b/docs/content/docs/configuration/reference/reference.adoc @@ -122,9 +122,6 @@ tracing: metrics: enabled: true - host: 0.0.0.0 - port: 9000 - metrics_path: /metrics profiling: enabled: false @@ -284,7 +281,7 @@ rules: foo: bar continue_pipeline_on_error: true - unifiers: + finalizers: - id: jwt type: jwt config: @@ -326,7 +323,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: jwt + - finalizer: jwt on_error: - error_handler: authenticate_with_kratos diff --git a/docs/content/docs/configuration/rules/configuration.adoc b/docs/content/docs/configuration/rules/configuration.adoc index fc61ea95e..0014f1a5b 100644 --- a/docs/content/docs/configuration/rules/configuration.adoc +++ b/docs/content/docs/configuration/rules/configuration.adoc @@ -81,7 +81,7 @@ Defines where to forward the proxied request to. Used only when heimdall is oper + Host (and port) to be used for request forwarding. If no `rewrite` property (see below) is specified, all other parts, like scheme, path, etc. of the original url are preserved. E.g. if the original request is `\https://mydomain.com/api/v1/something?foo=bar&bar=baz` and the value of this property is set to `my-backend:8080`, the url used to forward the request to the upstream will be `\https://my-backend:8080/api/v1/something?foo=bar&bar=baz` + -NOTE: The `Host` header is not preserved while forwarding the request. If you need it to be set to the value from the original request, make use of the link:{{< relref "pipeline_mechanisms/unifiers.adoc#_header" >}}[header unifier] in your `execute` pipeline and set it accordingly. The example below demonstrates that. +NOTE: The `Host` header is not preserved while forwarding the request. If you need it to be set to the value from the original request, make use of the link:{{< relref "pipeline_mechanisms/finalizers.adoc#_header" >}}[header finalizer] in your `execute` pipeline and set it accordingly. The example below demonstrates that. ** *`rewrite`*: _OriginalURLRewriter_ (optional) + @@ -105,7 +105,7 @@ If defined, heimdall will remove the specified query parameters from the origina * *`execute`*: _link:{{< relref "#_regular_pipeline" >}}[Regular Pipeline]_ (mandatory) + -Which mechanisms to use to authenticate, authorize, contextualize (enrich) and unify the subject and other information available in the request. +Which mechanisms to use to authenticate, authorize, contextualize (enrich) and finalize the pipeline. * *`on_error`*: _link:{{< relref "#_error_handler_pipeline" >}}[Error Handler Pipeline]_ (optional) + @@ -133,13 +133,13 @@ execute: - authenticator: foo - authorizer: bar - contextualizer: foo - - unifier: zab + - finalizer: zab # the following one demonstrates how to preserve the # Host header from the original request, while forwarding # it to the upstream service - - unifier: preserve-host + - finalizer: preserve-host # the config property can be omitted, if already configured - # in the header unifier mechanism () + # in the header finalizer mechanism config: headers: Host: '{{ .Request.Header("Host") }}' @@ -150,17 +150,17 @@ on_error: === Regular Pipeline -As described in the link:{{< relref "/docs/getting_started/concepts.adoc" >}}[Concepts] section, heimdall's decision pipeline consists of multiple mechanisms - at least consisting of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] and link:{{< relref "pipeline_mechanisms/unifiers.adoc" >}}[unifiers]. The definition of such a pipeline happens as a list of required mechanisms (previously link:{{< relref "pipeline_mechanisms/overview.adoc" >}}[configured]) with the corresponding ids in the following order: +As described in the link:{{< relref "/docs/getting_started/concepts.adoc" >}}[Concepts] section, heimdall's decision pipeline consists of multiple mechanisms - at least consisting of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] and link:{{< relref "pipeline_mechanisms/finalizers.adoc" >}}[finalizers]. The definition of such a pipeline happens as a list of required mechanisms (previously link:{{< relref "pipeline_mechanisms/overview.adoc" >}}[configured]) with the corresponding IDs in the following order: * List of link:{{< relref "pipeline_mechanisms/authenticators.adoc" >}}[authenticators] using `authenticator` as key, followed by the required authenticator `id`. Authenticators following the first defined in the list are used by heimdall as fallback. That is, if first authenticator fails due to missing authentication data, second is executed, etc. By default, fallback is not used if an authenticator fails due to validation errors of the given authentication data. E.g. if an authenticator fails to validate the signature of a JWT token, the next authenticator in the list will not be executed. Instead, the entire pipeline will fail and lead to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured. + NOTE: Some authenticators use the same sources to get subject authentication object from. E.g. the `jwt` and the `oauth2_introspection` authenticators can retrieve tokens from the same places in the request. If such authenticators are used in the same pipeline, you should configure the more specific ones before the more general ones to have working default fallbacks. To stay with the above example, the `jwt` authenticator is more specific compared to `oauth2_introspection`, as it will be only executed, if the token is in a JWT format. In contrast to this, the `oauth2_introspection` authenticator is more general and does not care about the token format, thus will feel responsible for the request as soon as it finds a bearer token. You can however also make use of the `allow_fallback_on_error` configuration property and set it to `true`. This will allow a fallback even if the verification of the credentials fail. * List of link:({{< relref "pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers] and link:({{< relref "pipeline_mechanisms/authorizers.adoc" >}}[authorizers] in any order (optional). Can also be mixed. As with authenticators, the list definition happens using either `contextualizer` or `authorizer` as key, followed by the required `id`. All mechanisms in this list are executed in the order, they are defined. If any of these fails, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is optional. -* List of link:{{< relref "pipeline_mechanisms/unifiers.adoc" >}}[unifiers] using `unifiers` as key, followed by the required unifier `id`. All unifiers in this list are executed in the order, they are defined. If any of these fails, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured. +* List of link:{{< relref "pipeline_mechanisms/finalizers.adoc" >}}[finalizers] using `finalizers` as key, followed by the required finalizer `id`. All finalizers in this list are executed in the order they are defined. If any of these fail, the entire pipeline fails, which leads to the execution of the link:{{< relref "#_error_handler_pipeline" >}}[error handler pipeline]. This list is mandatory if no link:{{< relref "default.adoc" >}}[default rule] is configured. In all cases, the used mechanism can be partially reconfigured if supported by the corresponding type. Configuration goes into the `config` properties. These reconfigurations are always local to the given rule. With other words, you can adjust your rule specific pipeline as you want without any side effects. -Execution of an `contextualizer`, `authorizer`, or `unifier` mechanisms can optionally happen conditionally by making use of a https://github.com/google/cel-spec[CEL] expression in an `if` clause, which has access to the link:{{< relref "pipeline_mechanisms/overview.adoc#_subject" >}}[`Subject`] and the link:{{< relref "pipeline_mechanisms/overview.adoc#_request" >}}[`Request`] objects. If the `if` clause is not present, the corresponding mechanism is always executed. +Execution of an `contextualizer`, `authorizer`, or `finalizer` mechanisms can optionally happen conditionally by making use of a https://github.com/google/cel-spec[CEL] expression in an `if` clause, which has access to the link:{{< relref "pipeline_mechanisms/overview.adoc#_subject" >}}[`Subject`] and the link:{{< relref "pipeline_mechanisms/overview.adoc#_request" >}}[`Request`] objects. If the `if` clause is not present, the corresponding mechanism is always executed. .Complex pipeline ==== @@ -189,20 +189,20 @@ Execution of an `contextualizer`, `authorizer`, or `unifier` mechanisms can opti // some expression logic deviating from the // definition in the pipeline configuration. # ... any further required authorizer or contextualizer -# list of unifiers -- unifier: foo -- unifier: bar +# list of finalizers +- finalizer: foo +- finalizer: bar config: headers: - X-User-ID: {{ quote .ID }} - # ... any further required unifiers + # ... any further required finalizers ---- This example uses * two authenticators, with authenticator named `bar` being the fallback for the authenticator named `foo`. This fallback authenticator is obviously of type link:{{< relref "pipeline_mechanisms/authenticators.adoc#_anonymous" >}}[anonymous] as it reconfigures the referenced prototype to use `anon` for subject id. * multiple contextualizers and authorizers, with first contextualizer having its cache disabled (`cache_ttl` set to 0s) and the last authorizer being of type link:{{< relref "pipeline_mechanisms/authorizers.adoc#_local_cel" >}}[cel] as it reconfigures the referenced prototype to use a different authorization script. -* two unifiers, with the second one being obviously of type link:{{< relref "pipeline_mechanisms/unifiers.adoc#_header" >}}[header], as it defines a `X-User-ID` header set to the value of the subject id to be forwarded to the upstream service. +* two finalizers, with the second one being obviously of type link:{{< relref "pipeline_mechanisms/finalizers.adoc#_header" >}}[header], as it defines a `X-User-ID` header set to the value of the subject id to be forwarded to the upstream service. * contextualizer `foo` is only executed if the authenticated subject is not anonymous. * authorizer `foo` is only executed if the request method is HTTP POST. ==== diff --git a/docs/content/docs/configuration/rules/default.adoc b/docs/content/docs/configuration/rules/default.adoc index 62026a75b..07178a907 100644 --- a/docs/content/docs/configuration/rules/default.adoc +++ b/docs/content/docs/configuration/rules/default.adoc @@ -21,7 +21,7 @@ Which HTTP methods (`GET`, `POST`, `PATCH`, etc) are allowed. Expansion using `A * *`execute`*: _link:{{< relref "configuration.adoc#_regular_pipeline" >}}[Regular Pipeline]_ (mandatory) + -Which mechanisms to use for authentication, authorization, contextualization (enrich) and unification of the request and the subject. At least one link:{{< relref "./pipeline_mechanisms/authenticators.adoc" >}}[authenticator] and one link:{{< relref "./pipeline_mechanisms/unifiers.adoc" >}}[unifier] must be defined. A specific rule (see also link:{{< relref "configuration.adoc" >}}[Rule]) can omit the definition of authenticators, if it wants to reuse the authenticators defined in the default rule. Same is true for other mechanisms. Exception are link:{{< relref "./pipeline_mechanisms/authorizers.adoc" >}}[authorizers] and link:{{< relref "./pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers]. As soon, as a specific rule defines at least one authorizer or contextualizer, those authorizers and contextualizers (defined in the default rule) are not considered anymore. +Which mechanisms to use for authentication, authorization, contextualization (enrich) and finalization of the pipeline. At least one link:{{< relref "./pipeline_mechanisms/authenticators.adoc" >}}[authenticator] and one link:{{< relref "./pipeline_mechanisms/finalizers.adoc" >}}[finalizer] must be defined. A specific rule (see also link:{{< relref "configuration.adoc" >}}[Rule]) can omit the definition of authenticators, if it wants to reuse the authenticators defined in the default rule. Same is true for other mechanisms. Exception are link:{{< relref "./pipeline_mechanisms/authorizers.adoc" >}}[authorizers] and link:{{< relref "./pipeline_mechanisms/contextualizers.adoc" >}}[contextualizers]. As soon, as a specific rule defines at least one authorizer or contextualizer, those authorizers and contextualizers (defined in the default rule) are not considered anymore. * *`on_error`*: _link:{{< relref "configuration.adoc#_error_handler_pipeline" >}}[Error Handler Pipeline]_ (mandatory) + @@ -40,12 +40,12 @@ rules: - authenticator: session_cookie_from_kratos_authn - authenticator: oauth2_introspect_token_from_keycloak_authn - authorizer: deny_all_requests_authz - - unifier: jwt_unifier + - finalizer: create_jwt on_error: - error_handler: authenticate_with_kratos_eh ---- -This example defines a default rule, which allows HTTP `GET` and `PATCH` requests on any URL (will respond with `405 Method Not Allowed` for any other HTTP method used by a client). The regular pipeline consists of two authenticators, with `session_cookie_from_kratos_authn` being the first and `oauth2_introspect_token_from_keycloak_authn` being the fallback (if the first one fails), a `deny_all_requests_authz` authorizer and the `jwt_unifier` unifier. The error pipeline is configured to execute only the `authenticate_with_kratos_eh` error handler. +This example defines a default rule, which allows HTTP `GET` and `PATCH` requests on any URL (will respond with `405 Method Not Allowed` for any other HTTP method used by a client). The regular pipeline consists of two authenticators, with `session_cookie_from_kratos_authn` being the first and `oauth2_introspect_token_from_keycloak_authn` being the fallback (if the first one fails), a `deny_all_requests_authz` authorizer and the `create_jwt` finalizer. The error pipeline is configured to execute only the `authenticate_with_kratos_eh` error handler. Obviously, the regular pipeline (defined in the `execute` property) of this default rule will always result in an error due to `deny_all_requests_authz`. This way it is thought to provide secure defaults and let the upstream specific rules override at least the part dealing with authorization. Such an upstream specific rule could then look like follows: @@ -58,6 +58,6 @@ execute: - authorizer: allow_all_requests_authz ---- -Take a look at how `methods`, `on_error`, as well as the authenticators and unifiers from the `execute` definition of the default rule are reused. Easy, no? +Take a look at how `methods`, `on_error`, as well as the authenticators and finalizers from the `execute` definition of the default rule are reused. Easy, no? ==== diff --git a/docs/content/docs/configuration/rules/pipeline_mechanisms/error_handlers.adoc b/docs/content/docs/configuration/rules/pipeline_mechanisms/error_handlers.adoc index be1c3fccf..95312e170 100644 --- a/docs/content/docs/configuration/rules/pipeline_mechanisms/error_handlers.adoc +++ b/docs/content/docs/configuration/rules/pipeline_mechanisms/error_handlers.adoc @@ -9,7 +9,7 @@ menu: parent: "Pipeline Mechanisms" --- -Error Handlers are responsible for execution of logic if any of the link:{{< relref "authenticators.adoc" >}}[authenticators], link:{{< relref "authorizers.adoc" >}}[authorizers], link:{{< relref "contextualizers.adoc" >}}[contextualizers] or link:{{< relref "unifiers.adoc" >}}[unifiers] fails. The error handler mechanisms range from a simple error response to the client which sent the request to sophisticated ones, supporting complex logic and redirects. +Error Handlers are responsible for execution of logic if any of the link:{{< relref "authenticators.adoc" >}}[authenticators], link:{{< relref "authorizers.adoc" >}}[authorizers], link:{{< relref "contextualizers.adoc" >}}[contextualizers] or link:{{< relref "finalizers.adoc" >}}[finalizers] fails. The error handler mechanisms range from a simple error response to the client which sent the request to sophisticated ones, supporting complex logic and redirects. == Error Handler Types diff --git a/docs/content/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc b/docs/content/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc new file mode 100644 index 000000000..1995de849 --- /dev/null +++ b/docs/content/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc @@ -0,0 +1,124 @@ +--- +title: "Finalizers" +date: 2022-06-09T18:57:16+02:00 +draft: false +weight: 90 +menu: + docs: + weight: 40 + parent: "Pipeline Mechanisms" +--- + +Finalizers, as the name implies, finalize the successful execution of the pipeline and make the available information about the link:{{< relref "overview.adoc#_subject" >}}[`Subject`] and the link:{{< relref "overview.adoc#_request" >}}[`Request`] to the upstream service in a format expected, respectively required by it. This ranges from adding a simple header to a structured JWT in a specific header. + +== Finalizer Types + +The following sections describe the available finalizer types in more detail. Some of these may support or require additional configuration. The corresponding properties are annotated with `mandatory`, respectively `optional` to denote configuration requirement, as well as with `overridable`, `not overriddable` and `partially overridable` to indicate whether the property can be overridden in a rule pipeline. + +=== Noop + +As the name implies, this finalizer does nothing. As finalizer are the last step in a rule pipeline and act on the available link:{{< relref "overview.adoc#_subject" >}}[`Subject`] information, the usage of this finalizer makes only sense in combination with the link:{{< relref "authenticators.adoc#_noop">}}[Noop Authenticator], e.g. if your API should be publicly available. This finalizer type also doesn't have any configuration options. + +To enable the usage of this finalizer, you have to set the `type` property to `noop`. + +.Noop finalizer configuration +==== +[source, yaml] +---- +id: foo +type: noop +---- +==== + +=== Header + +This finalizer enables transformation of a link:{{< relref "overview.adoc#_subject" >}}[`Subject`] into HTTP headers. It can also be used to map information from the original link:{{< relref "overview.adoc#_request" >}}[`Request`] into headers expected by the upstream service. + +To enable the usage of this finalizer, you have to set the `type` property to `header`. + +Configuration using the `config` property is mandatory. Following properties are available: + +* *`headers`*: _string map_ (mandatory, overridable) ++ +Enables configuration of arbitrary headers with any values build from available subject and request information (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). + +.Header finalizer configuration +==== +[source, yaml] +---- +id: foo +type: header +config: + headers: + X-User-ID: '{{ quote .Subject.ID }}' + X-User-Email: '{{ quote .Subject.Attributes["email"] }}' + Host: '{{ quote .Request.Header("Host") }}' +---- +==== + +=== Cookie + +This finalizer enables transformation of a link:{{< relref "overview.adoc#_subject" >}}[`Subject`] into cookies. It can also be used to map information from the original link:{{< relref "overview.adoc#_request" >}}[`Request`] into cookies expected by the upstream service. + +To enable the usage of this finalizer, you have to set the `type` property to `cookie`. + +Configuration using the `config` property is mandatory. Following properties are available: + +* *`cookies`*: _string map_ (mandatory, overridable) ++ +Enables configuration of arbitrary cookies with any values build from available subject information (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). + +.Cookie finalizer configuration +==== +[source, yaml] +---- +id: foo +type: cookies +config: + cookies: + user_id_cookie: '{{ quote .Subject.ID }}' + user_email_cookie: '{{ quote .Subject.Attributes["email"] }}' +---- +==== + +=== JWT + +This finalizer enables transformation of the link:{{< relref "overview.adoc#_subject" >}}[`Subject`] and the link:{{< relref "overview.adoc#_request" >}}[`Request`] object into a token in a https://www.rfc-editor.org/rfc/rfc7519[JWT] format, which is then made available to your upstream service in either the HTTP `Authorization` header with `Bearer` scheme set, or in a custom header. In addition to setting the JWT specific claims, it allows setting custom claims as well. Your upstream service can then verify the signature of the JWT by making use of heimdall's JWKS endpoint to retrieve the required public keys/certificates from. + +NOTE: To enable the usage of this finalizer, you have to set the `type` property to `jwt`. The usage of this finalizer type requires a configured link:{{< relref "/docs/configuration/cryptographic_material.adoc" >}}[Signer] as well. At least it is a must in production environments. + +Configuration using the `config` property is optional. Following properties are available: + +* *`claims`*: _string_ (optional, overridable) ++ +Your template with custom claims, you would like to add to the JWT (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). + +* *`ttl`*: _link:{{< relref "/docs/configuration/reference/types.adoc#_duration" >}}[Duration]_ (optional, overridable) ++ +Defines how long the JWT should be valid. Defaults to 5 minutes. Heimdall sets the `iat` and the `nbf` claims to the current system time. The value of the `exp` claim is then influenced by the `ttl` property. + +* *`header`*: _object_ (optional, not overridable) ++ +Defines the `name` and `scheme` to be used for the header. Defaults to `Authorization` with scheme `Bearer`. If defined, the `name` property must be set. If `scheme` is not defined, no scheme will be prepended to the resulting JWT. + +The generated JWT is always cached until 5 seconds before its expiration. The cache key is calculated from the entire configuration of the finalizer instance and the available information about the current subject. + +.JWT finalizer configuration +==== +[source, yaml] +---- +id: jwt_finalizer +type: jwt +config: + ttl: 5m + header: + name: X-Token + claims: | + { + {{ $user_name := .Subject.Attributes.identity.user_name -}} + "email": {{ quote .Subject.Attributes.identity.email }}, + "email_verified": {{ .Subject.Attributes.identity.email_verified }}, + "name": {{ if $user_name }}{{ quote $user_name }}{{ else }}{{ quote $email }}{{ end }} + } +---- +==== diff --git a/docs/content/docs/configuration/rules/pipeline_mechanisms/overview.adoc b/docs/content/docs/configuration/rules/pipeline_mechanisms/overview.adoc index 6664731d6..31973c572 100644 --- a/docs/content/docs/configuration/rules/pipeline_mechanisms/overview.adoc +++ b/docs/content/docs/configuration/rules/pipeline_mechanisms/overview.adoc @@ -14,7 +14,7 @@ All mechanisms supported by heimdall fall into following categories: * link:{{< relref "authenticators.adoc">}}[Authenticators], which inspect HTTP requests for presence of authentication objects, like e.g. the presence of a specific cookie. If such objects exist, authenticators verify the related authentication status and obtain information about the corresponding subject. A subject, could be a user who tries to use particular functionality of the upstream service, a machine (if you have machine-2-machine interaction), or something different. Authenticators ensure the subject is authenticated and the information available about it is valid. * link:{{< relref "authorizers.adoc">}}[Authorizers], which ensure that the subject obtained via an authenticator has the required permissions to submit the given HTTP request and thus to execute the corresponding logic in the upstream service. E.g. a specific endpoint of the upstream service might only be accessible to a "user" from the "admin" group, or to an HTTP request if a specific HTTP header is set. * link:{{< relref "contextualizers.adoc">}}[Contextualizers], which enrich the information about the subject obtained via an authenticator with further contextual information, required either by the upstream service itself or an authorizer. This can be handy if the actual authentication system doesn't have all information about the subject (which is usually the case in microservice architectures), or if dynamic information about the subject, like the current location based on the IP address, is required. -* link:{{< relref "unifiers.adoc">}}[Unifiers], which finalize the successful execution of the pipeline and unify the available information about the subject by transforming it into a format expected, respectively required by the upstream service. This ranges from adding a query parameter, to a structured JWT in a specific header. +* link:{{< relref "finalizers.adoc">}}[Finalizers], which, as the name implies, finalize the successful execution of the pipeline and make the gathered information about the subject and the request available to the upstream service in a format expected, respectively required by it. This ranges from adding a simple header or cookie, to a structured JWT. * link:{{< relref "error_handlers.adoc">}}[Error Handlers], which are responsible for execution of logic if any of the mechanisms described above fail. These range from a simple error response to the client, which sent the request, to sophisticated ones, supporting complex logic and redirects. == General Configuration @@ -31,8 +31,8 @@ rules: contextualizers: - unifiers: - + finalizers: + error_handlers: ---- @@ -108,8 +108,8 @@ rules: forward_headers: - Authorization cache_ttl: 1m - unifiers: - - id: jwt_unifier + finalizers: + - id: jwt_finalizer type: jwt config: ttl: 5m diff --git a/docs/content/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc b/docs/content/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc deleted file mode 100644 index 48bae2c30..000000000 --- a/docs/content/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: "Unifiers" -date: 2022-06-09T18:57:16+02:00 -draft: false -weight: 90 -menu: - docs: - weight: 40 - parent: "Pipeline Mechanisms" ---- - -Unifiers finalize the successful execution of the pipeline and unify the available information about the link:{{< relref "overview.adoc#_subject" >}}[`Subject`] by transforming it into a format expected, respectively required by the upstream service. This ranges from adding a simple header to a structured JWT in a specific header. - -== Unifier Types - -The following sections describe the available unifier types in more detail. Some of these may support or require additional configuration. The corresponding properties are annotated with `mandatory`, respectively `optional` to denote configuration requirement, as well as with `overridable`, `not overriddable` and `partially overridable` to indicate whether the property can be overridden in a rule pipeline. Those unifiers, which support creation of custom objects via templating, have access to at least the link:{{< relref "overview.adoc#_subject" >}}[`Subject`] objects in the template. Some can also make use of the link:{{< relref "overview.adoc#_request" >}}[`Request`] object. - -=== Noop - -As the name implies, this unifier does nothing. As unifier are the last step in a rule pipeline and transform the available link:{{< relref "overview.adoc#_subject" >}}[`Subject`] information into a format required by the upstream service, the usage of this unifier makes only sense in combination with the link:{{< relref "authenticators.adoc#_noop">}}[Noop Authenticator], e.g. if your API should be publicly available. This authenticator type also doesn't have any configuration options. - -To enable the usage of this unifier, you have to set the `type` property to `noop`. - -.Noop unifier configuration -==== -[source, yaml] ----- -id: foo -type: noop ----- -==== - -=== Header - -This unifier enables transformation of a link:{{< relref "overview.adoc#_subject" >}}[`Subject`] into HTTP headers. - -To enable the usage of this unifier, you have to set the `type` property to `header`. - -Configuration using the `config` property is mandatory. Following properties are available: - -* *`headers`*: _string map_ (mandatory, overridable) -+ -Enables configuration of arbitrary headers with any values build from available subject information (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). Can also be used to build headers from the processed request object. - -.Header unifier configuration -==== -[source, yaml] ----- -id: foo -type: header -config: - headers: - X-User-ID: '{{ quote .Subject.ID }}' - X-User-Email: '{{ quote .Subject.Attributes["email"] }}' ----- -==== - -=== Cookie - -This unifier enables transformation of a link:{{< relref "overview.adoc#_subject" >}}[`Subject`] into cookies. - -To enable the usage of this unifier, you have to set the `type` property to `cookie`. - -Configuration using the `config` property is mandatory. Following properties are available: - -* *`cookies`*: _string map_ (mandatory, overridable) -+ -Enables configuration of arbitrary cookies with any values build from available subject information (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). Can also be used to build cookies from the processed request object. - -.Cookie unifier configuration -==== -[source, yaml] ----- -id: foo -type: cookies -config: - cookies: - user_id_cookie: '{{ quote .Subject.ID }}' - user_email_cookie: '{{ quote .Subject.Attributes["email"] }}' ----- -==== - -=== JWT - -This unifier enables transformation of a link:{{< relref "overview.adoc#_subject" >}}[`Subject`] object into a token in a https://www.rfc-editor.org/rfc/rfc7519[JWT] format, which is made available to your upstream service in either the HTTP `Authorization` header with `Bearer` scheme set, or in a custom header. In addition to setting the JWT specific claims, it allows setting custom claims as well. Your upstream service can then verify the signature of the JWT by making use of heimdall's JWKS endpoint to retrieve the required public keys/certificates from. - -To enable the usage of this unifier, you have to set the `type` property to `jwt`. The usage of this unifier type requires a configured link:{{< relref "/docs/configuration/cryptographic_material.adoc" >}}[Signer] as well. At least it is a must in production environments. - -Configuration using the `config` property is optional. Following properties are available: - -* *`claims`*: _string_ (optional, overridable) -+ -Your template with custom claims, you would like to add to the JWT (See also link:{{< relref "overview.adoc#_templating" >}}[Templating]). - -* *`ttl`*: _link:{{< relref "/docs/configuration/reference/types.adoc#_duration" >}}[Duration]_ (optional, overridable) -+ -Defines how long the JWT should be valid. Defaults to 5 minutes. Heimdall sets the `iat` and the `nbf` claims to the current system time. The value of the `exp` claim is then influenced by the `ttl` property. - -* *`header`*: _object_ (optional, not overridable) -+ -Defines the `name` and `scheme` to be used for the header. Defaults to `Authorization` with scheme `Bearer`. If defined, the `name` property must be set. If `scheme` is not defined, no scheme will be prepended to the resulting JWT. - -The generated JWT is always cached until 5 seconds before its expiration. The cache key is calculated from the entire configuration of the unifier instance and the available information about the current subject. - -.JWT unifier configuration -==== -[source, yaml] ----- -id: jwt_unifier -type: jwt -config: - ttl: 5m - header: - name: X-Token - claims: | - { - {{ $user_name := .Subject.Attributes.identity.user_name -}} - "email": {{ quote .Subject.Attributes.identity.email }}, - "email_verified": {{ .Subject.Attributes.identity.email_verified }}, - "name": {{ if $user_name }}{{ quote $user_name }}{{ else }}{{ quote $email }}{{ end }} - } ----- -==== diff --git a/docs/content/docs/getting_started/concepts.adoc b/docs/content/docs/getting_started/concepts.adoc index 43fc207b6..611817d24 100644 --- a/docs/content/docs/getting_started/concepts.adoc +++ b/docs/content/docs/getting_started/concepts.adoc @@ -27,7 +27,7 @@ As described in the link:{{< relref "/docs/welcome.adoc" >}}[Welcome] section an | | | |+------------------+ +------------------+ +------------------+ +------------------+| | || cCCC | | cCCC | | cCCC | | cCCC || : - || 1. Authenticate | | 2. Contextualize | | 3. Authorize | | 4. Unify || | + || 1. Authenticate | | 2. Contextualize | | 3. Authorize | | 4. Finalize || | || | | | | | | || +------------------+ |+------------------+ +------------------+ +------------------+ +------------------+| | Backend Service | | | | | @@ -58,9 +58,9 @@ Here, heimdall communicates with other systems as well, either to get further in ** *authorization* mechanisms, so-called link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/authorizers.adoc" >}}[Authorizers], to be executed (if multiple are defined, they are executed in the order of their definition; can be mixed with contextualization mechanisms) - step 3 in the figure above. + Here, heimdall performs authorization checks, either locally, or by communicating with yet again further systems, like Open Policy Agent, Ory Keto and alike. -** *unification* mechanisms, so-called link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers], to be executed (if multiple are defined, they are executed in the order of their definition) - step 4 in the figure above. +** *finalization* mechanisms, so-called link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers], to be executed (if multiple are defined, they are executed in the order of their definition) - step 4 in the figure above. + -This step unifies the information collected so far about the subject and the request by transforming it into an object expected by the upstream service. That reaches from a simple custom header, carrying e.g. the id of the subject, to a JWT carried in the `Authorization` header. +This step finalizes the execution of the pipeline and transform the information collected so far about the subject and the request into objects expected by the upstream service. That reaches from a simple custom header, carrying e.g. the id of the subject, to a JWT carried in the `Authorization` header. * an error pipeline, consisting of link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/error_handlers.adoc" >}}[error handler] mechanisms (if multiple are defined, they are executed as fallbacks), which are executed if any of the regular pipeline mechanisms fail. These mechanisms range from a simple error response to the client (which sent the request), to sophisticated ones supporting complex logic and redirects. The diagram below sketches the related execution logic @@ -153,7 +153,7 @@ methods: - GET execute: - authenticator: anonymous-authn - - unifier: id-header + - finalizer: id-header ---- Then the request will be forwarded as follows: @@ -241,7 +241,7 @@ methods: - GET execute: - authenticator: anonymous-authn - - unifier: id-header + - finalizer: id-header ---- Then heimdall will respond with: diff --git a/docs/content/docs/getting_started/configuration_introduction.adoc b/docs/content/docs/getting_started/configuration_introduction.adoc index 4e0505805..14544d450 100644 --- a/docs/content/docs/getting_started/configuration_introduction.adoc +++ b/docs/content/docs/getting_started/configuration_introduction.adoc @@ -65,7 +65,7 @@ rules: authenticators: - id: anonymous_authenticator type: anonymous - unifiers: + finalizers: - id: create_jwt type: jwt @@ -75,7 +75,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: create_jwt + - finalizer: create_jwt ---- ==== @@ -96,7 +96,7 @@ rules: config: user: ${INTROSPECT_EP_USER} password: ${INTROSPECT_EP_PASSWORD} - unifiers: + finalizers: - id: create_jwt type: jwt ---- @@ -167,7 +167,7 @@ The corresponding environment variables would be [source,bash] ---- HEIMDALLCFG_RULES_MECHANISMS_AUTHENTICATORS_0_ID=anonymous_authenticator -HEIMDALLCFG_RULES_MECHANISMS__AUTHENTICATORS_0_TYPE=anonymous +HEIMDALLCFG_RULES_MECHANISMS_AUTHENTICATORS_0_TYPE=anonymous ---- * If a name of a property has `\_` it must be escaped with an additional `_`. @@ -193,4 +193,4 @@ Heimdall gets the rule sets from link:{{< relref "/docs/configuration/rules/prov In all cases, a single rule definition adheres to the schema defined in link:{{< relref "/docs/configuration/rules/configuration.adoc" >}}[rule configuration]. -NOTE: Usage of environment variables is not possible with, respectively in rule sets. +NOTE: Usage of environment variables in rule sets depend on the used provider. diff --git a/docs/content/docs/getting_started/decision_service_quickstart.adoc b/docs/content/docs/getting_started/decision_service_quickstart.adoc index 2701ef17c..194f2a2c9 100644 --- a/docs/content/docs/getting_started/decision_service_quickstart.adoc +++ b/docs/content/docs/getting_started/decision_service_quickstart.adoc @@ -42,7 +42,7 @@ rules: type: anonymous - id: reject_requests type: unauthorized - unifiers: # <4> + finalizers: # <4> - id: do_nothing type: noop - id: create_jwt @@ -54,7 +54,7 @@ rules: - POST execute: - authenticator: reject_requests - - unifier: create_jwt + - finalizer: create_jwt providers: file_system: # <6> @@ -64,7 +64,7 @@ rules: <1> Here we are setting the log level to `info` to be able to see any log output. By default, heimdall logs on `error` log level. <2> Configures heimdall's decision service to trust requests from all sources. This allows usage of `X-Forwarded-*` headers. This configuration is only required if you want to try out the docker compose example from below. <3> Configures a couple of authenticators - the `noop` authenticator, which does nothing, the `anonymous` authenticator, which treats every request as anonymous (creates a subject with its id set to anonymous) and the `unauthorized` authenticator, which rejects every request with `401 Unauthorized` HTTP code. -<4> Configured a couple of unifiers - the `noop` unifier, which does nothing and the jwt` unifier, which transforms the information about the subject into a JWT. +<4> Configured a couple of finalizers - the `noop` finalizer, which does nothing and the jwt` finalizer, which transforms the information about the subject into a JWT. <5> Configures the default rule, which will obviously reject every request. <6> Configures a `file_system` provider, which allows heimdall loading rules from the local filesystem; here from the `/heimdall/conf/rule.yaml` file. @@ -80,7 +80,7 @@ rules: url: http://<**>/public execute: - authenticator: do_nothing - - unifier: do_nothing + - finalizer: do_nothing - id: rule2 # <2> match: @@ -91,8 +91,8 @@ rules: This file contains two rules: -<1> This rule should match the `\http://<**>/public` url and accept every request without performing any authentication and unification. -<2> This rule should match the `\http://<**>/anonymous` url. It uses the `anon` authenticator from our mechanisms definitions and since it does not specify a unifier, the unifier from the default rule `create_jwt` is used. +<1> This rule should match the `\http://<**>/public` url and accept every request without performing any authentication and finalization. +<2> This rule should match the `\http://<**>/anonymous` url. It uses the `anon` authenticator from our mechanisms definitions and since it does not specify any finalizers, the finalizers from the default rule, here the `create_jwt` finalizer, is used. == Run Standalone Run heimdall specifying the configuration file from above diff --git a/docs/content/docs/getting_started/proxy_service_quickstart.adoc b/docs/content/docs/getting_started/proxy_service_quickstart.adoc index 43afb9ca5..5570eded3 100644 --- a/docs/content/docs/getting_started/proxy_service_quickstart.adoc +++ b/docs/content/docs/getting_started/proxy_service_quickstart.adoc @@ -41,7 +41,7 @@ rules: type: deny - id: allow_all_requests # <4> type: allow - unifiers: + finalizers: - id: create_jwt # <5> type: jwt - id: noop @@ -54,7 +54,7 @@ rules: execute: - authenticator: anonymous_authenticator - authorizer: deny_all_requests - - unifier: create_jwt + - finalizer: create_jwt providers: file_system: # <7> @@ -65,7 +65,7 @@ rules: <2> Configures the `anonymous` authenticator. <3> Configures the `deny` authorizer. <4> Configures the `allow` authorizer. It will be used in our rule to allow requests. -<5> Configures the `jwt` unifier. +<5> Configures the `jwt` finalizer. <6> Configures the default rule. <7> Configures the `file_system` provider, which will allow loading of our rule from the file system. + @@ -93,10 +93,10 @@ rules: execute: - authenticator: noop - authorizer: allow_all_requests - - unifier: noop + - finalizer: noop ---- + -<1> This rule matches any host and the `/anonymous` path and forwards the request to our upstream service (which we're going to define next). In addition, it reuses the configuration from the default rule. Here, the methods, which are allowed, as well as the authorizers and unifiers. So we don't need to define them here. +<1> This rule matches any host and the `/anonymous` path and forwards the request to our upstream service (which we're going to define next). In addition, it reuses the configuration from the default rule. Here, the methods, which are allowed, as well as the authorizers and finalizers. So we don't need to define them in the rule. <2> This rule matches any host and the `/public` path and forwards the request as the previous rule to our upstream service. This rule doesn't perform any kind of request verification or transformation. . Create or copy the following `docker-compose.yaml` file and modify it to include the correct paths to your `config.yaml` and `rule.yaml` files: diff --git a/docs/content/docs/guides/envoy.adoc b/docs/content/docs/guides/envoy.adoc index fbc9f9466..cc17a8da5 100644 --- a/docs/content/docs/guides/envoy.adoc +++ b/docs/content/docs/guides/envoy.adoc @@ -60,7 +60,7 @@ clusters: port_value: 4456 # other cluster entries ---- -* to include an https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto.html[External Authorization] HTTP filter in the definition of the HTTP connection manager and depending on the used configuration, either configure the `http_service` and let it contain the required header name(s), heimdall sets in the HTTP responses (depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration), or configure the `grpc_service`. +* to include an https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto.html[External Authorization] HTTP filter in the definition of the HTTP connection manager and depending on the used configuration, either configure the `http_service` and let it contain the required header name(s), heimdall sets in the HTTP responses (depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers] configuration), or configure the `grpc_service`. + The following snipped shows, how an https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto.html[External Authorization] can be defined using `http_service` to let Envoy communicating with heimdall by making use of the previously defined `cluster` (see snippet from above) as well as forwarding all request headers to heimdall and to let it forward headers, set by heimdall in its responses (here the `Authorization` header) to the upstream services. + diff --git a/docs/content/docs/guides/haproxy.adoc b/docs/content/docs/guides/haproxy.adoc index 077f1228f..0ae44ec30 100644 --- a/docs/content/docs/guides/haproxy.adoc +++ b/docs/content/docs/guides/haproxy.adoc @@ -33,7 +33,7 @@ haproxy-ingress.github.io/headers: | <3> ---- <1> Configures the controller to use heimdall's decision service endpoint with ``, `` and `` depending on your configuration. <2> Let HAProxy forward the `Authorization` header set by heimdall to the upstream service upon successful response. This configuration depends on -your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration. +your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers] configuration. + NOTE: There is currently a limitation in HAProxy Ingress Controller regarding the case-insensitivity for headers. Since heimdall returns the header in lower-case, it is important to set the names of the required to be forwarded headers in lower case as well. <3> Configures the required headers to pass the information about the used HTTP scheme, host and port, request path and used query parameters to be forwarded to heimdall. `X-Forwarded-Proto` is not used, as it is already set by HAProxy by default. diff --git a/docs/content/docs/guides/nginx.adoc b/docs/content/docs/guides/nginx.adoc index 9a6930ab4..0d66cb491 100644 --- a/docs/content/docs/guides/nginx.adoc +++ b/docs/content/docs/guides/nginx.adoc @@ -53,8 +53,8 @@ location = /_auth { <4> } ---- <1> Configures NGINX to forward every request to the internal `/_auth` endpoint (this is where the actual heimdall integration happens - see below). -<2> When the response from heimdall returns, this and the next line set the Cookies set by heimdall in the response (whether you need this depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration) -<3> When the response from heimdall returns, this and the next line set the `Authorization` header set by heimdall in the response (which header to set depends again on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration) +<2> When the response from heimdall returns, this and the next line set the Cookies set by heimdall in the response (whether you need this depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/Finalizers.adoc" >}}[Finalizers] configuration) +<3> When the response from heimdall returns, this and the next line set the `Authorization` header set by heimdall in the response (which header to set depends again on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers] configuration) <4> This is where the "magic" happens <5> Configure NGINX to use the HTTP method used by its client. Without this setting the implementation of `proxy_path` will use the HTTP GET method. <6> Configures NGINX to pass the request to heimdall and sets the request path and queries from the original request @@ -118,7 +118,7 @@ nginx.ingress.kubernetes.io/auth-snippet: | <3> ---- <1> Configures the controller to use heimdall's decision service endpoint with ``, `` and `` depending on your configuration. <2> Let NGINX forward the `Authorization` header set by heimdall to the upstream service upon successful response. This configuration depends on -your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration. If not configured, NGINX will only react on `Set-Cookie` headers in responses from heimdall by default. +your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers] configuration. If not configured, NGINX will only react on `Set-Cookie` headers in responses from heimdall by default. <3> Configures the required headers to pass the information about the used HTTP scheme, host and port, request path and used query parameters to be forwarded to heimdall. + NOTE: Without that, heimdall will not be able extracting relevant information from the NGINX request as it does not support NGINX proprietary `X-Original-Method` and `X-Original-Uri` used by it for the same purposes. diff --git a/docs/content/docs/guides/opa.adoc b/docs/content/docs/guides/opa.adoc index 1f3a42a36..e15a935c4 100644 --- a/docs/content/docs/guides/opa.adoc +++ b/docs/content/docs/guides/opa.adoc @@ -105,6 +105,6 @@ config: { "input": { "user": {{ quote .Subject.ID }} } } ---- -Upon successful execution of the corresponding request, the response from the OPA endpoint will be stored in the `Subject.Attributes["billing_contextualizer"]` field. That way, you can use that information in a link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifier] to forward the group membership to the billing service API. +Upon successful execution of the corresponding request, the response from the OPA endpoint will be stored in the `Subject.Attributes["billing_contextualizer"]` field. That way, you can use that information in a link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizer] to forward the group membership to the billing service API. ==== diff --git a/docs/content/docs/guides/traefik.adoc b/docs/content/docs/guides/traefik.adoc index dd05fb0f8..94080608f 100644 --- a/docs/content/docs/guides/traefik.adoc +++ b/docs/content/docs/guides/traefik.adoc @@ -15,7 +15,7 @@ https://doc.traefik.io/traefik/[Traefik Proxy] is a modern HTTP proxy and load b To achieve this, configure traefik * to make use of the aforesaid ForwardAuth middleware by setting the `address` property to the decision service endpoint and -* configure the `authResponseHeaders` to contain the required header name(s), heimdall sets in the HTTP responses (depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/unifiers.adoc" >}}[Unifiers] configuration). +* configure the `authResponseHeaders` to contain the required header name(s), heimdall sets in the HTTP responses (depends on your link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/contextualizers.adoc" >}}[Contextualizers] and link:{{< relref "/docs/configuration/rules/pipeline_mechanisms/finalizers.adoc" >}}[Finalizers] configuration). * Configure the route of your service to make use of this middleware. [CAUTION] diff --git a/docs/content/docs/operations/observability.adoc b/docs/content/docs/operations/observability.adoc index b82b36cc8..a22a8e40c 100644 --- a/docs/content/docs/operations/observability.adoc +++ b/docs/content/docs/operations/observability.adoc @@ -35,7 +35,7 @@ If you configure heimdall to log in `text` format, you can expect output similar 2022-08-03T12:51:52+02:00 DBG Decision endpoint called 2022-08-03T12:51:52+02:00 DBG Executing default rule 2022-08-03T12:51:52+02:00 DBG Authenticating using anonymous authenticator -2022-08-03T12:51:52+02:00 DBG Unifying using JWT unifier +2022-08-03T12:51:52+02:00 DBG Finalizing using JWT finalizer 2022-08-03T12:51:52+02:00 DBG Generating new JWT 2022-08-03T12:51:52+02:00 DBG Finalizing request ---- @@ -76,7 +76,7 @@ Otherwise, if you configure it to use `gelf` (see https://docs.graylog.org/v1/do "_trace_id": "00000000000000000a5af97bffe6a8a2", "short_message": "Authenticating using anonymous authenticator"} {"_level_name": "DEBUG", "version": "1.1", "host": "unknown", "timestamp": 1659523295, "level": 7, "_parent_id": "3449bda63ed70206", "_span_id": "f57c007257fee0ed", - "_trace_id": "00000000000000000a5af97bffe6a8a2", "short_message": "Unifying using JWT unifier"} + "_trace_id": "00000000000000000a5af97bffe6a8a2", "short_message": "Finalizing using JWT finalizer"} {"_level_name": "DEBUG", "version": "1.1", "host": "unknown", "timestamp": 1659523295, "level": 7, "_parent_id": "3449bda63ed70206", "_span_id": "f57c007257fee0ed", "_trace_id": "00000000000000000a5af97bffe6a8a2", "short_message": "Generating new JWT"} diff --git a/docs/content/docs/welcome.adoc b/docs/content/docs/welcome.adoc index 03acd6f79..c2240fefa 100644 --- a/docs/content/docs/welcome.adoc +++ b/docs/content/docs/welcome.adoc @@ -76,7 +76,7 @@ Heimdall intercepts all your application related HTTP(s) traffic, allowing a bro | | | |+------------------+ +------------------+ +------------------+ +------------------+| | || cCCC | | cCCC | | cCCC | | cCCC || : - || 1. Authenticate | | 2. Contextualize | | 3. Authorize | | 4. Unify || | + || 1. Authenticate | | 2. Contextualize | | 3. Authorize | | 4. Finalize || | || | | | | | | || +------------------+ |+------------------+ +------------------+ +------------------+ +------------------+| | Backend Service | | | | | diff --git a/docs/package-lock.json b/docs/package-lock.json index 3054aa704..7431b0459 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -1,7 +1,7 @@ { "name": "heimdall-docs", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -16,37 +16,86 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -60,6 +109,19 @@ "node": ">=4" } }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "node_modules/@mermaid-js/mermaid-cli": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-10.4.0.tgz", @@ -86,16 +148,45 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@puppeteer/browsers": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", + "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=14.1.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@types/node": { - "version": "18.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz", - "integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==", + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", "optional": true }, "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.1.tgz", + "integrity": "sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==", "optional": true, "dependencies": { "@types/node": "*" @@ -112,15 +203,26 @@ "node": ">= 6.0.0" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/argparse": { @@ -128,11 +230,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -195,15 +292,6 @@ } ] }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -244,9 +332,9 @@ } }, "node_modules/chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -260,9 +348,9 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "node_modules/chromium-bidi": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.4.tgz", - "integrity": "sha512-4BX5cSaponuvVT1+SbLYTOAgDoVtX/Khoc9UsbFJ/AsPVUeFAM3RiIDFI6XFhLYMi9WmVJqh1ZH+dRpNKkKwiQ==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz", + "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==", "dependencies": { "mitt": "3.0.0" }, @@ -270,36 +358,47 @@ "devtools-protocol": "*" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "engines": { "node": ">=14" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, "node_modules/cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dependencies": { "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -308,6 +407,9 @@ }, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" } }, "node_modules/cross-fetch": { @@ -335,9 +437,14 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1094867", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", - "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==" + "version": "0.0.1107588", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", + "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/end-of-stream": { "version": "1.4.4", @@ -355,6 +462,14 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -400,10 +515,13 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, "node_modules/get-stream": { "version": "5.2.0", @@ -419,25 +537,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -500,15 +599,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -519,6 +609,14 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -545,17 +643,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mitt": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", @@ -626,14 +713,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -670,40 +749,38 @@ } }, "node_modules/puppeteer": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.7.2.tgz", - "integrity": "sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==", + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz", + "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==", "hasInstallScript": true, "dependencies": { - "cosmiconfig": "8.0.0", + "@puppeteer/browsers": "0.5.0", + "cosmiconfig": "8.1.3", "https-proxy-agent": "5.0.1", "progress": "2.0.3", "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - }, - "engines": { - "node": ">=14.1.0" + "puppeteer-core": "19.11.1" } }, "node_modules/puppeteer-core": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.2.tgz", - "integrity": "sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==", + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz", + "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==", "dependencies": { - "chromium-bidi": "0.4.4", + "@puppeteer/browsers": "0.5.0", + "chromium-bidi": "0.4.7", "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", + "devtools-protocol": "0.0.1107588", "extract-zip": "2.0.1", "https-proxy-agent": "5.0.1", "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", "tar-fs": "2.1.1", "unbzip2-stream": "1.4.3", - "ws": "8.11.0" + "ws": "8.13.0" }, "engines": { - "node": ">=14.1.0" + "node": ">=14.14.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -715,9 +792,9 @@ } }, "node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -727,6 +804,14 @@ "node": ">= 6" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -735,20 +820,6 @@ "node": ">=4" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -776,6 +847,30 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -851,21 +946,37 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -876,633 +987,44 @@ } } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, + }, + "node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "@mermaid-js/mermaid-cli": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-10.4.0.tgz", - "integrity": "sha512-sXohfGD6xgR8VEKvLdvSCndFaFNVTlyXjgZlJ3x8U3/J0V2VTfLIZO94Gt8KUPUccFWci8dRYDGG0fQerB+aIA==", - "requires": { - "chalk": "^5.0.1", - "commander": "^10.0.0", - "puppeteer": "^19.0.0" + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" } }, - "@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "peer": true - }, - "@types/node": { - "version": "18.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz", - "integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==", - "optional": true - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bootstrap": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", - "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", - "requires": {} - }, - "bootstrap-icons": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.1.tgz", - "integrity": "sha512-F0DDp7nKUX+x/QtpfRZ+XHFya60ng9nfdpdS59vDDfs4Uhuxp7zym/QavMsu/xx51txkoM9eVmpE7D08N35blw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==" - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "chromium-bidi": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.4.tgz", - "integrity": "sha512-4BX5cSaponuvVT1+SbLYTOAgDoVtX/Khoc9UsbFJ/AsPVUeFAM3RiIDFI6XFhLYMi9WmVJqh1ZH+dRpNKkKwiQ==", - "requires": { - "mitt": "3.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "requires": { - "node-fetch": "2.6.7" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1094867", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", - "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "requires": { - "pend": "~1.2.0" - } - }, - "flexsearch": { - "version": "0.6.32", - "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.6.32.tgz", - "integrity": "sha512-EF1BWkhwoeLtbIlDbY/vDSLBen/E5l/f1Vg7iX5CDymQCamcx1vhlc3tIZxIDplPjgi0jhG37c67idFbjg+v+Q==" - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "hugo-flexsearch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hugo-flexsearch/-/hugo-flexsearch-1.0.2.tgz", - "integrity": "sha512-vJDRMFYj77zeU95vnBpM3fvI8HVsygzZZDwciuy1ZiKwUdwDpsy7wF1Ss1TDPe4HTIiLzUwrc0qIsG2V7esZSw==", - "requires": { - "flexsearch": "^0.6.32" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "puppeteer": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.7.2.tgz", - "integrity": "sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==", - "requires": { - "cosmiconfig": "8.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - } - }, - "puppeteer-core": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.2.tgz", - "integrity": "sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==", - "requires": { - "chromium-bidi": "0.4.4", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.11.0" - } - }, - "readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "requires": {} - }, - "yauzl": { + "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "requires": { + "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } diff --git a/example_config.yaml b/example_config.yaml index f9af3bf22..31ac72046 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -148,7 +148,7 @@ rules: url: http://profile headers: foo: bar - unifiers: + finalizers: - id: jwt type: jwt config: @@ -186,7 +186,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: jwt + - finalizer: jwt on_error: - error_handler: authenticate_with_kratos diff --git a/example_rules.yaml b/example_rules.yaml index e8c81ba05..03bb7c4b1 100644 --- a/example_rules.yaml +++ b/example_rules.yaml @@ -24,13 +24,13 @@ rules: - authenticator: hydra_authenticator - contextualizer: subscription_contextualizer - authorizer: allow_all_authorizer - - unifier: jwt + - finalizer: jwt config: claims: | {"foo": "bar"} - - unifier: bla + - finalizer: bla config: headers: foo-bar: bla - - unifier: blabla + - finalizer: blabla # no on_error (reuses default) \ No newline at end of file diff --git a/examples/docker-compose/quickstarts/heimdall-config.yaml b/examples/docker-compose/quickstarts/heimdall-config.yaml index 7fc44035b..fef5434de 100644 --- a/examples/docker-compose/quickstarts/heimdall-config.yaml +++ b/examples/docker-compose/quickstarts/heimdall-config.yaml @@ -15,7 +15,7 @@ rules: type: anonymous - id: reject_requests type: unauthorized - unifiers: + finalizers: - id: do_nothing type: noop - id: create_jwt @@ -41,7 +41,7 @@ rules: - POST execute: - authenticator: reject_requests - - unifier: create_jwt + - finalizer: create_jwt on_error: - error_handler: redirect_to_login diff --git a/examples/docker-compose/quickstarts/upstream-rules.yaml b/examples/docker-compose/quickstarts/upstream-rules.yaml index ffd6822a7..6c4af0131 100644 --- a/examples/docker-compose/quickstarts/upstream-rules.yaml +++ b/examples/docker-compose/quickstarts/upstream-rules.yaml @@ -11,7 +11,7 @@ rules: add_path_prefix: /v1 execute: - authenticator: do_nothing - - unifier: do_nothing + - finalizer: do_nothing - id: rule2 match: diff --git a/examples/kubernetes/quickstarts/demo-app/base/rules.yaml b/examples/kubernetes/quickstarts/demo-app/base/rules.yaml index 587d5da35..54e9d3b85 100644 --- a/examples/kubernetes/quickstarts/demo-app/base/rules.yaml +++ b/examples/kubernetes/quickstarts/demo-app/base/rules.yaml @@ -15,7 +15,7 @@ spec: execute: - authenticator: noop_authenticator - authorizer: allow_all_requests - - unifier: noop_unifier + - finalizer: noop_finalizer - id: anonymous-access match: url: <**>://<**>/anon/<**> diff --git a/examples/kubernetes/quickstarts/heimdall/config.yaml b/examples/kubernetes/quickstarts/heimdall/config.yaml index bf5d294da..b4ded259a 100644 --- a/examples/kubernetes/quickstarts/heimdall/config.yaml +++ b/examples/kubernetes/quickstarts/heimdall/config.yaml @@ -28,10 +28,10 @@ rules: type: deny - id: allow_all_requests type: allow - unifiers: + finalizers: - id: create_jwt type: jwt - - id: noop_unifier + - id: noop_finalizer type: noop error_handlers: - id: redirect @@ -48,7 +48,7 @@ rules: execute: - authenticator: anonymous_authenticator - authorizer: deny_all_requests - - unifier: create_jwt + - finalizer: create_jwt on_error: - error_handler: redirect diff --git a/examples/kubernetes/quickstarts/proxy-demo/deployment.yaml b/examples/kubernetes/quickstarts/proxy-demo/deployment.yaml new file mode 100644 index 000000000..37faa1b12 --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/deployment.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: echo-app + namespace: quickstarts + labels: + app.kubernetes.io/name: echo-app +spec: + selector: + matchLabels: + app.kubernetes.io/name: echo-app + template: + metadata: + labels: + app.kubernetes.io/name: echo-app + spec: + automountServiceAccountToken: false + containers: + - name: heimdall + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + image: "heimdall:local" + args: [ "-c", "/heimdall/heimdall.yaml", "serve", "proxy2" ] + ports: + - name: http-port + protocol: TCP + containerPort: 4455 + volumeMounts: + - name: config + mountPath: /heimdall/heimdall.yaml + subPath: heimdall.yaml + readOnly: true + - name: rules + mountPath: /heimdall/rules.yaml + subPath: rules.yaml + readOnly: true + - name: echo-app + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + image: "containous/whoami:latest" + args: [ "--port", "8080", "--name", "echo-app" ] + + volumes: + - name: config + configMap: + name: heimdall-config + items: + - key: heimdall.yaml + path: heimdall.yaml + - name: rules + configMap: + name: heimdall-rules + items: + - key: rules.yaml + path: rules.yaml + diff --git a/examples/kubernetes/quickstarts/proxy-demo/heimdall-config.yaml b/examples/kubernetes/quickstarts/proxy-demo/heimdall-config.yaml new file mode 100644 index 000000000..62b5d8a26 --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/heimdall-config.yaml @@ -0,0 +1,59 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: heimdall-config + namespace: quickstarts + labels: + app.kubernetes.io/name: echo-app +immutable: true +data: + heimdall.yaml: | + log: + level: debug + + serve: + proxy: + trusted_proxies: + - 0.0.0.0/0 + + rules: + mechanisms: + authenticators: + - id: anonymous_authenticator + type: anonymous + - id: noop_authenticator + type: noop + - id: deny_authenticator + type: unauthorized + authorizers: + - id: deny_all_requests + type: deny + - id: allow_all_requests + type: allow + finalizers: + - id: create_jwt + type: jwt + - id: noop_finalizer + type: noop + error_handlers: + - id: redirect + type: redirect + config: + to: http://foo.bar?origin={{ .Request.URL | urlenc }} + when: + - error: + - type: authentication_error + default: + methods: + - GET + - POST + execute: + - authenticator: anonymous_authenticator + - authorizer: deny_all_requests + - finalizer: create_jwt + on_error: + - error_handler: redirect + + providers: + file_system: + src: /heimdall/rules.yaml \ No newline at end of file diff --git a/examples/kubernetes/quickstarts/proxy-demo/heimdall-rules.yaml b/examples/kubernetes/quickstarts/proxy-demo/heimdall-rules.yaml new file mode 100644 index 000000000..a96c1b11b --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/heimdall-rules.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: heimdall-rules + namespace: quickstarts + labels: + app.kubernetes.io/name: echo-app +immutable: true +data: + rules.yaml: | + version: "1alpha2" + rules: + - id: public-access + match: + url: <**>://<**>/pub/<**> + forward_to: + host: localhost:8080 + rewrite: + scheme: http + execute: + - authenticator: noop_authenticator + - authorizer: allow_all_requests + - finalizer: noop_finalizer + + - id: anonymous-access + match: + url: <**>://<**>/anon/<**> + forward_to: + host: localhost:8080 + rewrite: + scheme: http + execute: + - authorizer: allow_all_requests + + - id: redirect + match: + url: <**>://<**>/redir/<**> + forward_to: + host: localhost:8080 + rewrite: + scheme: http + execute: + - authenticator: deny_authenticator \ No newline at end of file diff --git a/examples/kubernetes/quickstarts/proxy-demo/ingress.yaml b/examples/kubernetes/quickstarts/proxy-demo/ingress.yaml new file mode 100644 index 000000000..cc15a8168 --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: echo-app + namespace: quickstarts + labels: + app.kubernetes.io/name: echo-app +spec: + ingressClassName: "nginx" + tls: + - hosts: + - echo-app.local + secretName: echo-app + rules: + - host: echo-app.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: echo-app + port: + number: 8080 \ No newline at end of file diff --git a/examples/kubernetes/quickstarts/proxy-demo/kustomization.yaml b/examples/kubernetes/quickstarts/proxy-demo/kustomization.yaml new file mode 100644 index 000000000..9543649bf --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - namespace.yaml + - heimdall-config.yaml + - heimdall-rules.yaml + - deployment.yaml + - service.yaml + - ingress.yaml diff --git a/examples/kubernetes/quickstarts/proxy-demo/namespace.yaml b/examples/kubernetes/quickstarts/proxy-demo/namespace.yaml new file mode 100644 index 000000000..eb34edde7 --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: quickstarts diff --git a/examples/kubernetes/quickstarts/proxy-demo/service.yaml b/examples/kubernetes/quickstarts/proxy-demo/service.yaml new file mode 100644 index 000000000..88bdc4dc0 --- /dev/null +++ b/examples/kubernetes/quickstarts/proxy-demo/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: echo-app + namespace: quickstarts + labels: + app.kubernetes.io/name: echo-app +spec: + ports: + - name: app-port + port: 8080 + targetPort: http-port + selector: + app.kubernetes.io/name: echo-app \ No newline at end of file diff --git a/internal/config/mechanism_prototypes.go b/internal/config/mechanism_prototypes.go index 26bfd5d72..3db966161 100644 --- a/internal/config/mechanism_prototypes.go +++ b/internal/config/mechanism_prototypes.go @@ -20,6 +20,6 @@ type MechanismPrototypes struct { Authenticators []Mechanism `koanf:"authenticators"` Authorizers []Mechanism `koanf:"authorizers"` Contextualizers []Mechanism `koanf:"contextualizers"` - Unifiers []Mechanism `koanf:"unifiers"` + Finalizers []Mechanism `koanf:"finalizers"` ErrorHandlers []Mechanism `koanf:"error_handlers"` } diff --git a/internal/config/test_data/test_config.yaml b/internal/config/test_data/test_config.yaml index 62a274f45..6760c546f 100644 --- a/internal/config/test_data/test_config.yaml +++ b/internal/config/test_data/test_config.yaml @@ -329,7 +329,7 @@ rules: value: super duper secret values: some-key: some-value - unifiers: + finalizers: - id: jwt type: jwt config: @@ -377,7 +377,7 @@ rules: - POST execute: - authenticator: anonymous_authenticator - - unifier: jwt + - finalizer: jwt on_error: - error_handler: authenticate_with_kratos diff --git a/internal/handler/decision/request_context.go b/internal/handler/decision/request_context.go index 09687e067..901fb5e9a 100644 --- a/internal/handler/decision/request_context.go +++ b/internal/handler/decision/request_context.go @@ -31,13 +31,12 @@ type requestContext struct { } func (r *requestContext) Finalize(_ rule.Backend) error { - logger := zerolog.Ctx(r.AppContext()) - logger.Debug().Msg("Finalizing request") - if err := r.PipelineError(); err != nil { return err } + zerolog.Ctx(r.AppContext()).Debug().Msg("Creating response") + uh := r.UpstreamHeaders() for k := range uh { r.rw.Header().Set(k, uh.Get(k)) diff --git a/internal/handler/envoyextauth/grpcv3/request_context.go b/internal/handler/envoyextauth/grpcv3/request_context.go index 4f6bfde81..7b96ac57d 100644 --- a/internal/handler/envoyextauth/grpcv3/request_context.go +++ b/internal/handler/envoyextauth/grpcv3/request_context.go @@ -123,12 +123,12 @@ func (s *RequestContext) AddCookieForUpstream(name, value string) { s.upstreamCo func (s *RequestContext) Signer() heimdall.JWTSigner { return s.jwtSigner } func (s *RequestContext) Finalize() (*envoy_auth.CheckResponse, error) { - zerolog.Ctx(s.ctx).Debug().Msg("Finalizing request") - if s.err != nil { return nil, s.err } + zerolog.Ctx(s.ctx).Debug().Msg("Creating response") + headers := make([]*envoy_core.HeaderValueOption, len(s.upstreamHeaders)+x.IfThenElse(len(s.upstreamCookies) == 0, 0, 1)) hidx := 0 diff --git a/internal/handler/proxy/request_context.go b/internal/handler/proxy/request_context.go index dcb2d8777..5ca956d18 100644 --- a/internal/handler/proxy/request_context.go +++ b/internal/handler/proxy/request_context.go @@ -66,7 +66,6 @@ func newContextFactory( func (r *requestContext) Finalize(upstream rule.Backend) error { logger := zerolog.Ctx(r.AppContext()) - logger.Debug().Msg("Finalizing request") if err := r.PipelineError(); err != nil { return err diff --git a/internal/rules/mechanisms/factory.go b/internal/rules/mechanisms/factory.go index 6754526b9..9acbd2c3b 100644 --- a/internal/rules/mechanisms/factory.go +++ b/internal/rules/mechanisms/factory.go @@ -24,13 +24,13 @@ import ( "github.com/dadrus/heimdall/internal/rules/mechanisms/authorizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/contextualizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers" - "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" + "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" ) var ( ErrAuthenticatorCreation = errors.New("failed to create authenticator") ErrAuthorizerCreation = errors.New("failed to create authorizer") - ErrUnifierCreation = errors.New("failed to create unifier") + ErrFinalizerCreation = errors.New("failed to create finalizer") ErrContextualizerCreation = errors.New("failed to create contextualizer") ErrErrorHandlerCreation = errors.New("failed to create error handler") ) @@ -41,6 +41,6 @@ type Factory interface { CreateAuthenticator(version, id string, conf config.MechanismConfig) (authenticators.Authenticator, error) CreateAuthorizer(version, id string, conf config.MechanismConfig) (authorizers.Authorizer, error) CreateContextualizer(version, id string, conf config.MechanismConfig) (contextualizers.Contextualizer, error) - CreateUnifier(version, id string, conf config.MechanismConfig) (unifiers.Unifier, error) + CreateFinalizer(version, id string, conf config.MechanismConfig) (finalizers.Finalizer, error) CreateErrorHandler(version, id string, conf config.MechanismConfig) (errorhandlers.ErrorHandler, error) } diff --git a/internal/rules/mechanisms/factory_impl.go b/internal/rules/mechanisms/factory_impl.go index edf0f003f..1329d1fa7 100644 --- a/internal/rules/mechanisms/factory_impl.go +++ b/internal/rules/mechanisms/factory_impl.go @@ -24,7 +24,7 @@ import ( "github.com/dadrus/heimdall/internal/rules/mechanisms/authorizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/contextualizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers" - "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" + "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" "github.com/dadrus/heimdall/internal/x/errorchain" ) @@ -105,21 +105,21 @@ func (hf *mechanismsFactory) CreateContextualizer(_, id string, conf config.Mech return prototype, nil } -func (hf *mechanismsFactory) CreateUnifier(_, id string, conf config.MechanismConfig) ( - unifiers.Unifier, error, +func (hf *mechanismsFactory) CreateFinalizer(_, id string, conf config.MechanismConfig) ( + finalizers.Finalizer, error, ) { - prototype, err := hf.r.Unifier(id) + prototype, err := hf.r.Finalizer(id) if err != nil { - return nil, errorchain.New(ErrUnifierCreation).CausedBy(err) + return nil, errorchain.New(ErrFinalizerCreation).CausedBy(err) } if conf != nil { - unifier, err := prototype.WithConfig(conf) + finalizer, err := prototype.WithConfig(conf) if err != nil { - return nil, errorchain.New(ErrUnifierCreation).CausedBy(err) + return nil, errorchain.New(ErrFinalizerCreation).CausedBy(err) } - return unifier, nil + return finalizer, nil } return prototype, nil diff --git a/internal/rules/mechanisms/factory_test.go b/internal/rules/mechanisms/factory_test.go index 1de86ed21..bac47e799 100644 --- a/internal/rules/mechanisms/factory_test.go +++ b/internal/rules/mechanisms/factory_test.go @@ -34,8 +34,8 @@ import ( mocks4 "github.com/dadrus/heimdall/internal/rules/mechanisms/contextualizers/mocks" "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers" mocks5 "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers/mocks" - "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" - mocks6 "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers/mocks" + "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" + mocks6 "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers/mocks" "github.com/dadrus/heimdall/internal/x" ) @@ -316,7 +316,7 @@ func TestHandlerFactoryCreateContextualizer(t *testing.T) { } } -func TestHandlerFactoryCreateUnifier(t *testing.T) { +func TestHandlerFactoryCreateFinalizer(t *testing.T) { t.Parallel() ID := "foo" @@ -325,58 +325,58 @@ func TestHandlerFactoryCreateUnifier(t *testing.T) { uc string id string conf map[string]any - configureMock func(t *testing.T, mUn *mocks6.UnifierMock) - assert func(t *testing.T, err error, unifier unifiers.Unifier) + configureMock func(t *testing.T, mFin *mocks6.FinalizerMock) + assert func(t *testing.T, err error, finalizer finalizers.Finalizer) }{ { - uc: "no unifier for given id", + uc: "no finalizer for given id", id: "bar", - assert: func(t *testing.T, err error, unifier unifiers.Unifier) { + assert: func(t *testing.T, err error, _ finalizers.Finalizer) { t.Helper() require.Error(t, err) - assert.ErrorIs(t, err, ErrUnifierCreation) - assert.Contains(t, err.Error(), "no unifier prototype") + assert.ErrorIs(t, err, ErrFinalizerCreation) + assert.Contains(t, err.Error(), "no finalizer prototype") }, }, { uc: "with failing creation from prototype", conf: map[string]any{"foo": "bar"}, - configureMock: func(t *testing.T, mUn *mocks6.UnifierMock) { + configureMock: func(t *testing.T, finalizer *mocks6.FinalizerMock) { t.Helper() - mUn.EXPECT().WithConfig(mock.Anything).Return(nil, heimdall.ErrArgument) + finalizer.EXPECT().WithConfig(mock.Anything).Return(nil, heimdall.ErrArgument) }, - assert: func(t *testing.T, err error, unifier unifiers.Unifier) { + assert: func(t *testing.T, err error, _ finalizers.Finalizer) { t.Helper() require.Error(t, err) - assert.ErrorIs(t, err, ErrUnifierCreation) + assert.ErrorIs(t, err, ErrFinalizerCreation) assert.Contains(t, err.Error(), heimdall.ErrArgument.Error()) }, }, { uc: "successful creation from prototype", conf: map[string]any{"foo": "bar"}, - configureMock: func(t *testing.T, mUn *mocks6.UnifierMock) { + configureMock: func(t *testing.T, finalizer *mocks6.FinalizerMock) { t.Helper() - mUn.EXPECT().WithConfig(mock.Anything).Return(mUn, nil) + finalizer.EXPECT().WithConfig(mock.Anything).Return(finalizer, nil) }, - assert: func(t *testing.T, err error, unifier unifiers.Unifier) { + assert: func(t *testing.T, err error, finalizer finalizers.Finalizer) { t.Helper() require.NoError(t, err) - assert.NotNil(t, unifier) + assert.NotNil(t, finalizer) }, }, { uc: "successful creation with empty config", - assert: func(t *testing.T, err error, unifier unifiers.Unifier) { + assert: func(t *testing.T, err error, finalizer finalizers.Finalizer) { t.Helper() require.NoError(t, err) - assert.NotNil(t, unifier) + assert.NotNil(t, finalizer) }, }, } { @@ -384,15 +384,15 @@ func TestHandlerFactoryCreateUnifier(t *testing.T) { // GIVEN configureMock := x.IfThenElse(tc.configureMock != nil, tc.configureMock, - func(t *testing.T, mUn *mocks6.UnifierMock) { t.Helper() }) + func(t *testing.T, mFin *mocks6.FinalizerMock) { t.Helper() }) - mUn := mocks6.NewUnifierMock(t) - configureMock(t, mUn) + mFin := mocks6.NewFinalizerMock(t) + configureMock(t, mFin) factory := &mechanismsFactory{ r: &prototypeRepository{ - unifiers: map[string]unifiers.Unifier{ - ID: mUn, + finalizers: map[string]finalizers.Finalizer{ + ID: mFin, }, }, } @@ -400,10 +400,10 @@ func TestHandlerFactoryCreateUnifier(t *testing.T) { id := x.IfThenElse(len(tc.id) != 0, tc.id, ID) // WHEN - unifier, err := factory.CreateUnifier("test", id, tc.conf) + finalizer, err := factory.CreateFinalizer("test", id, tc.conf) // THEN - tc.assert(t, err, unifier) + tc.assert(t, err, finalizer) }) } } @@ -519,7 +519,7 @@ func TestCreateHandlerFactory(t *testing.T) { require.NotNil(t, factory.r) assert.Empty(t, factory.r.errorHandlers) assert.Empty(t, factory.r.contextualizers) - assert.Empty(t, factory.r.unifiers) + assert.Empty(t, factory.r.finalizers) assert.Empty(t, factory.r.authenticators) assert.Empty(t, factory.r.authorizers) }, diff --git a/internal/rules/mechanisms/unifiers/config_decoder.go b/internal/rules/mechanisms/finalizers/config_decoder.go similarity index 98% rename from internal/rules/mechanisms/unifiers/config_decoder.go rename to internal/rules/mechanisms/finalizers/config_decoder.go index 983c2cd9c..ebfa452f9 100644 --- a/internal/rules/mechanisms/unifiers/config_decoder.go +++ b/internal/rules/mechanisms/finalizers/config_decoder.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "github.com/mitchellh/mapstructure" diff --git a/internal/rules/mechanisms/unifiers/constants.go b/internal/rules/mechanisms/finalizers/constants.go similarity index 83% rename from internal/rules/mechanisms/unifiers/constants.go rename to internal/rules/mechanisms/finalizers/constants.go index b454be401..6fa27a607 100644 --- a/internal/rules/mechanisms/unifiers/constants.go +++ b/internal/rules/mechanisms/finalizers/constants.go @@ -14,11 +14,11 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers const ( - UnifierNoop = "noop" - UnifierJwt = "jwt" - UnifierHeader = "header" - UnifierCookie = "cookie" + FinalizerNoop = "noop" + FinalizerJwt = "jwt" + FinalizerHeader = "header" + FinalizerCookie = "cookie" ) diff --git a/internal/rules/mechanisms/unifiers/cookie_unifier.go b/internal/rules/mechanisms/finalizers/cookie_finalizer.go similarity index 71% rename from internal/rules/mechanisms/unifiers/cookie_unifier.go rename to internal/rules/mechanisms/finalizers/cookie_finalizer.go index d89a5f2cc..6a5037590 100644 --- a/internal/rules/mechanisms/unifiers/cookie_unifier.go +++ b/internal/rules/mechanisms/finalizers/cookie_finalizer.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "github.com/rs/zerolog" @@ -29,24 +29,24 @@ import ( // //nolint:gochecknoinits func init() { - registerUnifierTypeFactory( - func(id string, typ string, conf map[string]any) (bool, Unifier, error) { - if typ != UnifierCookie { + registerTypeFactory( + func(id string, typ string, conf map[string]any) (bool, Finalizer, error) { + if typ != FinalizerCookie { return false, nil, nil } - unifier, err := newCookieUnifier(id, conf) + finalizer, err := newCookieFinalizer(id, conf) - return true, unifier, err + return true, finalizer, err }) } -type cookieUnifier struct { +type cookieFinalizer struct { id string cookies map[string]template.Template } -func newCookieUnifier(id string, rawConfig map[string]any) (*cookieUnifier, error) { +func newCookieFinalizer(id string, rawConfig map[string]any) (*cookieFinalizer, error) { type Config struct { Cookies map[string]template.Template `mapstructure:"cookies"` } @@ -54,7 +54,7 @@ func newCookieUnifier(id string, rawConfig map[string]any) (*cookieUnifier, erro var conf Config if err := decodeConfig(rawConfig, &conf); err != nil { return nil, errorchain. - NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal cookie unifier config"). + NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal cookie finalizer config"). CausedBy(err) } @@ -63,19 +63,19 @@ func newCookieUnifier(id string, rawConfig map[string]any) (*cookieUnifier, erro NewWithMessage(heimdall.ErrConfiguration, "no cookie definitions provided") } - return &cookieUnifier{ + return &cookieFinalizer{ id: id, cookies: conf.Cookies, }, nil } -func (u *cookieUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) error { +func (u *cookieFinalizer) Execute(ctx heimdall.Context, sub *subject.Subject) error { logger := zerolog.Ctx(ctx.AppContext()) - logger.Debug().Str("_id", u.id).Msg("Unifying using cookie unifier") + logger.Debug().Str("_id", u.id).Msg("Finalizing using cookie finalizer") if sub == nil { return errorchain. - NewWithMessage(heimdall.ErrInternal, "failed to execute cookie unifier due to 'nil' subject"). + NewWithMessage(heimdall.ErrInternal, "failed to execute cookie finalizer due to 'nil' subject"). WithErrorContext(u) } @@ -97,14 +97,14 @@ func (u *cookieUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) erro return nil } -func (u *cookieUnifier) WithConfig(config map[string]any) (Unifier, error) { +func (u *cookieFinalizer) WithConfig(config map[string]any) (Finalizer, error) { if len(config) == 0 { return u, nil } - return newCookieUnifier(u.id, config) + return newCookieFinalizer(u.id, config) } -func (u *cookieUnifier) ID() string { return u.id } +func (u *cookieFinalizer) ID() string { return u.id } -func (u *cookieUnifier) ContinueOnError() bool { return false } +func (u *cookieFinalizer) ContinueOnError() bool { return false } diff --git a/internal/rules/mechanisms/unifiers/cookie_unifier_test.go b/internal/rules/mechanisms/finalizers/cookie_finalizer_test.go similarity index 80% rename from internal/rules/mechanisms/unifiers/cookie_unifier_test.go rename to internal/rules/mechanisms/finalizers/cookie_finalizer_test.go index a82819c59..2b23dd325 100644 --- a/internal/rules/mechanisms/unifiers/cookie_unifier_test.go +++ b/internal/rules/mechanisms/finalizers/cookie_finalizer_test.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "context" @@ -31,18 +31,18 @@ import ( "github.com/dadrus/heimdall/internal/x/testsupport" ) -func TestCreateCookieUnifier(t *testing.T) { +func TestCreateCookieFinalizer(t *testing.T) { t.Parallel() for _, tc := range []struct { uc string id string config []byte - assert func(t *testing.T, err error, unifier *cookieUnifier) + assert func(t *testing.T, err error, finalizer *cookieFinalizer) }{ { uc: "without configuration", - assert: func(t *testing.T, err error, _ *cookieUnifier) { + assert: func(t *testing.T, err error, _ *cookieFinalizer) { t.Helper() require.Error(t, err) @@ -53,7 +53,7 @@ func TestCreateCookieUnifier(t *testing.T) { { uc: "without cookie configuration", config: []byte(``), - assert: func(t *testing.T, err error, _ *cookieUnifier) { + assert: func(t *testing.T, err error, _ *cookieFinalizer) { t.Helper() require.Error(t, err) @@ -68,7 +68,7 @@ cookies: foo: bar foo: bar `), - assert: func(t *testing.T, err error, _ *cookieUnifier) { + assert: func(t *testing.T, err error, _ *cookieFinalizer) { t.Helper() require.Error(t, err) @@ -82,10 +82,10 @@ foo: bar cookies: bar: "{{ .Subject.ID | foobar }}" `), - assert: func(t *testing.T, err error, unifier *cookieUnifier) { + assert: func(t *testing.T, err error, finalizer *cookieFinalizer) { t.Helper() - require.Nil(t, unifier) + require.Nil(t, finalizer) require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) assert.Contains(t, err.Error(), "failed to unmarshal") @@ -98,24 +98,24 @@ cookies: cookies: foo: bar bar: "{{ .Subject.ID }}"`), - assert: func(t *testing.T, err error, unifier *cookieUnifier) { + assert: func(t *testing.T, err error, finalizer *cookieFinalizer) { t.Helper() require.NoError(t, err) - assert.Len(t, unifier.cookies, 2) - assert.Equal(t, "cun", unifier.ID()) + assert.Len(t, finalizer.cookies, 2) + assert.Equal(t, "cun", finalizer.ID()) - val, err := unifier.cookies["foo"].Render(nil) + val, err := finalizer.cookies["foo"].Render(nil) require.NoError(t, err) assert.Equal(t, "bar", val) - val, err = unifier.cookies["bar"].Render(map[string]any{ + val, err = finalizer.cookies["bar"].Render(map[string]any{ "Subject": &subject.Subject{ID: "baz"}, }) require.NoError(t, err) assert.Equal(t, "baz", val) - assert.False(t, unifier.ContinueOnError()) + assert.False(t, finalizer.ContinueOnError()) }, }, } { @@ -124,15 +124,15 @@ cookies: require.NoError(t, err) // WHEN - unifier, err := newCookieUnifier(tc.id, conf) + finalizer, err := newCookieFinalizer(tc.id, conf) // THEN - tc.assert(t, err, unifier) + tc.assert(t, err, finalizer) }) } } -func TestCreateCookieUnifierFromPrototype(t *testing.T) { +func TestCreateCookieFinalizerFromPrototype(t *testing.T) { t.Parallel() for _, tc := range []struct { @@ -140,7 +140,7 @@ func TestCreateCookieUnifierFromPrototype(t *testing.T) { id string prototypeConfig []byte config []byte - assert func(t *testing.T, err error, prototype *cookieUnifier, configured *cookieUnifier) + assert func(t *testing.T, err error, prototype *cookieFinalizer, configured *cookieFinalizer) }{ { uc: "no new configuration provided", @@ -149,7 +149,7 @@ func TestCreateCookieUnifierFromPrototype(t *testing.T) { cookies: foo: bar `), - assert: func(t *testing.T, err error, prototype *cookieUnifier, configured *cookieUnifier) { + assert: func(t *testing.T, err error, prototype *cookieFinalizer, configured *cookieFinalizer) { t.Helper() require.NoError(t, err) @@ -165,7 +165,7 @@ cookies: foo: bar `), config: []byte(``), - assert: func(t *testing.T, err error, prototype *cookieUnifier, configured *cookieUnifier) { + assert: func(t *testing.T, err error, prototype *cookieFinalizer, configured *cookieFinalizer) { t.Helper() require.NoError(t, err) @@ -184,7 +184,7 @@ cookies: cookies: bar: foo `), - assert: func(t *testing.T, err error, prototype *cookieUnifier, configured *cookieUnifier) { + assert: func(t *testing.T, err error, prototype *cookieFinalizer, configured *cookieFinalizer) { t.Helper() require.NoError(t, err) @@ -210,22 +210,22 @@ cookies: conf, err := testsupport.DecodeTestConfig(tc.config) require.NoError(t, err) - prototype, err := newCookieUnifier(tc.id, pc) + prototype, err := newCookieFinalizer(tc.id, pc) require.NoError(t, err) // WHEN - unifier, err := prototype.WithConfig(conf) + finalizer, err := prototype.WithConfig(conf) // THEN - cookieUnifier, ok := unifier.(*cookieUnifier) + realFinalizer, ok := finalizer.(*cookieFinalizer) require.True(t, ok) - tc.assert(t, err, prototype, cookieUnifier) + tc.assert(t, err, prototype, realFinalizer) }) } } -func TestCookieUnifierExecute(t *testing.T) { +func TestCookieFinalizerExecute(t *testing.T) { t.Parallel() for _, tc := range []struct { @@ -313,11 +313,11 @@ cookies: configureContext(t, mctx) - unifier, err := newCookieUnifier(tc.id, conf) + finalizer, err := newCookieFinalizer(tc.id, conf) require.NoError(t, err) // WHEN - err = unifier.Execute(mctx, sub) + err = finalizer.Execute(mctx, sub) // THEN tc.assert(t, err) diff --git a/internal/rules/mechanisms/unifiers/unifier.go b/internal/rules/mechanisms/finalizers/finalizer.go similarity index 84% rename from internal/rules/mechanisms/unifiers/unifier.go rename to internal/rules/mechanisms/finalizers/finalizer.go index cb2860446..5a707eaee 100644 --- a/internal/rules/mechanisms/unifiers/unifier.go +++ b/internal/rules/mechanisms/finalizers/finalizer.go @@ -14,18 +14,18 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "github.com/dadrus/heimdall/internal/heimdall" "github.com/dadrus/heimdall/internal/rules/mechanisms/subject" ) -//go:generate mockery --name Unifier --structname UnifierMock +//go:generate mockery --name Finalizer --structname FinalizerMock -type Unifier interface { +type Finalizer interface { ID() string Execute(ctx heimdall.Context, sub *subject.Subject) error - WithConfig(config map[string]any) (Unifier, error) + WithConfig(config map[string]any) (Finalizer, error) ContinueOnError() bool } diff --git a/internal/rules/mechanisms/unifiers/unifier_type_registry.go b/internal/rules/mechanisms/finalizers/finalizer_type_registry.go similarity index 65% rename from internal/rules/mechanisms/unifiers/unifier_type_registry.go rename to internal/rules/mechanisms/finalizers/finalizer_type_registry.go index 85347b779..4bba4eac6 100644 --- a/internal/rules/mechanisms/unifiers/unifier_type_registry.go +++ b/internal/rules/mechanisms/finalizers/finalizer_type_registry.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "errors" @@ -24,27 +24,27 @@ import ( ) var ( - ErrUnsupportedUnifierType = errors.New("unifier type unsupported") + ErrUnsupportedType = errors.New("finalizer type unsupported") // by intention. Used only during application bootstrap. - typeFactories []UnifierTypeFactory //nolint:gochecknoglobals - typeFactoriesMu sync.RWMutex //nolint:gochecknoglobals + typeFactories []TypeFactory //nolint:gochecknoglobals + typeFactoriesMu sync.RWMutex //nolint:gochecknoglobals ) -type UnifierTypeFactory func(id string, typ string, c map[string]any) (bool, Unifier, error) +type TypeFactory func(id string, typ string, c map[string]any) (bool, Finalizer, error) -func registerUnifierTypeFactory(factory UnifierTypeFactory) { +func registerTypeFactory(factory TypeFactory) { typeFactoriesMu.Lock() defer typeFactoriesMu.Unlock() if factory == nil { - panic("RegisterUnifierType factory is nil") + panic("finalizer type factory is nil") } typeFactories = append(typeFactories, factory) } -func CreateUnifierPrototype(id string, typ string, mConfig map[string]any) (Unifier, error) { +func CreatePrototype(id string, typ string, mConfig map[string]any) (Finalizer, error) { typeFactoriesMu.RLock() defer typeFactoriesMu.RUnlock() @@ -54,5 +54,5 @@ func CreateUnifierPrototype(id string, typ string, mConfig map[string]any) (Unif } } - return nil, errorchain.NewWithMessagef(ErrUnsupportedUnifierType, "'%s'", typ) + return nil, errorchain.NewWithMessagef(ErrUnsupportedType, "'%s'", typ) } diff --git a/internal/rules/mechanisms/unifiers/unifier_type_registry_test.go b/internal/rules/mechanisms/finalizers/finalizer_type_registry_test.go similarity index 68% rename from internal/rules/mechanisms/unifiers/unifier_type_registry_test.go rename to internal/rules/mechanisms/finalizers/finalizer_type_registry_test.go index 2f2adef0f..26feb3f39 100644 --- a/internal/rules/mechanisms/unifiers/unifier_type_registry_test.go +++ b/internal/rules/mechanisms/finalizers/finalizer_type_registry_test.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "testing" @@ -23,44 +23,44 @@ import ( "github.com/stretchr/testify/require" ) -func TestCreateUnifierPrototype(t *testing.T) { +func TestCreateFinalizerPrototype(t *testing.T) { t.Parallel() - // there are 4 unifiers implemented, which should have been registered + // there are 4 finalizers implemented, which should have been registered require.Len(t, typeFactories, 4) for _, tc := range []struct { uc string typ string - assert func(t *testing.T, err error, unifier Unifier) + assert func(t *testing.T, err error, finalizer Finalizer) }{ { uc: "using known type", - typ: UnifierNoop, - assert: func(t *testing.T, err error, unifier Unifier) { + typ: FinalizerNoop, + assert: func(t *testing.T, err error, finalizer Finalizer) { t.Helper() require.NoError(t, err) - assert.IsType(t, &noopUnifier{}, unifier) + assert.IsType(t, &noopFinalizer{}, finalizer) }, }, { uc: "using unknown type", typ: "foo", - assert: func(t *testing.T, err error, unifier Unifier) { + assert: func(t *testing.T, err error, _ Finalizer) { t.Helper() require.Error(t, err) - assert.ErrorIs(t, err, ErrUnsupportedUnifierType) + assert.ErrorIs(t, err, ErrUnsupportedType) }, }, } { t.Run("case="+tc.uc, func(t *testing.T) { // WHEN - unifier, err := CreateUnifierPrototype("foo", tc.typ, nil) + finalizer, err := CreatePrototype("foo", tc.typ, nil) // THEN - tc.assert(t, err, unifier) + tc.assert(t, err, finalizer) }) } } diff --git a/internal/rules/mechanisms/unifiers/header_unifier.go b/internal/rules/mechanisms/finalizers/header_finalizer.go similarity index 72% rename from internal/rules/mechanisms/unifiers/header_unifier.go rename to internal/rules/mechanisms/finalizers/header_finalizer.go index 8ebafd4fa..d290bcc1c 100644 --- a/internal/rules/mechanisms/unifiers/header_unifier.go +++ b/internal/rules/mechanisms/finalizers/header_finalizer.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "github.com/rs/zerolog" @@ -29,24 +29,24 @@ import ( // //nolint:gochecknoinits func init() { - registerUnifierTypeFactory( - func(id string, typ string, conf map[string]any) (bool, Unifier, error) { - if typ != UnifierHeader { + registerTypeFactory( + func(id string, typ string, conf map[string]any) (bool, Finalizer, error) { + if typ != FinalizerHeader { return false, nil, nil } - unifier, err := newHeaderUnifier(id, conf) + finalizer, err := newHeaderFinalizer(id, conf) - return true, unifier, err + return true, finalizer, err }) } -type headerUnifier struct { +type headerFinalizer struct { id string headers map[string]template.Template } -func newHeaderUnifier(id string, rawConfig map[string]any) (*headerUnifier, error) { +func newHeaderFinalizer(id string, rawConfig map[string]any) (*headerFinalizer, error) { type Config struct { Headers map[string]template.Template `mapstructure:"headers"` } @@ -54,7 +54,7 @@ func newHeaderUnifier(id string, rawConfig map[string]any) (*headerUnifier, erro var conf Config if err := decodeConfig(rawConfig, &conf); err != nil { return nil, errorchain. - NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal header unifier config"). + NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal header finalizer config"). CausedBy(err) } @@ -63,19 +63,19 @@ func newHeaderUnifier(id string, rawConfig map[string]any) (*headerUnifier, erro NewWithMessage(heimdall.ErrConfiguration, "no headers definitions provided") } - return &headerUnifier{ + return &headerFinalizer{ id: id, headers: conf.Headers, }, nil } -func (u *headerUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) error { +func (u *headerFinalizer) Execute(ctx heimdall.Context, sub *subject.Subject) error { logger := zerolog.Ctx(ctx.AppContext()) - logger.Debug().Str("_id", u.id).Msg("Unifying using header unifier") + logger.Debug().Str("_id", u.id).Msg("Finalizing using header finalizer") if sub == nil { return errorchain. - NewWithMessage(heimdall.ErrInternal, "failed to execute header unifier due to 'nil' subject"). + NewWithMessage(heimdall.ErrInternal, "failed to execute header finalizer due to 'nil' subject"). WithErrorContext(u) } @@ -97,14 +97,14 @@ func (u *headerUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) erro return nil } -func (u *headerUnifier) WithConfig(config map[string]any) (Unifier, error) { +func (u *headerFinalizer) WithConfig(config map[string]any) (Finalizer, error) { if len(config) == 0 { return u, nil } - return newHeaderUnifier(u.id, config) + return newHeaderFinalizer(u.id, config) } -func (u *headerUnifier) ID() string { return u.id } +func (u *headerFinalizer) ID() string { return u.id } -func (u *headerUnifier) ContinueOnError() bool { return false } +func (u *headerFinalizer) ContinueOnError() bool { return false } diff --git a/internal/rules/mechanisms/unifiers/header_unifier_test.go b/internal/rules/mechanisms/finalizers/header_finalizer_test.go similarity index 81% rename from internal/rules/mechanisms/unifiers/header_unifier_test.go rename to internal/rules/mechanisms/finalizers/header_finalizer_test.go index c88c5d1cf..1e0bb5479 100644 --- a/internal/rules/mechanisms/unifiers/header_unifier_test.go +++ b/internal/rules/mechanisms/finalizers/header_finalizer_test.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "context" @@ -31,18 +31,18 @@ import ( "github.com/dadrus/heimdall/internal/x/testsupport" ) -func TestCreateHeaderUnifier(t *testing.T) { +func TestCreateHeaderFinalizer(t *testing.T) { t.Parallel() for _, tc := range []struct { uc string id string config []byte - assert func(t *testing.T, err error, unifier *headerUnifier) + assert func(t *testing.T, err error, finalizer *headerFinalizer) }{ { uc: "without configuration", - assert: func(t *testing.T, err error, _ *headerUnifier) { + assert: func(t *testing.T, err error, _ *headerFinalizer) { t.Helper() require.Error(t, err) @@ -53,7 +53,7 @@ func TestCreateHeaderUnifier(t *testing.T) { { uc: "without header configuration", config: []byte(``), - assert: func(t *testing.T, err error, _ *headerUnifier) { + assert: func(t *testing.T, err error, _ *headerFinalizer) { t.Helper() require.Error(t, err) @@ -68,7 +68,7 @@ headers: foo: bar foo: bar `), - assert: func(t *testing.T, err error, _ *headerUnifier) { + assert: func(t *testing.T, err error, _ *headerFinalizer) { t.Helper() require.Error(t, err) @@ -82,7 +82,7 @@ foo: bar headers: bar: "{{ .Subject.ID | foobar }}" `), - assert: func(t *testing.T, err error, _ *headerUnifier) { + assert: func(t *testing.T, err error, _ *headerFinalizer) { t.Helper() require.Error(t, err) @@ -97,24 +97,24 @@ headers: headers: foo: bar bar: "{{ .Subject.ID }}"`), - assert: func(t *testing.T, err error, unifier *headerUnifier) { + assert: func(t *testing.T, err error, finalizer *headerFinalizer) { t.Helper() require.NoError(t, err) - assert.Len(t, unifier.headers, 2) - assert.Equal(t, "hun", unifier.ID()) + assert.Len(t, finalizer.headers, 2) + assert.Equal(t, "hun", finalizer.ID()) - val, err := unifier.headers["foo"].Render(nil) + val, err := finalizer.headers["foo"].Render(nil) require.NoError(t, err) assert.Equal(t, "bar", val) - val, err = unifier.headers["bar"].Render(map[string]any{ + val, err = finalizer.headers["bar"].Render(map[string]any{ "Subject": &subject.Subject{ID: "baz"}, }) require.NoError(t, err) assert.Equal(t, "baz", val) - assert.False(t, unifier.ContinueOnError()) + assert.False(t, finalizer.ContinueOnError()) }, }, } { @@ -123,15 +123,15 @@ headers: require.NoError(t, err) // WHEN - unifier, err := newHeaderUnifier(tc.id, conf) + finalizer, err := newHeaderFinalizer(tc.id, conf) // THEN - tc.assert(t, err, unifier) + tc.assert(t, err, finalizer) }) } } -func TestCreateHeaderUnifierFromPrototype(t *testing.T) { +func TestCreateHeaderFinalizerFromPrototype(t *testing.T) { t.Parallel() for _, tc := range []struct { @@ -139,7 +139,7 @@ func TestCreateHeaderUnifierFromPrototype(t *testing.T) { id string prototypeConfig []byte config []byte - assert func(t *testing.T, err error, prototype *headerUnifier, configured *headerUnifier) + assert func(t *testing.T, err error, prototype *headerFinalizer, configured *headerFinalizer) }{ { uc: "no new configuration provided", @@ -148,7 +148,7 @@ func TestCreateHeaderUnifierFromPrototype(t *testing.T) { headers: foo: bar `), - assert: func(t *testing.T, err error, prototype *headerUnifier, configured *headerUnifier) { + assert: func(t *testing.T, err error, prototype *headerFinalizer, configured *headerFinalizer) { t.Helper() require.NoError(t, err) @@ -164,7 +164,7 @@ headers: foo: bar `), config: []byte(``), - assert: func(t *testing.T, err error, prototype *headerUnifier, configured *headerUnifier) { + assert: func(t *testing.T, err error, prototype *headerFinalizer, configured *headerFinalizer) { t.Helper() require.NoError(t, err) @@ -183,7 +183,7 @@ headers: headers: bar: foo `), - assert: func(t *testing.T, err error, prototype *headerUnifier, configured *headerUnifier) { + assert: func(t *testing.T, err error, prototype *headerFinalizer, configured *headerFinalizer) { t.Helper() require.NoError(t, err) @@ -209,22 +209,22 @@ headers: conf, err := testsupport.DecodeTestConfig(tc.config) require.NoError(t, err) - prototype, err := newHeaderUnifier(tc.id, pc) + prototype, err := newHeaderFinalizer(tc.id, pc) require.NoError(t, err) // WHEN - unifier, err := prototype.WithConfig(conf) + finalizer, err := prototype.WithConfig(conf) // THEN - headerUnifier, ok := unifier.(*headerUnifier) + realFinalizer, ok := finalizer.(*headerFinalizer) require.True(t, ok) - tc.assert(t, err, prototype, headerUnifier) + tc.assert(t, err, prototype, realFinalizer) }) } } -func TestHeaderUnifierExecute(t *testing.T) { +func TestHeaderFinalizerExecute(t *testing.T) { t.Parallel() for _, tc := range []struct { @@ -312,11 +312,11 @@ headers: configureContext(t, ctx) - unifier, err := newHeaderUnifier(tc.id, conf) + finalizer, err := newHeaderFinalizer(tc.id, conf) require.NoError(t, err) // WHEN - err = unifier.Execute(ctx, sub) + err = finalizer.Execute(ctx, sub) // THEN tc.assert(t, err) diff --git a/internal/rules/mechanisms/unifiers/jwt_unifier.go b/internal/rules/mechanisms/finalizers/jwt_finalizer.go similarity index 84% rename from internal/rules/mechanisms/unifiers/jwt_unifier.go rename to internal/rules/mechanisms/finalizers/jwt_finalizer.go index fc6484eea..59ee21f8f 100644 --- a/internal/rules/mechanisms/unifiers/jwt_unifier.go +++ b/internal/rules/mechanisms/finalizers/jwt_finalizer.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "crypto/sha256" @@ -45,19 +45,19 @@ const ( // //nolint:gochecknoinits func init() { - registerUnifierTypeFactory( - func(id string, typ string, conf map[string]any) (bool, Unifier, error) { - if typ != UnifierJwt { + registerTypeFactory( + func(id string, typ string, conf map[string]any) (bool, Finalizer, error) { + if typ != FinalizerJwt { return false, nil, nil } - unifier, err := newJWTUnifier(id, conf) + finalizer, err := newJWTFinalizer(id, conf) - return true, unifier, err + return true, finalizer, err }) } -type jwtUnifier struct { +type jwtFinalizer struct { id string claims template.Template ttl time.Duration @@ -65,7 +65,7 @@ type jwtUnifier struct { headerScheme string } -func newJWTUnifier(id string, rawConfig map[string]any) (*jwtUnifier, error) { +func newJWTFinalizer(id string, rawConfig map[string]any) (*jwtFinalizer, error) { type HeaderConfig struct { Name string `mapstructure:"name"` Scheme string `mapstructure:"scheme"` @@ -80,7 +80,7 @@ func newJWTUnifier(id string, rawConfig map[string]any) (*jwtUnifier, error) { var conf Config if err := decodeConfig(rawConfig, &conf); err != nil { return nil, errorchain. - NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal JWT unifier config"). + NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal JWT finalizer config"). CausedBy(err) } @@ -94,7 +94,7 @@ func newJWTUnifier(id string, rawConfig map[string]any) (*jwtUnifier, error) { NewWithMessage(heimdall.ErrConfiguration, "configured JWT header name is an empty string") } - return &jwtUnifier{ + return &jwtFinalizer{ id: id, claims: conf.Claims, ttl: x.IfThenElseExec(conf.TTL != nil, @@ -109,13 +109,13 @@ func newJWTUnifier(id string, rawConfig map[string]any) (*jwtUnifier, error) { }, nil } -func (u *jwtUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) error { +func (u *jwtFinalizer) Execute(ctx heimdall.Context, sub *subject.Subject) error { logger := zerolog.Ctx(ctx.AppContext()) - logger.Debug().Str("_id", u.id).Msg("Unifying using JWT unifier") + logger.Debug().Str("_id", u.id).Msg("Finalizing using JWT finalizer") if sub == nil { return errorchain. - NewWithMessage(heimdall.ErrInternal, "failed to execute jwt unifier due to 'nil' subject"). + NewWithMessage(heimdall.ErrInternal, "failed to execute jwt finalizer due to 'nil' subject"). WithErrorContext(u) } @@ -158,7 +158,7 @@ func (u *jwtUnifier) Execute(ctx heimdall.Context, sub *subject.Subject) error { return nil } -func (u *jwtUnifier) WithConfig(rawConfig map[string]any) (Unifier, error) { +func (u *jwtFinalizer) WithConfig(rawConfig map[string]any) (Finalizer, error) { if len(rawConfig) == 0 { return u, nil } @@ -171,7 +171,7 @@ func (u *jwtUnifier) WithConfig(rawConfig map[string]any) (Unifier, error) { var conf Config if err := decodeConfig(rawConfig, &conf); err != nil { return nil, errorchain. - NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal JWT unifier config"). + NewWithMessage(heimdall.ErrConfiguration, "failed to unmarshal JWT finalizer config"). CausedBy(err) } @@ -180,7 +180,7 @@ func (u *jwtUnifier) WithConfig(rawConfig map[string]any) (Unifier, error) { NewWithMessage(heimdall.ErrConfiguration, "configured JWT ttl is less than one second") } - return &jwtUnifier{ + return &jwtFinalizer{ id: u.id, claims: x.IfThenElse(conf.Claims != nil, conf.Claims, u.claims), ttl: x.IfThenElseExec(conf.TTL != nil, @@ -191,11 +191,11 @@ func (u *jwtUnifier) WithConfig(rawConfig map[string]any) (Unifier, error) { }, nil } -func (u *jwtUnifier) ID() string { return u.id } +func (u *jwtFinalizer) ID() string { return u.id } -func (u *jwtUnifier) ContinueOnError() bool { return false } +func (u *jwtFinalizer) ContinueOnError() bool { return false } -func (u *jwtUnifier) generateToken(ctx heimdall.Context, sub *subject.Subject) (string, error) { +func (u *jwtFinalizer) generateToken(ctx heimdall.Context, sub *subject.Subject) (string, error) { iss := ctx.Signer() claims := map[string]any{} @@ -230,7 +230,7 @@ func (u *jwtUnifier) generateToken(ctx heimdall.Context, sub *subject.Subject) ( return token, nil } -func (u *jwtUnifier) calculateCacheKey(sub *subject.Subject, iss heimdall.JWTSigner) string { +func (u *jwtFinalizer) calculateCacheKey(sub *subject.Subject, iss heimdall.JWTSigner) string { const int64BytesCount = 8 ttlBytes := make([]byte, int64BytesCount) diff --git a/internal/rules/mechanisms/unifiers/jwt_unifier_test.go b/internal/rules/mechanisms/finalizers/jwt_finalizer_test.go similarity index 76% rename from internal/rules/mechanisms/unifiers/jwt_unifier_test.go rename to internal/rules/mechanisms/finalizers/jwt_finalizer_test.go index 9e6129cfd..f82cd2848 100644 --- a/internal/rules/mechanisms/unifiers/jwt_unifier_test.go +++ b/internal/rules/mechanisms/finalizers/jwt_finalizer_test.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "context" @@ -35,7 +35,7 @@ import ( "github.com/dadrus/heimdall/internal/x/testsupport" ) -func TestCreateJWTUnifier(t *testing.T) { +func TestCreateJWTFinalizer(t *testing.T) { t.Parallel() const expectedTTL = 5 * time.Second @@ -44,62 +44,62 @@ func TestCreateJWTUnifier(t *testing.T) { uc string id string config []byte - assert func(t *testing.T, err error, unifier *jwtUnifier) + assert func(t *testing.T, err error, finalizer *jwtFinalizer) }{ { uc: "without config", id: "jun", - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, defaultJWTTTL, unifier.ttl) - assert.Nil(t, unifier.claims) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Authorization", unifier.headerName) - assert.Equal(t, "Bearer", unifier.headerScheme) + require.NotNil(t, finalizer) + assert.Equal(t, defaultJWTTTL, finalizer.ttl) + assert.Nil(t, finalizer.claims) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Authorization", finalizer.headerName) + assert.Equal(t, "Bearer", finalizer.headerScheme) }, }, { uc: "with empty config", id: "jun", config: []byte(``), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, defaultJWTTTL, unifier.ttl) - assert.Nil(t, unifier.claims) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Authorization", unifier.headerName) - assert.Equal(t, "Bearer", unifier.headerScheme) + require.NotNil(t, finalizer) + assert.Equal(t, defaultJWTTTL, finalizer.ttl) + assert.Nil(t, finalizer.claims) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Authorization", finalizer.headerName) + assert.Equal(t, "Bearer", finalizer.headerScheme) }, }, { uc: "with ttl only", id: "jun", config: []byte(`ttl: 5s`), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, expectedTTL, unifier.ttl) - assert.Nil(t, unifier.claims) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Authorization", unifier.headerName) - assert.Equal(t, "Bearer", unifier.headerScheme) + require.NotNil(t, finalizer) + assert.Equal(t, expectedTTL, finalizer.ttl) + assert.Nil(t, finalizer.claims) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Authorization", finalizer.headerName) + assert.Equal(t, "Bearer", finalizer.headerScheme) }, }, { uc: "with too short ttl", config: []byte(`ttl: 5ms`), - assert: func(t *testing.T, err error, _ *jwtUnifier) { + assert: func(t *testing.T, err error, _ *jwtFinalizer) { t.Helper() require.Error(t, err) @@ -114,23 +114,23 @@ func TestCreateJWTUnifier(t *testing.T) { claims: '{ "sub": {{ quote .Subject.ID }} }' `), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, defaultJWTTTL, unifier.ttl) - require.NotNil(t, unifier.claims) - val, err := unifier.claims.Render(map[string]any{ + require.NotNil(t, finalizer) + assert.Equal(t, defaultJWTTTL, finalizer.ttl) + require.NotNil(t, finalizer.claims) + val, err := finalizer.claims.Render(map[string]any{ "Subject": &subject.Subject{ID: "bar"}, }) require.NoError(t, err) assert.Equal(t, `{ "sub": "bar" }`, val) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Authorization", unifier.headerName) - assert.Equal(t, "Bearer", unifier.headerScheme) - assert.False(t, unifier.ContinueOnError()) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Authorization", finalizer.headerName) + assert.Equal(t, "Bearer", finalizer.headerScheme) + assert.False(t, finalizer.ContinueOnError()) }, }, { @@ -141,23 +141,23 @@ ttl: 5s claims: '{ "sub": {{ quote .Subject.ID }} }' `), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, expectedTTL, unifier.ttl) - require.NotNil(t, unifier.claims) - val, err := unifier.claims.Render(map[string]any{ + require.NotNil(t, finalizer) + assert.Equal(t, expectedTTL, finalizer.ttl) + require.NotNil(t, finalizer.claims) + val, err := finalizer.claims.Render(map[string]any{ "Subject": &subject.Subject{ID: "bar"}, }) require.NoError(t, err) assert.Equal(t, `{ "sub": "bar" }`, val) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Authorization", unifier.headerName) - assert.Equal(t, "Bearer", unifier.headerScheme) - assert.False(t, unifier.ContinueOnError()) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Authorization", finalizer.headerName) + assert.Equal(t, "Bearer", finalizer.headerScheme) + assert.False(t, finalizer.ContinueOnError()) }, }, { @@ -166,7 +166,7 @@ claims: ttl: 5s foo: bar" `), - assert: func(t *testing.T, err error, _ *jwtUnifier) { + assert: func(t *testing.T, err error, _ *jwtFinalizer) { t.Helper() require.Error(t, err) @@ -181,7 +181,7 @@ foo: bar" header: scheme: Foo `), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, _ *jwtFinalizer) { t.Helper() require.Error(t, err) @@ -196,16 +196,16 @@ header: header: name: Foo `), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, defaultJWTTTL, unifier.ttl) - assert.Nil(t, unifier.claims) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Foo", unifier.headerName) - assert.Empty(t, unifier.headerScheme) + require.NotNil(t, finalizer) + assert.Equal(t, defaultJWTTTL, finalizer.ttl) + assert.Nil(t, finalizer.claims) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Foo", finalizer.headerName) + assert.Empty(t, finalizer.headerScheme) }, }, { @@ -216,16 +216,16 @@ header: name: Foo scheme: Bar `), - assert: func(t *testing.T, err error, unifier *jwtUnifier) { + assert: func(t *testing.T, err error, finalizer *jwtFinalizer) { t.Helper() require.NoError(t, err) - require.NotNil(t, unifier) - assert.Equal(t, defaultJWTTTL, unifier.ttl) - assert.Nil(t, unifier.claims) - assert.Equal(t, "jun", unifier.ID()) - assert.Equal(t, "Foo", unifier.headerName) - assert.Equal(t, "Bar", unifier.headerScheme) + require.NotNil(t, finalizer) + assert.Equal(t, defaultJWTTTL, finalizer.ttl) + assert.Nil(t, finalizer.claims) + assert.Equal(t, "jun", finalizer.ID()) + assert.Equal(t, "Foo", finalizer.headerName) + assert.Equal(t, "Bar", finalizer.headerScheme) }, }, } { @@ -234,15 +234,15 @@ header: require.NoError(t, err) // WHEN - unifier, err := newJWTUnifier(tc.id, conf) + finalizer, err := newJWTFinalizer(tc.id, conf) // THEN - tc.assert(t, err, unifier) + tc.assert(t, err, finalizer) }) } } -func TestCreateJWTUnifierFromPrototype(t *testing.T) { +func TestCreateJWTFinalizerFromPrototype(t *testing.T) { t.Parallel() const ( @@ -253,12 +253,12 @@ func TestCreateJWTUnifierFromPrototype(t *testing.T) { uc string id string config []byte - assert func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) + assert func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) }{ { uc: "no new configuration provided", id: "jun1", - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.NoError(t, err) @@ -271,7 +271,7 @@ func TestCreateJWTUnifierFromPrototype(t *testing.T) { uc: "empty configuration provided", id: "jun2", config: []byte(``), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.NoError(t, err) @@ -284,7 +284,7 @@ func TestCreateJWTUnifierFromPrototype(t *testing.T) { uc: "configuration with ttl only provided", id: "jun3", config: []byte(`ttl: 5s`), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.NoError(t, err) @@ -302,7 +302,7 @@ func TestCreateJWTUnifierFromPrototype(t *testing.T) { { uc: "configuration with too short ttl", config: []byte(`ttl: 5ms`), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.Error(t, err) @@ -317,7 +317,7 @@ func TestCreateJWTUnifierFromPrototype(t *testing.T) { claims: '{ "sub": {{ quote .Subject.ID }} }' `), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.NoError(t, err) @@ -345,7 +345,7 @@ ttl: 5s claims: '{ "sub": {{ quote .Subject.ID }} }' `), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.NoError(t, err) @@ -372,7 +372,7 @@ claims: ttl: 5s foo: bar `), - assert: func(t *testing.T, err error, prototype *jwtUnifier, configured *jwtUnifier) { + assert: func(t *testing.T, err error, prototype *jwtFinalizer, configured *jwtFinalizer) { t.Helper() require.Error(t, err) @@ -385,29 +385,29 @@ foo: bar conf, err := testsupport.DecodeTestConfig(tc.config) require.NoError(t, err) - prototype, err := newJWTUnifier(tc.id, nil) + prototype, err := newJWTFinalizer(tc.id, nil) require.NoError(t, err) // WHEN - unifier, err := prototype.WithConfig(conf) + finalizer, err := prototype.WithConfig(conf) // THEN var ( - jwtUn *jwtUnifier - ok bool + jwtFin *jwtFinalizer + ok bool ) if err == nil { - jwtUn, ok = unifier.(*jwtUnifier) + jwtFin, ok = finalizer.(*jwtFinalizer) require.True(t, ok) } - tc.assert(t, err, prototype, jwtUn) + tc.assert(t, err, prototype, jwtFin) }) } } -func TestJWTUnifierExecute(t *testing.T) { +func TestJWTFinalizerExecute(t *testing.T) { t.Parallel() const configuredTTL = 1 * time.Minute @@ -452,9 +452,9 @@ func TestJWTUnifierExecute(t *testing.T) { ctx.EXPECT().Signer().Return(signer) ctx.EXPECT().AddHeaderForUpstream("Authorization", "Bearer TestToken") - unifier := jwtUnifier{ttl: defaultJWTTTL} + finalizer := jwtFinalizer{ttl: defaultJWTTTL} - cacheKey := unifier.calculateCacheKey(sub, signer) + cacheKey := finalizer.calculateCacheKey(sub, signer) cch.EXPECT().Get(cacheKey).Return("TestToken") }, assert: func(t *testing.T, err error) { @@ -479,8 +479,8 @@ func TestJWTUnifierExecute(t *testing.T) { ctx.EXPECT().Signer().Return(signer) ctx.EXPECT().AddHeaderForUpstream("Authorization", "Bearer barfoo") - unifier := jwtUnifier{ttl: configuredTTL} - cacheKey := unifier.calculateCacheKey(sub, signer) + finalizer := jwtFinalizer{ttl: configuredTTL} + cacheKey := finalizer.calculateCacheKey(sub, signer) cch.EXPECT().Get(cacheKey).Return(time.Second) cch.EXPECT().Delete(cacheKey) @@ -632,11 +632,11 @@ claims: '{ mctx.EXPECT().AppContext().Return(cache.WithContext(context.Background(), cch)) configureMocks(t, mctx, signer, cch, tc.subject) - unifier, err := newJWTUnifier(tc.id, conf) + finalizer, err := newJWTFinalizer(tc.id, conf) require.NoError(t, err) // WHEN - err = unifier.Execute(mctx, tc.subject) + err = finalizer.Execute(mctx, tc.subject) // THEN tc.assert(t, err) diff --git a/internal/rules/mechanisms/finalizers/mocks/finalizer.go b/internal/rules/mechanisms/finalizers/mocks/finalizer.go new file mode 100644 index 000000000..bb5afa0e5 --- /dev/null +++ b/internal/rules/mechanisms/finalizers/mocks/finalizer.go @@ -0,0 +1,219 @@ +// Code generated by mockery v2.23.1. DO NOT EDIT. + +package mocks + +import ( + heimdall "github.com/dadrus/heimdall/internal/heimdall" + finalizers "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" + + mock "github.com/stretchr/testify/mock" + + subject "github.com/dadrus/heimdall/internal/rules/mechanisms/subject" +) + +// FinalizerMock is an autogenerated mock type for the Finalizer type +type FinalizerMock struct { + mock.Mock +} + +type FinalizerMock_Expecter struct { + mock *mock.Mock +} + +func (_m *FinalizerMock) EXPECT() *FinalizerMock_Expecter { + return &FinalizerMock_Expecter{mock: &_m.Mock} +} + +// ContinueOnError provides a mock function with given fields: +func (_m *FinalizerMock) ContinueOnError() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// FinalizerMock_ContinueOnError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ContinueOnError' +type FinalizerMock_ContinueOnError_Call struct { + *mock.Call +} + +// ContinueOnError is a helper method to define mock.On call +func (_e *FinalizerMock_Expecter) ContinueOnError() *FinalizerMock_ContinueOnError_Call { + return &FinalizerMock_ContinueOnError_Call{Call: _e.mock.On("ContinueOnError")} +} + +func (_c *FinalizerMock_ContinueOnError_Call) Run(run func()) *FinalizerMock_ContinueOnError_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FinalizerMock_ContinueOnError_Call) Return(_a0 bool) *FinalizerMock_ContinueOnError_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FinalizerMock_ContinueOnError_Call) RunAndReturn(run func() bool) *FinalizerMock_ContinueOnError_Call { + _c.Call.Return(run) + return _c +} + +// Execute provides a mock function with given fields: ctx, sub +func (_m *FinalizerMock) Execute(ctx heimdall.Context, sub *subject.Subject) error { + ret := _m.Called(ctx, sub) + + var r0 error + if rf, ok := ret.Get(0).(func(heimdall.Context, *subject.Subject) error); ok { + r0 = rf(ctx, sub) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FinalizerMock_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type FinalizerMock_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - ctx heimdall.Context +// - sub *subject.Subject +func (_e *FinalizerMock_Expecter) Execute(ctx interface{}, sub interface{}) *FinalizerMock_Execute_Call { + return &FinalizerMock_Execute_Call{Call: _e.mock.On("Execute", ctx, sub)} +} + +func (_c *FinalizerMock_Execute_Call) Run(run func(ctx heimdall.Context, sub *subject.Subject)) *FinalizerMock_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(heimdall.Context), args[1].(*subject.Subject)) + }) + return _c +} + +func (_c *FinalizerMock_Execute_Call) Return(_a0 error) *FinalizerMock_Execute_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FinalizerMock_Execute_Call) RunAndReturn(run func(heimdall.Context, *subject.Subject) error) *FinalizerMock_Execute_Call { + _c.Call.Return(run) + return _c +} + +// ID provides a mock function with given fields: +func (_m *FinalizerMock) ID() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// FinalizerMock_ID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ID' +type FinalizerMock_ID_Call struct { + *mock.Call +} + +// ID is a helper method to define mock.On call +func (_e *FinalizerMock_Expecter) ID() *FinalizerMock_ID_Call { + return &FinalizerMock_ID_Call{Call: _e.mock.On("ID")} +} + +func (_c *FinalizerMock_ID_Call) Run(run func()) *FinalizerMock_ID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FinalizerMock_ID_Call) Return(_a0 string) *FinalizerMock_ID_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FinalizerMock_ID_Call) RunAndReturn(run func() string) *FinalizerMock_ID_Call { + _c.Call.Return(run) + return _c +} + +// WithConfig provides a mock function with given fields: config +func (_m *FinalizerMock) WithConfig(config map[string]interface{}) (finalizers.Finalizer, error) { + ret := _m.Called(config) + + var r0 finalizers.Finalizer + var r1 error + if rf, ok := ret.Get(0).(func(map[string]interface{}) (finalizers.Finalizer, error)); ok { + return rf(config) + } + if rf, ok := ret.Get(0).(func(map[string]interface{}) finalizers.Finalizer); ok { + r0 = rf(config) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(finalizers.Finalizer) + } + } + + if rf, ok := ret.Get(1).(func(map[string]interface{}) error); ok { + r1 = rf(config) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FinalizerMock_WithConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithConfig' +type FinalizerMock_WithConfig_Call struct { + *mock.Call +} + +// WithConfig is a helper method to define mock.On call +// - config map[string]interface{} +func (_e *FinalizerMock_Expecter) WithConfig(config interface{}) *FinalizerMock_WithConfig_Call { + return &FinalizerMock_WithConfig_Call{Call: _e.mock.On("WithConfig", config)} +} + +func (_c *FinalizerMock_WithConfig_Call) Run(run func(config map[string]interface{})) *FinalizerMock_WithConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(map[string]interface{})) + }) + return _c +} + +func (_c *FinalizerMock_WithConfig_Call) Return(_a0 finalizers.Finalizer, _a1 error) *FinalizerMock_WithConfig_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FinalizerMock_WithConfig_Call) RunAndReturn(run func(map[string]interface{}) (finalizers.Finalizer, error)) *FinalizerMock_WithConfig_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewFinalizerMock interface { + mock.TestingT + Cleanup(func()) +} + +// NewFinalizerMock creates a new instance of FinalizerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewFinalizerMock(t mockConstructorTestingTNewFinalizerMock) *FinalizerMock { + mock := &FinalizerMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/rules/mechanisms/unifiers/noop_unifier.go b/internal/rules/mechanisms/finalizers/noop_finalizer.go similarity index 60% rename from internal/rules/mechanisms/unifiers/noop_unifier.go rename to internal/rules/mechanisms/finalizers/noop_finalizer.go index edd323910..3457536e4 100644 --- a/internal/rules/mechanisms/unifiers/noop_unifier.go +++ b/internal/rules/mechanisms/finalizers/noop_finalizer.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "github.com/rs/zerolog" @@ -27,31 +27,31 @@ import ( // //nolint:gochecknoinits func init() { - registerUnifierTypeFactory( - func(id string, typ string, conf map[string]any) (bool, Unifier, error) { - if typ != UnifierNoop { + registerTypeFactory( + func(id string, typ string, conf map[string]any) (bool, Finalizer, error) { + if typ != FinalizerNoop { return false, nil, nil } - return true, newNoopUnifier(id), nil + return true, newNoopFinalizer(id), nil }) } -func newNoopUnifier(id string) *noopUnifier { return &noopUnifier{id: id} } +func newNoopFinalizer(id string) *noopFinalizer { return &noopFinalizer{id: id} } -type noopUnifier struct { +type noopFinalizer struct { id string } -func (u *noopUnifier) Execute(ctx heimdall.Context, _ *subject.Subject) error { +func (u *noopFinalizer) Execute(ctx heimdall.Context, _ *subject.Subject) error { logger := zerolog.Ctx(ctx.AppContext()) - logger.Debug().Str("_id", u.id).Msg("Unifying using noop unifier") + logger.Debug().Str("_id", u.id).Msg("Finalizing using noop finalizer") return nil } -func (u *noopUnifier) WithConfig(map[string]any) (Unifier, error) { return u, nil } +func (u *noopFinalizer) WithConfig(map[string]any) (Finalizer, error) { return u, nil } -func (u *noopUnifier) ID() string { return u.id } +func (u *noopFinalizer) ID() string { return u.id } -func (u *noopUnifier) ContinueOnError() bool { return false } +func (u *noopFinalizer) ContinueOnError() bool { return false } diff --git a/internal/rules/mechanisms/unifiers/noop_unifier_test.go b/internal/rules/mechanisms/finalizers/noop_finalizer_test.go similarity index 68% rename from internal/rules/mechanisms/unifiers/noop_unifier_test.go rename to internal/rules/mechanisms/finalizers/noop_finalizer_test.go index d4da04bcb..ab0d8b93b 100644 --- a/internal/rules/mechanisms/unifiers/noop_unifier_test.go +++ b/internal/rules/mechanisms/finalizers/noop_finalizer_test.go @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package unifiers +package finalizers import ( "context" @@ -26,38 +26,38 @@ import ( "github.com/dadrus/heimdall/internal/heimdall/mocks" ) -func TestNoopUnifierExecution(t *testing.T) { +func TestNoopFinalizerExecution(t *testing.T) { t.Parallel() // GIVEN ctx := mocks.NewContextMock(t) ctx.EXPECT().AppContext().Return(context.Background()) - unifier := newNoopUnifier("foo") + finalizer := newNoopFinalizer("foo") // WHEN - err := unifier.Execute(ctx, nil) + err := finalizer.Execute(ctx, nil) // THEN require.NoError(t, err) - assert.Equal(t, "foo", unifier.ID()) - assert.False(t, unifier.ContinueOnError()) + assert.Equal(t, "foo", finalizer.ID()) + assert.False(t, finalizer.ContinueOnError()) } -func TestCreateNoopUnifierFromPrototype(t *testing.T) { +func TestCreateNoopFinalizerFromPrototype(t *testing.T) { t.Parallel() // GIVEN - prototype := newNoopUnifier("baz") + prototype := newNoopFinalizer("baz") // WHEN - un1, err1 := prototype.WithConfig(nil) - un2, err2 := prototype.WithConfig(map[string]any{"foo": "bar"}) + fin1, err1 := prototype.WithConfig(nil) + fin2, err2 := prototype.WithConfig(map[string]any{"foo": "bar"}) // THEN assert.NoError(t, err1) - assert.Equal(t, prototype, un1) + assert.Equal(t, prototype, fin1) assert.NoError(t, err2) - assert.Equal(t, prototype, un2) + assert.Equal(t, prototype, fin2) } diff --git a/internal/rules/mechanisms/mocks/factory.go b/internal/rules/mechanisms/mocks/factory.go index 695889ad4..101a5c455 100644 --- a/internal/rules/mechanisms/mocks/factory.go +++ b/internal/rules/mechanisms/mocks/factory.go @@ -12,9 +12,9 @@ import ( errorhandlers "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers" - mock "github.com/stretchr/testify/mock" + finalizers "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" - unifiers "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" + mock "github.com/stretchr/testify/mock" ) // FactoryMock is an autogenerated mock type for the Factory type @@ -254,20 +254,20 @@ func (_c *FactoryMock_CreateErrorHandler_Call) RunAndReturn(run func(string, str return _c } -// CreateUnifier provides a mock function with given fields: version, id, conf -func (_m *FactoryMock) CreateUnifier(version string, id string, conf config.MechanismConfig) (unifiers.Unifier, error) { +// CreateFinalizer provides a mock function with given fields: version, id, conf +func (_m *FactoryMock) CreateFinalizer(version string, id string, conf config.MechanismConfig) (finalizers.Finalizer, error) { ret := _m.Called(version, id, conf) - var r0 unifiers.Unifier + var r0 finalizers.Finalizer var r1 error - if rf, ok := ret.Get(0).(func(string, string, config.MechanismConfig) (unifiers.Unifier, error)); ok { + if rf, ok := ret.Get(0).(func(string, string, config.MechanismConfig) (finalizers.Finalizer, error)); ok { return rf(version, id, conf) } - if rf, ok := ret.Get(0).(func(string, string, config.MechanismConfig) unifiers.Unifier); ok { + if rf, ok := ret.Get(0).(func(string, string, config.MechanismConfig) finalizers.Finalizer); ok { r0 = rf(version, id, conf) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(unifiers.Unifier) + r0 = ret.Get(0).(finalizers.Finalizer) } } @@ -280,32 +280,32 @@ func (_m *FactoryMock) CreateUnifier(version string, id string, conf config.Mech return r0, r1 } -// FactoryMock_CreateUnifier_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateUnifier' -type FactoryMock_CreateUnifier_Call struct { +// FactoryMock_CreateFinalizer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateFinalizer' +type FactoryMock_CreateFinalizer_Call struct { *mock.Call } -// CreateUnifier is a helper method to define mock.On call +// CreateFinalizer is a helper method to define mock.On call // - version string // - id string // - conf config.MechanismConfig -func (_e *FactoryMock_Expecter) CreateUnifier(version interface{}, id interface{}, conf interface{}) *FactoryMock_CreateUnifier_Call { - return &FactoryMock_CreateUnifier_Call{Call: _e.mock.On("CreateUnifier", version, id, conf)} +func (_e *FactoryMock_Expecter) CreateFinalizer(version interface{}, id interface{}, conf interface{}) *FactoryMock_CreateFinalizer_Call { + return &FactoryMock_CreateFinalizer_Call{Call: _e.mock.On("CreateFinalizer", version, id, conf)} } -func (_c *FactoryMock_CreateUnifier_Call) Run(run func(version string, id string, conf config.MechanismConfig)) *FactoryMock_CreateUnifier_Call { +func (_c *FactoryMock_CreateFinalizer_Call) Run(run func(version string, id string, conf config.MechanismConfig)) *FactoryMock_CreateFinalizer_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(string), args[2].(config.MechanismConfig)) }) return _c } -func (_c *FactoryMock_CreateUnifier_Call) Return(_a0 unifiers.Unifier, _a1 error) *FactoryMock_CreateUnifier_Call { +func (_c *FactoryMock_CreateFinalizer_Call) Return(_a0 finalizers.Finalizer, _a1 error) *FactoryMock_CreateFinalizer_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *FactoryMock_CreateUnifier_Call) RunAndReturn(run func(string, string, config.MechanismConfig) (unifiers.Unifier, error)) *FactoryMock_CreateUnifier_Call { +func (_c *FactoryMock_CreateFinalizer_Call) RunAndReturn(run func(string, string, config.MechanismConfig) (finalizers.Finalizer, error)) *FactoryMock_CreateFinalizer_Call { _c.Call.Return(run) return _c } diff --git a/internal/rules/mechanisms/prototype_repository.go b/internal/rules/mechanisms/prototype_repository.go index 781195165..0d11a70a1 100644 --- a/internal/rules/mechanisms/prototype_repository.go +++ b/internal/rules/mechanisms/prototype_repository.go @@ -26,7 +26,7 @@ import ( "github.com/dadrus/heimdall/internal/rules/mechanisms/authorizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/contextualizers" "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers" - "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" + "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers" "github.com/dadrus/heimdall/internal/x/errorchain" ) @@ -66,12 +66,12 @@ func newPrototypeRepository( return nil, err } - logger.Debug().Msg("Loading definitions for unifiers") + logger.Debug().Msg("Loading definitions for finalizers") - unifierMap, err := createPipelineObjects(conf.Rules.Prototypes.Unifiers, logger, - unifiers.CreateUnifierPrototype) + finalizerMap, err := createPipelineObjects(conf.Rules.Prototypes.Finalizers, logger, + finalizers.CreatePrototype) if err != nil { - logger.Error().Err(err).Msg("Failed loading unifier definitions") + logger.Error().Err(err).Msg("Failed loading finalizer definitions") return nil, err } @@ -90,7 +90,7 @@ func newPrototypeRepository( authenticators: authenticatorMap, authorizers: authorizerMap, contextualizers: contextualizerMap, - unifiers: unifierMap, + finalizers: finalizerMap, errorHandlers: ehMap, }, nil } @@ -119,7 +119,7 @@ type prototypeRepository struct { authenticators map[string]authenticators.Authenticator authorizers map[string]authorizers.Authorizer contextualizers map[string]contextualizers.Contextualizer - unifiers map[string]unifiers.Unifier + finalizers map[string]finalizers.Finalizer errorHandlers map[string]errorhandlers.ErrorHandler } @@ -153,14 +153,14 @@ func (r *prototypeRepository) Contextualizer(id string) (contextualizers.Context return contextualizer, nil } -func (r *prototypeRepository) Unifier(id string) (unifiers.Unifier, error) { - unifier, ok := r.unifiers[id] +func (r *prototypeRepository) Finalizer(id string) (finalizers.Finalizer, error) { + finalizer, ok := r.finalizers[id] if !ok { return nil, errorchain.NewWithMessagef(ErrNoSuchPipelineObject, - "no unifier prototype for id='%s' found", id) + "no finalizer prototype for id='%s' found", id) } - return unifier, nil + return finalizer, nil } func (r *prototypeRepository) ErrorHandler(id string) (errorhandlers.ErrorHandler, error) { diff --git a/internal/rules/mechanisms/unifiers/mocks/unifier.go b/internal/rules/mechanisms/unifiers/mocks/unifier.go deleted file mode 100644 index 1660c07df..000000000 --- a/internal/rules/mechanisms/unifiers/mocks/unifier.go +++ /dev/null @@ -1,219 +0,0 @@ -// Code generated by mockery v2.23.1. DO NOT EDIT. - -package mocks - -import ( - heimdall "github.com/dadrus/heimdall/internal/heimdall" - mock "github.com/stretchr/testify/mock" - - subject "github.com/dadrus/heimdall/internal/rules/mechanisms/subject" - - unifiers "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers" -) - -// UnifierMock is an autogenerated mock type for the Unifier type -type UnifierMock struct { - mock.Mock -} - -type UnifierMock_Expecter struct { - mock *mock.Mock -} - -func (_m *UnifierMock) EXPECT() *UnifierMock_Expecter { - return &UnifierMock_Expecter{mock: &_m.Mock} -} - -// ContinueOnError provides a mock function with given fields: -func (_m *UnifierMock) ContinueOnError() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// UnifierMock_ContinueOnError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ContinueOnError' -type UnifierMock_ContinueOnError_Call struct { - *mock.Call -} - -// ContinueOnError is a helper method to define mock.On call -func (_e *UnifierMock_Expecter) ContinueOnError() *UnifierMock_ContinueOnError_Call { - return &UnifierMock_ContinueOnError_Call{Call: _e.mock.On("ContinueOnError")} -} - -func (_c *UnifierMock_ContinueOnError_Call) Run(run func()) *UnifierMock_ContinueOnError_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *UnifierMock_ContinueOnError_Call) Return(_a0 bool) *UnifierMock_ContinueOnError_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *UnifierMock_ContinueOnError_Call) RunAndReturn(run func() bool) *UnifierMock_ContinueOnError_Call { - _c.Call.Return(run) - return _c -} - -// Execute provides a mock function with given fields: ctx, sub -func (_m *UnifierMock) Execute(ctx heimdall.Context, sub *subject.Subject) error { - ret := _m.Called(ctx, sub) - - var r0 error - if rf, ok := ret.Get(0).(func(heimdall.Context, *subject.Subject) error); ok { - r0 = rf(ctx, sub) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// UnifierMock_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' -type UnifierMock_Execute_Call struct { - *mock.Call -} - -// Execute is a helper method to define mock.On call -// - ctx heimdall.Context -// - sub *subject.Subject -func (_e *UnifierMock_Expecter) Execute(ctx interface{}, sub interface{}) *UnifierMock_Execute_Call { - return &UnifierMock_Execute_Call{Call: _e.mock.On("Execute", ctx, sub)} -} - -func (_c *UnifierMock_Execute_Call) Run(run func(ctx heimdall.Context, sub *subject.Subject)) *UnifierMock_Execute_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(heimdall.Context), args[1].(*subject.Subject)) - }) - return _c -} - -func (_c *UnifierMock_Execute_Call) Return(_a0 error) *UnifierMock_Execute_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *UnifierMock_Execute_Call) RunAndReturn(run func(heimdall.Context, *subject.Subject) error) *UnifierMock_Execute_Call { - _c.Call.Return(run) - return _c -} - -// ID provides a mock function with given fields: -func (_m *UnifierMock) ID() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// UnifierMock_ID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ID' -type UnifierMock_ID_Call struct { - *mock.Call -} - -// ID is a helper method to define mock.On call -func (_e *UnifierMock_Expecter) ID() *UnifierMock_ID_Call { - return &UnifierMock_ID_Call{Call: _e.mock.On("ID")} -} - -func (_c *UnifierMock_ID_Call) Run(run func()) *UnifierMock_ID_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *UnifierMock_ID_Call) Return(_a0 string) *UnifierMock_ID_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *UnifierMock_ID_Call) RunAndReturn(run func() string) *UnifierMock_ID_Call { - _c.Call.Return(run) - return _c -} - -// WithConfig provides a mock function with given fields: config -func (_m *UnifierMock) WithConfig(config map[string]interface{}) (unifiers.Unifier, error) { - ret := _m.Called(config) - - var r0 unifiers.Unifier - var r1 error - if rf, ok := ret.Get(0).(func(map[string]interface{}) (unifiers.Unifier, error)); ok { - return rf(config) - } - if rf, ok := ret.Get(0).(func(map[string]interface{}) unifiers.Unifier); ok { - r0 = rf(config) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(unifiers.Unifier) - } - } - - if rf, ok := ret.Get(1).(func(map[string]interface{}) error); ok { - r1 = rf(config) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// UnifierMock_WithConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithConfig' -type UnifierMock_WithConfig_Call struct { - *mock.Call -} - -// WithConfig is a helper method to define mock.On call -// - config map[string]interface{} -func (_e *UnifierMock_Expecter) WithConfig(config interface{}) *UnifierMock_WithConfig_Call { - return &UnifierMock_WithConfig_Call{Call: _e.mock.On("WithConfig", config)} -} - -func (_c *UnifierMock_WithConfig_Call) Run(run func(config map[string]interface{})) *UnifierMock_WithConfig_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(map[string]interface{})) - }) - return _c -} - -func (_c *UnifierMock_WithConfig_Call) Return(_a0 unifiers.Unifier, _a1 error) *UnifierMock_WithConfig_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *UnifierMock_WithConfig_Call) RunAndReturn(run func(map[string]interface{}) (unifiers.Unifier, error)) *UnifierMock_WithConfig_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewUnifierMock interface { - mock.TestingT - Cleanup(func()) -} - -// NewUnifierMock creates a new instance of UnifierMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewUnifierMock(t mockConstructorTestingTNewUnifierMock) *UnifierMock { - mock := &UnifierMock{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/internal/rules/rule_factory_impl.go b/internal/rules/rule_factory_impl.go index 5fee40ab2..3e3f112c3 100644 --- a/internal/rules/rule_factory_impl.go +++ b/internal/rules/rule_factory_impl.go @@ -73,33 +73,33 @@ func (f *ruleFactory) createExecutePipeline( var ( authenticators compositeSubjectCreator subjectHandlers compositeSubjectHandler - unifiers compositeSubjectHandler + finalizers compositeSubjectHandler ) contextualizersCheck := func() error { - if len(unifiers) != 0 { + if len(finalizers) != 0 { return errorchain.NewWithMessage(heimdall.ErrConfiguration, - "at least one unifier is defined before a contextualizer") + "at least one finalizer is defined before a contextualizer") } return nil } authorizersCheck := func() error { - if len(unifiers) != 0 { + if len(finalizers) != 0 { return errorchain.NewWithMessage(heimdall.ErrConfiguration, - "at least one unifier is defined before an authorizer") + "at least one finalizer is defined before an authorizer") } return nil } - unifiersCheck := func() error { return nil } + finalizersCheck := func() error { return nil } for _, pipelineStep := range pipeline { id, found := pipelineStep["authenticator"] if found { - if len(subjectHandlers) != 0 || len(unifiers) != 0 { + if len(subjectHandlers) != 0 || len(finalizers) != 0 { return nil, nil, nil, errorchain.NewWithMessage(heimdall.ErrConfiguration, "an authenticator is defined after some other non authenticator type") } @@ -134,12 +134,12 @@ func (f *ruleFactory) createExecutePipeline( continue } - handler, err = createHandler(version, "unifier", pipelineStep, unifiersCheck, - f.hf.CreateUnifier) + handler, err = createHandler(version, "finalizer", pipelineStep, finalizersCheck, + f.hf.CreateFinalizer) if err != nil && !errors.Is(err, errHandlerNotFound) { return nil, nil, nil, err } else if handler != nil { - unifiers = append(unifiers, handler) + finalizers = append(finalizers, handler) continue } @@ -148,7 +148,7 @@ func (f *ruleFactory) createExecutePipeline( "unsupported configuration in execute") } - return authenticators, subjectHandlers, unifiers, nil + return authenticators, subjectHandlers, finalizers, nil } func (f *ruleFactory) DefaultRule() rule.Rule { return f.defaultRule } @@ -177,7 +177,7 @@ func (f *ruleFactory) CreateRule(version, srcID string, ruleConfig config2.Rule) ruleConfig.RuleMatcher.Strategy, ruleConfig.ID, srcID).CausedBy(err) } - authenticators, subHandlers, unifiers, err := f.createExecutePipeline(version, ruleConfig.Execute) + authenticators, subHandlers, finalizers, err := f.createExecutePipeline(version, ruleConfig.Execute) if err != nil { return nil, err } @@ -196,7 +196,7 @@ func (f *ruleFactory) CreateRule(version, srcID string, ruleConfig config2.Rule) if f.defaultRule != nil { authenticators = x.IfThenElse(len(authenticators) != 0, authenticators, f.defaultRule.sc) subHandlers = x.IfThenElse(len(subHandlers) != 0, subHandlers, f.defaultRule.sh) - unifiers = x.IfThenElse(len(unifiers) != 0, unifiers, f.defaultRule.un) + finalizers = x.IfThenElse(len(finalizers) != 0, finalizers, f.defaultRule.fi) errorHandlers = x.IfThenElse(len(errorHandlers) != 0, errorHandlers, f.defaultRule.eh) methods = x.IfThenElse(len(methods) != 0, methods, f.defaultRule.methods) } @@ -206,9 +206,9 @@ func (f *ruleFactory) CreateRule(version, srcID string, ruleConfig config2.Rule) "no authenticator defined for rule ID=%s from %s", ruleConfig.ID, srcID) } - if len(unifiers) == 0 { + if len(finalizers) == 0 { return nil, errorchain.NewWithMessagef(heimdall.ErrConfiguration, - "no unifier defined for rule ID=%s from %s", ruleConfig.ID, srcID) + "no finalizer defined for rule ID=%s from %s", ruleConfig.ID, srcID) } if len(methods) == 0 { @@ -232,7 +232,7 @@ func (f *ruleFactory) CreateRule(version, srcID string, ruleConfig config2.Rule) hash: hash, sc: authenticators, sh: subHandlers, - un: unifiers, + fi: finalizers, eh: errorHandlers, }, nil } @@ -313,7 +313,7 @@ func (f *ruleFactory) initWithDefaultRule(ruleConfig *config.DefaultRule, logger logger.Debug().Msg("Loading default rule") - authenticators, subHandlers, unifiers, err := f.createExecutePipeline( + authenticators, subHandlers, finalizers, err := f.createExecutePipeline( config2.CurrentRuleSetVersion, ruleConfig.Execute, ) @@ -333,8 +333,8 @@ func (f *ruleFactory) initWithDefaultRule(ruleConfig *config.DefaultRule, logger return errorchain.NewWithMessage(heimdall.ErrConfiguration, "no authenticator defined for default rule") } - if len(unifiers) == 0 { - return errorchain.NewWithMessagef(heimdall.ErrConfiguration, "no unifier defined for default rule") + if len(finalizers) == 0 { + return errorchain.NewWithMessagef(heimdall.ErrConfiguration, "no finalizer defined for default rule") } methods, err := expandHTTPMethods(ruleConfig.Methods) @@ -354,7 +354,7 @@ func (f *ruleFactory) initWithDefaultRule(ruleConfig *config.DefaultRule, logger isDefault: true, sc: authenticators, sh: subHandlers, - un: unifiers, + fi: finalizers, eh: errorHandlers, } diff --git a/internal/rules/rule_factory_impl_test.go b/internal/rules/rule_factory_impl_test.go index 6eba1c387..292059ef8 100644 --- a/internal/rules/rule_factory_impl_test.go +++ b/internal/rules/rule_factory_impl_test.go @@ -33,8 +33,8 @@ import ( mocks4 "github.com/dadrus/heimdall/internal/rules/mechanisms/authorizers/mocks" mocks5 "github.com/dadrus/heimdall/internal/rules/mechanisms/contextualizers/mocks" mocks6 "github.com/dadrus/heimdall/internal/rules/mechanisms/errorhandlers/mocks" + mocks7 "github.com/dadrus/heimdall/internal/rules/mechanisms/finalizers/mocks" mocks3 "github.com/dadrus/heimdall/internal/rules/mechanisms/mocks" - mocks7 "github.com/dadrus/heimdall/internal/rules/mechanisms/unifiers/mocks" "github.com/dadrus/heimdall/internal/rules/mocks" "github.com/dadrus/heimdall/internal/x" "github.com/dadrus/heimdall/internal/x/testsupport" @@ -70,7 +70,7 @@ func TestRuleFactoryNew(t *testing.T) { }, }, }}, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -87,7 +87,7 @@ func TestRuleFactoryNew(t *testing.T) { }, }, }}, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -111,7 +111,7 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateContextualizer(mock.Anything, "bar", mock.Anything). Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -120,11 +120,11 @@ func TestRuleFactoryNew(t *testing.T) { }, }, { - uc: "new factory with malformed default rule, where authenticator loading happens after unifier handlers", + uc: "new factory with malformed default rule, where authenticator loading happens after finalizers", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ - {"unifier": "bar"}, + {"finalizer": "bar"}, {"authenticator": "foo"}, }, }, @@ -132,9 +132,9 @@ func TestRuleFactoryNew(t *testing.T) { configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { t.Helper() - mhf.EXPECT().CreateUnifier(mock.Anything, "bar", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "bar", mock.Anything).Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -154,7 +154,7 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateAuthenticator(mock.Anything, "foo", mock.Anything).Return(nil, testsupport.ErrTestPurpose) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -162,11 +162,11 @@ func TestRuleFactoryNew(t *testing.T) { }, }, { - uc: "new factory with malformed default rule, where authorizer loading happens after unifier handlers", + uc: "new factory with malformed default rule, where authorizer loading happens after finalizers", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ - {"unifier": "bar"}, + {"finalizer": "bar"}, {"authorizer": "foo"}, }, }, @@ -174,9 +174,9 @@ func TestRuleFactoryNew(t *testing.T) { configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { t.Helper() - mhf.EXPECT().CreateUnifier(mock.Anything, "bar", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "bar", mock.Anything).Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -196,7 +196,7 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateAuthorizer(mock.Anything, "foo", mock.Anything).Return(nil, testsupport.ErrTestPurpose) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -204,11 +204,11 @@ func TestRuleFactoryNew(t *testing.T) { }, }, { - uc: "new factory with malformed default rule, where contextualizer loading happens after unifier handlers", + uc: "new factory with malformed default rule, where contextualizer loading happens after finalizers", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ - {"unifier": "bar"}, + {"finalizer": "bar"}, {"contextualizer": "foo"}, }, }, @@ -216,9 +216,9 @@ func TestRuleFactoryNew(t *testing.T) { configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { t.Helper() - mhf.EXPECT().CreateUnifier(mock.Anything, "bar", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "bar", mock.Anything).Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -239,7 +239,7 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateContextualizer(mock.Anything, "foo", mock.Anything). Return(nil, testsupport.ErrTestPurpose) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -247,18 +247,18 @@ func TestRuleFactoryNew(t *testing.T) { }, }, { - uc: "new factory with default rule, where unifier loading results in an error", + uc: "new factory with default rule, where finalizer loading results in an error", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ - Execute: []config.MechanismConfig{{"unifier": "foo"}}, + Execute: []config.MechanismConfig{{"finalizer": "foo"}}, }, }}, configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { t.Helper() - mhf.EXPECT().CreateUnifier(mock.Anything, "foo", mock.Anything).Return(nil, testsupport.ErrTestPurpose) + mhf.EXPECT().CreateFinalizer(mock.Anything, "foo", mock.Anything).Return(nil, testsupport.ErrTestPurpose) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -277,7 +277,7 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateErrorHandler(mock.Anything, "foo", mock.Anything).Return(nil, testsupport.ErrTestPurpose) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -291,7 +291,7 @@ func TestRuleFactoryNew(t *testing.T) { Execute: []config.MechanismConfig{}, }, }}, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) @@ -313,12 +313,12 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier") + assert.Contains(t, err.Error(), "no finalizer") }, }, { @@ -337,12 +337,12 @@ func TestRuleFactoryNew(t *testing.T) { mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) mhf.EXPECT().CreateContextualizer(mock.Anything, "baz", mock.Anything).Return(nil, nil) }, - assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { + assert: func(t *testing.T, err error, _ *ruleFactory) { t.Helper() require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier") + assert.Contains(t, err.Error(), "no finalizer") }, }, { @@ -368,16 +368,16 @@ func TestRuleFactoryNew(t *testing.T) { require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier") + assert.Contains(t, err.Error(), "no finalizer") }, }, { - uc: "new factory with default rule, consisting of authorizer and unifier with error while expanding methods", + uc: "new factory with default rule, consisting of authorizer and finalizer with error while expanding methods", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ {"authenticator": "bar"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, Methods: []string{"FOO", ""}, }, @@ -386,7 +386,7 @@ func TestRuleFactoryNew(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) - mhf.EXPECT().CreateUnifier(mock.Anything, "baz", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "baz", mock.Anything).Return(nil, nil) }, assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { t.Helper() @@ -397,12 +397,12 @@ func TestRuleFactoryNew(t *testing.T) { }, }, { - uc: "new factory with default rule, consisting of authorizer and unifier without methods defined", + uc: "new factory with default rule, consisting of authorizer and finalizer without methods defined", config: &config.Configuration{Rules: config.Rules{ Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ {"authenticator": "bar"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, }, }}, @@ -410,7 +410,7 @@ func TestRuleFactoryNew(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) - mhf.EXPECT().CreateUnifier(mock.Anything, "baz", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "baz", mock.Anything).Return(nil, nil) }, assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { t.Helper() @@ -426,7 +426,7 @@ func TestRuleFactoryNew(t *testing.T) { Default: &config.DefaultRule{ Execute: []config.MechanismConfig{ {"authenticator": "bar"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, Methods: []string{"FOO"}, }, @@ -435,7 +435,7 @@ func TestRuleFactoryNew(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) - mhf.EXPECT().CreateUnifier(mock.Anything, "baz", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "baz", mock.Anything).Return(nil, nil) }, assert: func(t *testing.T, err error, ruleFactory *ruleFactory) { t.Helper() @@ -452,7 +452,7 @@ func TestRuleFactoryNew(t *testing.T) { assert.ElementsMatch(t, defRule.methods, []string{"FOO"}) assert.Len(t, defRule.sc, 1) assert.Len(t, defRule.sh, 0) - assert.Len(t, defRule.un, 1) + assert.Len(t, defRule.fi, 1) assert.Len(t, defRule.eh, 0) }, }, @@ -464,7 +464,7 @@ func TestRuleFactoryNew(t *testing.T) { {"authenticator": "bar"}, {"contextualizer": "foo"}, {"authorizer": "zab"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, ErrorHandler: []config.MechanismConfig{ {"error_handler": "foobar"}, @@ -477,7 +477,7 @@ func TestRuleFactoryNew(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator(mock.Anything, "bar", mock.Anything).Return(nil, nil) - mhf.EXPECT().CreateUnifier(mock.Anything, "baz", mock.Anything).Return(nil, nil) + mhf.EXPECT().CreateFinalizer(mock.Anything, "baz", mock.Anything).Return(nil, nil) mhf.EXPECT().CreateAuthorizer(mock.Anything, "zab", mock.Anything).Return(nil, nil) mhf.EXPECT().CreateContextualizer(mock.Anything, "foo", mock.Anything).Return(nil, nil) mhf.EXPECT().CreateErrorHandler(mock.Anything, "foobar", mock.Anything).Return(nil, nil) @@ -498,7 +498,7 @@ func TestRuleFactoryNew(t *testing.T) { assert.ElementsMatch(t, defRule.methods, []string{"FOO", "BAR"}) assert.Len(t, defRule.sc, 1) assert.Len(t, defRule.sh, 2) - assert.Len(t, defRule.un, 1) + assert.Len(t, defRule.fi, 1) assert.Len(t, defRule.eh, 2) }, }, @@ -687,7 +687,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier defined") + assert.Contains(t, err.Error(), "no finalizer defined") }, }, { @@ -711,7 +711,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier defined") + assert.Contains(t, err.Error(), "no finalizer defined") }, }, { @@ -737,17 +737,17 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.Error(t, err) assert.ErrorIs(t, err, heimdall.ErrConfiguration) - assert.Contains(t, err.Error(), "no unifier defined") + assert.Contains(t, err.Error(), "no finalizer defined") }, }, { - uc: "without default rule and with authenticator and unifier configured, but with error while expanding methods", + uc: "without default rule and with authenticator and finalizer configured, but with error while expanding methods", config: config2.Rule{ ID: "foobar", RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar"}, + {"finalizer": "bar"}, }, Methods: []string{"FOO", ""}, }, @@ -755,7 +755,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator("test", "foo", mock.Anything).Return(&mocks2.AuthenticatorMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "bar", mock.Anything).Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "bar", mock.Anything).Return(&mocks7.FinalizerMock{}, nil) }, assert: func(t *testing.T, err error, rul *ruleImpl) { t.Helper() @@ -766,20 +766,20 @@ func TestRuleFactoryCreateRule(t *testing.T) { }, }, { - uc: "without default rule and with authenticator and unifier configured, but without methods", + uc: "without default rule and with authenticator and finalizer configured, but without methods", config: config2.Rule{ ID: "foobar", RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar"}, + {"finalizer": "bar"}, }, }, configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { t.Helper() mhf.EXPECT().CreateAuthenticator("test", "foo", mock.Anything).Return(&mocks2.AuthenticatorMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "bar", mock.Anything).Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "bar", mock.Anything).Return(&mocks7.FinalizerMock{}, nil) }, assert: func(t *testing.T, err error, rul *ruleImpl) { t.Helper() @@ -796,7 +796,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar"}, + {"finalizer": "bar"}, }, Methods: []string{"FOO", "BAR"}, }, @@ -804,7 +804,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator("test", "foo", mock.Anything).Return(&mocks2.AuthenticatorMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "bar", mock.Anything).Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "bar", mock.Anything).Return(&mocks7.FinalizerMock{}, nil) }, assert: func(t *testing.T, err error, rul *ruleImpl) { t.Helper() @@ -819,7 +819,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { assert.ElementsMatch(t, rul.methods, []string{"FOO", "BAR"}) assert.Len(t, rul.sc, 1) assert.Len(t, rul.sh, 0) - assert.Len(t, rul.un, 1) + assert.Len(t, rul.fi, 1) assert.Len(t, rul.eh, 0) }, }, @@ -832,7 +832,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar"}, + {"finalizer": "bar"}, }, Methods: []string{"FOO", "BAR"}, }, @@ -840,7 +840,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { t.Helper() mhf.EXPECT().CreateAuthenticator("test", "foo", mock.Anything).Return(&mocks2.AuthenticatorMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "bar", mock.Anything).Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "bar", mock.Anything).Return(&mocks7.FinalizerMock{}, nil) }, assert: func(t *testing.T, err error, rul *ruleImpl) { t.Helper() @@ -855,7 +855,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { assert.ElementsMatch(t, rul.methods, []string{"FOO", "BAR"}) assert.Len(t, rul.sc, 1) assert.Len(t, rul.sh, 0) - assert.Len(t, rul.un, 1) + assert.Len(t, rul.fi, 1) assert.Len(t, rul.eh, 0) assert.NotNil(t, rul.backend) }, @@ -870,7 +870,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { methods: []string{"FOO"}, sc: compositeSubjectCreator{&mocks.SubjectCreatorMock{}}, sh: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, - un: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, + fi: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, eh: compositeErrorHandler{&mocks.ErrorHandlerMock{}}, }, assert: func(t *testing.T, err error, rul *ruleImpl) { @@ -886,7 +886,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { assert.ElementsMatch(t, rul.methods, []string{"FOO"}) assert.Len(t, rul.sc, 1) assert.Len(t, rul.sh, 1) - assert.Len(t, rul.un, 1) + assert.Len(t, rul.fi, 1) assert.Len(t, rul.eh, 1) }, }, @@ -899,7 +899,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { {"authenticator": "foo"}, {"contextualizer": "bar"}, {"authorizer": "zab"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, ErrorHandler: []config.MechanismConfig{ {"error_handler": "foo"}, @@ -910,7 +910,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { methods: []string{"FOO"}, sc: compositeSubjectCreator{&mocks.SubjectCreatorMock{}}, sh: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, - un: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, + fi: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, eh: compositeErrorHandler{&mocks.ErrorHandlerMock{}}, }, configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { @@ -922,8 +922,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { Return(&mocks5.ContextualizerMock{}, nil) mhf.EXPECT().CreateAuthorizer("test", "zab", mock.Anything). Return(&mocks4.AuthorizerMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "baz", mock.Anything). - Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "baz", mock.Anything). + Return(&mocks7.FinalizerMock{}, nil) mhf.EXPECT().CreateErrorHandler("test", "foo", mock.Anything). Return(&mocks6.ErrorHandlerMock{}, nil) }, @@ -946,8 +946,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.Len(t, rul.sh, 2) assert.NotNil(t, rul.sh[0]) assert.NotNil(t, rul.sh[1]) - require.Len(t, rul.un, 1) - assert.NotNil(t, rul.un[0]) + require.Len(t, rul.fi, 1) + assert.NotNil(t, rul.fi[0]) require.Len(t, rul.eh, 1) assert.NotNil(t, rul.eh[0]) }, @@ -971,7 +971,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { {"authenticator": "foo"}, {"contextualizer": "bar"}, {"authorizer": "zab"}, - {"unifier": "baz"}, + {"finalizer": "baz"}, }, ErrorHandler: []config.MechanismConfig{ {"error_handler": "foo"}, @@ -982,7 +982,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { methods: []string{"FOO"}, sc: compositeSubjectCreator{&mocks.SubjectCreatorMock{}}, sh: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, - un: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, + fi: compositeSubjectHandler{&mocks.SubjectHandlerMock{}}, eh: compositeErrorHandler{&mocks.ErrorHandlerMock{}}, }, configureMocks: func(t *testing.T, mhf *mocks3.FactoryMock) { @@ -994,8 +994,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { Return(&mocks5.ContextualizerMock{}, nil) mhf.EXPECT().CreateAuthorizer("test", "zab", mock.Anything). Return(&mocks4.AuthorizerMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "baz", mock.Anything). - Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "baz", mock.Anything). + Return(&mocks7.FinalizerMock{}, nil) mhf.EXPECT().CreateErrorHandler("test", "foo", mock.Anything). Return(&mocks6.ErrorHandlerMock{}, nil) }, @@ -1024,8 +1024,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.Len(t, rul.sh, 2) assert.NotNil(t, rul.sh[0]) assert.NotNil(t, rul.sh[1]) - require.Len(t, rul.un, 1) - assert.NotNil(t, rul.un[0]) + require.Len(t, rul.fi, 1) + assert.NotNil(t, rul.fi[0]) require.Len(t, rul.eh, 1) assert.NotNil(t, rul.eh[0]) assert.NotNil(t, rul.backend) @@ -1038,7 +1038,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar", "if": 1}, + {"finalizer": "bar", "if": 1}, }, Methods: []string{"FOO"}, }, @@ -1062,7 +1062,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { RuleMatcher: config2.Matcher{URL: "http://foo.bar", Strategy: "glob"}, Execute: []config.MechanismConfig{ {"authenticator": "foo"}, - {"unifier": "bar", "if": ""}, + {"finalizer": "bar", "if": ""}, }, Methods: []string{"FOO"}, }, @@ -1089,7 +1089,7 @@ func TestRuleFactoryCreateRule(t *testing.T) { {"authorizer": "bar", "if": "false"}, {"contextualizer": "bar", "if": "true"}, {"authorizer": "baz"}, - {"unifier": "bar", "if": "true"}, + {"finalizer": "bar", "if": "true"}, }, Methods: []string{"FOO"}, }, @@ -1102,8 +1102,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { Return(&mocks4.AuthorizerMock{}, nil).Times(2) mhf.EXPECT().CreateContextualizer("test", "bar", mock.Anything). Return(&mocks5.ContextualizerMock{}, nil) - mhf.EXPECT().CreateUnifier("test", "bar", mock.Anything). - Return(&mocks7.UnifierMock{}, nil) + mhf.EXPECT().CreateFinalizer("test", "bar", mock.Anything). + Return(&mocks7.FinalizerMock{}, nil) }, assert: func(t *testing.T, err error, rul *ruleImpl) { t.Helper() @@ -1137,8 +1137,8 @@ func TestRuleFactoryCreateRule(t *testing.T) { require.True(t, ok) assert.IsType(t, defaultExecutionCondition{}, sh.c) - require.Len(t, rul.un, 1) - un, ok := rul.un[0].(*conditionalSubjectHandler) + require.Len(t, rul.fi, 1) + un, ok := rul.fi[0].(*conditionalSubjectHandler) require.True(t, ok) assert.IsType(t, &celExecutionCondition{}, un.c) diff --git a/internal/rules/rule_impl.go b/internal/rules/rule_impl.go index 39762c021..cbd5a9479 100644 --- a/internal/rules/rule_impl.go +++ b/internal/rules/rule_impl.go @@ -39,7 +39,7 @@ type ruleImpl struct { hash []byte sc compositeSubjectCreator sh compositeSubjectHandler - un compositeSubjectHandler + fi compositeSubjectHandler eh compositeErrorHandler } @@ -67,8 +67,8 @@ func (r *ruleImpl) Execute(ctx heimdall.Context) (rule.Backend, error) { return nil, err } - // unifiers - if err = r.un.Execute(ctx, sub); err != nil { + // finalizers + if err = r.fi.Execute(ctx, sub); err != nil { _, err := r.eh.Execute(ctx, err) return nil, err diff --git a/internal/rules/rule_impl_test.go b/internal/rules/rule_impl_test.go index 64ed63063..2653ff61e 100644 --- a/internal/rules/rule_impl_test.go +++ b/internal/rules/rule_impl_test.go @@ -182,7 +182,7 @@ func TestRuleExecute(t *testing.T) { ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, authorizer *mocks.SubjectHandlerMock, - unifier *mocks.SubjectHandlerMock, + finalizer *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) assert func(t *testing.T, err error, backend rule.Backend) @@ -190,7 +190,7 @@ func TestRuleExecute(t *testing.T) { { uc: "authenticator fails, but error handler succeeds", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + _ *mocks.SubjectHandlerMock, _ *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -209,7 +209,7 @@ func TestRuleExecute(t *testing.T) { { uc: "authenticator fails, and error handler fails", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + _ *mocks.SubjectHandlerMock, _ *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -229,7 +229,7 @@ func TestRuleExecute(t *testing.T) { { uc: "authenticator succeeds, authorizer fails, but error handler succeeds", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + authorizer *mocks.SubjectHandlerMock, _ *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -251,7 +251,7 @@ func TestRuleExecute(t *testing.T) { { uc: "authenticator succeeds, authorizer fails and error handler fails", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + authorizer *mocks.SubjectHandlerMock, _ *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -272,9 +272,9 @@ func TestRuleExecute(t *testing.T) { }, }, { - uc: "authenticator succeeds, authorizer succeeds, unifier fails, but error handler succeeds", + uc: "authenticator succeeds, authorizer succeeds, finalizer fails, but error handler succeeds", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + authorizer *mocks.SubjectHandlerMock, finalizer *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -283,8 +283,8 @@ func TestRuleExecute(t *testing.T) { authenticator.EXPECT().Execute(ctx).Return(sub, nil) authorizer.EXPECT().Execute(ctx, sub).Return(nil) - unifier.EXPECT().Execute(ctx, sub).Return(testsupport.ErrTestPurpose) - unifier.EXPECT().ContinueOnError().Return(false) + finalizer.EXPECT().Execute(ctx, sub).Return(testsupport.ErrTestPurpose) + finalizer.EXPECT().ContinueOnError().Return(false) errHandler.EXPECT().Execute(ctx, testsupport.ErrTestPurpose).Return(true, nil) }, assert: func(t *testing.T, err error, backend rule.Backend) { @@ -295,9 +295,9 @@ func TestRuleExecute(t *testing.T) { }, }, { - uc: "authenticator succeeds, authorizer succeeds, unifier fails and error handler fails", + uc: "authenticator succeeds, authorizer succeeds, finalizer fails and error handler fails", configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, + authorizer *mocks.SubjectHandlerMock, finalizer *mocks.SubjectHandlerMock, errHandler *mocks.ErrorHandlerMock, ) { t.Helper() @@ -306,8 +306,8 @@ func TestRuleExecute(t *testing.T) { authenticator.EXPECT().Execute(ctx).Return(sub, nil) authorizer.EXPECT().Execute(ctx, sub).Return(nil) - unifier.EXPECT().Execute(ctx, sub).Return(testsupport.ErrTestPurpose) - unifier.EXPECT().ContinueOnError().Return(false) + finalizer.EXPECT().Execute(ctx, sub).Return(testsupport.ErrTestPurpose) + finalizer.EXPECT().ContinueOnError().Return(false) errHandler.EXPECT().Execute(ctx, testsupport.ErrTestPurpose).Return(true, testsupport.ErrTestPurpose2) }, assert: func(t *testing.T, err error, backend rule.Backend) { @@ -324,8 +324,8 @@ func TestRuleExecute(t *testing.T) { Host: "foo.bar", }, configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, - errHandler *mocks.ErrorHandlerMock, + authorizer *mocks.SubjectHandlerMock, finalizer *mocks.SubjectHandlerMock, + _ *mocks.ErrorHandlerMock, ) { t.Helper() @@ -333,7 +333,7 @@ func TestRuleExecute(t *testing.T) { authenticator.EXPECT().Execute(ctx).Return(sub, nil) authorizer.EXPECT().Execute(ctx, sub).Return(nil) - unifier.EXPECT().Execute(ctx, sub).Return(nil) + finalizer.EXPECT().Execute(ctx, sub).Return(nil) ctx.EXPECT().Request().Return(&heimdall.Request{URL: &url.URL{Scheme: "http", Host: "foo.local", Path: "/api/v1/foo"}}) }, @@ -351,8 +351,8 @@ func TestRuleExecute(t *testing.T) { URLRewriter: &config.URLRewriter{PathPrefixToCut: "/api/v1"}, }, configureMocks: func(t *testing.T, ctx *heimdallmocks.ContextMock, authenticator *mocks.SubjectCreatorMock, - authorizer *mocks.SubjectHandlerMock, unifier *mocks.SubjectHandlerMock, - errHandler *mocks.ErrorHandlerMock, + authorizer *mocks.SubjectHandlerMock, finalizer *mocks.SubjectHandlerMock, + _ *mocks.ErrorHandlerMock, ) { t.Helper() @@ -360,7 +360,7 @@ func TestRuleExecute(t *testing.T) { authenticator.EXPECT().Execute(ctx).Return(sub, nil) authorizer.EXPECT().Execute(ctx, sub).Return(nil) - unifier.EXPECT().Execute(ctx, sub).Return(nil) + finalizer.EXPECT().Execute(ctx, sub).Return(nil) ctx.EXPECT().Request().Return(&heimdall.Request{URL: &url.URL{Scheme: "http", Host: "foo.local", Path: "/api/v1/foo"}}) }, @@ -379,18 +379,18 @@ func TestRuleExecute(t *testing.T) { authenticator := mocks.NewSubjectCreatorMock(t) authorizer := mocks.NewSubjectHandlerMock(t) - unifier := mocks.NewSubjectHandlerMock(t) + finalizer := mocks.NewSubjectHandlerMock(t) errHandler := mocks.NewErrorHandlerMock(t) rul := &ruleImpl{ backend: tc.backend, sc: compositeSubjectCreator{authenticator}, sh: compositeSubjectHandler{authorizer}, - un: compositeSubjectHandler{unifier}, + fi: compositeSubjectHandler{finalizer}, eh: compositeErrorHandler{errHandler}, } - tc.configureMocks(t, ctx, authenticator, authorizer, unifier, errHandler) + tc.configureMocks(t, ctx, authenticator, authorizer, finalizer, errHandler) // WHEN upstream, err := rul.Execute(ctx) diff --git a/schema/config.schema.json b/schema/config.schema.json index 97e8fccc0..65b859ea9 100644 --- a/schema/config.schema.json +++ b/schema/config.schema.json @@ -1272,8 +1272,8 @@ } } }, - "unifierJwt": { - "description": "Creates a JWT Token from the given subject information", + "finalizerJwt": { + "description": "Creates a JWT Token from the available subject and request information to be passed to the upstream service", "type": "object", "additionalProperties": false, "required": [ @@ -1285,11 +1285,11 @@ "const": "jwt" }, "id": { - "description": "The unique id of the unifier to be used in the rule definition", + "description": "The unique id of the finalizer to be used in the rule definition", "type": "string" }, "config": { - "description": "JWT unifier Configuration", + "description": "JWT finalizer configuration", "type": "object", "additionalProperties": false, "required": [ @@ -1297,6 +1297,7 @@ ], "properties": { "claims": { + "description": "Custom claims, which should be included into the JWT.", "type": "string" }, "ttl": { @@ -1330,8 +1331,8 @@ } } }, - "unifierHeader": { - "description": "Transforms the request, allowing passing the credentials to the upstream application via headers", + "finalizerHeader": { + "description": "Allowing passing any information to the upstream service via headers", "type": "object", "additionalProperties": false, "required": [ @@ -1344,7 +1345,7 @@ "const": "header" }, "id": { - "description": "The unique id of the unifier to be used in the rule definition", + "description": "The unique id of the finalizer to be used in the rule definition", "type": "string" }, "config": { @@ -1366,8 +1367,8 @@ } } }, - "unifierCookie": { - "description": "Transforms the request, allowing passing the credentials to the upstream application via cookies", + "finalizerCookie": { + "description": "Transforms the request, allowing passing the credentials to the upstream service via cookies", "type": "object", "additionalProperties": false, "required": [ @@ -1380,7 +1381,7 @@ "const": "cookie" }, "id": { - "description": "The unique id of the unifier to be used in the rule definition", + "description": "The unique id of the finalizer to be used in the rule definition", "type": "string" }, "config": { @@ -1402,8 +1403,8 @@ } } }, - "unifierNoop": { - "description": "Noop Unifier", + "finalizerNoop": { + "description": "Does nothing", "type": "object", "additionalProperties": false, "properties": { @@ -1411,7 +1412,7 @@ "const": "noop" }, "id": { - "description": "The unique id of the unifier to be used in the rule definition", + "description": "The unique id of the finalizer to be used in the rule definition", "type": "string" } } @@ -1710,7 +1711,7 @@ "additionalProperties": false, "required": [ "authenticators", - "unifiers" + "finalizers" ], "properties": { "error_handlers": { @@ -1793,24 +1794,24 @@ "$ref": "#/definitions/contextualizerGeneric" } }, - "unifiers": { - "description": "Unifiers", + "finalizers": { + "description": "Finalizers", "type": "array", "additionalItems": false, "uniqueItems": true, "items": { "anyOf": [ { - "$ref": "#/definitions/unifierNoop" + "$ref": "#/definitions/finalizerNoop" }, { - "$ref": "#/definitions/unifierJwt" + "$ref": "#/definitions/finalizerJwt" }, { - "$ref": "#/definitions/unifierHeader" + "$ref": "#/definitions/finalizerHeader" }, { - "$ref": "#/definitions/unifierCookie" + "$ref": "#/definitions/finalizerCookie" } ] }