feat(microsoft365): add new check entra_admin_users_sign_in_frequency_enabled (#7020)

Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
Hugo Pereira Brito
2025-03-11 19:18:33 +01:00
committed by GitHub
parent 605613e220
commit c88ae32b7f
11 changed files with 1438 additions and 20 deletions
+7
View File
@@ -475,3 +475,10 @@ kubernetes:
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
]
# Microsoft365 Configuration
microsoft365:
# Conditional Access Policy
# policy.session_controls.sign_in_frequency.frequency in hours
sign_in_frequency: 4
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "entra_admin_portals_role_limited_access",
"CheckTitle": "Ensure that only administrative roles have access to Microsoft Admin Portals",
"CheckType": [],
"ServiceName": "entra",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Conditional Access Policy",
"Description": "Ensure that only administrative roles have access to Microsoft Admin Portals to prevent unauthorized changes, privilege escalation, and security misconfigurations.",
"Risk": "Allowing non-administrative users to access Microsoft Admin Portals increases the risk of unauthorized changes, privilege escalation, and potential security misconfigurations. Attackers could exploit these privileges to manipulate settings, disable security features, or access sensitive data.",
"RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/admin/add-users/about-admin-roles?view=o365-worldwide",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Navigate to the Microsoft Entra admin center https://entra.microsoft.com. 2. Click expand Protection > Conditional Access select Policies. 3. Click New Policy. Under Users include All Users. Under Users select Exclude and check Directory roles and select only administrative roles and a group of PIM eligible users. Under Target resources select Cloud apps and Select apps then select the Microsoft Admin Portals app. Confirm by clicking Select. Under Grant select Block access and click Select. 4. Under Enable policy set it to Report Only until the organization is ready to enable it. 5. Click Create.",
"Terraform": ""
},
"Recommendation": {
"Text": "Enforce Conditional Access policies to restrict Microsoft Admin Portals to predefined administrative roles. Ensure that only necessary users have access to these portals, applying the principle of least privilege and conducting periodic access reviews to maintain security compliance.",
"Url": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/overview"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,71 @@
from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.entra.entra_client import entra_client
from prowler.providers.microsoft365.services.entra.entra_service import (
AdminRoles,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
)
class entra_admin_portals_role_limited_access(Check):
"""Check if Conditional Access policies deny access to the Microsoft 365 admin center for users with limited access roles.
This check ensures that Conditional Access policies are in place to deny access to the Microsoft 365 admin center for users with limited access roles.
"""
def execute(self) -> list[CheckReportMicrosoft365]:
"""Execute the check to ensure that Conditional Access policies deny access to the Microsoft 365 admin center for users with limited access roles.
Returns:
list[CheckReportMicrosoft365]: A list containing the results of the check.
"""
findings = []
report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource={},
resource_name="Conditional Access Policies",
resource_id="conditionalAccessPolicies",
)
report.status = "FAIL"
report.status_extended = "No Conditional Access Policy limits Entra Admin Center access to administrative roles."
for policy in entra_client.conditional_access_policies.values():
if policy.state == ConditionalAccessPolicyState.DISABLED:
continue
if not (
{
role for role in policy.conditions.user_conditions.excluded_roles
}.issubset({admin_role.value for admin_role in AdminRoles})
and "All" in policy.conditions.user_conditions.included_users
):
continue
if (
"MicrosoftAdminPortals"
not in policy.conditions.application_conditions.included_applications
):
continue
if (
ConditionalAccessGrantControl.BLOCK
in policy.grant_controls.built_in_controls
):
report = CheckReportMicrosoft365(
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 Entra Admin Center access to administrative roles but does not limit it."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' limits Entra Admin Center access to administrative roles."
break
findings.append(report)
return findings
@@ -0,0 +1,30 @@
{
"Provider": "microsoft365",
"CheckID": "entra_admin_users_sign_in_frequency_enabled",
"CheckTitle": "Ensure Sign-in frequency periodic reauthentication is enabled and properly configured.",
"CheckType": [],
"ServiceName": "entra",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Conditional Access Policy",
"Description": "Ensure Sign-in frequency periodic reauthentication is enabled and properly configured to reduce the risk of unauthorized access and session hijacking.",
"Risk": "Allowing persistent browser sessions and long sign-in frequencies for administrative users increases the risk of unauthorized access. Attackers could exploit session persistence to maintain access to an admin account without reauthentication, increasing the likelihood of account compromise, especially in cases of credential theft or session hijacking.",
"RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-session#sign-in-frequency",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "1. Navigate to Microsoft Entra admin center https://entra.microsoft.com/. 2. Click to expand Protection > Conditional Access Select Policies. 3. Click New policy. Under Users include, select users and groups and check Directory roles. At a minimum, include the directory roles listed below in this section of the document. Under Target resources, include All cloud apps and do not create any exclusions. Under Grant, select Grant Access and check Require multifactor authentication. Under Session, select Sign-in frequency, select Periodic reauthentication, and set it to 4 hours for E3 tenants. E5 tenants with PIM can be set to a maximum value of 24 hours. Check Persistent browser session, then select Never persistent in the drop-down menu. 4. Under Enable policy, set it to Report Only until the organization is ready to enable it.",
"Terraform": ""
},
"Recommendation": {
"Text": "Enforce a sign-in frequency limit of no more than 4 hours for E3 tenants (or 24 hours for E5 with Privileged Identity Management) and set browser sessions to Never persistent. This ensures that administrative users are regularly reauthenticated, reducing the risk of prolonged unauthorized access and mitigating session hijacking threats.",
"Url": "https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-session-lifetime#user-sign-in-frequency"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,87 @@
from prowler.lib.check.models import Check, CheckReportMicrosoft365
from prowler.providers.microsoft365.services.entra.entra_client import entra_client
from prowler.providers.microsoft365.services.entra.entra_service import (
AdminRoles,
ConditionalAccessPolicyState,
SignInFrequencyInterval,
SignInFrequencyType,
)
class entra_admin_users_sign_in_frequency_enabled(Check):
"""Check if Conditional Access policies enforce sign-in frequency for admin users."""
def execute(self) -> list[CheckReportMicrosoft365]:
"""Validate sign-in frequency enforcement for admin users."""
findings = []
report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource={},
resource_name="Conditional Access Policies",
resource_id="conditionalAccessPolicies",
)
report.status = "FAIL"
report.status_extended = (
"No Conditional Access Policy enforces sign-in frequency for admin users."
)
recommended_frequency = entra_client.audit_config.get("sign_in_frequency", 4)
for policy in entra_client.conditional_access_policies.values():
if (
policy.state == ConditionalAccessPolicyState.DISABLED
or not {role.value for role in AdminRoles}.issuperset(
policy.conditions.user_conditions.included_roles
)
or "All"
not in policy.conditions.application_conditions.included_applications
or not policy.session_controls.sign_in_frequency.is_enabled
or not policy.session_controls.persistent_browser.is_enabled
or policy.session_controls.persistent_browser.mode != "never"
):
continue
report = CheckReportMicrosoft365(
metadata=self.metadata(),
resource=policy,
resource_name=policy.display_name,
resource_id=policy.id,
)
if (
policy.session_controls.sign_in_frequency.interval
== SignInFrequencyInterval.EVERY_TIME
):
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' only reports when sign-in frequency is 'Every Time' for admin users but does not enforce it."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces sign-in frequency 'Every Time' for admin users."
break
elif (
policy.session_controls.sign_in_frequency.interval
== SignInFrequencyInterval.TIME_BASED
):
frequency_hours = (
policy.session_controls.sign_in_frequency.frequency
if policy.session_controls.sign_in_frequency.type
== SignInFrequencyType.HOURS
else policy.session_controls.sign_in_frequency.frequency * 24
)
if frequency_hours > recommended_frequency:
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces sign-in frequency at {frequency_hours} hours for admin users, exceeding the recommended {recommended_frequency} hours."
else:
if (
policy.state
== ConditionalAccessPolicyState.ENABLED_FOR_REPORTING
):
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' only reports when sign-in frequency is {frequency_hours} hours for admin users but does not enforce it."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' enforces sign-in frequency at {frequency_hours} hours for admin users."
break
findings.append(report)
return findings
@@ -1,4 +1,5 @@
from asyncio import gather, get_event_loop
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel
@@ -17,18 +18,19 @@ class Entra(Microsoft365Service):
attributes = loop.run_until_complete(
gather(
self._get_authorization_policy(),
self._get_groups(),
self._get_conditional_access_policies(),
self._get_admin_consent_policy(),
self._get_groups(),
)
)
self.authorization_policy = attributes[0]
self.groups = attributes[1]
self.conditional_access_policies = attributes[1]
self.admin_consent_policy = attributes[2]
self.groups = attributes[3]
async def _get_authorization_policy(self):
logger.info("Entra - Getting authorization policy...")
authorization_policy = None
try:
auth_policy = await self.client.policies.authorization_policy.get()
@@ -84,9 +86,175 @@ class Entra(Microsoft365Service):
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return authorization_policy
async def _get_conditional_access_policies(self):
logger.info("Entra - Getting conditional access policies...")
conditional_access_policies = {}
try:
conditional_access_policies_list = (
await self.client.identity.conditional_access.policies.get()
)
for policy in conditional_access_policies_list.value:
conditional_access_policies[policy.id] = ConditionalAccessPolicy(
id=policy.id,
display_name=policy.display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=[
application
for application in getattr(
policy.conditions.applications,
"include_applications",
[],
)
],
excluded_applications=[
application
for application in getattr(
policy.conditions.applications,
"exclude_applications",
[],
)
],
),
user_conditions=UsersConditions(
included_groups=[
group
for group in getattr(
policy.conditions.users,
"include_groups",
[],
)
],
excluded_groups=[
group
for group in getattr(
policy.conditions.users,
"exclude_groups",
[],
)
],
included_users=[
user
for user in getattr(
policy.conditions.users,
"include_users",
[],
)
],
excluded_users=[
user
for user in getattr(
policy.conditions.users,
"exclude_users",
[],
)
],
included_roles=[
role
for role in getattr(
policy.conditions.users,
"include_roles",
[],
)
],
excluded_roles=[
role
for role in getattr(
policy.conditions.users,
"exclude_roles",
[],
)
],
),
),
grant_controls=GrantControls(
built_in_controls=(
[
ConditionalAccessGrantControl(control.value)
for control in getattr(
policy.grant_controls, "built_in_controls", {}
)
]
if policy.grant_controls
else []
)
),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=(
policy.session_controls.persistent_browser.is_enabled
if policy.session_controls
and policy.session_controls.persistent_browser
else False
),
mode=(
policy.session_controls.persistent_browser.mode
if policy.session_controls
and policy.session_controls.persistent_browser
else "always"
),
),
sign_in_frequency=SignInFrequency(
is_enabled=(
policy.session_controls.sign_in_frequency.is_enabled
if policy.session_controls
and policy.session_controls.sign_in_frequency
else False
),
frequency=(
policy.session_controls.sign_in_frequency.value
if policy.session_controls
and policy.session_controls.sign_in_frequency
else None
),
type=(
SignInFrequencyType(
policy.session_controls.sign_in_frequency.type
)
if policy.session_controls
and policy.session_controls.sign_in_frequency
and policy.session_controls.sign_in_frequency.type
else None
),
interval=(
SignInFrequencyInterval(
policy.session_controls.sign_in_frequency.frequency_interval
)
if policy.session_controls
and policy.session_controls.sign_in_frequency
else None
),
),
),
state=ConditionalAccessPolicyState(
getattr(policy, "state", "disabled")
),
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return conditional_access_policies
async def _get_admin_consent_policy(self):
logger.info("Entra - Getting group settings...")
admin_consent_policy = None
try:
policy = await self.client.policies.admin_consent_request_policy.get()
admin_consent_policy = AdminConsentPolicy(
admin_consent_enabled=policy.is_enabled,
notify_reviewers=policy.notify_reviewers,
email_reminders_to_reviewers=policy.reminders_enabled,
duration_in_days=policy.request_duration_in_days,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return admin_consent_policy
async def _get_groups(self):
logger.info("Entra - Getting groups...")
groups = []
@@ -107,23 +275,75 @@ class Entra(Microsoft365Service):
)
return groups
async def _get_admin_consent_policy(self):
logger.info("Entra - Getting group settings...")
admin_consent_policy = None
try:
policy = await self.client.policies.admin_consent_request_policy.get()
admin_consent_policy = AdminConsentPolicy(
admin_consent_enabled=policy.is_enabled,
notify_reviewers=policy.notify_reviewers,
email_reminders_to_reviewers=policy.reminders_enabled,
duration_in_days=policy.request_duration_in_days,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return admin_consent_policy
class ConditionalAccessPolicyState(Enum):
ENABLED = "enabled"
DISABLED = "disabled"
ENABLED_FOR_REPORTING = "enabledForReportingButNotEnforced"
class ApplicationsConditions(BaseModel):
included_applications: List[str]
excluded_applications: List[str]
class UsersConditions(BaseModel):
included_groups: List[str]
excluded_groups: List[str]
included_users: List[str]
excluded_users: List[str]
included_roles: List[str]
excluded_roles: List[str]
class Conditions(BaseModel):
application_conditions: Optional[ApplicationsConditions]
user_conditions: Optional[UsersConditions]
class PersistentBrowser(BaseModel):
is_enabled: bool
mode: str
class SignInFrequencyInterval(Enum):
TIME_BASED = "timeBased"
EVERY_TIME = "everyTime"
class SignInFrequencyType(Enum):
HOURS = "hours"
DAYS = "days"
class SignInFrequency(BaseModel):
is_enabled: bool
frequency: Optional[int]
type: Optional[SignInFrequencyType]
interval: Optional[SignInFrequencyInterval]
class SessionControls(BaseModel):
persistent_browser: PersistentBrowser
sign_in_frequency: SignInFrequency
class ConditionalAccessGrantControl(Enum):
MFA = "mfa"
BLOCK = "block"
class GrantControls(BaseModel):
built_in_controls: List[ConditionalAccessGrantControl]
class ConditionalAccessPolicy(BaseModel):
id: str
display_name: str
conditions: Conditions
session_controls: SessionControls
grant_controls: GrantControls
state: ConditionalAccessPolicyState
class DefaultUserRolePermissions(BaseModel):
@@ -155,3 +375,21 @@ class AdminConsentPolicy(BaseModel):
notify_reviewers: bool
email_reminders_to_reviewers: bool
duration_in_days: int
class AdminRoles(Enum):
APPLICATION_ADMINISTRATOR = "9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3"
AUTHENTICATION_ADMINISTRATOR = "c4e39bd9-1100-46d3-8c65-fb160da0071f"
BILLING_ADMINISTRATOR = "b0f54661-2d74-4c50-afa3-1ec803f12efe"
CLOUD_APPLICATION_ADMINISTRATOR = "158c047a-c907-4556-b7ef-446551a6b5f7"
CONDITIONAL_ACCESS_ADMINISTRATOR = "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9"
EXCHANGE_ADMINISTRATOR = "29232cdf-9323-42fd-ade2-1d097af3e4de"
GLOBAL_ADMINISTRATOR = "62e90394-69f5-4237-9190-012177145e10"
GLOBAL_READER = "f2ef992c-3afb-46b9-b7cf-a126ee74c451"
HELPDESK_ADMINISTRATOR = "729827e3-9c14-49f7-bb1b-9608f156bbb8"
PASSWORD_ADMINISTRATOR = "966707d0-3269-4727-9be2-8c3a10f19b9d"
PRIVILEGED_AUTHENTICATION_ADMINISTRATOR = "7be44c8a-adaf-4e2a-84d6-ab2649e08a13"
PRIVILEGED_ROLE_ADMINISTRATOR = "e8611ab8-c189-46e8-94e1-60213ab1f814"
SECURITY_ADMINISTRATOR = "194ae4cb-b126-40b2-bd5b-6091b380977d"
SHAREPOINT_ADMINISTRATOR = "f28a1f50-f6e7-4571-818b-6a12f2af6b6c"
USER_ADMINISTRATOR = "fe930be7-5e62-47db-91af-98c3a49a38b1"
@@ -0,0 +1,275 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.microsoft365.services.entra.entra_service import (
ApplicationsConditions,
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
Conditions,
GrantControls,
PersistentBrowser,
SessionControls,
SignInFrequency,
SignInFrequencyInterval,
UsersConditions,
)
from tests.providers.microsoft365.microsoft365_fixtures import (
DOMAIN,
set_mocked_microsoft365_provider,
)
class Test_entra_admin_portals_role_limited_access:
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import (
entra_admin_portals_role_limited_access,
)
entra_client.conditional_access_policies = {}
check = entra_admin_portals_role_limited_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy limits Entra Admin Center access to administrative roles."
)
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_admin_center_limited_access_disabled(self):
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import (
entra_admin_portals_role_limited_access,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name="Test",
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=[], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
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_admin_portals_role_limited_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy limits Entra Admin Center access to administrative roles."
)
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_admin_center_limited_access_enabled_for_reporting(self):
id = str(uuid4())
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import (
entra_admin_portals_role_limited_access,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["MicrosoftAdminPortals"],
excluded_applications=[],
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=["All"],
excluded_users=[],
included_roles=[],
excluded_roles=["9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3"],
),
),
grant_controls=GrantControls(
built_in_controls=[ConditionalAccessGrantControl.BLOCK]
),
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_admin_portals_role_limited_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' reports Entra Admin Center access to administrative roles but does not limit it."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_admin_center_limited_access_enabled(self):
id = str(uuid4())
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_portals_role_limited_access.entra_admin_portals_role_limited_access import (
entra_admin_portals_role_limited_access,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["MicrosoftAdminPortals"],
excluded_applications=[],
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=["All"],
excluded_users=[],
included_roles=[],
excluded_roles=["9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3"],
),
),
grant_controls=GrantControls(
built_in_controls=[ConditionalAccessGrantControl.BLOCK]
),
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_admin_portals_role_limited_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' limits Entra Admin Center access to administrative roles."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
@@ -0,0 +1,586 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.microsoft365.services.entra.entra_service import (
ApplicationsConditions,
ConditionalAccessPolicyState,
Conditions,
GrantControls,
PersistentBrowser,
SessionControls,
SignInFrequency,
SignInFrequencyInterval,
SignInFrequencyType,
UsersConditions,
)
from tests.providers.microsoft365.microsoft365_fixtures import (
DOMAIN,
set_mocked_microsoft365_provider,
)
class Test_entra_admin_users_sign_in_frequency_enabled:
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
entra_client.conditional_access_policies = {}
entra_client.audit_config = {"sign_in_frequency": 4}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy enforces sign-in frequency for admin 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_entra_sign_in_frequency_disabled(self):
id = str(uuid4())
entra_client = mock.MagicMock
entra_client.audited_tenant = "audited_tenant"
entra_client.audited_domain = DOMAIN
entra_client.audit_config = {"sign_in_frequency": 4}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name="Test",
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=[], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
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_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "No Conditional Access Policy enforces sign-in frequency for admin 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_entra_sign_in_frequency_enabled_every_time(self):
id = str(uuid4())
freq = None
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.audit_config = {"sign_in_frequency": 4}
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["All"], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"c4e39bd9-1100-46d3-8c65-fb160da0071f",
"b0f54661-2d74-4c50-afa3-1ec803f12efe",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"29232cdf-9323-42fd-ade2-1d097af3e4de",
"62e90394-69f5-4237-9190-012177145e10",
"f2ef992c-3afb-46b9-b7cf-a126ee74c451",
"729827e3-9c14-49f7-bb1b-9608f156bbb8",
"966707d0-3269-4727-9be2-8c3a10f19b9d",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d",
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c",
"fe930be7-5e62-47db-91af-98c3a49a38b1",
],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True, mode="never"
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=freq,
type=None,
interval=SignInFrequencyInterval.EVERY_TIME,
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' enforces sign-in frequency 'Every Time' for admin users."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_sign_in_frequency_enabled_bad_frequency(self):
id = str(uuid4())
freq = 3600
recommended_sign_in_frequency = 4
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.audit_config = {
"sign_in_frequency": recommended_sign_in_frequency
}
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["All"], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"c4e39bd9-1100-46d3-8c65-fb160da0071f",
"b0f54661-2d74-4c50-afa3-1ec803f12efe",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"29232cdf-9323-42fd-ade2-1d097af3e4de",
"62e90394-69f5-4237-9190-012177145e10",
"f2ef992c-3afb-46b9-b7cf-a126ee74c451",
"729827e3-9c14-49f7-bb1b-9608f156bbb8",
"966707d0-3269-4727-9be2-8c3a10f19b9d",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d",
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c",
"fe930be7-5e62-47db-91af-98c3a49a38b1",
],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True, mode="never"
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=freq,
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' enforces sign-in frequency at {freq} hours for admin users, exceeding the recommended {recommended_sign_in_frequency} hours."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_sign_in_frequency_enabled_for_reporting(self):
id = str(uuid4())
freq = 4
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.audit_config = {"sign_in_frequency": freq}
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["All"], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"c4e39bd9-1100-46d3-8c65-fb160da0071f",
"b0f54661-2d74-4c50-afa3-1ec803f12efe",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"29232cdf-9323-42fd-ade2-1d097af3e4de",
"62e90394-69f5-4237-9190-012177145e10",
"f2ef992c-3afb-46b9-b7cf-a126ee74c451",
"729827e3-9c14-49f7-bb1b-9608f156bbb8",
"966707d0-3269-4727-9be2-8c3a10f19b9d",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d",
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c",
"fe930be7-5e62-47db-91af-98c3a49a38b1",
],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True, mode="never"
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=freq,
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' only reports when sign-in frequency is {freq} hours for admin users but does not enforce it."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_sign_in_frequency_enabled(self):
id = str(uuid4())
freq = 4
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.audit_config = {"sign_in_frequency": freq}
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["All"], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"c4e39bd9-1100-46d3-8c65-fb160da0071f",
"b0f54661-2d74-4c50-afa3-1ec803f12efe",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"29232cdf-9323-42fd-ade2-1d097af3e4de",
"62e90394-69f5-4237-9190-012177145e10",
"f2ef992c-3afb-46b9-b7cf-a126ee74c451",
"729827e3-9c14-49f7-bb1b-9608f156bbb8",
"966707d0-3269-4727-9be2-8c3a10f19b9d",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d",
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c",
"fe930be7-5e62-47db-91af-98c3a49a38b1",
],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True, mode="never"
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=freq,
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' enforces sign-in frequency at {freq} hours for admin users."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
def test_entra_sign_in_frequency_enabled_in_days(self):
id = str(uuid4())
freq = 1
recommended_sign_in_frequency = 24
display_name = "Test"
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_microsoft365_provider(),
),
mock.patch(
"prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled.entra_client",
new=entra_client,
),
):
from prowler.providers.microsoft365.services.entra.entra_admin_users_sign_in_frequency_enabled.entra_admin_users_sign_in_frequency_enabled import (
entra_admin_users_sign_in_frequency_enabled,
)
from prowler.providers.microsoft365.services.entra.entra_service import (
ConditionalAccessPolicy,
)
entra_client.audit_config = {
"sign_in_frequency": recommended_sign_in_frequency
}
entra_client.conditional_access_policies = {
id: ConditionalAccessPolicy(
id=id,
display_name=display_name,
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["All"], excluded_applications=[]
),
user_conditions=UsersConditions(
included_groups=[],
excluded_groups=[],
included_users=[],
excluded_users=[],
included_roles=[
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3",
"c4e39bd9-1100-46d3-8c65-fb160da0071f",
"b0f54661-2d74-4c50-afa3-1ec803f12efe",
"158c047a-c907-4556-b7ef-446551a6b5f7",
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9",
"29232cdf-9323-42fd-ade2-1d097af3e4de",
"62e90394-69f5-4237-9190-012177145e10",
"f2ef992c-3afb-46b9-b7cf-a126ee74c451",
"729827e3-9c14-49f7-bb1b-9608f156bbb8",
"966707d0-3269-4727-9be2-8c3a10f19b9d",
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13",
"e8611ab8-c189-46e8-94e1-60213ab1f814",
"194ae4cb-b126-40b2-bd5b-6091b380977d",
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c",
"fe930be7-5e62-47db-91af-98c3a49a38b1",
],
excluded_roles=[],
),
),
grant_controls=GrantControls(built_in_controls=[]),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True, mode="never"
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=freq,
type=SignInFrequencyType.DAYS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED,
)
}
check = entra_admin_users_sign_in_frequency_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Conditional Access Policy '{display_name}' enforces sign-in frequency at {recommended_sign_in_frequency} hours for admin users."
)
assert (
result[0].resource
== entra_client.conditional_access_policies[id].dict()
)
assert result[0].resource_name == display_name
assert result[0].resource_id == id
assert result[0].location == "global"
@@ -3,9 +3,21 @@ from unittest.mock import patch
from prowler.providers.microsoft365.models import Microsoft365IdentityInfo
from prowler.providers.microsoft365.services.entra.entra_service import (
AdminConsentPolicy,
ApplicationsConditions,
AuthorizationPolicy,
ConditionalAccessGrantControl,
ConditionalAccessPolicy,
ConditionalAccessPolicyState,
Conditions,
DefaultUserRolePermissions,
Entra,
GrantControls,
PersistentBrowser,
SessionControls,
SignInFrequency,
SignInFrequencyInterval,
SignInFrequencyType,
UsersConditions,
)
from tests.providers.microsoft365.microsoft365_fixtures import (
DOMAIN,
@@ -28,6 +40,45 @@ async def mock_entra_get_authorization_policy(_):
)
async def mock_entra_get_conditional_access_policies(_):
return {
"id-1": ConditionalAccessPolicy(
id="id-1",
display_name="Name 1",
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["app-1", "app-2"],
excluded_applications=["app-3", "app-4"],
),
user_conditions=UsersConditions(
included_groups=["group-1", "group-2"],
excluded_groups=["group-3", "group-4"],
included_users=["user-1", "user-2"],
excluded_users=["user-3", "user-4"],
included_roles=["role-1", "role-2"],
excluded_roles=["role-3", "role-4"],
),
),
grant_controls=GrantControls(
built_in_controls=[ConditionalAccessGrantControl.BLOCK]
),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True,
mode="always",
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=24,
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
}
async def mock_entra_get_groups(_):
group1 = {
"id": "id-1",
@@ -82,6 +133,49 @@ class Test_Entra_Service:
)
)
@patch(
"prowler.providers.microsoft365.services.entra.entra_service.Entra._get_conditional_access_policies",
new=mock_entra_get_conditional_access_policies,
)
def test_get_conditional_access_policies(self):
entra_client = Entra(set_mocked_microsoft365_provider())
assert entra_client.conditional_access_policies == {
"id-1": ConditionalAccessPolicy(
id="id-1",
display_name="Name 1",
conditions=Conditions(
application_conditions=ApplicationsConditions(
included_applications=["app-1", "app-2"],
excluded_applications=["app-3", "app-4"],
),
user_conditions=UsersConditions(
included_groups=["group-1", "group-2"],
excluded_groups=["group-3", "group-4"],
included_users=["user-1", "user-2"],
excluded_users=["user-3", "user-4"],
included_roles=["role-1", "role-2"],
excluded_roles=["role-3", "role-4"],
),
),
grant_controls=GrantControls(
built_in_controls=[ConditionalAccessGrantControl.BLOCK]
),
session_controls=SessionControls(
persistent_browser=PersistentBrowser(
is_enabled=True,
mode="always",
),
sign_in_frequency=SignInFrequency(
is_enabled=True,
frequency=24,
type=SignInFrequencyType.HOURS,
interval=SignInFrequencyInterval.TIME_BASED,
),
),
state=ConditionalAccessPolicyState.ENABLED_FOR_REPORTING,
)
}
@patch(
"prowler.providers.microsoft365.services.entra.entra_service.Entra._get_groups",
new=mock_entra_get_groups,