mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 21:11:53 +00:00
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:
@@ -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>"
|
||||
)
|
||||
+42
-89
@@ -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},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user