feat(m365): add entra_app_enforced_restrictions security check (#10058)

This commit is contained in:
Hugo Pereira Brito
2026-02-25 11:53:35 +01:00
committed by GitHub
parent e47f2b4033
commit 6935c4eb1b
22 changed files with 1418 additions and 79 deletions

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -106,6 +107,9 @@ class Test_entra_admin_portals_access_restriction:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -181,6 +185,9 @@ class Test_entra_admin_portals_access_restriction:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -259,6 +266,9 @@ class Test_entra_admin_portals_access_restriction:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicy,
@@ -108,6 +109,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -184,6 +188,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -260,6 +267,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -341,6 +351,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -436,6 +449,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -530,6 +546,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -626,6 +645,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
),
@@ -677,6 +699,9 @@ class Test_entra_admin_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
),

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -125,6 +126,9 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -217,6 +221,9 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -312,6 +319,9 @@ class Test_entra_admin_users_phishing_resistant_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessPolicyState,
Conditions,
@@ -108,6 +109,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -200,6 +204,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -298,6 +305,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -393,6 +403,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -488,6 +501,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -586,6 +602,9 @@ class Test_entra_admin_users_sign_in_frequency_enabled:
type=SignInFrequencyType.DAYS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -225,17 +225,14 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
assert len(result) == 2
for finding in result:
assert finding.status == "FAIL"
assert (
"does not have any user or group excluded as emergency access"
in finding.status_extended
)
assert result[0].resource_name == "Policy 1"
assert result[0].resource_id == policy_id_1
assert result[1].resource_name == "Policy 2"
assert result[1].resource_id == policy_id_2
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
"No user or group is excluded as emergency access from all 2 enabled Conditional Access policies"
in result[0].status_extended
)
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
def test_entra_user_excluded_from_all_policies(self):
"""Test when a user is excluded from all enabled policies."""
@@ -339,17 +336,14 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
assert len(result) == 2
for finding in result:
assert finding.status == "PASS"
assert (
"1 user(s) excluded as emergency access across all 2 enabled policies"
in finding.status_extended
)
assert result[0].resource_name == "Policy 1"
assert result[0].resource_id == policy_id_1
assert result[1].resource_name == "Policy 2"
assert result[1].resource_id == policy_id_2
assert len(result) == 1
assert result[0].status == "PASS"
assert (
"1 user(s) excluded as emergency access across all 2 enabled Conditional Access policies"
in result[0].status_extended
)
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
def test_entra_group_excluded_from_all_policies(self):
"""Test when a group is excluded from all enabled policies."""
@@ -453,13 +447,14 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
assert len(result) == 2
for finding in result:
assert finding.status == "PASS"
assert (
"1 group(s) excluded as emergency access across all 2 enabled policies"
in finding.status_extended
)
assert len(result) == 1
assert result[0].status == "PASS"
assert (
"1 group(s) excluded as emergency access across all 2 enabled Conditional Access policies"
in result[0].status_extended
)
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
def test_entra_user_and_group_excluded_from_all_policies(self):
"""Test when both a user and group are excluded from all enabled policies."""
@@ -564,13 +559,14 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
assert len(result) == 2
for finding in result:
assert finding.status == "PASS"
assert (
"1 user(s) and 1 group(s) excluded as emergency access across all 2 enabled policies"
in finding.status_extended
)
assert len(result) == 1
assert result[0].status == "PASS"
assert (
"1 user(s) and 1 group(s) excluded as emergency access across all 2 enabled Conditional Access policies"
in result[0].status_extended
)
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
def test_entra_disabled_policies_ignored(self):
"""Test that disabled policies are ignored when checking exclusions."""
@@ -674,13 +670,12 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
# Only 1 enabled policy, so only 1 finding
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_name == "Enabled Policy"
assert result[0].resource_id == policy_id_1
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"
assert (
"1 user(s) excluded as emergency access across all 1 enabled policies"
"1 user(s) excluded as emergency access across all 1 enabled Conditional Access policies"
in result[0].status_extended
)
@@ -787,10 +782,11 @@ class Test_entra_emergency_access_exclusion:
check = entra_emergency_access_exclusion()
result = check.execute()
assert len(result) == 2
for finding in result:
assert finding.status == "PASS"
assert (
"1 user(s) excluded as emergency access across all 2 enabled policies"
in finding.status_extended
)
assert len(result) == 1
assert result[0].status == "PASS"
assert (
"1 user(s) excluded as emergency access across all 2 enabled Conditional Access policies"
in result[0].status_extended
)
assert result[0].resource_name == "Conditional Access Policies"
assert result[0].resource_id == "conditionalAccessPolicies"

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -109,6 +110,9 @@ class Test_entra_identity_protection_sign_in_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -189,6 +193,9 @@ class Test_entra_identity_protection_sign_in_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -272,6 +279,9 @@ class Test_entra_identity_protection_sign_in_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -355,6 +365,9 @@ class Test_entra_identity_protection_sign_in_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -108,6 +109,9 @@ class Test_entra_identity_protection_user_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -187,6 +191,9 @@ class Test_entra_identity_protection_user_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -269,6 +276,9 @@ class Test_entra_identity_protection_user_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -351,6 +361,9 @@ class Test_entra_identity_protection_user_risk_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessPolicyState,
Conditions,
@@ -108,6 +109,9 @@ class Test_entra_intune_enrollment_sign_in_frequency_every_time:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -184,6 +188,9 @@ class Test_entra_intune_enrollment_sign_in_frequency_every_time:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -258,6 +265,9 @@ class Test_entra_intune_enrollment_sign_in_frequency_every_time:
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
@@ -334,6 +344,9 @@ class Test_entra_intune_enrollment_sign_in_frequency_every_time:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ClientAppType,
ConditionalAccessGrantControl,
@@ -116,6 +117,9 @@ class Test_entra_legacy_authentication_blocked:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -198,6 +202,9 @@ class Test_entra_legacy_authentication_blocked:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -283,6 +290,9 @@ class Test_entra_legacy_authentication_blocked:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -106,6 +107,7 @@ class Test_entra_managed_device_required_for_authentication:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(is_enabled=False),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -184,6 +186,7 @@ class Test_entra_managed_device_required_for_authentication:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(is_enabled=False),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -266,6 +269,7 @@ class Test_entra_managed_device_required_for_authentication:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(is_enabled=False),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
@@ -107,6 +108,9 @@ class Test_entra_managed_device_required_for_mfa_registration:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -185,6 +189,9 @@ class Test_entra_managed_device_required_for_mfa_registration:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -267,6 +274,9 @@ class Test_entra_managed_device_required_for_mfa_registration:
type=None,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -2,6 +2,7 @@ from unittest import mock
from uuid import uuid4
from prowler.providers.m365.services.entra.entra_service import (
ApplicationEnforcedRestrictions,
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicy,
@@ -108,6 +109,9 @@ class Test_entra_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.DISABLED,
)
@@ -189,6 +193,9 @@ class Test_entra_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -268,6 +275,9 @@ class Test_entra_users_mfa_enabled:
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED,
)

View File

@@ -6,6 +6,7 @@ from prowler.providers.m365.models import M365IdentityInfo
from prowler.providers.m365.services.entra.entra_service import (
AdminConsentPolicy,
AdminRoles,
ApplicationEnforcedRestrictions,
ApplicationsConditions,
AuthorizationPolicy,
AuthPolicyRoles,
@@ -87,6 +88,9 @@ async def mock_entra_get_conditional_access_policies(_):
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
@@ -238,6 +242,9 @@ class Test_Entra_Service:
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
application_enforced_restrictions=ApplicationEnforcedRestrictions(
is_enabled=False
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)