mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
refactor(microsoft365): CheckReportMicrosoft365 and resource metadata (#6952)
This commit is contained in:
@@ -536,26 +536,34 @@ class Check_Report_Kubernetes(Check_Report):
|
||||
|
||||
|
||||
@dataclass
|
||||
class Check_Report_Microsoft365(Check_Report):
|
||||
class CheckReportMicrosoft365(Check_Report):
|
||||
"""Contains the Microsoft365 Check's finding information."""
|
||||
|
||||
resource_name: str
|
||||
resource_id: str
|
||||
location: str
|
||||
|
||||
def __init__(self, metadata: Dict, resource: Any) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
metadata: Dict,
|
||||
resource: Any,
|
||||
resource_name: str,
|
||||
resource_id: str,
|
||||
resource_location: str = "global",
|
||||
) -> None:
|
||||
"""Initialize the Microsoft365 Check's finding information.
|
||||
|
||||
Args:
|
||||
metadata: The metadata of the check.
|
||||
resource: Basic information about the resource. Defaults to None.
|
||||
resource_name: The name of the resource related with the finding.
|
||||
resource_id: The id of the resource related with the finding.
|
||||
resource_location: The location of the resource related with the finding.
|
||||
"""
|
||||
super().__init__(metadata, resource)
|
||||
self.resource_name = getattr(
|
||||
resource, "name", getattr(resource, "resource_name", "")
|
||||
)
|
||||
self.resource_id = getattr(resource, "id", getattr(resource, "resource_id", ""))
|
||||
self.location = getattr(resource, "location", "global")
|
||||
self.resource_name = resource_name
|
||||
self.resource_id = resource_id
|
||||
self.location = resource_location
|
||||
|
||||
|
||||
# Testing Pending
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from prowler.lib.check.models import Check_Report_Microsoft365
|
||||
from prowler.lib.check.models import CheckReportMicrosoft365
|
||||
from prowler.lib.mutelist.mutelist import Mutelist
|
||||
from prowler.lib.outputs.utils import unroll_dict, unroll_tags
|
||||
|
||||
@@ -6,7 +6,7 @@ from prowler.lib.outputs.utils import unroll_dict, unroll_tags
|
||||
class Microsoft365Mutelist(Mutelist):
|
||||
def is_finding_muted(
|
||||
self,
|
||||
finding: Check_Report_Microsoft365,
|
||||
finding: CheckReportMicrosoft365,
|
||||
) -> bool:
|
||||
return self.is_muted(
|
||||
finding.tenant_id,
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Microsoft365Group",
|
||||
"ResourceType": "Active teams & groups",
|
||||
"Description": "Ensure that only organizationally managed and approved public groups exist to prevent unauthorized access to sensitive group resources like SharePoint, Teams, or other shared assets.",
|
||||
"Risk": "Unmanaged public groups can allow unauthorized access to organizational resources, posing a risk of data leakage or misuse through easily guessable SharePoint URLs or self-adding to groups via the Azure portal.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/admin/create-groups/manage-groups?view=o365-worldwide",
|
||||
@@ -15,7 +15,7 @@
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Other": "1. Navigate to Microsoft 365 admin center https://admin.microsoft.com. 2. Click to expand Teams & groups select Active teams & groups. 3. On the Active teams and groups page, select the group's name that is public. 4. On the popup groups name page, select Settings. 5. Under Privacy, select Private.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
|
||||
+27
-5
@@ -1,16 +1,38 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Microsoft365
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportMicrosoft365
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_client import (
|
||||
admincenter_client,
|
||||
)
|
||||
|
||||
|
||||
class admincenter_groups_not_public_visibility(Check):
|
||||
def execute(self) -> Check_Report_Microsoft365:
|
||||
"""Check if groups in Microsoft Admin Center have public visibility.
|
||||
|
||||
This check verifies whether the visibility of groups in Microsoft Admin Center
|
||||
is set to 'Private'. If any group has a 'Public' visibility, the check fails.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportMicrosoft365]:
|
||||
"""Execute the check for groups with public visibility.
|
||||
|
||||
This method iterates through all groups in Microsoft Admin Center and checks
|
||||
if any group has 'Public' visibility. If so, the check fails for that group.
|
||||
|
||||
Returns:
|
||||
List[CheckReportMicrosoft365]: A list containing the results of the check for each group.
|
||||
"""
|
||||
findings = []
|
||||
for group in admincenter_client.groups.values():
|
||||
report = Check_Report_Microsoft365(metadata=self.metadata(), resource=group)
|
||||
report.resource_id = group.id
|
||||
report.resource_name = group.name
|
||||
report = CheckReportMicrosoft365(
|
||||
metadata=self.metadata(),
|
||||
resource=group,
|
||||
resource_name=group.name,
|
||||
resource_id=group.id,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Group {group.name} has {group.visibility} visibility and should be Private."
|
||||
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "Microsoft365Domain",
|
||||
"ResourceType": "Security & privacy settings",
|
||||
"Description": "This control ensures that the password expiration policy is set to 'Set passwords to never expire (recommended)'. This aligns with modern recommendations to enhance security by avoiding arbitrary password changes and focusing on supplementary controls like MFA.",
|
||||
"Risk": "Arbitrary password expiration policies can lead to weaker passwords due to frequent changes. Users may adopt insecure habits such as using simple, memorable passwords.",
|
||||
"RelatedUrl": "https://www.cisecurity.org/insights/white-papers/cis-password-policy-guide",
|
||||
@@ -15,7 +15,7 @@
|
||||
"Code": {
|
||||
"CLI": "Set-MsolUser -UserPrincipalName <user> -PasswordNeverExpires $true",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Other": "1. Navigate to Microsoft 365 admin center https://admin.microsoft.com. 2. Click to expand Settings select Org Settings. 3. Click on Security & privacy. 4. Check the Set passwords to never expire (recommended) box. 5. Click Save.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
|
||||
+29
-4
@@ -1,15 +1,40 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Microsoft365
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportMicrosoft365
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_client import (
|
||||
admincenter_client,
|
||||
)
|
||||
|
||||
|
||||
class admincenter_settings_password_never_expire(Check):
|
||||
def execute(self) -> Check_Report_Microsoft365:
|
||||
"""Check if domains have a 'Password never expires' policy.
|
||||
|
||||
This check verifies whether the password policy for each domain is set to never expire.
|
||||
If the domain password validity period is set to `2147483647`, the policy is considered to
|
||||
have 'password never expires'.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportMicrosoft365]:
|
||||
"""Execute the check for password never expires policy.
|
||||
|
||||
This method iterates over all domains and checks if the password validity period is set
|
||||
to `2147483647`, indicating that passwords for users in the domain never expire.
|
||||
|
||||
Returns:
|
||||
List[CheckReportMicrosoft365]: A list of reports indicating whether the domain's password
|
||||
policy is set to never expire.
|
||||
"""
|
||||
findings = []
|
||||
for domain in admincenter_client.domains.values():
|
||||
report = Check_Report_Microsoft365(self.metadata(), resource=domain)
|
||||
report.resource_name = domain.id
|
||||
report = CheckReportMicrosoft365(
|
||||
self.metadata(),
|
||||
resource=domain,
|
||||
resource_name=domain.id,
|
||||
resource_id=domain.id,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Domain {domain.id} does not have a Password never expires policy."
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AdministrativeAccount",
|
||||
"ResourceType": "Active users",
|
||||
"Description": "Administrative accounts must use licenses with a reduced application footprint, such as Microsoft Entra ID P1 or P2, or avoid licenses entirely when possible. This minimizes the attack surface associated with privileged identities.",
|
||||
"Risk": "Licensing administrative accounts with applications like email or collaborative tools increases their exposure to social engineering attacks and malicious content, putting privileged accounts at risk.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/microsoft-365/enterprise/protect-your-global-administrator-accounts?view=o365-worldwide",
|
||||
@@ -15,7 +15,7 @@
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Other": "1. Navigate to Microsoft 365 admin center https://admin.microsoft.com. 2. Click to expand Users select Active users. 3. Click Add a user. 4. Fill out the appropriate fields for Name, user, etc. 5. When prompted to assign licenses select as needed Microsoft Entra ID P1 or Microsoft Entra ID P2, then click Next. 6. Under the Option settings screen you may choose from several types of privileged roles. Choose Admin center access followed by the appropriate role then click Next. 7. Select Finish adding.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
|
||||
+37
-11
@@ -1,11 +1,32 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Microsoft365
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportMicrosoft365
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_client import (
|
||||
admincenter_client,
|
||||
)
|
||||
|
||||
|
||||
class admincenter_users_admins_reduced_license_footprint(Check):
|
||||
def execute(self) -> Check_Report_Microsoft365:
|
||||
"""Check if users with administrative roles have a reduced license footprint.
|
||||
|
||||
This check ensures that users with administrative roles (like Global Administrator)
|
||||
have valid licenses, specifically one of the allowed licenses. If a user with
|
||||
administrative roles has an invalid license, the check fails.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportMicrosoft365]:
|
||||
"""Execute the check for users with administrative roles and their licenses.
|
||||
|
||||
This method iterates over all users and checks if those with administrative roles
|
||||
have an allowed license. If a user has a valid license (AAD_PREMIUM or AAD_PREMIUM_P2),
|
||||
the check passes; otherwise, it fails.
|
||||
|
||||
Returns:
|
||||
List[CheckReportMicrosoft365]: A list containing the result of the check for each user.
|
||||
"""
|
||||
findings = []
|
||||
allowed_licenses = ["AAD_PREMIUM", "AAD_PREMIUM_P2"]
|
||||
for user in admincenter_client.users.values():
|
||||
@@ -13,22 +34,27 @@ class admincenter_users_admins_reduced_license_footprint(Check):
|
||||
[
|
||||
role
|
||||
for role in user.directory_roles
|
||||
if "Administrator" in role or "Globar Reader" in role
|
||||
if "Administrator" in role or "Global Reader" in role
|
||||
]
|
||||
)
|
||||
|
||||
if admin_roles:
|
||||
report = Check_Report_Microsoft365(
|
||||
metadata=self.metadata(), resource=user
|
||||
report = CheckReportMicrosoft365(
|
||||
metadata=self.metadata(),
|
||||
resource=user,
|
||||
resource_name=user.name,
|
||||
resource_id=user.id,
|
||||
)
|
||||
report.resource_id = user.id
|
||||
report.resource_name = user.name
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user.name} has administrative roles {admin_roles} and an invalid license {user.license if user.license else ''}."
|
||||
report.status_extended = f"User {user.name} has administrative roles {admin_roles} and does not have a license."
|
||||
|
||||
if user.license in allowed_licenses:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user.name} has administrative roles {admin_roles} and a valid license: {user.license}."
|
||||
if user.license:
|
||||
if user.license not in allowed_licenses:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"User {user.name} has administrative roles {admin_roles} and an invalid license: {user.license}."
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"User {user.name} has administrative roles {admin_roles} and a valid license: {user.license}."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AdministrativeRole",
|
||||
"ResourceType": "Active users",
|
||||
"Description": "Ensure that there are between two and four global administrators designated in your tenant. This ensures monitoring, redundancy, and reduces the risk associated with having too many privileged accounts.",
|
||||
"Risk": "Having only one global administrator increases the risk of unmonitored actions and operational disruptions if that administrator is unavailable. Having more than four increases the likelihood of a breach through one of these highly privileged accounts.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/best-practices#5-limit-the-number-of-global-administrators-to-less-than-5",
|
||||
@@ -15,7 +15,7 @@
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Other": "1. Navigate to the Microsoft 365 admin center https://admin.microsoft.com 2. Select Users > Active Users. 3. In the Search field enter the name of the user to be made a Global Administrator. 4. To create a new Global Admin: 1. Select the user's name. 2. A window will appear to the right. 3. Select Manage roles. 4. Select Admin center access. 5. Check Global Administrator. 6. Click Save changes. 5. To remove Global Admins: 1. Select User. 2. Under Roles select Manage roles. 3. De-Select the appropriate role. 4. Click Save changes.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
|
||||
+34
-16
@@ -1,30 +1,48 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Microsoft365
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportMicrosoft365
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_client import (
|
||||
admincenter_client,
|
||||
)
|
||||
|
||||
|
||||
class admincenter_users_between_two_and_four_global_admins(Check):
|
||||
def execute(self) -> Check_Report_Microsoft365:
|
||||
"""Check if there are between two and four Global Administrators in Microsoft Admin Center.
|
||||
|
||||
This check verifies that the number of users with the 'Global Administrator' role is
|
||||
between 2 and 4, inclusive. If there are fewer than two or more than four, the check fails.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportMicrosoft365]:
|
||||
"""Execute the check for the number of Global Administrators.
|
||||
|
||||
This method checks if the number of users with the 'Global Administrator' role
|
||||
is between two and four. If the condition is met, the check passes; otherwise, it fails.
|
||||
|
||||
Returns:
|
||||
List[CheckReportMicrosoft365]: A list containing the result of the check for the Global Administrators.
|
||||
"""
|
||||
findings = []
|
||||
|
||||
directory_roles = admincenter_client.directory_roles
|
||||
report = Check_Report_Microsoft365(metadata=self.metadata(), resource={})
|
||||
report.status = "FAIL"
|
||||
report.resource_name = "Global Administrator"
|
||||
global_admin_role = directory_roles.get("Global Administrator", {})
|
||||
|
||||
if "Global Administrator" in directory_roles:
|
||||
report.resource_id = getattr(
|
||||
directory_roles["Global Administrator"],
|
||||
"id",
|
||||
"Global Administrator",
|
||||
if global_admin_role:
|
||||
report = CheckReportMicrosoft365(
|
||||
metadata=self.metadata(),
|
||||
resource=global_admin_role,
|
||||
resource_name=global_admin_role.name,
|
||||
resource_id=global_admin_role.id,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"There are not between two and four global administrators."
|
||||
)
|
||||
|
||||
num_global_admins = len(
|
||||
getattr(directory_roles["Global Administrator"], "members", [])
|
||||
)
|
||||
|
||||
if num_global_admins >= 2 and num_global_admins < 5:
|
||||
num_global_admins = len(getattr(global_admin_role, "members", []))
|
||||
if 1 < num_global_admins < 5:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"There are {num_global_admins} global administrators."
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "",
|
||||
"ResourceType": "User settings",
|
||||
"Description": "Require administrators or appropriately delegated users to register third-party applications.",
|
||||
"Risk": "It is recommended to only allow an administrator to register custom-developed applications. This ensures that the application undergoes a formal security review and approval process prior to exposing Azure Active Directory data. Certain users like developers or other high-request users may also be delegated permissions to prevent them from waiting on an administrative user. Your organization should review your policies and decide your needs.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/entra/identity-platform/how-applications-are-added#who-has-permission-to-add-applications-to-my-microsoft-entra-instance",
|
||||
@@ -15,11 +15,11 @@
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Other": "1. From Entra select the Portal Menu 2. Select Azure Active Directory 3. Select Users 4. Select User settings 5. Ensure that Users can register applications is set to No",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "1. From Entra select the Portal Menu 2. Select Azure Active Directory 3. Select Users 4. Select User settings 5. Ensure that Users can register applications is set to No",
|
||||
"Text": "Disable third-party integrated application permissions unless explicitly required. If third-party applications are necessary, implement strict approval processes and security controls to mitigate risks associated with external integrations.",
|
||||
"Url": "https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications"
|
||||
}
|
||||
},
|
||||
|
||||
+46
-15
@@ -1,25 +1,56 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Microsoft365
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportMicrosoft365
|
||||
from prowler.providers.microsoft365.services.entra.entra_client import entra_client
|
||||
|
||||
|
||||
class entra_thirdparty_integrated_apps_not_allowed(Check):
|
||||
def execute(self) -> Check_Report_Microsoft365:
|
||||
"""Check if third-party integrated apps are not allowed for non-admin users in Entra.
|
||||
|
||||
This check verifies that non-admin users are not allowed to create third-party apps.
|
||||
If the policy allows app creation, the check fails.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportMicrosoft365]:
|
||||
"""Execute the check to ensure third-party integrated apps are not allowed for non-admin users.
|
||||
|
||||
This method checks if the authorization policy allows non-admin users to create apps.
|
||||
If the policy allows app creation, the check fails. Otherwise, the check passes.
|
||||
|
||||
Returns:
|
||||
List[CheckReportMicrosoft365]: A list containing the result of the check for app creation policy.
|
||||
"""
|
||||
findings = []
|
||||
|
||||
auth_policy = entra_client.authorization_policy
|
||||
report = Check_Report_Microsoft365(self.metadata(), auth_policy)
|
||||
report.resource_name = getattr(auth_policy, "name", "Authorization Policy")
|
||||
report.resource_id = getattr(auth_policy, "id", "authorizationPolicy")
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "App creation is not disabled for non-admin users."
|
||||
|
||||
if getattr(auth_policy, "default_user_role_permissions", None) and not getattr(
|
||||
auth_policy.default_user_role_permissions,
|
||||
"allowed_to_create_apps",
|
||||
True,
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = "App creation is disabled for non-admin users."
|
||||
report = CheckReportMicrosoft365(
|
||||
metadata=self.metadata(),
|
||||
resource=auth_policy if auth_policy else {},
|
||||
resource_name=auth_policy.name if auth_policy else "Authorization Policy",
|
||||
resource_id=auth_policy.id if auth_policy else "authorizationPolicy",
|
||||
)
|
||||
|
||||
if auth_policy:
|
||||
if getattr(
|
||||
auth_policy, "default_user_role_permissions", None
|
||||
) and not getattr(
|
||||
auth_policy.default_user_role_permissions,
|
||||
"allowed_to_create_apps",
|
||||
True,
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = "App creation is disabled for non-admin users."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"App creation is not disabled for non-admin users."
|
||||
)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Authorization Policy was not found."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
|
||||
+12
@@ -60,8 +60,14 @@ class Test_admincenter_groups_not_public_visibility:
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].status_extended == "Group Group1 has Private visibility."
|
||||
assert result[0].resource == {
|
||||
"id": id_group1,
|
||||
"name": "Group1",
|
||||
"visibility": "Private",
|
||||
}
|
||||
assert result[0].resource_name == "Group1"
|
||||
assert result[0].resource_id == id_group1
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_user_admin_compliant_license(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
@@ -93,5 +99,11 @@ class Test_admincenter_groups_not_public_visibility:
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].status_extended == "Group Group1 has Private visibility."
|
||||
assert result[0].resource == {
|
||||
"id": id_group1,
|
||||
"name": "Group1",
|
||||
"visibility": "Private",
|
||||
}
|
||||
assert result[0].resource_name == "Group1"
|
||||
assert result[0].resource_id == id_group1
|
||||
assert result[0].location == "global"
|
||||
|
||||
+10
@@ -69,8 +69,13 @@ class Test_admincenter_settings_password_never_expire:
|
||||
result[0].status_extended
|
||||
== f"Domain {id_domain} does not have a Password never expires policy."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id_domain,
|
||||
"password_validity_period": 5,
|
||||
}
|
||||
assert result[0].resource_name == id_domain
|
||||
assert result[0].resource_id == id_domain
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_password_not_expire(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
@@ -108,5 +113,10 @@ class Test_admincenter_settings_password_never_expire:
|
||||
result[0].status_extended
|
||||
== f"Domain {id_domain} Password policy is set to never expire."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id_domain,
|
||||
"password_validity_period": 2147483647,
|
||||
}
|
||||
assert result[0].resource_name == id_domain
|
||||
assert result[0].resource_id == id_domain
|
||||
assert result[0].location == "global"
|
||||
|
||||
+69
-1
@@ -111,8 +111,16 @@ class Test_admincenter_users_admins_reduced_license_footprint:
|
||||
result[0].status_extended
|
||||
== "User User1 has administrative roles Global Administrator and a valid license: AAD_PREMIUM."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": ["Global Administrator"],
|
||||
"license": "AAD_PREMIUM",
|
||||
"user_type": None,
|
||||
}
|
||||
assert result[0].resource_name == "User1"
|
||||
assert result[0].resource_id == id_user1
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_user_admin_non_compliant_license(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
@@ -153,7 +161,67 @@ class Test_admincenter_users_admins_reduced_license_footprint:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "User User1 has administrative roles Global Administrator and an invalid license O365 BUSINESS."
|
||||
== "User User1 has administrative roles Global Administrator and an invalid license: O365 BUSINESS."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": ["Global Administrator"],
|
||||
"license": "O365 BUSINESS",
|
||||
"user_type": None,
|
||||
}
|
||||
assert result[0].resource_name == "User1"
|
||||
assert result[0].resource_id == id_user1
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_user_admin_no_license(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
admincenter_client.audited_tenant = "audited_tenant"
|
||||
admincenter_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.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint.admincenter_client",
|
||||
new=admincenter_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_service import (
|
||||
User,
|
||||
)
|
||||
from prowler.providers.microsoft365.services.admincenter.admincenter_users_admins_reduced_license_footprint.admincenter_users_admins_reduced_license_footprint import (
|
||||
admincenter_users_admins_reduced_license_footprint,
|
||||
)
|
||||
|
||||
id_user1 = str(uuid4())
|
||||
|
||||
admincenter_client.users = {
|
||||
id_user1: User(
|
||||
id=id_user1,
|
||||
name="User1",
|
||||
directory_roles=["Global Administrator"],
|
||||
license=None,
|
||||
),
|
||||
}
|
||||
|
||||
check = admincenter_users_admins_reduced_license_footprint()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "User User1 has administrative roles Global Administrator and does not have a license."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": ["Global Administrator"],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
}
|
||||
assert result[0].resource_name == "User1"
|
||||
assert result[0].resource_id == id_user1
|
||||
assert result[0].location == "global"
|
||||
|
||||
+84
@@ -70,8 +70,29 @@ class Test_admincenter_users_between_two_and_four_global_admins:
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].status_extended == "There are 2 global administrators."
|
||||
assert result[0].resource == {
|
||||
"id": id,
|
||||
"name": "Global Administrator",
|
||||
"members": [
|
||||
{
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user2,
|
||||
"name": "User2",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
],
|
||||
}
|
||||
assert result[0].resource_name == "Global Administrator"
|
||||
assert result[0].resource_id == id
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_more_than_five_global_admins(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
@@ -124,8 +145,57 @@ class Test_admincenter_users_between_two_and_four_global_admins:
|
||||
result[0].status_extended
|
||||
== "There are 6 global administrators. It should be more than one and less than five."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id,
|
||||
"name": "Global Administrator",
|
||||
"members": [
|
||||
{
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user2,
|
||||
"name": "User2",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user3,
|
||||
"name": "User3",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user4,
|
||||
"name": "User4",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user5,
|
||||
"name": "User5",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
{
|
||||
"id": id_user6,
|
||||
"name": "User6",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
],
|
||||
}
|
||||
assert result[0].resource_name == "Global Administrator"
|
||||
assert result[0].resource_id == id
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_admincenter_one_global_admin(self):
|
||||
admincenter_client = mock.MagicMock
|
||||
@@ -168,5 +238,19 @@ class Test_admincenter_users_between_two_and_four_global_admins:
|
||||
result[0].status_extended
|
||||
== "There are 1 global administrators. It should be more than one and less than five."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id,
|
||||
"name": "Global Administrator",
|
||||
"members": [
|
||||
{
|
||||
"id": id_user1,
|
||||
"name": "User1",
|
||||
"directory_roles": [],
|
||||
"license": None,
|
||||
"user_type": None,
|
||||
},
|
||||
],
|
||||
}
|
||||
assert result[0].resource_name == "Global Administrator"
|
||||
assert result[0].resource_id == id
|
||||
assert result[0].location == "global"
|
||||
|
||||
+17
-4
@@ -35,12 +35,11 @@ class Test_entra_thirdparty_integrated_apps_not_allowed:
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Authorization Policy"
|
||||
assert result[0].resource_id == "authorizationPolicy"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "App creation is not disabled for non-admin users."
|
||||
)
|
||||
assert result[0].status_extended == "Authorization Policy was not found."
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_default_user_role_permissions_not_allowed_to_create_apps(self):
|
||||
id = str(uuid4())
|
||||
@@ -81,8 +80,15 @@ class Test_entra_thirdparty_integrated_apps_not_allowed:
|
||||
result[0].status_extended
|
||||
== "App creation is disabled for non-admin users."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id,
|
||||
"name": "Test",
|
||||
"description": "Test",
|
||||
"default_user_role_permissions": role_permissions,
|
||||
}
|
||||
assert result[0].resource_name == "Test"
|
||||
assert result[0].resource_id == id
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_entra_default_user_role_permissions_allowed_to_create_apps(self):
|
||||
id = str(uuid4())
|
||||
@@ -123,5 +129,12 @@ class Test_entra_thirdparty_integrated_apps_not_allowed:
|
||||
result[0].status_extended
|
||||
== "App creation is not disabled for non-admin users."
|
||||
)
|
||||
assert result[0].resource == {
|
||||
"id": id,
|
||||
"name": "Test",
|
||||
"description": "Test",
|
||||
"default_user_role_permissions": role_permissions,
|
||||
}
|
||||
assert result[0].resource_name == "Test"
|
||||
assert result[0].resource_id == id
|
||||
assert result[0].location == "global"
|
||||
|
||||
Reference in New Issue
Block a user