feat(okta): scan every policy

This commit is contained in:
Daniel Barranquero committed 2026-05-19 13:54:05 +02:00
1 parent 1ce6458c6e
commit 7856e7d6cd
12 files changed
+925 -1003

No files matched your search

@@ -9,7 +9,7 @@
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "governance",
"Description": "The **Default Global Session Policy** must have a **Priority 1** rule that is **not** the built-in `Default Rule`, and that rule must set **Okta global session cookies persist across browser sessions** to `Disabled` (DISA STIG V-273206 / OKTA-APP-001710).",
"Description": "Every active Global Session Policy must have a **Priority 1** rule that is **not** the built-in `Default Rule`, setting **Okta global session cookies persist across browser sessions** to `Disabled` (DISA STIG V-273206 / OKTA-APP-001710). Okta evaluates policies by group assignment, so a permissive custom policy can govern users even when the Default Policy is strict.",
"Risk": "Persistent global session cookies keep an authenticated Okta session alive across browser restarts. Cached authentication that survives the original browsing context can grant continued access long after a user closes the browser, and any cached authorization decisions outlive the session window the user expected.",
"RelatedUrl": "",
"AdditionalURLs": [
@@ -6,114 +6,135 @@ from prowler.providers.okta.services.signon.signon_service import GlobalSessionP
class signon_global_session_cookies_not_persistent(Check):
"""STIG V-273206 / OKTA-APP-001710.
The DISA STIG requires the Okta Default Policy to have an active
Priority 1 rule that is not the built-in Default Rule, and that
rule must disable persistent global session cookies so the session
does not survive across browser restarts.
Every active Global Session Policy must have an active Priority 1
rule that is not the built-in Default Rule, and that rule must
disable persistent global session cookies so the session does not
survive across browser restarts.
Okta evaluates sign-on policies in priority order based on group
assignments, so a permissive custom policy can govern a user's
session even when the Default Policy is strict. The check emits one
finding per active policy to surface that risk.
"""
def execute(self) -> list[CheckReportOkta]:
org_domain = signon_client.provider.identity.org_domain
policy = self._get_default_policy()
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
active_policies = _active_policies()
if not active_policies:
return [_no_policies_finding(self.metadata(), org_domain)]
findings: list[CheckReportOkta] = []
for policy in active_policies:
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
)
status, status_extended = _evaluate_policy(policy)
report.status = status
report.status_extended = status_extended
findings.append(report)
return findings
def _evaluate_policy(policy: GlobalSessionPolicy) -> tuple[str, str]:
label = _policy_label(policy)
priority_one_rule = _priority_one_active_rule(policy)
if priority_one_rule is None:
return (
"FAIL",
f"{label} has no Priority 1 active rule. STIG V-273206 requires "
"a non-default Priority 1 rule that disables persistent global "
"session cookies.",
)
if policy.id == "default-policy-missing":
report.status = "FAIL"
report.status_extended = (
"Default Global Session Policy was not found. STIG V-273206 "
"requires the Default Policy to contain an active Priority 1 "
"non-default rule that disables persistent global session cookies."
)
return [report]
if policy.status and policy.status.upper() != "ACTIVE":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' is in "
f"status '{policy.status}'. STIG V-273206 requires an active "
"Default Policy with an active Priority 1 non-default rule."
)
return [report]
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
return (
"FAIL",
f"{label} uses '{priority_one_rule.name}' as its active Priority 1 "
"rule. The STIG requires a non-default Priority 1 rule.",
)
if not active_rules:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
"rules. STIG V-273206 requires an active Priority 1 non-default "
"rule that disables persistent global session cookies."
)
return [report]
priority_one_rule = active_rules[0]
if priority_one_rule.priority != 1:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
f"Priority 1 rule. The first active rule is '{priority_one_rule.name}' "
f"at priority {priority_one_rule.priority}."
)
return [report]
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' uses "
f"'{priority_one_rule.name}' as its active Priority 1 rule. "
"The STIG requires a non-default Priority 1 rule."
)
return [report]
use_persistent_cookie = priority_one_rule.use_persistent_cookie
if use_persistent_cookie is None:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' does not "
"assert the 'Okta global session cookies persist across browser "
"sessions' setting."
)
return [report]
if use_persistent_cookie is False:
report.status = "PASS"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' disables "
"persistent global session cookies."
)
else:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' allows "
"persistent global session cookies, leaving the session "
"active across browser restarts."
)
return [report]
@staticmethod
def _get_default_policy() -> GlobalSessionPolicy:
for policy in signon_client.global_session_policies.values():
if policy.is_default or policy.name == "Default Policy":
return policy
return GlobalSessionPolicy(
id="default-policy-missing",
name="Default Policy",
priority=1,
status="MISSING",
is_default=True,
rules=[],
use_persistent_cookie = priority_one_rule.use_persistent_cookie
if use_persistent_cookie is None:
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"does not assert the 'Okta global session cookies persist across "
"browser sessions' setting.",
)
if use_persistent_cookie is False:
return (
"PASS",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"disables persistent global session cookies.",
)
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"allows persistent global session cookies, leaving the session active "
"across browser restarts.",
)
def _active_policies() -> list[GlobalSessionPolicy]:
return sorted(
[
policy
for policy in signon_client.global_session_policies.values()
if not policy.status or policy.status.upper() == "ACTIVE"
],
key=lambda policy: (
policy.priority if policy.priority is not None else float("inf"),
policy.name,
),
)
def _priority_one_active_rule(policy: GlobalSessionPolicy):
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
)
if not active_rules:
return None
candidate = active_rules[0]
if candidate.priority != 1:
return None
return candidate
def _policy_label(policy: GlobalSessionPolicy) -> str:
kind = "default" if policy.is_default else "custom"
priority = policy.priority if policy.priority is not None else "unset"
return f"Global Session Policy '{policy.name}' (priority {priority}, {kind})"
def _no_policies_finding(metadata, org_domain) -> CheckReportOkta:
placeholder = GlobalSessionPolicy(
id="signon-policies-missing",
name="(no active sign-on policies)",
priority=1,
status="MISSING",
is_default=False,
rules=[],
)
report = CheckReportOkta(
metadata=metadata, resource=placeholder, org_domain=org_domain
)
report.status = "FAIL"
report.status_extended = (
"No active Okta Global Session Policies were returned by the API. "
"STIG V-273206 requires the policy that governs each user to enforce "
"a Priority 1 non-default rule that disables persistent global "
"session cookies."
)
return report
@@ -9,7 +9,7 @@
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "governance",
"Description": "The **Default Global Session Policy** must have a **Priority 1** rule that is **not** the built-in `Default Rule`, and that rule must set **Maximum Okta global session idle time** to 15 minutes or less. The threshold defaults to 15 minutes and is overridable via the `okta_max_session_idle_minutes` key in the audit config.",
"Description": "Every active Global Session Policy must have a **Priority 1** rule that is **not** the built-in `Default Rule`, setting **Maximum Okta global session idle time** to 15 minutes or less. Okta evaluates policies by group assignment, so a permissive custom policy can govern users even when the Default Policy is strict. Override the threshold via `okta_max_session_idle_minutes`.",
"Risk": "Without a 15-minute idle timeout, an unattended workstation leaves an authenticated Okta session open indefinitely, allowing an attacker physical or remote access to take over the user's identity and pivot into every downstream application that trusts Okta SSO.",
"RelatedUrl": "",
"AdditionalURLs": [
@@ -8,11 +8,16 @@ DEFAULT_THRESHOLD_MINUTES = 15
class signon_global_session_idle_timeout_15min(Check):
"""STIG V-273186 / OKTA-APP-000020.
The DISA STIG requires the Okta Default Policy to have an active
Priority 1 rule that is not the built-in Default Rule, and that
rule must set the maximum Okta global session idle time to the
configured threshold or lower (defaults to 15 minutes per STIG;
override via `okta_max_session_idle_minutes` in the audit config).
Every active Global Session Policy must have an active Priority 1
rule that is not the built-in Default Rule, and that rule must set
the maximum Okta global session idle time to the configured
threshold or lower (defaults to 15 minutes per STIG; override via
`okta_max_session_idle_minutes` in the audit config).
Okta evaluates sign-on policies in priority order based on group
assignments, so a permissive custom policy can govern a user's
session even when the Default Policy is strict. The check emits one
finding per active policy to surface that risk.
"""
def execute(self) -> list[CheckReportOkta]:
@@ -21,106 +26,121 @@ class signon_global_session_idle_timeout_15min(Check):
"okta_max_session_idle_minutes", DEFAULT_THRESHOLD_MINUTES
)
org_domain = signon_client.provider.identity.org_domain
policy = self._get_default_policy()
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
active_policies = _active_policies()
if not active_policies:
return [_no_policies_finding(self.metadata(), org_domain)]
findings: list[CheckReportOkta] = []
for policy in active_policies:
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
)
status, status_extended = _evaluate_policy(policy, threshold)
report.status = status
report.status_extended = status_extended
findings.append(report)
return findings
def _evaluate_policy(policy: GlobalSessionPolicy, threshold: int) -> tuple[str, str]:
label = _policy_label(policy)
priority_one_rule = _priority_one_active_rule(policy)
if priority_one_rule is None:
return (
"FAIL",
f"{label} has no Priority 1 active rule. STIG V-273186 requires "
f"a non-default Priority 1 rule with idle timeout <= {threshold} "
"minutes.",
)
if policy.id == "default-policy-missing":
report.status = "FAIL"
report.status_extended = (
"Default Global Session Policy was not found. STIG V-273186 "
"requires the Default Policy to contain an active Priority 1 "
f"non-default rule with idle timeout <= {threshold} minutes."
)
return [report]
if policy.status and policy.status.upper() != "ACTIVE":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' is in "
f"status '{policy.status}'. STIG V-273186 requires an active "
"Default Policy with an active Priority 1 non-default rule."
)
return [report]
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
return (
"FAIL",
f"{label} uses '{priority_one_rule.name}' as its active Priority 1 "
"rule. The STIG requires a non-default Priority 1 rule.",
)
if not active_rules:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
"rules. STIG V-273186 requires an active Priority 1 non-default "
f"rule with idle timeout <= {threshold} minutes."
)
return [report]
priority_one_rule = active_rules[0]
if priority_one_rule.priority != 1:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
f"Priority 1 rule. The first active rule is '{priority_one_rule.name}' "
f"at priority {priority_one_rule.priority}."
)
return [report]
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' uses "
f"'{priority_one_rule.name}' as its active Priority 1 rule. "
"The STIG requires a non-default Priority 1 rule."
)
return [report]
idle_timeout = priority_one_rule.max_session_idle_minutes
if idle_timeout is None:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' does not define "
"a maximum Okta global session idle time."
)
return [report]
if idle_timeout <= threshold:
report.status = "PASS"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' sets the "
f"maximum Okta global session idle time to {idle_timeout} "
f"minutes, meeting the configured threshold of {threshold} minutes."
)
else:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' sets the "
f"maximum Okta global session idle time to {idle_timeout} "
f"minutes, exceeding the configured threshold of {threshold} minutes."
)
return [report]
@staticmethod
def _get_default_policy() -> GlobalSessionPolicy:
for policy in signon_client.global_session_policies.values():
if policy.is_default or policy.name == "Default Policy":
return policy
return GlobalSessionPolicy(
id="default-policy-missing",
name="Default Policy",
priority=1,
status="MISSING",
is_default=True,
rules=[],
idle_timeout = priority_one_rule.max_session_idle_minutes
if idle_timeout is None:
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"does not define a maximum Okta global session idle time.",
)
if idle_timeout <= threshold:
return (
"PASS",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
f"sets the maximum Okta global session idle time to {idle_timeout} "
f"minutes, meeting the configured threshold of {threshold} minutes.",
)
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
f"sets the maximum Okta global session idle time to {idle_timeout} "
f"minutes, exceeding the configured threshold of {threshold} minutes.",
)
def _active_policies() -> list[GlobalSessionPolicy]:
return sorted(
[
policy
for policy in signon_client.global_session_policies.values()
if not policy.status or policy.status.upper() == "ACTIVE"
],
key=lambda policy: (
policy.priority if policy.priority is not None else float("inf"),
policy.name,
),
)
def _priority_one_active_rule(policy: GlobalSessionPolicy):
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
)
if not active_rules:
return None
candidate = active_rules[0]
if candidate.priority != 1:
return None
return candidate
def _policy_label(policy: GlobalSessionPolicy) -> str:
kind = "default" if policy.is_default else "custom"
priority = policy.priority if policy.priority is not None else "unset"
return f"Global Session Policy '{policy.name}' (priority {priority}, {kind})"
def _no_policies_finding(metadata, org_domain) -> CheckReportOkta:
placeholder = GlobalSessionPolicy(
id="signon-policies-missing",
name="(no active sign-on policies)",
priority=1,
status="MISSING",
is_default=False,
rules=[],
)
report = CheckReportOkta(
metadata=metadata, resource=placeholder, org_domain=org_domain
)
report.status = "FAIL"
report.status_extended = (
"No active Okta Global Session Policies were returned by the API. "
"STIG V-273186 requires the policy that governs each user to enforce "
"a Priority 1 non-default rule with a 15-minute idle timeout."
)
return report
@@ -9,7 +9,7 @@
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "governance",
"Description": "The **Default Global Session Policy** must have a **Priority 1** rule that is **not** the built-in `Default Rule`, and that rule must set **Maximum Okta global session lifetime** to 18 hours or less (DISA STIG V-273203 / OKTA-APP-001665). The threshold defaults to 1080 minutes and is overridable via the `okta_max_session_lifetime_minutes` key in the audit config.",
"Description": "Every active Global Session Policy must have a **Priority 1** rule that is **not** the built-in `Default Rule`, setting **Maximum Okta global session lifetime** to 18 hours or less (DISA STIG V-273203 / OKTA-APP-001665). Okta evaluates policies by group assignment, so a permissive custom policy can govern users. Override the threshold via `okta_max_session_lifetime_minutes`.",
"Risk": "Without an enforced session lifetime, an authenticated Okta session can be reused indefinitely without reauthentication. Stolen session material continues to grant access long after the original sign-in event, and authorization changes (role revocation, group removal) take effect only on the next forced reauth.",
"RelatedUrl": "",
"AdditionalURLs": [
@@ -8,11 +8,16 @@ DEFAULT_THRESHOLD_MINUTES = 18 * 60
class signon_global_session_lifetime_18h(Check):
"""STIG V-273203 / OKTA-APP-001665.
The DISA STIG requires the Okta Default Policy to have an active
Priority 1 rule that is not the built-in Default Rule, and that
rule must set the maximum Okta global session lifetime to the
configured threshold or lower (defaults to 18 hours per STIG;
override via `okta_max_session_lifetime_minutes` in the audit config).
Every active Global Session Policy must have an active Priority 1
rule that is not the built-in Default Rule, and that rule must set
the maximum Okta global session lifetime to the configured threshold
or lower (defaults to 18 hours per STIG; override via
`okta_max_session_lifetime_minutes` in the audit config).
Okta evaluates sign-on policies in priority order based on group
assignments, so a permissive custom policy can govern a user's
session even when the Default Policy is strict. The check emits one
finding per active policy to surface that risk.
"""
def execute(self) -> list[CheckReportOkta]:
@@ -21,115 +26,129 @@ class signon_global_session_lifetime_18h(Check):
"okta_max_session_lifetime_minutes", DEFAULT_THRESHOLD_MINUTES
)
org_domain = signon_client.provider.identity.org_domain
policy = self._get_default_policy()
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
active_policies = _active_policies()
if not active_policies:
return [_no_policies_finding(self.metadata(), org_domain)]
findings: list[CheckReportOkta] = []
for policy in active_policies:
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
)
status, status_extended = _evaluate_policy(policy, threshold)
report.status = status
report.status_extended = status_extended
findings.append(report)
return findings
def _evaluate_policy(policy: GlobalSessionPolicy, threshold: int) -> tuple[str, str]:
label = _policy_label(policy)
priority_one_rule = _priority_one_active_rule(policy)
if priority_one_rule is None:
return (
"FAIL",
f"{label} has no Priority 1 active rule. STIG V-273203 requires "
f"a non-default Priority 1 rule with session lifetime <= {threshold} "
"minutes.",
)
if policy.id == "default-policy-missing":
report.status = "FAIL"
report.status_extended = (
"Default Global Session Policy was not found. STIG V-273203 "
"requires the Default Policy to contain an active Priority 1 "
f"non-default rule with session lifetime <= {threshold} minutes."
)
return [report]
if policy.status and policy.status.upper() != "ACTIVE":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' is in "
f"status '{policy.status}'. STIG V-273203 requires an active "
"Default Policy with an active Priority 1 non-default rule."
)
return [report]
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
return (
"FAIL",
f"{label} uses '{priority_one_rule.name}' as its active Priority 1 "
"rule. The STIG requires a non-default Priority 1 rule.",
)
if not active_rules:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
"rules. STIG V-273203 requires an active Priority 1 non-default "
f"rule with session lifetime <= {threshold} minutes."
)
return [report]
priority_one_rule = active_rules[0]
if priority_one_rule.priority != 1:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
f"Priority 1 rule. The first active rule is '{priority_one_rule.name}' "
f"at priority {priority_one_rule.priority}."
)
return [report]
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' uses "
f"'{priority_one_rule.name}' as its active Priority 1 rule. "
"The STIG requires a non-default Priority 1 rule."
)
return [report]
lifetime = priority_one_rule.max_session_lifetime_minutes
if lifetime is None:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' does not define "
"a maximum Okta global session lifetime."
)
return [report]
if lifetime == 0:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' disables the "
"maximum Okta global session lifetime by setting it to 0 minutes."
)
return [report]
if lifetime <= threshold:
report.status = "PASS"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' sets the "
f"maximum Okta global session lifetime to {lifetime} minutes, "
f"meeting the configured threshold of {threshold} minutes."
)
else:
report.status = "FAIL"
report.status_extended = (
f"Priority 1 non-default rule '{priority_one_rule.name}' in "
f"Default Global Session Policy '{policy.name}' sets the "
f"maximum Okta global session lifetime to {lifetime} minutes, "
f"exceeding the configured threshold of {threshold} minutes."
)
return [report]
@staticmethod
def _get_default_policy() -> GlobalSessionPolicy:
for policy in signon_client.global_session_policies.values():
if policy.is_default or policy.name == "Default Policy":
return policy
return GlobalSessionPolicy(
id="default-policy-missing",
name="Default Policy",
priority=1,
status="MISSING",
is_default=True,
rules=[],
lifetime = priority_one_rule.max_session_lifetime_minutes
if lifetime is None:
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"does not define a maximum Okta global session lifetime.",
)
if lifetime == 0:
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
"disables the maximum Okta global session lifetime by setting it "
"to 0 minutes.",
)
if lifetime <= threshold:
return (
"PASS",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
f"sets the maximum Okta global session lifetime to {lifetime} "
f"minutes, meeting the configured threshold of {threshold} minutes.",
)
return (
"FAIL",
f"Priority 1 non-default rule '{priority_one_rule.name}' in {label} "
f"sets the maximum Okta global session lifetime to {lifetime} minutes, "
f"exceeding the configured threshold of {threshold} minutes.",
)
def _active_policies() -> list[GlobalSessionPolicy]:
return sorted(
[
policy
for policy in signon_client.global_session_policies.values()
if not policy.status or policy.status.upper() == "ACTIVE"
],
key=lambda policy: (
policy.priority if policy.priority is not None else float("inf"),
policy.name,
),
)
def _priority_one_active_rule(policy: GlobalSessionPolicy):
active_rules = sorted(
[
rule
for rule in policy.rules
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
)
if not active_rules:
return None
candidate = active_rules[0]
if candidate.priority != 1:
return None
return candidate
def _policy_label(policy: GlobalSessionPolicy) -> str:
kind = "default" if policy.is_default else "custom"
priority = policy.priority if policy.priority is not None else "unset"
return f"Global Session Policy '{policy.name}' (priority {priority}, {kind})"
def _no_policies_finding(metadata, org_domain) -> CheckReportOkta:
placeholder = GlobalSessionPolicy(
id="signon-policies-missing",
name="(no active sign-on policies)",
priority=1,
status="MISSING",
is_default=False,
rules=[],
)
report = CheckReportOkta(
metadata=metadata, resource=placeholder, org_domain=org_domain
)
report.status = "FAIL"
report.status_extended = (
"No active Okta Global Session Policies were returned by the API. "
"STIG V-273203 requires the policy that governs each user to enforce "
"a Priority 1 non-default rule with an 18-hour session lifetime."
)
return report
@@ -9,7 +9,7 @@
"Severity": "medium",
"ResourceType": "NotDefined",
"ResourceGroup": "governance",
"Description": "The **Default Global Session Policy** must use the **IF User's IP is** condition, mapped to a Network Zone, on at least one active non-default rule (DISA STIG V-279691 / OKTA-APP-003242). The condition lets Okta allow or deny access according to the organization's Access Control Policy rather than relying solely on credential possession.",
"Description": "Every active Global Session Policy must use the **IF User's IP is** condition, mapped to a Network Zone, on its **Priority 1 active rule** (DISA STIG V-279691 / OKTA-APP-003242). Okta evaluates rules in priority order, and policies by group assignment, so the zone condition must sit on the rule that fires first for each policy that governs users.",
"Risk": "When the Global Session Policy does not restrict access by Network Zone, every authenticated entity is granted session establishment regardless of source IP. Authorization that does not factor in network location lets stolen credentials or out-of-band sessions reach the Okta dashboard from any internet-routable address, undermining the organization's Access Control Policy.",
"RelatedUrl": "",
"AdditionalURLs": [
@@ -6,74 +6,133 @@ from prowler.providers.okta.services.signon.signon_service import GlobalSessionP
class signon_global_session_policy_network_zone_enforced(Check):
"""STIG V-279691 / OKTA-APP-003242.
The DISA STIG requires the Default Global Session Policy to use an
"IF User's IP is" condition mapped to a Network Zone on at least one
active non-default rule, so access can be allowed or denied per the
organization's Access Control Policy.
Every active Global Session Policy must apply an "IF User's IP is"
condition mapped to a Network Zone on its Priority 1 active rule so
access can be allowed or denied per the organization's Access
Control Policy.
Unlike the idle / lifetime / persistent-cookie STIGs, V-279691 does
not exclude the built-in Default Rule, so a zone condition on the
Default Rule is still effective when no non-default rule sits at
Priority 1.
The check emits one finding per active policy because Okta evaluates
sign-on policies in priority order based on group assignments, and a
permissive custom policy can govern a user's session even when the
Default Policy is strict.
"""
def execute(self) -> list[CheckReportOkta]:
org_domain = signon_client.provider.identity.org_domain
policy = self._get_default_policy()
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
active_policies = _active_policies()
if not active_policies:
return [_no_policies_finding(self.metadata(), org_domain)]
findings: list[CheckReportOkta] = []
for policy in active_policies:
report = CheckReportOkta(
metadata=self.metadata(), resource=policy, org_domain=org_domain
)
status, status_extended = _evaluate_policy(policy)
report.status = status
report.status_extended = status_extended
findings.append(report)
return findings
def _evaluate_policy(policy: GlobalSessionPolicy) -> tuple[str, str]:
label = _policy_label(policy)
priority_one_rule = _priority_one_active_rule(policy)
if priority_one_rule is None:
return (
"FAIL",
f"{label} has no Priority 1 active rule. STIG V-279691 requires "
"the policy to apply an IP-based Network Zone condition on its "
"Priority 1 active rule.",
)
if policy.id == "default-policy-missing":
report.status = "FAIL"
report.status_extended = (
"Default Global Session Policy was not found. STIG V-279691 "
"requires the Default Policy to apply an IP-based Network "
"Zone condition on at least one active non-default rule."
)
return [report]
rule_kind = (
"built-in Default Rule"
if priority_one_rule.is_default or priority_one_rule.name == "Default Rule"
else "non-default rule"
)
has_zones = bool(
priority_one_rule.network_zones_include
or priority_one_rule.network_zones_exclude
)
if policy.status and policy.status.upper() != "ACTIVE":
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' is in "
f"status '{policy.status}'. STIG V-279691 requires an active "
"Default Policy with an IP-based Network Zone condition."
)
return [report]
if has_zones:
return (
"PASS",
f"Priority 1 active {rule_kind} '{priority_one_rule.name}' in "
f"{label} maps User's IP to a Network Zone.",
)
return (
"FAIL",
f"Priority 1 active {rule_kind} '{priority_one_rule.name}' in {label} "
"does not map User's IP to a Network Zone. The policy cannot allow "
"or deny access based on the organization's Access Control Policy.",
)
rules_with_zones = [
def _active_policies() -> list[GlobalSessionPolicy]:
return sorted(
[
policy
for policy in signon_client.global_session_policies.values()
if not policy.status or policy.status.upper() == "ACTIVE"
],
key=lambda policy: (
policy.priority if policy.priority is not None else float("inf"),
policy.name,
),
)
def _priority_one_active_rule(policy: GlobalSessionPolicy):
active_rules = sorted(
[
rule
for rule in policy.rules
if (not rule.status or rule.status.upper() == "ACTIVE")
and not rule.is_default
and rule.name != "Default Rule"
and (rule.network_zones_include or rule.network_zones_exclude)
]
if not rule.status or rule.status.upper() == "ACTIVE"
],
key=lambda rule: (
rule.priority if rule.priority is not None else float("inf"),
rule.name,
),
)
if not active_rules:
return None
candidate = active_rules[0]
if candidate.priority != 1:
return None
return candidate
if not rules_with_zones:
report.status = "FAIL"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' has no active "
"non-default rule mapping User's IP to a Network Zone. The "
"policy cannot allow or deny access based on the organization's "
"Access Control Policy."
)
return [report]
rule_names = ", ".join(f"'{rule.name}'" for rule in rules_with_zones)
report.status = "PASS"
report.status_extended = (
f"Default Global Session Policy '{policy.name}' uses Network Zone "
f"conditions on the following active non-default rule(s): {rule_names}."
)
return [report]
def _policy_label(policy: GlobalSessionPolicy) -> str:
kind = "default" if policy.is_default else "custom"
priority = policy.priority if policy.priority is not None else "unset"
return f"Global Session Policy '{policy.name}' (priority {priority}, {kind})"
@staticmethod
def _get_default_policy() -> GlobalSessionPolicy:
for policy in signon_client.global_session_policies.values():
if policy.is_default or policy.name == "Default Policy":
return policy
return GlobalSessionPolicy(
id="default-policy-missing",
name="Default Policy",
priority=1,
status="MISSING",
is_default=True,
rules=[],
)
def _no_policies_finding(metadata, org_domain) -> CheckReportOkta:
placeholder = GlobalSessionPolicy(
id="signon-policies-missing",
name="(no active sign-on policies)",
priority=1,
status="MISSING",
is_default=False,
rules=[],
)
report = CheckReportOkta(
metadata=metadata, resource=placeholder, org_domain=org_domain
)
report.status = "FAIL"
report.status_extended = (
"No active Okta Global Session Policies were returned by the API. "
"STIG V-279691 requires the policy that governs each user to map "
"User's IP to a Network Zone on its Priority 1 active rule."
)
return report
@@ -20,24 +20,27 @@ CHECK_PATH = (
)
def _run_check(signon_client):
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
return signon_global_session_cookies_not_persistent().execute()
class Test_signon_global_session_cookies_not_persistent:
def test_no_policies(self):
signon_client = build_signon_client({})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "was not found" in findings[0].status_extended
findings = _run_check(build_signon_client({}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
def test_pass_when_priority_one_rule_disables_persistent_cookies(self):
policy = default_policy(
@@ -50,24 +53,13 @@ class Test_signon_global_session_cookies_not_persistent:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "disables persistent global session cookies" in (
findings[0].status_extended
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "disables persistent global session cookies" in (
findings[0].status_extended
)
assert "priority 99, default" in findings[0].status_extended
def test_fail_when_priority_one_rule_uses_persistent_cookies(self):
policy = default_policy(
@@ -80,24 +72,12 @@ class Test_signon_global_session_cookies_not_persistent:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "allows persistent global session cookies" in (
findings[0].status_extended
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "allows persistent global session cookies" in (
findings[0].status_extended
)
def test_fail_when_priority_one_rule_does_not_assert_setting(self):
policy = default_policy(
@@ -113,58 +93,23 @@ class Test_signon_global_session_cookies_not_persistent:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "does not assert" in findings[0].status_extended
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "does not" in findings[0].status_extended
assert "assert" in findings[0].status_extended
def test_fail_when_default_policy_is_inactive(self):
policy = GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
status="INACTIVE",
is_default=True,
rules=[
def test_emits_one_finding_per_policy(self):
admins_policy = custom_policy(
[
non_default_rule(
"Compliant",
use_persistent_cookie=False,
"Sticky admin",
use_persistent_cookie=True,
priority=1,
)
],
name="Admins Policy",
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
)
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "status 'INACTIVE'" in findings[0].status_extended
def test_ignores_other_custom_policies(self):
compliant_default = default_policy(
strict_default = default_policy(
[
non_default_rule(
"Non-persistent",
@@ -174,30 +119,57 @@ class Test_signon_global_session_cookies_not_persistent:
default_rule(priority=2),
]
)
permissive_custom = custom_policy(
findings = _run_check(
build_signon_client(
{"pol-custom": admins_policy, "pol-default": strict_default}
)
)
assert len(findings) == 2
by_name = {f.resource_name: f for f in findings}
assert by_name["Admins Policy"].status == "FAIL"
assert "priority 1, custom" in by_name["Admins Policy"].status_extended
assert by_name["Default Policy"].status == "PASS"
def test_inactive_policy_is_skipped(self):
inactive = GlobalSessionPolicy(
id="pol-inactive",
name="Disabled Policy",
priority=1,
status="INACTIVE",
is_default=False,
rules=[non_default_rule("Sticky", use_persistent_cookie=True, priority=1)],
)
active_default = default_policy(
[
non_default_rule(
"Sticky admin",
use_persistent_cookie=True,
"Non-persistent",
use_persistent_cookie=False,
priority=1,
)
),
default_rule(priority=2),
]
)
signon_client = build_signon_client(
{"pol-custom": permissive_custom, "pol-default": compliant_default}
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_cookies_not_persistent.signon_global_session_cookies_not_persistent import (
signon_global_session_cookies_not_persistent,
findings = _run_check(
build_signon_client(
{"pol-inactive": inactive, "pol-default": active_default}
)
)
assert len(findings) == 1
assert findings[0].resource_name == "Default Policy"
assert findings[0].status == "PASS"
findings = signon_global_session_cookies_not_persistent().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert findings[0].resource_name == "Default Policy"
def test_fail_when_all_policies_inactive(self):
only_inactive = GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
status="INACTIVE",
is_default=True,
rules=[
non_default_rule("Compliant", use_persistent_cookie=False, priority=1)
],
)
findings = _run_check(build_signon_client({"pol-default": only_inactive}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
@@ -20,24 +20,27 @@ CHECK_PATH = (
)
def _run_check(signon_client):
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
return signon_global_session_idle_timeout_15min().execute()
class Test_signon_global_session_idle_timeout_15min:
def test_no_policies(self):
signon_client = build_signon_client({})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "was not found" in findings[0].status_extended
findings = _run_check(build_signon_client({}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
def test_pass_when_priority_one_non_default_rule_is_compliant(self):
policy = default_policy(
@@ -46,44 +49,21 @@ class Test_signon_global_session_idle_timeout_15min:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Strict 15min" in findings[0].status_extended
assert "Priority 1 non-default rule" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Strict 15min" in findings[0].status_extended
assert "Default Policy" in findings[0].status_extended
assert "priority 99, default" 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})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
)
def test_fail_when_priority_one_non_default_rule_has_null_idle(self):
policy = default_policy(
@@ -99,23 +79,11 @@ class Test_signon_global_session_idle_timeout_15min:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No Session Block" in findings[0].status_extended
assert "does not define" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No Session Block" in findings[0].status_extended
assert "does not define" in findings[0].status_extended
def test_fail_when_priority_one_non_default_rule_exceeds_threshold(self):
policy = default_policy(
@@ -124,23 +92,11 @@ class Test_signon_global_session_idle_timeout_15min:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "Loose 60min" in findings[0].status_extended
assert "exceeding the configured threshold" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "Loose 60min" in findings[0].status_extended
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(
@@ -149,62 +105,67 @@ class Test_signon_global_session_idle_timeout_15min:
non_default_rule("Strict 15min", idle_min=15, priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
)
def test_ignores_other_custom_policies(self):
default_policy_with_strict_rule = default_policy(
def test_emits_one_finding_per_policy(self):
# Custom policy at priority 1 with a permissive rule + Default Policy
# with a strict rule -> two findings, ordered by policy priority.
admins_policy = custom_policy(
[
non_default_rule("Admin Loose", idle_min=120, priority=1),
default_rule(priority=2),
],
name="Admins Policy",
)
strict_default = default_policy(
[
non_default_rule("Strict 15min", idle_min=15, priority=1),
default_rule(priority=2),
]
)
custom_loose_policy = custom_policy(
findings = _run_check(
build_signon_client(
{"pol-custom": admins_policy, "pol-default": strict_default}
)
)
assert len(findings) == 2
by_name = {f.resource_name: f for f in findings}
assert by_name["Admins Policy"].status == "FAIL"
assert "priority 1, custom" in by_name["Admins Policy"].status_extended
assert by_name["Default Policy"].status == "PASS"
assert "priority 99, default" in by_name["Default Policy"].status_extended
def test_inactive_policy_is_skipped(self):
inactive = GlobalSessionPolicy(
id="pol-inactive",
name="Disabled Policy",
priority=1,
status="INACTIVE",
is_default=False,
rules=[non_default_rule("Loose 120min", idle_min=120, priority=1)],
)
active_default = default_policy(
[
non_default_rule("Loose Admin Rule", idle_min=60, priority=1),
non_default_rule("Strict 15min", idle_min=15, priority=1),
default_rule(priority=2),
]
)
signon_client = build_signon_client(
{
"pol-custom": custom_loose_policy,
"pol-default": default_policy_with_strict_rule,
}
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
findings = _run_check(
build_signon_client(
{"pol-inactive": inactive, "pol-default": active_default}
)
)
assert len(findings) == 1
assert findings[0].resource_name == "Default Policy"
assert findings[0].status == "PASS"
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert findings[0].resource_name == "Default Policy"
def test_fail_when_default_policy_is_inactive(self):
policy = GlobalSessionPolicy(
def test_fail_when_all_policies_inactive(self):
only_inactive = GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
@@ -212,22 +173,10 @@ class Test_signon_global_session_idle_timeout_15min:
is_default=True,
rules=[non_default_rule("Strict 15min", idle_min=15, priority=1)],
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "status 'INACTIVE'" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": only_inactive}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
def test_threshold_overridden_via_audit_config(self):
policy = default_policy(
@@ -236,22 +185,12 @@ class Test_signon_global_session_idle_timeout_15min:
default_rule(priority=2),
]
)
signon_client = build_signon_client(
{"pol-default": policy},
audit_config={"okta_max_session_idle_minutes": 60},
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_idle_timeout_15min.signon_global_session_idle_timeout_15min import (
signon_global_session_idle_timeout_15min,
findings = _run_check(
build_signon_client(
{"pol-default": policy},
audit_config={"okta_max_session_idle_minutes": 60},
)
findings = signon_global_session_idle_timeout_15min().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "threshold of 60 minutes" in findings[0].status_extended
)
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "threshold of 60 minutes" in findings[0].status_extended
@@ -20,24 +20,27 @@ CHECK_PATH = (
)
def _run_check(signon_client):
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
return signon_global_session_lifetime_18h().execute()
class Test_signon_global_session_lifetime_18h:
def test_no_policies(self):
signon_client = build_signon_client({})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "was not found" in findings[0].status_extended
findings = _run_check(build_signon_client({}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
def test_pass_when_priority_one_non_default_rule_is_compliant(self):
policy = default_policy(
@@ -46,23 +49,12 @@ class Test_signon_global_session_lifetime_18h:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "18h rule" in findings[0].status_extended
assert "1080 minutes" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "18h rule" in findings[0].status_extended
assert "1080 minutes" in findings[0].status_extended
assert "priority 99, default" in findings[0].status_extended
def test_fail_when_lifetime_exceeds_threshold(self):
policy = default_policy(
@@ -71,23 +63,11 @@ class Test_signon_global_session_lifetime_18h:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "1440 minutes" in findings[0].status_extended
assert "exceeding the configured threshold" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "1440 minutes" in findings[0].status_extended
assert "exceeding the configured threshold" in findings[0].status_extended
def test_fail_when_priority_one_rule_has_no_lifetime(self):
policy = default_policy(
@@ -103,22 +83,10 @@ class Test_signon_global_session_lifetime_18h:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "does not define" in findings[0].status_extended
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "does not define" in findings[0].status_extended
def test_fail_when_lifetime_is_disabled_with_zero(self):
policy = default_policy(
@@ -127,25 +95,13 @@ class Test_signon_global_session_lifetime_18h:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "0 minutes" in findings[0].status_extended
assert "disables the maximum Okta global session lifetime" in (
findings[0].status_extended
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "0 minutes" in findings[0].status_extended
assert "disables the maximum Okta global session lifetime" in (
findings[0].status_extended
)
def test_fail_when_default_rule_is_priority_one(self):
policy = default_policy(
@@ -154,27 +110,64 @@ class Test_signon_global_session_lifetime_18h:
non_default_rule("Compliant", lifetime_min=1080, priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "uses 'Default Rule' as its active Priority 1 rule" in (
findings[0].status_extended
def test_emits_one_finding_per_policy(self):
admins_policy = custom_policy(
[
non_default_rule("Admin Long Lived", lifetime_min=2880, priority=1),
default_rule(priority=2),
],
name="Admins Policy",
)
strict_default = default_policy(
[
non_default_rule("18h rule", lifetime_min=1080, priority=1),
default_rule(priority=2),
]
)
findings = _run_check(
build_signon_client(
{"pol-custom": admins_policy, "pol-default": strict_default}
)
)
assert len(findings) == 2
by_name = {f.resource_name: f for f in findings}
assert by_name["Admins Policy"].status == "FAIL"
assert "priority 1, custom" in by_name["Admins Policy"].status_extended
assert by_name["Default Policy"].status == "PASS"
def test_fail_when_default_policy_is_inactive(self):
policy = GlobalSessionPolicy(
def test_inactive_policy_is_skipped(self):
inactive = GlobalSessionPolicy(
id="pol-inactive",
name="Disabled Policy",
priority=1,
status="INACTIVE",
is_default=False,
rules=[non_default_rule("Loose", lifetime_min=2880, priority=1)],
)
active_default = default_policy(
[
non_default_rule("18h rule", lifetime_min=1080, priority=1),
default_rule(priority=2),
]
)
findings = _run_check(
build_signon_client(
{"pol-inactive": inactive, "pol-default": active_default}
)
)
assert len(findings) == 1
assert findings[0].resource_name == "Default Policy"
assert findings[0].status == "PASS"
def test_fail_when_all_policies_inactive(self):
only_inactive = GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
@@ -182,54 +175,10 @@ class Test_signon_global_session_lifetime_18h:
is_default=True,
rules=[non_default_rule("18h rule", lifetime_min=1080, priority=1)],
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "status 'INACTIVE'" in findings[0].status_extended
def test_ignores_other_custom_policies(self):
compliant_default = default_policy(
[
non_default_rule("18h rule", lifetime_min=1080, priority=1),
default_rule(priority=2),
]
)
loose_custom = custom_policy(
[
non_default_rule("Long-lived admin", lifetime_min=4320, priority=1),
default_rule(priority=2),
]
)
signon_client = build_signon_client(
{"pol-custom": loose_custom, "pol-default": compliant_default}
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert findings[0].resource_name == "Default Policy"
findings = _run_check(build_signon_client({"pol-default": only_inactive}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
def test_threshold_overridden_via_audit_config(self):
policy = default_policy(
@@ -238,22 +187,12 @@ class Test_signon_global_session_lifetime_18h:
default_rule(priority=2),
]
)
signon_client = build_signon_client(
{"pol-default": policy},
audit_config={"okta_max_session_lifetime_minutes": 1440},
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_lifetime_18h.signon_global_session_lifetime_18h import (
signon_global_session_lifetime_18h,
findings = _run_check(
build_signon_client(
{"pol-default": policy},
audit_config={"okta_max_session_lifetime_minutes": 1440},
)
findings = signon_global_session_lifetime_18h().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "threshold of 1440 minutes" in findings[0].status_extended
)
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "threshold of 1440 minutes" in findings[0].status_extended
@@ -2,6 +2,7 @@ from unittest import mock
from prowler.providers.okta.services.signon.signon_service import (
GlobalSessionPolicy,
GlobalSessionPolicyRule,
)
from tests.providers.okta.okta_fixtures import set_mocked_okta_provider
from tests.providers.okta.services.signon.signon_fixtures import (
@@ -19,26 +20,29 @@ CHECK_PATH = (
)
def _run_check(signon_client):
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
return signon_global_session_policy_network_zone_enforced().execute()
class Test_signon_global_session_policy_network_zone_enforced:
def test_no_policies(self):
signon_client = build_signon_client({})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = _run_check(build_signon_client({}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "was not found" in findings[0].status_extended
def test_pass_when_active_rule_includes_zone(self):
def test_pass_when_priority_one_non_default_rule_includes_zone(self):
policy = default_policy(
[
non_default_rule(
@@ -49,24 +53,14 @@ class Test_signon_global_session_policy_network_zone_enforced:
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Allow-from-VPN" in findings[0].status_extended
assert "non-default rule" in findings[0].status_extended
assert "priority 99, default" in findings[0].status_extended
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Allow-from-VPN" in findings[0].status_extended
def test_pass_when_active_rule_excludes_zone(self):
def test_pass_when_priority_one_non_default_rule_excludes_zone(self):
policy = default_policy(
[
non_default_rule(
@@ -76,102 +70,125 @@ class Test_signon_global_session_policy_network_zone_enforced:
),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Block-blacklist" in findings[0].status_extended
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "Block-blacklist" in findings[0].status_extended
def test_fail_when_no_rule_uses_network_zone(self):
def test_pass_when_only_default_rule_has_zones(self):
policy = default_policy(
[
non_default_rule("No-zones rule", priority=1),
GlobalSessionPolicyRule(
id="rule-default-zoned",
name="Default Rule",
priority=1,
status="ACTIVE",
is_default=True,
network_zones_include=["zone-corp"],
),
]
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "PASS"
assert "built-in Default Rule" in findings[0].status_extended
def test_fail_when_priority_one_rule_has_no_zones(self):
policy = default_policy(
[
non_default_rule("Plain non-default", priority=1),
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "Plain non-default" in findings[0].status_extended
assert "does not map" in findings[0].status_extended
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "no active non-default rule mapping" in findings[0].status_extended
def test_fail_when_only_default_rule_uses_zones(self):
# The built-in Default Rule should not be counted as satisfying
# the STIG even if it carries zone conditions — the STIG requires
# an explicit non-default rule.
def test_fail_when_only_lower_priority_rule_has_zones(self):
policy = default_policy(
[
GlobalSessionPolicyRule_with_zones(),
non_default_rule("No-zones top", priority=1),
non_default_rule(
"Zoned-but-low",
network_zones_include=["zone-corp"],
priority=2,
),
default_rule(priority=3),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No-zones top" in findings[0].status_extended
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
def test_fail_when_only_default_rule_has_no_zones(self):
policy = default_policy([default_rule(priority=1)])
findings = _run_check(build_signon_client({"pol-default": policy}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "built-in Default Rule" in findings[0].status_extended
def test_fail_when_inactive_rule_has_zones(self):
policy = default_policy(
def test_emits_one_finding_per_policy(self):
admins_policy = custom_policy(
[
non_default_rule("No-zones admin", priority=1),
default_rule(priority=2),
],
name="Admins Policy",
)
zoned_default = default_policy(
[
non_default_rule(
"Inactive zone rule",
"Allow-corp",
network_zones_include=["zone-corp"],
priority=1,
status="INACTIVE",
),
default_rule(priority=2),
]
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
findings = _run_check(
build_signon_client(
{"pol-custom": admins_policy, "pol-default": zoned_default}
)
)
assert len(findings) == 2
by_name = {f.resource_name: f for f in findings}
assert by_name["Admins Policy"].status == "FAIL"
assert "priority 1, custom" in by_name["Admins Policy"].status_extended
assert by_name["Default Policy"].status == "PASS"
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
def test_inactive_policy_is_skipped(self):
inactive = GlobalSessionPolicy(
id="pol-inactive",
name="Disabled Policy",
priority=1,
status="INACTIVE",
is_default=False,
rules=[non_default_rule("No-zones", priority=1)],
)
active_default = default_policy(
[
non_default_rule(
"Allow-corp",
network_zones_include=["zone-corp"],
priority=1,
),
default_rule(priority=2),
]
)
findings = _run_check(
build_signon_client(
{"pol-inactive": inactive, "pol-default": active_default}
)
)
assert len(findings) == 1
assert findings[0].resource_name == "Default Policy"
assert findings[0].status == "PASS"
def test_fail_when_default_policy_inactive(self):
policy = GlobalSessionPolicy(
def test_fail_when_all_policies_inactive(self):
only_inactive = GlobalSessionPolicy(
id="pol-default",
name="Default Policy",
priority=99,
@@ -185,71 +202,7 @@ class Test_signon_global_session_policy_network_zone_enforced:
)
],
)
signon_client = build_signon_client({"pol-default": policy})
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "status 'INACTIVE'" in findings[0].status_extended
def test_ignores_zones_on_other_custom_policies(self):
default_no_zones = default_policy(
[
non_default_rule("Plain rule", priority=1),
default_rule(priority=2),
]
)
custom_with_zones = custom_policy(
[
non_default_rule(
"Custom-allow",
network_zones_include=["zone-corp"],
priority=1,
)
]
)
signon_client = build_signon_client(
{"pol-default": default_no_zones, "pol-custom": custom_with_zones}
)
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_okta_provider(),
),
mock.patch(CHECK_PATH, new=signon_client),
):
from prowler.providers.okta.services.signon.signon_global_session_policy_network_zone_enforced.signon_global_session_policy_network_zone_enforced import (
signon_global_session_policy_network_zone_enforced,
)
findings = signon_global_session_policy_network_zone_enforced().execute()
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert findings[0].resource_name == "Default Policy"
def GlobalSessionPolicyRule_with_zones():
# Built-in Default Rule that still carries zone conditions — the STIG
# requires the rule to be non-default, so this scenario must FAIL.
from prowler.providers.okta.services.signon.signon_service import (
GlobalSessionPolicyRule,
)
return GlobalSessionPolicyRule(
id="rule-default-zoned",
name="Default Rule",
priority=1,
status="ACTIVE",
is_default=True,
network_zones_include=["zone-corp"],
)
findings = _run_check(build_signon_client({"pol-default": only_inactive}))
assert len(findings) == 1
assert findings[0].status == "FAIL"
assert "No active Okta Global Session Policies" in findings[0].status_extended