mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-25 12:54:18 +00:00
feat(okta): scan every policy
This commit is contained in:
12 files changed
+925
-1003
No files matched your search
+1
-1
@@ -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": [
|
||||
|
||||
+123
-102
@@ -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
|
||||
+1
-1
@@ -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": [
|
||||
|
||||
+123
-103
@@ -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
|
||||
+1
-1
@@ -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": [
|
||||
|
||||
+131
-112
@@ -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
|
||||
+1
-1
@@ -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": [
|
||||
|
||||
+117
-58
@@ -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
|
||||
+90
-118
@@ -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
|
||||
+102
-163
@@ -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
|
||||
+108
-169
@@ -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
|
||||
+127
-174
@@ -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
|
||||
Reference in new issue
Block a user