mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-08-21 05:13:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9e0086b5a | ||
|
|
b34b11482a |
@@ -6,6 +6,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- `signon_dod_warning_banner_configured` check for okta provider [(#11221)](https://github.com/prowler-cloud/prowler/pull/11221)
|
||||
- 6 Chat file sharing, external messaging, spaces, and apps access checks for Google Workspace provider using the Cloud Identity Policy API [(#11126)](https://github.com/prowler-cloud/prowler/pull/11126)
|
||||
- `entra_service_principal_no_secrets_for_permanent_tier0_roles` check for M365 provider [(#10788)](https://github.com/prowler-cloud/prowler/pull/10788)
|
||||
- `iam_user_access_not_stale_to_sagemaker` check for AWS provider with configurable `max_unused_sagemaker_access_days` (default 90) [(#11000)](https://github.com/prowler-cloud/prowler/pull/11000)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"Framework": "Okta-STIG",
|
||||
"Name": "Okta STIG - Global Session Policy",
|
||||
"Version": "1.0",
|
||||
"Provider": "Okta",
|
||||
"Description": "DISA STIG requirements for Okta Global Session Policy configuration. These checks validate session management, cookie persistence, network zone enforcement, and DOD notice banner display.",
|
||||
"Requirements": [
|
||||
{
|
||||
"Id": "V-273186",
|
||||
"Name": "Default Global Session Policy must have a non-default rule with Maximum Okta global session idle time of 15 minutes",
|
||||
"Description": "The Default Global Session Policy must have an active Priority 1 rule (not the built-in Default Rule) with Maximum Okta global session idle time set to 15 minutes or less.",
|
||||
"Checks": [
|
||||
"signon_global_session_idle_timeout_15min"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "V-273186",
|
||||
"StigId": "OKTA-APP-000020",
|
||||
"Severity": "medium",
|
||||
"Section": "Global Session Policy",
|
||||
"SectionDescription": "Checks related to Okta Global Session Policy session management settings.",
|
||||
"Service": "signon"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "V-273203",
|
||||
"Name": "Global Session Policy must limit Maximum Okta global session lifetime to 18 hours",
|
||||
"Description": "The Global Session Policy must limit Maximum Okta global session lifetime to 18 hours (1080 minutes) to force periodic reauthentication.",
|
||||
"Checks": [
|
||||
"signon_global_session_lifetime_18h"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "V-273203",
|
||||
"StigId": "OKTA-APP-001665",
|
||||
"Severity": "medium",
|
||||
"Section": "Global Session Policy",
|
||||
"SectionDescription": "Checks related to Okta Global Session Policy session management settings.",
|
||||
"Service": "signon"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "V-273206",
|
||||
"Name": "Okta global session cookies persist across browser sessions must be Disabled in the Default Global Session Policy",
|
||||
"Description": "The Default Global Session Policy must have persistent cookies disabled in all active rules to prevent session reuse across browser restarts.",
|
||||
"Checks": [
|
||||
"signon_global_session_cookies_not_persistent"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "V-273206",
|
||||
"StigId": "OKTA-APP-001710",
|
||||
"Severity": "medium",
|
||||
"Section": "Global Session Policy",
|
||||
"SectionDescription": "Checks related to Okta Global Session Policy session management settings.",
|
||||
"Service": "signon"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "V-279691",
|
||||
"Name": "Global Session Policy must use IF User's IP is condition mapped to a Network Zone",
|
||||
"Description": "The Global Session Policy must use an 'IF User's IP is' condition mapped to a Network Zone for allow/deny per Access Control Policy.",
|
||||
"Checks": [
|
||||
"signon_global_session_policy_network_zone_enforced"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "V-279691",
|
||||
"StigId": "OKTA-APP-003242",
|
||||
"Severity": "medium",
|
||||
"Section": "Global Session Policy",
|
||||
"SectionDescription": "Checks related to Okta Global Session Policy network zone enforcement.",
|
||||
"Service": "signon"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Id": "V-273192",
|
||||
"Name": "Sign-in widget/brand must display the Standard Mandatory DOD Notice and Consent Banner before login",
|
||||
"Description": "The Okta sign-in widget or brand must display the Standard Mandatory DOD Notice and Consent Banner (DTM-08-060) before login. Partially auditable via API; non-determinable items reported as MANUAL.",
|
||||
"Checks": [
|
||||
"signon_dod_warning_banner_configured"
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "V-273192",
|
||||
"StigId": "OKTA-APP-000200",
|
||||
"Severity": "medium",
|
||||
"Section": "Sign-In Customization",
|
||||
"SectionDescription": "Checks related to Okta sign-in page branding and customization.",
|
||||
"Service": "signon"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Provider": "okta",
|
||||
"CheckID": "signon_dod_warning_banner_configured",
|
||||
"CheckTitle": "Okta sign-in page enforces Standard Mandatory DOD Notice and Consent Banner before login",
|
||||
"CheckType": [],
|
||||
"ServiceName": "signon",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "NotDefined",
|
||||
"ResourceGroup": "governance",
|
||||
"Description": "The Okta sign-in widget or brand must display the **Standard Mandatory DOD Notice and Consent Banner** (DTM-08-060) before the login prompt. Not all aspects of the banner content can be verified programmatically via the Branding/Customization API, so this check returns **MANUAL** and requires visual confirmation.",
|
||||
"Risk": "Without the DOD consent banner, users are not legally notified that their activity is monitored, which may invalidate the organization's authority to audit, inspect, and investigate user actions on DoD systems.",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [
|
||||
"https://help.okta.com/oie/en-us/content/topics/settings/custom-okta-hosted-sign-in-page.htm",
|
||||
"https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Brands/"
|
||||
],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Sign in to the Okta Admin Console as a Super Admin\n2. Go to Customizations > Brands\n3. Select the relevant brand\n4. Edit the Sign-in page\n5. Add the Standard Mandatory DOD Notice and Consent Banner text before the login form\n6. Save the customization\n7. Visually confirm the banner appears on the login page",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Customize the Okta sign-in page to prominently display the Standard Mandatory DOD Notice and Consent Banner (DTM-08-060) before any login form elements, and periodically verify the banner is present and unmodified.",
|
||||
"Url": "https://hub.prowler.com/check/signon_dod_warning_banner_configured"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"identity-access"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This check always returns MANUAL because the Okta API does not expose sufficient detail to programmatically verify the full DOD banner content."
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
from prowler.lib.check.models import Check, CheckReportOkta
|
||||
from prowler.providers.okta.services.signon.signon_client import signon_client
|
||||
|
||||
|
||||
class signon_dod_warning_banner_configured(Check):
|
||||
"""STIG V-273192 / OKTA-APP-000200.
|
||||
|
||||
The DISA STIG requires the Okta sign-in widget/brand to display the
|
||||
Standard Mandatory DOD Notice and Consent Banner before login
|
||||
(DTM-08-060).
|
||||
|
||||
The Okta Branding/Customization API allows partial verification of
|
||||
the sign-in page customization, but not all aspects of the banner
|
||||
content can be confirmed programmatically. Therefore this check
|
||||
always returns a MANUAL status, instructing the administrator to
|
||||
visually confirm that the DOD banner is present and accurate.
|
||||
|
||||
- MANUAL: The sign-in page customization cannot be fully verified
|
||||
via the API; manual review is required.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportOkta]:
|
||||
"""Execute the check logic.
|
||||
|
||||
Returns:
|
||||
A list of reports containing the result of the check.
|
||||
"""
|
||||
org_domain = signon_client.provider.identity.org_domain
|
||||
|
||||
report = CheckReportOkta(
|
||||
metadata=self.metadata(),
|
||||
resource=signon_client,
|
||||
resource_id=org_domain,
|
||||
resource_name=org_domain,
|
||||
org_domain=org_domain,
|
||||
)
|
||||
report.status = "MANUAL"
|
||||
report.status_extended = (
|
||||
f"Okta organization '{org_domain}' sign-in page customization "
|
||||
"cannot be fully verified via the API. Manually confirm that the "
|
||||
"Standard Mandatory DOD Notice and Consent Banner (DTM-08-060) "
|
||||
"is displayed before the login prompt."
|
||||
)
|
||||
|
||||
return [report]
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.okta.okta_fixtures import OKTA_ORG_DOMAIN, set_mocked_okta_provider
|
||||
|
||||
CHECK_PATH = (
|
||||
"prowler.providers.okta.services.signon."
|
||||
"signon_dod_warning_banner_configured."
|
||||
"signon_dod_warning_banner_configured.signon_client"
|
||||
)
|
||||
|
||||
|
||||
def _build_signon_client(audit_config: dict = None):
|
||||
"""Build a mock signon_client."""
|
||||
client = mock.MagicMock()
|
||||
client.global_session_policies = {}
|
||||
client.provider = set_mocked_okta_provider()
|
||||
client.audit_config = audit_config or {}
|
||||
return client
|
||||
|
||||
|
||||
class Test_signon_dod_warning_banner_configured:
|
||||
"""Tests for the signon_dod_warning_banner_configured check.
|
||||
|
||||
This check always returns MANUAL because the DOD warning banner
|
||||
configuration cannot be fully verified via the Okta API.
|
||||
"""
|
||||
|
||||
def test_returns_manual_status(self):
|
||||
"""MANUAL is always returned since banner cannot be fully verified via API."""
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
assert findings[0].status == "MANUAL"
|
||||
assert "DOD Notice and Consent Banner" in findings[0].status_extended
|
||||
assert "DTM-08-060" in findings[0].status_extended
|
||||
|
||||
def test_resource_id_is_org_domain(self):
|
||||
"""The resource ID and name should be the org domain."""
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
assert findings[0].resource_id == OKTA_ORG_DOMAIN
|
||||
assert findings[0].resource_name == OKTA_ORG_DOMAIN
|
||||
|
||||
def test_single_finding_returned(self):
|
||||
"""Only one finding should be returned per execution."""
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
assert "cannot be fully verified" in findings[0].status_extended
|
||||
|
||||
def test_status_extended_mentions_org_domain(self):
|
||||
"""The status_extended message should reference the org domain."""
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
assert OKTA_ORG_DOMAIN in findings[0].status_extended
|
||||
|
||||
def test_status_extended_full_message(self):
|
||||
"""Verify the exact status_extended message content."""
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
expected_message = (
|
||||
f"Okta organization '{OKTA_ORG_DOMAIN}' sign-in page customization "
|
||||
"cannot be fully verified via the API. Manually confirm that the "
|
||||
"Standard Mandatory DOD Notice and Consent Banner (DTM-08-060) "
|
||||
"is displayed before the login prompt."
|
||||
)
|
||||
assert findings[0].status_extended == expected_message
|
||||
|
||||
def test_manual_status_regardless_of_policies(self):
|
||||
"""MANUAL status is returned even when policies exist (check is API-limited)."""
|
||||
signon_client = _build_signon_client()
|
||||
# Simulate having policies — should not affect the MANUAL outcome.
|
||||
signon_client.global_session_policies = {"pol-1": mock.MagicMock()}
|
||||
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_dod_warning_banner_configured.signon_dod_warning_banner_configured import (
|
||||
signon_dod_warning_banner_configured,
|
||||
)
|
||||
|
||||
findings = signon_dod_warning_banner_configured().execute()
|
||||
assert len(findings) == 1
|
||||
assert findings[0].status == "MANUAL"
|
||||
Reference in New Issue
Block a user