From 88fed67d671a04712841c950522b540914ab8408 Mon Sep 17 00:00:00 2001 From: Alex Zgabur Date: Mon, 23 Oct 2023 19:15:08 +0200 Subject: [PATCH 1/3] AuthPolicy upgrade to v2 --- testsuite/objects/__init__.py | 42 +---- .../openshift/objects/auth_config/__init__.py | 11 +- .../objects/auth_config/auth_policy.py | 4 +- .../openshift/objects/auth_config/sections.py | 165 ++++++++++++------ 4 files changed, 117 insertions(+), 105 deletions(-) diff --git a/testsuite/objects/__init__.py b/testsuite/objects/__init__.py index debc2dc8..063e5f68 100644 --- a/testsuite/objects/__init__.py +++ b/testsuite/objects/__init__.py @@ -73,12 +73,14 @@ def __post_init__(self): class Credentials: """Dataclass for Credentials structure""" - in_location: str + in_location: Literal["authorizationHeader", "customHeader", "queryString", "cookie"] keySelector: str def asdict(self): - """Custom asdict, because I cannot use 'in' as a name""" - return {"in": self.in_location, "keySelector": self.keySelector} + """Custom asdict because of needing to put location as parent dict key for inner dict""" + if self.in_location == "authorizationHeader": + return {self.in_location: {"prefix": self.keySelector}} + return {self.in_location: {"name": self.keySelector}} @dataclass @@ -116,39 +118,7 @@ class Value(ABCValue): class ValueFrom(ABCValue): """Dataclass for dynamic Value. It contains reference path to existing value in AuthJson.""" - authJSON: str - - def asdict(self): - """Override `asdict` function""" - return {"valueFrom": {"authJSON": self.authJSON}} - - -@dataclass -class Property: - """Dataclass for static and dynamic values. Property is a Value with name.""" - - name: str - value: ABCValue - - def asdict(self): - """Override `asdict` function""" - return {"name": self.name, **asdict(self.value)} - - -@dataclass -class ExtendedProperty(Property): - """ - Dataclass extending Property class adding optional `overwrite` feature - used in extended_properties functionality in Identity section. - """ - - overwrite: Optional[bool] = None - - def asdict(self): - """Extend inherited `asdict` function to include new attributes.""" - if self.overwrite is not None: - return {**super().asdict(), "overwrite": self.overwrite} - return super().asdict() + selector: str @dataclass diff --git a/testsuite/openshift/objects/auth_config/__init__.py b/testsuite/openshift/objects/auth_config/__init__.py index df9f50f1..485755ba 100644 --- a/testsuite/openshift/objects/auth_config/__init__.py +++ b/testsuite/openshift/objects/auth_config/__init__.py @@ -25,7 +25,7 @@ def authorization(self) -> AuthorizationSection: @cached_property def identity(self) -> IdentitySection: """Gives access to identity settings""" - return IdentitySection(self, "identity") + return IdentitySection(self, "authentication") @cached_property def metadata(self) -> MetadataSection: @@ -48,7 +48,7 @@ def create_instance( ): """Creates base instance""" model: Dict = { - "apiVersion": "authorino.kuadrant.io/v1beta1", + "apiVersion": "authorino.kuadrant.io/v1beta2", "kind": "AuthConfig", "metadata": {"name": name, "namespace": openshift.project, "labels": labels}, "spec": {"hosts": hostnames or [route.hostname]}, # type: ignore @@ -71,13 +71,6 @@ def remove_all_hosts(self): """Remove all hosts""" self.model.spec.hosts = [] - @modify - def set_deny_with(self, code, value): - """Set denyWith""" - self.auth_section["denyWith"] = { - "unauthenticated": {"code": code, "headers": [{"name": "Location", "valueFrom": {"authJSON": value}}]} - } - @modify def add_rule(self, when: list[Rule]): """Add rule for the skip of entire AuthConfig""" diff --git a/testsuite/openshift/objects/auth_config/auth_policy.py b/testsuite/openshift/objects/auth_config/auth_policy.py index 0e57549d..bc991fc2 100644 --- a/testsuite/openshift/objects/auth_config/auth_policy.py +++ b/testsuite/openshift/objects/auth_config/auth_policy.py @@ -23,7 +23,7 @@ def route(self) -> HTTPRoute: @property def auth_section(self): - return self.model.spec.setdefault("authScheme", {}) + return self.model.spec.setdefault("rules", {}) # pylint: disable=unused-argument @classmethod @@ -37,7 +37,7 @@ def create_instance( # type: ignore ): """Creates base instance""" model: Dict = { - "apiVersion": "kuadrant.io/v1beta1", + "apiVersion": "kuadrant.io/v1beta2", "kind": "AuthPolicy", "metadata": {"name": name, "namespace": openshift.project, "labels": labels}, "spec": { diff --git a/testsuite/openshift/objects/auth_config/sections.py b/testsuite/openshift/objects/auth_config/sections.py index db975c9c..ff2344a9 100644 --- a/testsuite/openshift/objects/auth_config/sections.py +++ b/testsuite/openshift/objects/auth_config/sections.py @@ -9,8 +9,6 @@ Selector, Credentials, ValueFrom, - Property, - ExtendedProperty, ) from testsuite.openshift.objects import modify @@ -18,6 +16,26 @@ from testsuite.openshift.objects.auth_config import AuthConfig +def add_common_features( + value: dict, + *, + priority: int = None, + when: Iterable[Rule] = None, + metrics: bool = None, + cache: Cache = None, +) -> None: + """Add common features to value dict.""" + + if when: + value["when"] = [asdict(x) for x in when] + if metrics: + value["metrics"] = metrics + if cache: + value["cache"] = asdict(cache) + if priority: + value["priority"] = priority + + class Section: """Common class for all Sections""" @@ -42,29 +60,12 @@ def committed(self): @property def section(self): """The actual dict section which will be edited""" - return self.obj.auth_section.setdefault(self.section_name, []) + return self.obj.auth_section.setdefault(self.section_name, {}) - def add_item( - self, - name, - value, - *, - priority: int = None, - when: Iterable[Rule] = None, - metrics: bool = None, - cache: Cache = None - ): + def add_item(self, name: str, value: dict, **common_features): """Adds item to the section""" - item = {"name": name, **value} - if when: - item["when"] = [asdict(x) for x in when] - if metrics: - item["metrics"] = metrics - if cache: - item["cache"] = asdict(cache) - if priority: - item["priority"] = priority - self.section.append(item) + add_common_features(value, **common_features) + self.section.update({name: value}) @modify def clear_all(self): @@ -75,12 +76,28 @@ def clear_all(self): class IdentitySection(Section): """Section which contains identity configuration""" - def add_item(self, name, value, *, extended_properties: list[ExtendedProperty] = None, **common_features): + def add_item( + self, + name, + value, + *, + defaults_properties: dict[str, ABCValue] = None, + overrides_properties: dict[str, ABCValue] = None, + **common_features, + ): """ - Adds optional extendedProperties feature specific to IdentitySection and then calls parent add_item() method + Adds "defaults" and "overrides" properties for values in AuthJson. + Properties of "defaults" type are used as default value when none is defined. + Properties of "overrides" type are overriding any existing value. """ - if extended_properties: - value["extendedProperties"] = [asdict(i) for i in extended_properties] + if defaults_properties: + for key, val in defaults_properties.items(): + value.setdefault("defaults", {}).update({key: asdict(val)}) + + if overrides_properties: + for key, val in overrides_properties.items(): + value.setdefault("overrides", {}).update({key: asdict(val)}) + super().add_item(name, value, **common_features) @modify @@ -90,7 +107,7 @@ def add_mtls(self, name: str, selector: Selector, **common_features): :param name: name of the identity :param selector: selector to match """ - self.add_item(name, {"mtls": {"selector": asdict(selector)}, **common_features}) + self.add_item(name, {"x509": {"selector": asdict(selector)}, **common_features}) @modify def add_kubernetes(self, name: str, audiences: list[str], **common_features): @@ -99,14 +116,14 @@ def add_kubernetes(self, name: str, audiences: list[str], **common_features): :param name: name of the identity :param audiences: token audiences """ - self.add_item(name, {"kubernetes": {"audiences": audiences}}, **common_features) + self.add_item(name, {"kubernetesTokenReview": {"audiences": audiences}}, **common_features) @modify def add_oidc(self, name, endpoint, *, credentials: Credentials = None, **common_features): """Adds OIDC identity""" if credentials is None: - credentials = Credentials("authorization_header", "Bearer") - self.add_item(name, {"oidc": {"endpoint": endpoint}, "credentials": asdict(credentials)}, **common_features) + credentials = Credentials("authorizationHeader", "Bearer") + self.add_item(name, {"jwt": {"issuerUrl": endpoint}, "credentials": asdict(credentials)}, **common_features) @modify def add_api_key( @@ -116,7 +133,7 @@ def add_api_key( *, all_namespaces: bool = False, credentials: Credentials = None, - **common_features + **common_features, ): """ Adds API Key identity @@ -127,14 +144,14 @@ def add_api_key( :param credentials: locations where credentials are passed """ if credentials is None: - credentials = Credentials("authorization_header", "APIKEY") + credentials = Credentials("authorizationHeader", "APIKEY") self.add_item( name, { "apiKey": {"selector": asdict(selector), "allNamespaces": all_namespaces}, "credentials": asdict(credentials), }, - **common_features + **common_features, ) @modify @@ -145,7 +162,7 @@ def add_anonymous(self, name, **common_features): @modify def add_plain(self, name, auth_json, **common_features): """Adds plain identity""" - self.add_item(name, {"plain": {"authJSON": auth_json}}, **common_features) + self.add_item(name, {"plain": asdict(ValueFrom(auth_json))}, **common_features) class MetadataSection(Section): @@ -158,12 +175,12 @@ def add_http(self, name, endpoint, method: Literal["GET", "POST"], **common_feat name, { "http": { - "endpoint": endpoint, + "url": endpoint, "method": method, - "headers": [{"name": "Accept", "value": "application/json"}], + "headers": {"Accept": {"value": "application/json"}}, } }, - **common_features + **common_features, ) @modify @@ -180,35 +197,41 @@ def add_uma(self, name, endpoint, credentials_secret, **common_features): class ResponseSection(Section): - """Section which contains response configuration""" + """Section which contains response configuration. todo envoyDynamicMetadata""" + + @property + def success_headers(self): + """Nested dict for most of the section.""" + return self.section.setdefault("success", {}).setdefault("headers", {}) + + @modify + def clear_success_headers(self): + """Clears content of a success headers""" + self.success_headers.clear() def _add( self, name: str, value: dict, - wrapper_key: str = None, - wrapper: Literal["httpHeader", "envoyDynamicMetadata"] = None, - **common_features + **common_features, ): """Add response to AuthConfig""" - if wrapper: - value["wrapper"] = wrapper - if wrapper_key: - value["wrapperKey"] = wrapper_key - - self.add_item(name, value, **common_features) + add_common_features(value, **common_features) + self.success_headers.update({name: value}) def add_simple(self, auth_json: str, name="simple", key="data", **common_features): """ Add simple response to AuthConfig, used for configuring response for debugging purposes, which can be easily read back using extract_response """ - self.add_json(name, [Property(key, ValueFrom(auth_json))], **common_features) + self.add_json(name, {key: ValueFrom(auth_json)}, **common_features) @modify - def add_json(self, name: str, properties: list[Property], **common_features): + def add_json(self, name: str, properties: dict[str, ABCValue], **common_features): """Adds json response to AuthConfig""" - asdict_properties = [asdict(p) for p in properties] + asdict_properties = {} + for key, value in properties.items(): + asdict_properties[key] = asdict(value) self._add(name, {"json": {"properties": asdict_properties}}, **common_features) @modify @@ -222,7 +245,6 @@ def add_wristband(self, name: str, issuer: str, secret_name: str, algorithm: str self._add( name, { - "name": name, "wristband": { "issuer": issuer, "signingKeyRefs": [ @@ -233,7 +255,34 @@ def add_wristband(self, name: str, issuer: str, secret_name: str, algorithm: str ], }, }, - **common_features + **common_features, + ) + + @modify + def set_deny_with( + self, + category: Literal["unauthenticated", "unauthorized"], + code: int = None, + message: ABCValue = None, + headers: dict[str, ABCValue] = None, + body: ABCValue = None, + ): + """Set default deny code, message, headers, and body for 'unauthenticated' and 'unauthorized' error.""" + asdict_message = asdict(message) if message else None + asdict_body = asdict(body) if body else None + asdict_headers = None + if headers: + asdict_headers = {} + for key, value in headers.items(): + asdict_headers[key] = asdict(value) + self.add_item( + category, + { + "code": code, + "message": asdict_message, + "headers": asdict_headers, + "body": asdict_body, + }, ) @@ -243,7 +292,7 @@ class AuthorizationSection(Section): @modify def add_auth_rules(self, name, rules: list[Rule], **common_features): """Adds JSON pattern-matching authorization rule (authorization.json)""" - self.add_item(name, {"json": {"rules": [asdict(rule) for rule in rules]}}, **common_features) + self.add_item(name, {"patternMatching": {"patterns": [asdict(rule) for rule in rules]}}, **common_features) def add_role_rule(self, name: str, role: str, path: str, **common_features): """ @@ -262,14 +311,14 @@ def add_role_rule(self, name: str, role: str, path: str, **common_features): @modify def add_opa_policy(self, name, inline_rego, **common_features): """Adds Opa (https://www.openpolicyagent.org/docs/latest/) policy to the AuthConfig""" - self.add_item(name, {"opa": {"inlineRego": inline_rego}}, **common_features) + self.add_item(name, {"opa": {"rego": inline_rego}}, **common_features) @modify def add_external_opa_policy(self, name, endpoint, ttl=0, **common_features): """ Adds OPA policy that is declared as an HTTP endpoint """ - self.add_item(name, {"opa": {"externalRegistry": {"endpoint": endpoint, "ttl": ttl}}}, **common_features) + self.add_item(name, {"opa": {"externalPolicy": {"url": endpoint, "ttl": ttl}}}, **common_features) @modify def add_kubernetes(self, name: str, user: ABCValue, resource_attributes: dict, **common_features): @@ -283,7 +332,7 @@ def add_kubernetes(self, name: str, user: ABCValue, resource_attributes: dict, * self.add_item( name, { - "kubernetes": {"user": asdict(user), "resourceAttributes": resource_attributes}, + "kubernetesSubjectAccessReview": {"user": asdict(user), "resourceAttributes": resource_attributes}, }, - **common_features + **common_features, ) From 1f9adad0cec13b869627ce07d17b1100b1f774fd Mon Sep 17 00:00:00 2001 From: Alex Zgabur Date: Mon, 23 Oct 2023 19:15:40 +0200 Subject: [PATCH 2/3] AuthPolicy upgrade to v2 tests --- .../test_response_condition.py | 4 +-- .../identity/api_key/test_auth_credentials.py | 2 +- .../test_extended_properties.py | 19 +++++++------- .../extended_properties/test_overwriting.py | 25 +++++++++++-------- .../test_token_normalization.py | 8 +++--- .../identity/rhsso/test_auth_credentials.py | 2 +- .../identity/rhsso/test_rhsso_context.py | 10 ++++---- .../authorino/metrics/test_deep_metrics.py | 4 +-- .../clusterwide/test_wildcard_collision.py | 6 ++--- .../authorino/operator/http/conftest.py | 6 ++--- .../authorino/operator/sharding/conftest.py | 4 +-- .../priority/test_sequence_api_key.py | 4 +-- .../authorino/response/test_auth_json.py | 4 +-- .../authorino/response/test_base64.py | 4 +-- .../{test_wrapper_key.py => test_headers.py} | 6 ++--- .../response/test_multiple_responses.py | 6 ++--- .../response/test_simple_response.py | 4 +-- .../tests/kuadrant/authorino/test_redirect.py | 8 +++++- .../authorino/wristband/test_wristband.py | 3 +++ 19 files changed, 71 insertions(+), 58 deletions(-) rename testsuite/tests/kuadrant/authorino/response/{test_wrapper_key.py => test_headers.py} (81%) diff --git a/testsuite/tests/kuadrant/authorino/conditions/section_conditions/test_response_condition.py b/testsuite/tests/kuadrant/authorino/conditions/section_conditions/test_response_condition.py index 910a2427..b0d45a33 100644 --- a/testsuite/tests/kuadrant/authorino/conditions/section_conditions/test_response_condition.py +++ b/testsuite/tests/kuadrant/authorino/conditions/section_conditions/test_response_condition.py @@ -1,7 +1,7 @@ """Test condition to skip the response section of AuthConfig""" import pytest -from testsuite.objects import Property, Rule, Value +from testsuite.objects import Rule, Value from testsuite.utils import extract_response @@ -9,7 +9,7 @@ def authorization(authorization): """Add to the AuthConfig response, which will only trigger on POST requests""" authorization.responses.add_json( - "simple", [Property("data", Value("response"))], when=[Rule("context.request.http.method", "eq", "POST")] + "simple", {"data": Value("response")}, when=[Rule("context.request.http.method", "eq", "POST")] ) return authorization diff --git a/testsuite/tests/kuadrant/authorino/identity/api_key/test_auth_credentials.py b/testsuite/tests/kuadrant/authorino/identity/api_key/test_auth_credentials.py index 258b73ab..f0a42151 100644 --- a/testsuite/tests/kuadrant/authorino/identity/api_key/test_auth_credentials.py +++ b/testsuite/tests/kuadrant/authorino/identity/api_key/test_auth_credentials.py @@ -4,7 +4,7 @@ from testsuite.objects import Credentials -@pytest.fixture(scope="module", params=["authorization_header", "custom_header", "query", "cookie"]) +@pytest.fixture(scope="module", params=["authorizationHeader", "customHeader", "queryString", "cookie"]) def credentials(request): """Location where are auth credentials passed""" return Credentials(request.param, "APIKEY") diff --git a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_extended_properties.py b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_extended_properties.py index 49f3c9f2..0cb1f021 100644 --- a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_extended_properties.py +++ b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_extended_properties.py @@ -1,7 +1,7 @@ """Basic tests for extended properties""" import pytest -from testsuite.objects import Value, ValueFrom, ExtendedProperty +from testsuite.objects import Value, ValueFrom from testsuite.utils import extract_response @@ -16,14 +16,15 @@ def authorization(authorization, rhsso): authorization.identity.add_oidc( "rhsso", rhsso.well_known["issuer"], - extended_properties=[ - ExtendedProperty("property_static", Value("static")), - # ValueFrom points to the request uri - ExtendedProperty("property_dynamic", ValueFrom("context.request.http.path")), - ExtendedProperty("property_chain_static", ValueFrom("auth.identity.property_static")), - ExtendedProperty("property_chain_dynamic", ValueFrom("auth.identity.property_dynamic")), - ExtendedProperty("property_chain_self", ValueFrom("auth.identity.property_chain_self"), overwrite=True), - ], + defaults_properties={ + "property_static": Value("static"), + "property_dynamic": ValueFrom("context.request.http.path"), + "property_chain_static": ValueFrom("auth.identity.property_static"), + "property_chain_dynamic": ValueFrom("auth.identity.property_dynamic"), + }, + overrides_properties={ + "property_chain_self": ValueFrom("auth.identity.property_chain_self"), + }, ) authorization.responses.add_simple("auth.identity") return authorization diff --git a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_overwriting.py b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_overwriting.py index e0036ea2..c4c52b8c 100644 --- a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_overwriting.py +++ b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_overwriting.py @@ -1,25 +1,27 @@ """https://github.com/Kuadrant/authorino/pull/399""" import pytest -from testsuite.objects import ExtendedProperty, Value +from testsuite.objects import Value from testsuite.utils import extract_response @pytest.fixture(scope="module") def authorization(authorization): """ - Add plain authentication with three extended properties: - explicit False, explicit True and missing which should be default False. + Add plain authentication with defaults and overrides properties. Add simple response to expose `auth.identity` part of AuthJson """ authorization.identity.add_plain( "plain", "context.request.http.headers.x-user|@fromstr", - extended_properties=[ - ExtendedProperty("name", Value("bar"), overwrite=False), - ExtendedProperty("age", Value(35), overwrite=True), - ExtendedProperty("group", Value("admin")), - ], + defaults_properties={ + "name": Value("bar"), + "group": Value("admin"), + }, + overrides_properties={ + "age": Value(35), + "expire": Value("1-12-1999"), + }, ) authorization.responses.add_simple("auth.identity") @@ -28,9 +30,10 @@ def authorization(authorization): def test_overwrite(client): """ - Test the ExtendedProperty overwrite functionality overwriting the value in headers when True. + Test overriding and defaults capability. Defaults must not override the value in header but Overrides must do so. """ - response = client.get("/get", headers={"x-user": '{"name":"foo","age":30,"group":"guest"}'}) + response = client.get("/get", headers={"x-user": '{"name":"foo","age":30}'}) assert extract_response(response)["name"] % "MISSING" == "foo" assert extract_response(response)["age"] % "MISSING" == 35 - assert extract_response(response)["group"] % "MISSING" == "guest" + assert extract_response(response)["group"] % "MISSING" == "admin" + assert extract_response(response)["expire"] % "MISSING" == "1-12-1999" diff --git a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_token_normalization.py b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_token_normalization.py index 18bfc833..071e71f3 100644 --- a/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_token_normalization.py +++ b/testsuite/tests/kuadrant/authorino/identity/extended_properties/test_token_normalization.py @@ -1,6 +1,6 @@ """https://github.com/Kuadrant/authorino/blob/main/docs/user-guides/token-normalization.md""" import pytest -from testsuite.objects import Value, ValueFrom, ExtendedProperty, Rule +from testsuite.objects import Value, ValueFrom, Rule from testsuite.httpx.auth import HeaderApiKeyAuth, HttpxOidcClientAuth @@ -37,10 +37,12 @@ def authorization(authorization, rhsso, api_key): authorization.identity.add_oidc( "rhsso", rhsso.well_known["issuer"], - extended_properties=[ExtendedProperty("roles", ValueFrom("auth.identity.realm_access.roles"))], + overrides_properties={"roles": ValueFrom("auth.identity.realm_access.roles")}, ) authorization.identity.add_api_key( - "api_key", selector=api_key.selector, extended_properties=[ExtendedProperty("roles", Value(["admin"]))] + "api_key", + selector=api_key.selector, + defaults_properties={"roles": Value(["admin"])}, ) rule = Rule(selector="auth.identity.roles", operator="incl", value="admin") diff --git a/testsuite/tests/kuadrant/authorino/identity/rhsso/test_auth_credentials.py b/testsuite/tests/kuadrant/authorino/identity/rhsso/test_auth_credentials.py index 75232375..30ac7823 100644 --- a/testsuite/tests/kuadrant/authorino/identity/rhsso/test_auth_credentials.py +++ b/testsuite/tests/kuadrant/authorino/identity/rhsso/test_auth_credentials.py @@ -5,7 +5,7 @@ from testsuite.objects import Credentials -@pytest.fixture(scope="module", params=["authorization_header", "custom_header", "query", "cookie"]) +@pytest.fixture(scope="module", params=["authorizationHeader", "customHeader", "queryString", "cookie"]) def credentials(request): """Location where are auth credentials passed""" return request.param diff --git a/testsuite/tests/kuadrant/authorino/identity/rhsso/test_rhsso_context.py b/testsuite/tests/kuadrant/authorino/identity/rhsso/test_rhsso_context.py index a2222234..f4c095b9 100644 --- a/testsuite/tests/kuadrant/authorino/identity/rhsso/test_rhsso_context.py +++ b/testsuite/tests/kuadrant/authorino/identity/rhsso/test_rhsso_context.py @@ -4,7 +4,7 @@ import pytest -from testsuite.objects import Property, ValueFrom +from testsuite.objects import ValueFrom @pytest.fixture(scope="module") @@ -12,10 +12,10 @@ def authorization(authorization): """Setup AuthConfig for test""" authorization.responses.add_json( "auth-json", - [ - Property("auth", ValueFrom("auth.identity")), - Property("context", ValueFrom("context.request.http.headers.authorization")), - ], + { + "auth": ValueFrom("auth.identity"), + "context": ValueFrom("context.request.http.headers.authorization"), + }, ) return authorization diff --git a/testsuite/tests/kuadrant/authorino/metrics/test_deep_metrics.py b/testsuite/tests/kuadrant/authorino/metrics/test_deep_metrics.py index 1ba4576a..d98e2a5d 100644 --- a/testsuite/tests/kuadrant/authorino/metrics/test_deep_metrics.py +++ b/testsuite/tests/kuadrant/authorino/metrics/test_deep_metrics.py @@ -1,7 +1,7 @@ """Tests for the functionality of the deep-evaluator metric samples""" import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value @pytest.fixture(scope="module") @@ -25,7 +25,7 @@ def authorization(authorization, mockserver_expectation): authorization.identity.add_anonymous("anonymous", metrics=True) authorization.authorization.add_opa_policy("opa", "allow { true }", metrics=True) authorization.metadata.add_http("http", mockserver_expectation, "GET", metrics=True) - authorization.responses.add_json("json", [Property("auth", Value("response"))], metrics=True) + authorization.responses.add_json("json", {"auth": Value("response")}, metrics=True) return authorization diff --git a/testsuite/tests/kuadrant/authorino/operator/clusterwide/test_wildcard_collision.py b/testsuite/tests/kuadrant/authorino/operator/clusterwide/test_wildcard_collision.py index d807eebc..0be7cc85 100644 --- a/testsuite/tests/kuadrant/authorino/operator/clusterwide/test_wildcard_collision.py +++ b/testsuite/tests/kuadrant/authorino/operator/clusterwide/test_wildcard_collision.py @@ -4,7 +4,7 @@ import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value from testsuite.openshift.objects.auth_config import AuthConfig @@ -15,7 +15,7 @@ def authorization(authorino, blame, openshift, module_label, proxy, wildcard_dom auth = AuthConfig.create_instance( openshift, blame("ac"), None, hostnames=[wildcard_domain], labels={"testRun": module_label} ) - auth.responses.add_json("header", [Property("anything", Value("one"))]) + auth.responses.add_json("header", {"anything": Value("one")}) return auth @@ -26,7 +26,7 @@ def authorization2(authorino, blame, openshift2, module_label, proxy, wildcard_d auth = AuthConfig.create_instance( openshift2, blame("ac"), None, hostnames=[wildcard_domain], labels={"testRun": module_label} ) - auth.responses.add_json("header", [Property("anything", Value("two"))]) + auth.responses.add_json("header", {"anything": Value("two")}) return auth diff --git a/testsuite/tests/kuadrant/authorino/operator/http/conftest.py b/testsuite/tests/kuadrant/authorino/operator/http/conftest.py index 21d06a88..fc3ccc86 100644 --- a/testsuite/tests/kuadrant/authorino/operator/http/conftest.py +++ b/testsuite/tests/kuadrant/authorino/operator/http/conftest.py @@ -1,7 +1,7 @@ """Conftest for all tests requiring custom deployment of Authorino""" import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value from testsuite.httpx import HttpxBackoffClient from testsuite.openshift.objects.auth_config import AuthConfig from testsuite.openshift.objects.route import OpenshiftRoute @@ -13,9 +13,7 @@ def authorization(authorization, wildcard_domain, openshift, module_label) -> Au """In case of Authorino, AuthConfig used for authorization""" authorization.remove_all_hosts() authorization.add_host(wildcard_domain) - authorization.responses.add_json( - "another-json-returned-in-a-header", [Property("propX", Value("valueX"))], wrapper_key="x-ext-auth-other-json" - ) + authorization.responses.add_json("x-ext-auth-other-json", {"propX": Value("valueX")}) return authorization diff --git a/testsuite/tests/kuadrant/authorino/operator/sharding/conftest.py b/testsuite/tests/kuadrant/authorino/operator/sharding/conftest.py index 45afe4ce..faf50909 100644 --- a/testsuite/tests/kuadrant/authorino/operator/sharding/conftest.py +++ b/testsuite/tests/kuadrant/authorino/operator/sharding/conftest.py @@ -1,7 +1,7 @@ """Conftest for authorino sharding tests""" import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value from testsuite.openshift.envoy import Envoy from testsuite.openshift.objects.auth_config import AuthConfig @@ -34,7 +34,7 @@ def _authorization(hostname=None, sharding_label=None): hostnames=[hostname], labels={"testRun": module_label, "sharding": sharding_label}, ) - auth.responses.add_json("header", [Property("anything", Value(sharding_label))]) + auth.responses.add_json("header", {"anything": Value(sharding_label)}) request.addfinalizer(auth.delete) auth.commit() return auth diff --git a/testsuite/tests/kuadrant/authorino/priority/test_sequence_api_key.py b/testsuite/tests/kuadrant/authorino/priority/test_sequence_api_key.py index bc7c450a..cae9e5d3 100644 --- a/testsuite/tests/kuadrant/authorino/priority/test_sequence_api_key.py +++ b/testsuite/tests/kuadrant/authorino/priority/test_sequence_api_key.py @@ -35,11 +35,11 @@ def authorization(authorization, first_api_key, second_api_key): authorization.identity.add_api_key( "priority-zero", selector=first_api_key.selector, - credentials=Credentials("authorization_header", "APIKEY"), + credentials=Credentials("authorizationHeader", "APIKEY"), priority=0, ) authorization.identity.add_api_key( - "priority-one", selector=second_api_key.selector, credentials=Credentials("query", "APIKEY"), priority=1 + "priority-one", selector=second_api_key.selector, credentials=Credentials("queryString", "APIKEY"), priority=1 ) return authorization diff --git a/testsuite/tests/kuadrant/authorino/response/test_auth_json.py b/testsuite/tests/kuadrant/authorino/response/test_auth_json.py index 1327bcd9..33db78ab 100644 --- a/testsuite/tests/kuadrant/authorino/response/test_auth_json.py +++ b/testsuite/tests/kuadrant/authorino/response/test_auth_json.py @@ -4,7 +4,7 @@ import pytest -from testsuite.objects import Property, ValueFrom +from testsuite.objects import ValueFrom @pytest.fixture(scope="module") @@ -31,7 +31,7 @@ def authorization(authorization, path_and_value): path, _ = path_and_value authorization.responses.clear_all() # delete previous responses due to the parametrization - authorization.responses.add_json("header", [Property("anything", ValueFrom(path))]) + authorization.responses.add_json("header", {"anything": ValueFrom(path)}) return authorization diff --git a/testsuite/tests/kuadrant/authorino/response/test_base64.py b/testsuite/tests/kuadrant/authorino/response/test_base64.py index 196895f3..10558589 100644 --- a/testsuite/tests/kuadrant/authorino/response/test_base64.py +++ b/testsuite/tests/kuadrant/authorino/response/test_base64.py @@ -6,14 +6,14 @@ import pytest -from testsuite.objects import Property, ValueFrom +from testsuite.objects import ValueFrom @pytest.fixture(scope="module") def authorization(authorization): """Add response to Authorization""" authorization.responses.add_json( - "header", [Property("anything", ValueFrom("context.request.http.headers.test|@base64:decode"))] + "header", {"anything": ValueFrom("context.request.http.headers.test|@base64:decode")} ) return authorization diff --git a/testsuite/tests/kuadrant/authorino/response/test_wrapper_key.py b/testsuite/tests/kuadrant/authorino/response/test_headers.py similarity index 81% rename from testsuite/tests/kuadrant/authorino/response/test_wrapper_key.py rename to testsuite/tests/kuadrant/authorino/response/test_headers.py index d6909e3e..2d07859d 100644 --- a/testsuite/tests/kuadrant/authorino/response/test_wrapper_key.py +++ b/testsuite/tests/kuadrant/authorino/response/test_headers.py @@ -3,7 +3,7 @@ import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value @pytest.fixture(scope="module", params=["123456789", "standardCharacters", "specialcharacters+*-."]) @@ -16,11 +16,11 @@ def header_name(request): def authorization(authorization, header_name): """Add response to Authorization""" authorization.responses.clear_all() # delete previous responses due to the parametrization - authorization.responses.add_json("header", [Property("anything", Value("one"))], wrapper_key=header_name) + authorization.responses.add_json(header_name, {"anything": Value("one")}) return authorization -def test_wrapper_key_with(auth, client, header_name): +def test_headers(auth, client, header_name): """Tests that value in correct Header""" response = client.get("/get", auth=auth) assert response.status_code == 200 diff --git a/testsuite/tests/kuadrant/authorino/response/test_multiple_responses.py b/testsuite/tests/kuadrant/authorino/response/test_multiple_responses.py index 373337c2..b9256447 100644 --- a/testsuite/tests/kuadrant/authorino/response/test_multiple_responses.py +++ b/testsuite/tests/kuadrant/authorino/response/test_multiple_responses.py @@ -3,14 +3,14 @@ import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value @pytest.fixture(scope="module") def authorization(authorization): """Add response to Authorization""" - authorization.responses.add_json("header", [Property("anything", Value("one"))]) - authorization.responses.add_json("X-Test", [Property("anything", Value("two"))]) + authorization.responses.add_json("header", {"anything": Value("one")}) + authorization.responses.add_json("X-Test", {"anything": Value("two")}) return authorization diff --git a/testsuite/tests/kuadrant/authorino/response/test_simple_response.py b/testsuite/tests/kuadrant/authorino/response/test_simple_response.py index 53db0942..fe83e476 100644 --- a/testsuite/tests/kuadrant/authorino/response/test_simple_response.py +++ b/testsuite/tests/kuadrant/authorino/response/test_simple_response.py @@ -3,13 +3,13 @@ import pytest -from testsuite.objects import Property, Value +from testsuite.objects import Value @pytest.fixture(scope="module") def authorization(authorization): """Add response to Authorization""" - authorization.responses.add_json("header", [Property("anything", Value("one"))]) + authorization.responses.add_json("header", {"anything": Value("one")}) return authorization diff --git a/testsuite/tests/kuadrant/authorino/test_redirect.py b/testsuite/tests/kuadrant/authorino/test_redirect.py index 56539c82..68280fcc 100644 --- a/testsuite/tests/kuadrant/authorino/test_redirect.py +++ b/testsuite/tests/kuadrant/authorino/test_redirect.py @@ -3,6 +3,8 @@ """ import pytest +from testsuite.objects import ValueFrom + STATUS_CODE = 302 REDIRECT_URL = "http://anything.inavlid?redirect_to=" @@ -10,7 +12,11 @@ @pytest.fixture(scope="module") def authorization(authorization): """In case of Authorino, AuthConfig used for authorization""" - authorization.set_deny_with(STATUS_CODE, REDIRECT_URL + "{context.request.http.path}") + authorization.responses.set_deny_with( + "unauthenticated", + code=STATUS_CODE, + headers={"Location": ValueFrom(REDIRECT_URL + "{context.request.http.path}")}, + ) return authorization diff --git a/testsuite/tests/kuadrant/authorino/wristband/test_wristband.py b/testsuite/tests/kuadrant/authorino/wristband/test_wristband.py index 4877592f..581682b6 100644 --- a/testsuite/tests/kuadrant/authorino/wristband/test_wristband.py +++ b/testsuite/tests/kuadrant/authorino/wristband/test_wristband.py @@ -1,6 +1,9 @@ """Test api authentication with wristband-token that was acquired after authentication on the edge layer""" +import pytest from jose import jwt +pytest.skip("Envoy dynamic metadata not yet implemented due to v1beta2 AuthConfig change", allow_module_level=True) + def test_wristband_token_claims(oidc_provider, auth, wristband_token, wristband_endpoint, certificates): """Verify acquired jwt token claims""" From 95ac31188ca273c665b8b7b8da7dba5bdbde7f0c Mon Sep 17 00:00:00 2001 From: Alex Zgabur Date: Mon, 30 Oct 2023 13:48:50 +0100 Subject: [PATCH 3/3] Reformat skipping of AuthPolicy using 'when' --- testsuite/openshift/objects/auth_config/__init__.py | 4 ++-- testsuite/openshift/objects/auth_config/auth_policy.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/testsuite/openshift/objects/auth_config/__init__.py b/testsuite/openshift/objects/auth_config/__init__.py index 485755ba..5e1e5499 100644 --- a/testsuite/openshift/objects/auth_config/__init__.py +++ b/testsuite/openshift/objects/auth_config/__init__.py @@ -2,7 +2,7 @@ from functools import cached_property from typing import Dict, List, Optional -from testsuite.objects import Rule +from testsuite.objects import Rule, asdict from testsuite.openshift.client import OpenShiftClient from testsuite.openshift.objects import OpenShiftObject, modify from .sections import IdentitySection, MetadataSection, ResponseSection, AuthorizationSection @@ -75,4 +75,4 @@ def remove_all_hosts(self): def add_rule(self, when: list[Rule]): """Add rule for the skip of entire AuthConfig""" self.auth_section.setdefault("when", []) - self.auth_section["when"].extend([vars(x) for x in when]) + self.auth_section["when"].extend([asdict(x) for x in when]) diff --git a/testsuite/openshift/objects/auth_config/auth_policy.py b/testsuite/openshift/objects/auth_config/auth_policy.py index bc991fc2..6ba87e15 100644 --- a/testsuite/openshift/objects/auth_config/auth_policy.py +++ b/testsuite/openshift/objects/auth_config/auth_policy.py @@ -1,7 +1,10 @@ """Module containing classes related to Auth Policy""" from typing import Dict, List +from testsuite.objects import Rule, asdict + from testsuite.openshift.client import OpenShiftClient +from testsuite.openshift.objects import modify from testsuite.openshift.objects.auth_config import AuthConfig from testsuite.openshift.objects.gateway_api.route import HTTPRoute @@ -55,3 +58,9 @@ def remove_host(self, hostname): def remove_all_hosts(self): return self.route.remove_all_hostnames() + + @modify + def add_rule(self, when: list[Rule]): + """Add rule for the skip of entire AuthPolicy""" + self.model.spec.setdefault("when", []) + self.model.spec["when"].extend([asdict(x) for x in when])