feat(entra): add new check entra_conditional_access_policy_all_apps_all_users (#10619)

Co-authored-by: Hugo P.Brito <hugopbrito@Mac.home>
This commit is contained in:
Hugo Pereira BritoandHugo P.Brito authored and GitHub committed 2026-04-14 12:47:57 +02:00
1 parent 0f4d8ff891
commit 4941ed5797
5 files changed
+1017

No files matched your search

+1
View File
@@ -6,6 +6,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
### 🚀 Added
- `entra_conditional_access_policy_all_apps_all_users` check for M365 provider [(#10619)](https://github.com/prowler-cloud/prowler/pull/10619)
- `bedrock_full_access_policy_attached` check for AWS provider [(#10577)](https://github.com/prowler-cloud/prowler/pull/10577)
- `iam_role_access_not_stale_to_bedrock` and `iam_user_access_not_stale_to_bedrock` checks for AWS provider [(#10536)](https://github.com/prowler-cloud/prowler/pull/10536)
- `iam_policy_no_wildcard_marketplace_subscribe` and `iam_inline_policy_no_wildcard_marketplace_subscribe` checks for AWS provider [(#10525)](https://github.com/prowler-cloud/prowler/pull/10525)
@@ -0,0 +1,37 @@
{
"Provider": "m365",
"CheckID": "entra_conditional_access_policy_all_apps_all_users",
"CheckTitle": "Conditional Access policy covers all cloud apps and all users",
"CheckType": [],
"ServiceName": "entra",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "low",
"ResourceType": "NotDefined",
"ResourceGroup": "IAM",
"Description": "Helper check that verifies whether **Microsoft Entra Conditional Access** includes at least one **enabled** policy scoped to **all cloud applications** and **all users**. Policies that only require a **password change** and **report-only** policies are excluded from passing. The result is intended to support other, more specific Conditional Access checks rather than enforce a baseline on its own.",
"Risk": "Without a Conditional Access policy that targets **all cloud apps** and **all users**, newly added applications or user accounts may not be covered by existing access controls until policies are explicitly updated.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://learn.microsoft.com/en-us/entra/identity/conditional-access/plan-conditional-access",
"https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-cloud-apps"
],
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Navigate to the Microsoft Entra admin center at https://entra.microsoft.com.\n2. Expand **Protection** > **Conditional Access** and select **Policies**.\n3. Click **New policy**.\n4. Under **Users**, select **Include** > **All users**. Exclude break-glass accounts as needed.\n5. Under **Target resources**, select **Include** > **All cloud apps**.\n6. Under **Grant**, select the desired access controls.\n7. Set the policy to **On** and click **Create**.",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure there is at least one **enabled** Conditional Access policy that targets **all cloud apps** and **all users** so that other Conditional Access checks have broad coverage to evaluate. Exclude only **break-glass accounts**.",
"Url": "https://hub.prowler.com/check/entra_conditional_access_policy_all_apps_all_users"
}
},
"Categories": [
"identity-access"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Generic helper check intended to support other Conditional Access checks. Conditional Access policies require Microsoft Entra ID P1 or P2 licenses."
}
@@ -0,0 +1,121 @@
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,
)
class entra_conditional_access_policy_all_apps_all_users(Check):
"""Check if at least one Conditional Access policy covers all cloud apps and all users.
This check verifies that at least one enabled Conditional Access policy
targets all cloud applications and all users, ensuring baseline protection
across the entire tenant. Policies that only require a password change are
excluded because they do not provide meaningful access control.
- PASS: An enabled Conditional Access policy covers all apps and all users with no exclusions.
- MANUAL: A policy targets all apps and all users but includes exclusions that require review.
- FAIL: No Conditional Access policy provides coverage for all apps and all users.
"""
def execute(self) -> list[CheckReportM365]:
"""Execute the check to verify Conditional Access coverage for all apps and all users.
Returns:
A list of reports containing the result 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 covers all cloud apps and all users."
)
manual_policy = None
reporting_only_policy = None
for policy in entra_client.conditional_access_policies.values():
if policy.state == ConditionalAccessPolicyState.DISABLED:
continue
application_conditions = policy.conditions.application_conditions
user_conditions = policy.conditions.user_conditions
if not application_conditions or not user_conditions:
continue
if "All" not in application_conditions.included_applications:
continue
if "All" not in user_conditions.included_users:
continue
# Exclude policies that only require a password change,
# as they do not provide meaningful access control.
if policy.grant_controls.built_in_controls == [
ConditionalAccessGrantControl.PASSWORD_CHANGE
]:
continue
has_exclusions = bool(
application_conditions.excluded_applications
or user_conditions.excluded_users
or user_conditions.excluded_groups
or user_conditions.excluded_roles
)
if has_exclusions:
if manual_policy is None:
manual_policy = policy
continue
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
if reporting_only_policy is None:
reporting_only_policy = policy
continue
report = CheckReportM365(
metadata=self.metadata(),
resource=policy,
resource_name=policy.display_name,
resource_id=policy.id,
)
report.status = "PASS"
report.status_extended = f"Conditional Access Policy {policy.display_name} covers all cloud apps and all users."
findings.append(report)
return findings
if manual_policy is not None:
report = CheckReportM365(
metadata=self.metadata(),
resource=manual_policy,
resource_name=manual_policy.display_name,
resource_id=manual_policy.id,
)
report.status = "MANUAL"
report.status_extended = (
f"Conditional Access Policy {manual_policy.display_name} "
"targets all cloud apps and all users but includes exclusions. "
"Review excluded users/groups/roles/applications and verify "
"compensating policies protect excluded identities and apps."
)
elif reporting_only_policy is not None:
report = CheckReportM365(
metadata=self.metadata(),
resource=reporting_only_policy,
resource_name=reporting_only_policy.display_name,
resource_id=reporting_only_policy.id,
)
report.status = "FAIL"
report.status_extended = (
f"Conditional Access Policy {reporting_only_policy.display_name} "
"covers all cloud apps and all users but is only in report-only mode."
)
findings.append(report)
return findings
@@ -0,0 +1,858 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
Conditions,
GrantControlOperator,
GrantControls,
PersistentBrowser,
SessionControls,
SignInFrequency,
SignInFrequencyInterval,
UsersConditions,
)
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users"
def _make_session_controls():
"""Return default session controls for test policies."""
return SessionControls(
persistent_browser=PersistentBrowser(is_enabled=False, mode="always"),
sign_in_frequency=SignInFrequency(
is_enabled=False,
frequency=None,
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
)
def _make_conditions(
included_applications=None,
included_users=None,
excluded_applications=None,
excluded_users=None,
excluded_groups=None,
excluded_roles=None,
):
"""Return Conditions with the given application and user scopes."""
return Conditions(
application_conditions=ApplicationsConditions(
included_applications=included_applications or ["All"],
excluded_applications=excluded_applications or [],
included_user_actions=[],
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=excluded_groups or [],
included_users=included_users or ["All"],
excluded_users=excluded_users or [],
included_roles=[],
excluded_roles=excluded_roles or [],
),
client_app_types=[],
user_risk_levels=[],
)
def _make_grant_controls(built_in_controls=None):
"""Return GrantControls with the given built-in controls."""
return GrantControls(
built_in_controls=built_in_controls or [ConditionalAccessGrantControl.MFA],
operator=GrantControlOperator.AND,
authentication_strength=None,
)
class Test_entra_conditional_access_policy_all_apps_all_users:
def test_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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
entra_client.conditional_access_policies = {}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_disabled(self):
policy_id = str(uuid4())
display_name = "All Apps All Users Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.DISABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_excluding_roles(self):
policy_id = str(uuid4())
display_name = "All Users Except Role Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(
excluded_roles=["62e90394-69f5-4237-9190-012177145e10"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} targets all cloud apps and all users but includes exclusions. Review excluded users/groups/roles/applications and verify compensating policies protect excluded identities and apps."
)
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_policy_not_targeting_all_apps(self):
policy_id = str(uuid4())
display_name = "Specific App Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(
included_applications=["some-app-id"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_not_targeting_all_users(self):
policy_id = str(uuid4())
display_name = "Specific Users Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(
included_users=["some-user-id"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_excluding_applications(self):
policy_id = str(uuid4())
display_name = "All Apps Except One Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(
excluded_applications=["excluded-app-id"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} targets all cloud apps and all users but includes exclusions. Review excluded users/groups/roles/applications and verify compensating policies protect excluded identities and apps."
)
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_policy_excluding_users(self):
policy_id = str(uuid4())
display_name = "All Users Except One Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(
excluded_users=["excluded-user-id"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} targets all cloud apps and all users but includes exclusions. Review excluded users/groups/roles/applications and verify compensating policies protect excluded identities and apps."
)
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_policy_only_password_change(self):
policy_id = str(uuid4())
display_name = "Password Change Only Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(),
grant_controls=_make_grant_controls(
built_in_controls=[
ConditionalAccessGrantControl.PASSWORD_CHANGE
],
),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_enabled_for_reporting(self):
policy_id = str(uuid4())
display_name = "All Apps All Users - 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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} covers all cloud apps and all users but is only in report-only mode."
)
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_policy_enabled_all_apps_all_users(self):
policy_id = str(uuid4())
display_name = "All Apps All Users Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} covers all cloud apps and all users."
)
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_multiple_policies_first_disabled_second_enabled(self):
disabled_id = str(uuid4())
enabled_id = str(uuid4())
enabled_name = "All Apps All Users - Enabled"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
from prowler.providers.m365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
disabled_id: ConditionalAccessPolicy(
id=disabled_id,
display_name="All Apps All Users - Disabled",
conditions=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.DISABLED,
),
enabled_id: ConditionalAccessPolicy(
id=enabled_id,
display_name=enabled_name,
conditions=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
),
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy {enabled_name} covers all cloud apps and all users."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[enabled_id].dict()
)
assert result[0].resource_name == enabled_name
assert result[0].resource_id == enabled_id
assert result[0].location == "global"
def test_policy_with_block_grant_control(self):
policy_id = str(uuid4())
display_name = "Block All Apps All Users"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=_make_conditions(),
grant_controls=_make_grant_controls(
built_in_controls=[ConditionalAccessGrantControl.BLOCK],
),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy {display_name} covers all cloud apps and all users."
)
assert result[0].resource_name == display_name
assert result[0].resource_id == policy_id
assert result[0].location == "global"
def test_manual_policy_does_not_prevent_later_pass(self):
manual_policy_id = str(uuid4())
pass_policy_id = str(uuid4())
manual_display_name = "All Apps All Users With Exclusions"
pass_display_name = "All Apps All Users Enforced"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
from prowler.providers.m365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
manual_policy_id: ConditionalAccessPolicy(
id=manual_policy_id,
display_name=manual_display_name,
conditions=_make_conditions(
excluded_users=["excluded-user-id"],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
),
pass_policy_id: ConditionalAccessPolicy(
id=pass_policy_id,
display_name=pass_display_name,
conditions=_make_conditions(),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
),
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy {pass_display_name} covers all cloud apps and all users."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[pass_policy_id].dict()
)
assert result[0].resource_name == pass_display_name
assert result[0].resource_id == pass_policy_id
def test_policy_no_application_conditions(self):
policy_id = str(uuid4())
display_name = "No App Conditions Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=None,
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=["All"],
excluded_users=[],
included_roles=[],
excluded_roles=[],
),
client_app_types=[],
user_risk_levels=[],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
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_policy_no_user_conditions(self):
policy_id = str(uuid4())
display_name = "No User Conditions Policy"
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(
f"{CHECK_MODULE_PATH}.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_conditional_access_policy_all_apps_all_users.entra_conditional_access_policy_all_apps_all_users import (
entra_conditional_access_policy_all_apps_all_users,
)
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=None,
client_app_types=[],
user_risk_levels=[],
),
grant_controls=_make_grant_controls(),
session_controls=_make_session_controls(),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_conditional_access_policy_all_apps_all_users()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy covers all cloud apps and all users."
)
assert result[0].resource == {}
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
assert result[0].location == "global"