mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-03-30 03:49:48 +00:00
Compare commits
1 Commits
v5.22
...
feat/prowl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e75814194 |
@@ -17,6 +17,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- OCI regions updater script and CI workflow [(#10020)](https://github.com/prowler-cloud/prowler/pull/10020)
|
||||
- `image` provider for container image scanning with Trivy integration [(#9984)](https://github.com/prowler-cloud/prowler/pull/9984)
|
||||
- CSA CCM 4.0 for the Alibaba Cloud provider [(#10061)](https://github.com/prowler-cloud/prowler/pull/10061)
|
||||
- `entra_policy_unknown_unsupported_device_platforms_blocked` check for M365 provider [(#10063)](https://github.com/prowler-cloud/prowler/pull/10063)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
|
||||
@@ -199,7 +199,8 @@
|
||||
"admincenter_users_admins_reduced_license_footprint",
|
||||
"entra_admin_portals_access_restriction",
|
||||
"entra_admin_users_phishing_resistant_mfa_enabled",
|
||||
"entra_policy_guest_users_access_restrictions"
|
||||
"entra_policy_guest_users_access_restrictions",
|
||||
"entra_policy_unknown_unsupported_device_platforms_blocked"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -603,10 +604,11 @@
|
||||
],
|
||||
"Checks": [
|
||||
"entra_managed_device_required_for_authentication",
|
||||
"entra_users_mfa_enabled",
|
||||
"entra_managed_device_required_for_mfa_registration",
|
||||
"entra_admin_users_phishing_resistant_mfa_enabled",
|
||||
"entra_users_mfa_capable"
|
||||
"entra_policy_unknown_unsupported_device_platforms_blocked",
|
||||
"entra_users_mfa_capable",
|
||||
"entra_users_mfa_enabled",
|
||||
"entra_admin_users_phishing_resistant_mfa_enabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -670,11 +672,12 @@
|
||||
}
|
||||
],
|
||||
"Checks": [
|
||||
"entra_admin_users_sign_in_frequency_enabled",
|
||||
"entra_admin_users_mfa_enabled",
|
||||
"entra_admin_users_sign_in_frequency_enabled",
|
||||
"entra_identity_protection_sign_in_risk_enabled",
|
||||
"entra_managed_device_required_for_authentication",
|
||||
"entra_users_mfa_enabled",
|
||||
"entra_identity_protection_sign_in_risk_enabled"
|
||||
"entra_policy_unknown_unsupported_device_platforms_blocked",
|
||||
"entra_users_mfa_enabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "entra_policy_unknown_unsupported_device_platforms_blocked",
|
||||
"CheckTitle": "Conditional Access policy blocks unknown or unsupported device platforms",
|
||||
"CheckType": [],
|
||||
"ServiceName": "entra",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "Conditional Access Policy",
|
||||
"ResourceGroup": "IAM",
|
||||
"Description": "Conditional Access policy blocks access from **unknown or unsupported device platforms** to protect the tenant from unmanaged or potentially compromised endpoints.\n\nThis check verifies that at least one enabled policy exists that blocks all device platforms, which includes unknown or unsupported platforms by default.",
|
||||
"Risk": "Without blocking unknown or unsupported device platforms, attackers may exploit unmanaged endpoints to gain unauthorized access.\n\n- **Unverified devices** may lack security controls\n- **Legacy platforms** may have known vulnerabilities\n- Devices with **spoofed user agents** could bypass security measures",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [
|
||||
"https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-conditions#device-platforms",
|
||||
"https://maester.dev/docs/tests/MT.1015"
|
||||
],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com\n2. Expand **Protection** > **Conditional Access** and select **Policies**\n3. Click **New policy**\n4. Under **Users**, include **All users**\n5. Under **Target resources**, include **All cloud apps**\n6. Under **Conditions** > **Device platforms**, configure as **Yes** and select **Any device**\n7. Under **Grant**, select **Block access**\n8. Set the policy state to **On** and click **Create**",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Create a Conditional Access policy that blocks access from all device platforms and uses exclusions for known, supported platforms like Windows, macOS, iOS, and Android. This approach ensures that unknown or unsupported platforms are blocked by default.",
|
||||
"Url": "https://hub.prowler.com/check/entra_policy_unknown_unsupported_device_platforms_blocked"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"e3"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "This check is based on Maester test MT.1015 - Test-MtCaBlockUnknownOrUnsupportedDevicePlatform."
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
from prowler.lib.check.models import Check, CheckReportM365
|
||||
from prowler.providers.m365.services.entra.entra_client import entra_client
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessGrantControl,
|
||||
ConditionalAccessPolicyState,
|
||||
DevicePlatform,
|
||||
)
|
||||
|
||||
|
||||
class entra_policy_unknown_unsupported_device_platforms_blocked(Check):
|
||||
"""Check if at least one Conditional Access policy blocks unknown or unsupported device platforms.
|
||||
|
||||
This check verifies that the tenant has at least one enabled Conditional Access
|
||||
policy configured to block access from unknown or unsupported device platforms.
|
||||
|
||||
- PASS: At least one enabled policy blocks all device platforms.
|
||||
- FAIL: No policy is configured to block unknown or unsupported device platforms.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportM365]:
|
||||
"""Execute the check for Conditional Access policy blocking unknown device platforms.
|
||||
|
||||
Returns:
|
||||
list[CheckReportM365]: A list containing the results of the check.
|
||||
"""
|
||||
findings = []
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource={},
|
||||
resource_name="Conditional Access Policies",
|
||||
resource_id="conditionalAccessPolicies",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
|
||||
for policy in entra_client.conditional_access_policies.values():
|
||||
# Skip disabled policies
|
||||
if policy.state == ConditionalAccessPolicyState.DISABLED:
|
||||
continue
|
||||
|
||||
# Check if policy has block control
|
||||
if (
|
||||
ConditionalAccessGrantControl.BLOCK
|
||||
not in policy.grant_controls.built_in_controls
|
||||
):
|
||||
continue
|
||||
|
||||
# Check if policy targets all platforms
|
||||
if (
|
||||
policy.conditions.platform_conditions is None
|
||||
or DevicePlatform.ALL
|
||||
not in policy.conditions.platform_conditions.included_platforms
|
||||
):
|
||||
continue
|
||||
|
||||
# Policy meets all criteria
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.display_name,
|
||||
resource_id=policy.id,
|
||||
)
|
||||
|
||||
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports unknown device platforms but does not block them."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Conditional Access Policy '{policy.display_name}' blocks unknown or unsupported device platforms."
|
||||
break
|
||||
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -235,6 +235,30 @@ class Entra(M365Service):
|
||||
[],
|
||||
)
|
||||
],
|
||||
platform_conditions=(
|
||||
PlatformConditions(
|
||||
included_platforms=[
|
||||
DevicePlatform(platform.value)
|
||||
for platform in getattr(
|
||||
policy.conditions.platforms,
|
||||
"include_platforms",
|
||||
[],
|
||||
)
|
||||
or []
|
||||
],
|
||||
excluded_platforms=[
|
||||
DevicePlatform(platform.value)
|
||||
for platform in getattr(
|
||||
policy.conditions.platforms,
|
||||
"exclude_platforms",
|
||||
[],
|
||||
)
|
||||
or []
|
||||
],
|
||||
)
|
||||
if getattr(policy.conditions, "platforms", None)
|
||||
else None
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=(
|
||||
@@ -503,12 +527,33 @@ class ClientAppType(Enum):
|
||||
OTHER_CLIENTS = "other"
|
||||
|
||||
|
||||
class DevicePlatform(Enum):
|
||||
"""Device platforms for Conditional Access policies."""
|
||||
|
||||
ANDROID = "android"
|
||||
IOS = "iOS"
|
||||
WINDOWS = "windows"
|
||||
WINDOWS_PHONE = "windowsPhone"
|
||||
MAC_OS = "macOS"
|
||||
LINUX = "linux"
|
||||
ALL = "all"
|
||||
UNKNOWN_FUTURE_VALUE = "unknownFutureValue"
|
||||
|
||||
|
||||
class PlatformConditions(BaseModel):
|
||||
"""Platform conditions for Conditional Access policies."""
|
||||
|
||||
included_platforms: List[DevicePlatform] = []
|
||||
excluded_platforms: List[DevicePlatform] = []
|
||||
|
||||
|
||||
class Conditions(BaseModel):
|
||||
application_conditions: Optional[ApplicationsConditions]
|
||||
user_conditions: Optional[UsersConditions]
|
||||
client_app_types: Optional[List[ClientAppType]]
|
||||
user_risk_levels: List[RiskLevel] = []
|
||||
sign_in_risk_levels: List[RiskLevel] = []
|
||||
platform_conditions: Optional[PlatformConditions] = None
|
||||
|
||||
|
||||
class PersistentBrowser(BaseModel):
|
||||
|
||||
@@ -0,0 +1,703 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ApplicationsConditions,
|
||||
ConditionalAccessGrantControl,
|
||||
ConditionalAccessPolicyState,
|
||||
Conditions,
|
||||
DevicePlatform,
|
||||
GrantControlOperator,
|
||||
GrantControls,
|
||||
PersistentBrowser,
|
||||
PlatformConditions,
|
||||
SessionControls,
|
||||
SignInFrequency,
|
||||
SignInFrequencyInterval,
|
||||
UsersConditions,
|
||||
)
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_entra_policy_unknown_unsupported_device_platforms_blocked:
|
||||
"""Test cases for entra_policy_unknown_unsupported_device_platforms_blocked check."""
|
||||
|
||||
def test_entra_no_conditional_access_policies(self):
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Conditional Access Policies"
|
||||
assert result[0].resource_id == "conditionalAccessPolicies"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_disabled(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Block Unknown Platforms"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[
|
||||
DevicePlatform.ANDROID,
|
||||
DevicePlatform.IOS,
|
||||
DevicePlatform.WINDOWS,
|
||||
DevicePlatform.MAC_OS,
|
||||
],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.DISABLED,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Conditional Access Policies"
|
||||
assert result[0].resource_id == "conditionalAccessPolicies"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_no_block_control(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Policy Without Block"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.MFA,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Conditional Access Policies"
|
||||
assert result[0].resource_id == "conditionalAccessPolicies"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_no_platform_conditions(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Policy Without Platform Conditions"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=None,
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Conditional Access Policies"
|
||||
assert result[0].resource_id == "conditionalAccessPolicies"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_platform_not_all(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Policy With Specific Platforms"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[
|
||||
DevicePlatform.ANDROID,
|
||||
DevicePlatform.IOS,
|
||||
],
|
||||
excluded_platforms=[],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No Conditional Access Policy blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Conditional Access Policies"
|
||||
assert result[0].resource_id == "conditionalAccessPolicies"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_enabled_for_reporting(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Block Unknown Platforms - Report Only"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Conditional Access Policy '{display_name}' reports unknown device platforms but does not block them."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== entra_client.conditional_access_policies[policy_id].dict()
|
||||
)
|
||||
assert result[0].resource_name == display_name
|
||||
assert result[0].resource_id == policy_id
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_policy_enabled_blocks_unknown_platforms(self):
|
||||
policy_id = str(uuid4())
|
||||
display_name = "Block Unknown Platforms"
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
policy_id: ConditionalAccessPolicy(
|
||||
id=policy_id,
|
||||
display_name=display_name,
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[
|
||||
DevicePlatform.ANDROID,
|
||||
DevicePlatform.IOS,
|
||||
DevicePlatform.WINDOWS,
|
||||
DevicePlatform.MAC_OS,
|
||||
],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED,
|
||||
)
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Conditional Access Policy '{display_name}' blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== entra_client.conditional_access_policies[policy_id].dict()
|
||||
)
|
||||
assert result[0].resource_name == display_name
|
||||
assert result[0].resource_id == policy_id
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_multiple_policies_one_valid(self):
|
||||
disabled_policy_id = str(uuid4())
|
||||
enabled_policy_id = str(uuid4())
|
||||
entra_client = mock.MagicMock
|
||||
entra_client.audited_tenant = "audited_tenant"
|
||||
entra_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked.entra_client",
|
||||
new=entra_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.entra.entra_policy_unknown_unsupported_device_platforms_blocked.entra_policy_unknown_unsupported_device_platforms_blocked import (
|
||||
entra_policy_unknown_unsupported_device_platforms_blocked,
|
||||
)
|
||||
from prowler.providers.m365.services.entra.entra_service import (
|
||||
ConditionalAccessPolicy,
|
||||
)
|
||||
|
||||
entra_client.conditional_access_policies = {
|
||||
disabled_policy_id: ConditionalAccessPolicy(
|
||||
id=disabled_policy_id,
|
||||
display_name="Disabled Policy",
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.DISABLED,
|
||||
),
|
||||
enabled_policy_id: ConditionalAccessPolicy(
|
||||
id=enabled_policy_id,
|
||||
display_name="Enabled Block Policy",
|
||||
conditions=Conditions(
|
||||
application_conditions=ApplicationsConditions(
|
||||
included_applications=["All"],
|
||||
excluded_applications=[],
|
||||
included_user_actions=[],
|
||||
),
|
||||
user_conditions=UsersConditions(
|
||||
included_groups=[],
|
||||
excluded_groups=[],
|
||||
included_users=["All"],
|
||||
excluded_users=[],
|
||||
included_roles=[],
|
||||
excluded_roles=[],
|
||||
),
|
||||
client_app_types=[],
|
||||
user_risk_levels=[],
|
||||
platform_conditions=PlatformConditions(
|
||||
included_platforms=[DevicePlatform.ALL],
|
||||
excluded_platforms=[],
|
||||
),
|
||||
),
|
||||
grant_controls=GrantControls(
|
||||
built_in_controls=[
|
||||
ConditionalAccessGrantControl.BLOCK,
|
||||
],
|
||||
operator=GrantControlOperator.AND,
|
||||
authentication_strength=None,
|
||||
),
|
||||
session_controls=SessionControls(
|
||||
persistent_browser=PersistentBrowser(
|
||||
is_enabled=False, mode="always"
|
||||
),
|
||||
sign_in_frequency=SignInFrequency(
|
||||
is_enabled=False,
|
||||
frequency=None,
|
||||
type=None,
|
||||
interval=SignInFrequencyInterval.EVERY_TIME,
|
||||
),
|
||||
),
|
||||
state=ConditionalAccessPolicyState.ENABLED,
|
||||
),
|
||||
}
|
||||
|
||||
check = entra_policy_unknown_unsupported_device_platforms_blocked()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Conditional Access Policy 'Enabled Block Policy' blocks unknown or unsupported device platforms."
|
||||
)
|
||||
assert result[0].resource_name == "Enabled Block Policy"
|
||||
assert result[0].resource_id == enabled_policy_id
|
||||
assert result[0].location == "global"
|
||||
Reference in New Issue
Block a user