diff --git a/tests/providers/okta/services/signon/signon_fixtures.py b/tests/providers/okta/services/signon/signon_fixtures.py new file mode 100644 index 0000000000..99859fad81 --- /dev/null +++ b/tests/providers/okta/services/signon/signon_fixtures.py @@ -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 = ( + "
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.
" +) diff --git a/tests/providers/okta/services/signon/signon_global_session_idle_timeout_15min/signon_global_session_idle_timeout_15min_test.py b/tests/providers/okta/services/signon/signon_global_session_idle_timeout_15min/signon_global_session_idle_timeout_15min_test.py index 912fd2014e..690eaaf771 100644 --- a/tests/providers/okta/services/signon/signon_global_session_idle_timeout_15min/signon_global_session_idle_timeout_15min_test.py +++ b/tests/providers/okta/services/signon/signon_global_session_idle_timeout_15min/signon_global_session_idle_timeout_15min_test.py @@ -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}, )