refactor(sdk): extract shared signon test fixtures

- Move policy/rule helpers into signon_fixtures.py for reuse across checks
- Add SignInPage helper and DOD banner HTML snippet for upcoming banner check
- Switch idle-timeout test to import from the shared module
This commit is contained in:
Daniel Barranquero
2026-05-19 12:57:47 +02:00
parent cb01769237
commit c73231ec95
2 changed files with 166 additions and 89 deletions
@@ -0,0 +1,124 @@
"""Shared helpers for `signon` service check tests.
The original idle-timeout check test file defined these helpers locally;
they were extracted here so the four checks added on top of the same
service (`signon_global_session_lifetime_18h`,
`signon_global_session_cookies_not_persistent`,
`signon_global_session_policy_network_zone_enforced`,
`signon_dod_warning_banner_configured`) can reuse them without copy-paste.
"""
from unittest import mock
from prowler.providers.okta.services.signon.signon_service import (
GlobalSessionPolicy,
GlobalSessionPolicyRule,
SignInPage,
)
from tests.providers.okta.okta_fixtures import set_mocked_okta_provider
def build_signon_client(
policies: dict = None,
audit_config: dict = None,
sign_in_pages: dict = None,
):
client = mock.MagicMock()
client.global_session_policies = policies or {}
client.provider = set_mocked_okta_provider()
client.audit_config = audit_config or {}
client.sign_in_pages = sign_in_pages or {}
return client
def default_policy(rules):
return GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
status="ACTIVE",
is_default=True,
rules=rules,
)
def custom_policy(rules, name: str = "Admins Policy"):
return GlobalSessionPolicy(
id="pol-custom",
name=name,
priority=1,
status="ACTIVE",
is_default=False,
rules=rules,
)
def default_rule(
idle_min: int = 480,
lifetime_min: int = None,
use_persistent_cookie: bool = None,
priority: int = 2,
status: str = "ACTIVE",
):
return GlobalSessionPolicyRule(
id="rule-default",
name="Default Rule",
priority=priority,
status=status,
is_default=True,
max_session_idle_minutes=idle_min,
max_session_lifetime_minutes=lifetime_min,
use_persistent_cookie=use_persistent_cookie,
)
def non_default_rule(
name: str,
*,
idle_min: int = None,
lifetime_min: int = None,
use_persistent_cookie: bool = None,
network_zones_include: list = None,
network_zones_exclude: list = None,
priority: int = 1,
status: str = "ACTIVE",
):
return GlobalSessionPolicyRule(
id=f"rule-{name.lower().replace(' ', '-')}",
name=name,
priority=priority,
status=status,
is_default=False,
max_session_idle_minutes=idle_min,
max_session_lifetime_minutes=lifetime_min,
use_persistent_cookie=use_persistent_cookie,
network_zones_include=network_zones_include or [],
network_zones_exclude=network_zones_exclude or [],
)
def sign_in_page(
brand_id: str = "brand-1",
brand_name: str = "Default Brand",
is_customized: bool = True,
page_content: str = None,
fetch_error: str = None,
):
return SignInPage(
brand_id=brand_id,
brand_name=brand_name,
is_customized=is_customized,
page_content=page_content,
fetch_error=fetch_error,
)
# Two distinctive marker phrases from the DTM-08-060 banner — enough to
# meet the check's MIN_MARKER_MATCHES=2 threshold without reproducing the
# full ~1300-char banner verbatim in tests.
DOD_BANNER_HTML_SNIPPET = (
"<div>You are accessing a U.S. Government (USG) Information System "
"(IS) that is provided for USG-authorized use only. "
"Communications using, or data stored on, this IS may be intercepted, "
"searched, monitored, and recorded.</div>"
)
@@ -5,6 +5,13 @@ from prowler.providers.okta.services.signon.signon_service import (
GlobalSessionPolicyRule,
)
from tests.providers.okta.okta_fixtures import set_mocked_okta_provider
from tests.providers.okta.services.signon.signon_fixtures import (
build_signon_client,
custom_policy,
default_policy,
default_rule,
non_default_rule,
)
CHECK_PATH = (
"prowler.providers.okta.services.signon."
@@ -13,61 +20,9 @@ CHECK_PATH = (
)
def _build_signon_client(policies, audit_config: dict = None):
client = mock.MagicMock()
client.global_session_policies = policies
client.provider = set_mocked_okta_provider()
client.audit_config = audit_config or {}
return client
def _default_policy(rules):
return GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
status="ACTIVE",
is_default=True,
rules=rules,
)
def _custom_policy(rules):
return GlobalSessionPolicy(
id="pol-custom",
name="Admins Policy",
priority=1,
status="ACTIVE",
is_default=False,
rules=rules,
)
def _default_rule(idle_min=480, priority=2, status="ACTIVE"):
return GlobalSessionPolicyRule(
id="rule-default",
name="Default Rule",
priority=priority,
status=status,
is_default=True,
max_session_idle_minutes=idle_min,
)
def _non_default_rule(name, idle_min, priority=1, status="ACTIVE"):
return GlobalSessionPolicyRule(
id=f"rule-{name.lower().replace(' ', '-')}",
name=name,
priority=priority,
status=status,
is_default=False,
max_session_idle_minutes=idle_min,
)
class Test_signon_global_session_idle_timeout_15min:
def test_no_policies(self):
signon_client = _build_signon_client({})
signon_client = build_signon_client({})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -85,13 +40,13 @@ class Test_signon_global_session_idle_timeout_15min:
assert "was not found" in findings[0].status_extended
def test_pass_when_priority_one_non_default_rule_is_compliant(self):
policy = _default_policy(
policy = default_policy(
[
_non_default_rule("Strict 15min", 15, priority=1),
_default_rule(priority=2),
non_default_rule("Strict 15min", idle_min=15, priority=1),
default_rule(priority=2),
]
)
signon_client = _build_signon_client({"pol-default": policy})
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -110,8 +65,8 @@ class Test_signon_global_session_idle_timeout_15min:
assert "Priority 1 non-default rule" in findings[0].status_extended
def test_fail_when_only_default_rule(self):
policy = _default_policy([_default_rule(priority=1)])
signon_client = _build_signon_client({"pol-default": policy})
policy = default_policy([default_rule(priority=1)])
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -131,10 +86,7 @@ class Test_signon_global_session_idle_timeout_15min:
)
def test_fail_when_priority_one_non_default_rule_has_null_idle(self):
# Rules without a session block leave max_session_idle_minutes as
# None. The check must treat those as non-compliant — they cannot
# enforce any timeout.
policy = _default_policy(
policy = default_policy(
[
GlobalSessionPolicyRule(
id="rule-no-session",
@@ -144,10 +96,10 @@ class Test_signon_global_session_idle_timeout_15min:
is_default=False,
max_session_idle_minutes=None,
),
_default_rule(priority=2),
default_rule(priority=2),
]
)
signon_client = _build_signon_client({"pol-default": policy})
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -166,13 +118,13 @@ class Test_signon_global_session_idle_timeout_15min:
assert "does not define" in findings[0].status_extended
def test_fail_when_priority_one_non_default_rule_exceeds_threshold(self):
policy = _default_policy(
policy = default_policy(
[
_non_default_rule("Loose 60min", 60, priority=1),
_default_rule(priority=2),
non_default_rule("Loose 60min", idle_min=60, priority=1),
default_rule(priority=2),
]
)
signon_client = _build_signon_client({"pol-default": policy})
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -191,13 +143,13 @@ class Test_signon_global_session_idle_timeout_15min:
assert "exceeding the configured threshold" in findings[0].status_extended
def test_fail_when_compliant_non_default_rule_is_not_priority_one(self):
policy = _default_policy(
policy = default_policy(
[
_default_rule(priority=1),
_non_default_rule("Strict 15min", 15, priority=2),
default_rule(priority=1),
non_default_rule("Strict 15min", idle_min=15, priority=2),
]
)
signon_client = _build_signon_client({"pol-default": policy})
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -217,20 +169,23 @@ class Test_signon_global_session_idle_timeout_15min:
)
def test_ignores_other_custom_policies(self):
default_policy = _default_policy(
default_policy_with_strict_rule = default_policy(
[
_non_default_rule("Strict 15min", 15, priority=1),
_default_rule(priority=2),
non_default_rule("Strict 15min", idle_min=15, priority=1),
default_rule(priority=2),
]
)
custom_policy = _custom_policy(
custom_loose_policy = custom_policy(
[
_non_default_rule("Loose Admin Rule", 60, priority=1),
_default_rule(priority=2),
non_default_rule("Loose Admin Rule", idle_min=60, priority=1),
default_rule(priority=2),
]
)
signon_client = _build_signon_client(
{"pol-custom": custom_policy, "pol-default": default_policy}
signon_client = build_signon_client(
{
"pol-custom": custom_loose_policy,
"pol-default": default_policy_with_strict_rule,
}
)
with (
mock.patch(
@@ -255,9 +210,9 @@ class Test_signon_global_session_idle_timeout_15min:
priority=99,
status="INACTIVE",
is_default=True,
rules=[_non_default_rule("Strict 15min", 15, priority=1)],
rules=[non_default_rule("Strict 15min", idle_min=15, priority=1)],
)
signon_client = _build_signon_client({"pol-default": policy})
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -275,15 +230,13 @@ class Test_signon_global_session_idle_timeout_15min:
assert "status 'INACTIVE'" in findings[0].status_extended
def test_threshold_overridden_via_audit_config(self):
# 30-minute rule fails the STIG default of 15, but passes a relaxed
# threshold of 60 minutes set in audit_config.
policy = _default_policy(
policy = default_policy(
[
_non_default_rule("Relaxed 30min", 30, priority=1),
_default_rule(priority=2),
non_default_rule("Relaxed 30min", idle_min=30, priority=1),
default_rule(priority=2),
]
)
signon_client = _build_signon_client(
signon_client = build_signon_client(
{"pol-default": policy},
audit_config={"okta_max_session_idle_minutes": 60},
)