mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(teams): add new check teams_meeting_external_lobby_bypass_disabled (#7568)
Co-authored-by: Andoni A <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
f85450d0b5
commit
d9782c7b8a
@@ -28,6 +28,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492)
|
||||
- Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485)
|
||||
- Add new check `teams_meeting_anonymous_user_start_disabled` [(#7567)](https://github.com/prowler-cloud/prowler/pull/7567)
|
||||
- Add new check `teams_meeting_external_lobby_bypass_disabled` [(#7568)](https://github.com/prowler-cloud/prowler/pull/7568)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "teams_meeting_external_lobby_bypass_disabled",
|
||||
"CheckTitle": "Ensure only people in the organization can bypass the lobby.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "teams",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "critical",
|
||||
"ResourceType": "Teams Global Meeting Policy",
|
||||
"Description": "Ensure only people in the organization can bypass the lobby.",
|
||||
"Risk": "Allowing external users or unauthenticated participants to bypass the lobby increases the risk of unauthorized access to sensitive meetings and potential disruptions. It may also lead to unscheduled meetings being initiated by external parties.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Set-CsTeamsMeetingPolicy -Identity Global -AutoAdmittedUsers 'EveryoneInCompanyExcludingGuests' ",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com. 2. Click to expand Meetings select Meeting policies. 3. Click Global (Org-wide default). 4. Under meeting join & lobby set Who can bypass the lobby to People in my org.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure that only people within the organization can bypass the lobby, requiring external users and dial-in participants to wait for approval from an organizer, co-organizer, or presenter. This helps secure sensitive meetings and prevents unauthorized access.",
|
||||
"Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-csteamsmeetingpolicy?view=teams-ps"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportM365
|
||||
from prowler.providers.m365.services.teams.teams_client import teams_client
|
||||
|
||||
|
||||
class teams_meeting_external_lobby_bypass_disabled(Check):
|
||||
"""Check if only people in the organization can bypass the lobby.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""Execute the check for only people in the organization can bypass the lobby.
|
||||
|
||||
This method checks if only people in the organization can bypass the lobby.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
global_meeting_policy = teams_client.global_meeting_policy
|
||||
if global_meeting_policy:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=global_meeting_policy if global_meeting_policy else {},
|
||||
resource_name="Teams Meetings Global (Org-wide default) Policy",
|
||||
resource_id="teamsMeetingsGlobalPolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"People outside the organization can bypass the lobby."
|
||||
)
|
||||
|
||||
allowed_bypass_settings = {
|
||||
"EveryoneInCompanyExcludingGuests",
|
||||
"OrganizerOnly",
|
||||
"InvitedUsers",
|
||||
}
|
||||
if (
|
||||
global_meeting_policy.allow_external_users_to_bypass_lobby
|
||||
in allowed_bypass_settings
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
"Only people in the organization can bypass the lobby."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -52,6 +52,9 @@ class Teams(M365Service):
|
||||
allow_anonymous_users_to_start_meeting=global_meeting_policy.get(
|
||||
"AllowAnonymousUsersToStartMeeting", True
|
||||
),
|
||||
allow_external_users_to_bypass_lobby=global_meeting_policy.get(
|
||||
"AutoAdmittedUsers", "Everyone"
|
||||
),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -95,6 +98,7 @@ class TeamsSettings(BaseModel):
|
||||
class GlobalMeetingPolicy(BaseModel):
|
||||
allow_anonymous_users_to_join_meeting: bool = True
|
||||
allow_anonymous_users_to_start_meeting: bool = True
|
||||
allow_external_users_to_bypass_lobby: str = "Everyone"
|
||||
|
||||
|
||||
class UserSettings(BaseModel):
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_teams_meeting_external_lobby_bypass_disabled:
|
||||
def test_no_global_meeting_policy(self):
|
||||
teams_client = mock.MagicMock()
|
||||
teams_client.global_meeting_policy = None
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import (
|
||||
teams_meeting_external_lobby_bypass_disabled,
|
||||
)
|
||||
|
||||
check = teams_meeting_external_lobby_bypass_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_external_users_can_bypass_lobby(self):
|
||||
teams_client = mock.MagicMock()
|
||||
teams_client.audited_tenant = "audited_tenant"
|
||||
teams_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import (
|
||||
teams_meeting_external_lobby_bypass_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import (
|
||||
GlobalMeetingPolicy,
|
||||
)
|
||||
|
||||
teams_client.global_meeting_policy = GlobalMeetingPolicy(
|
||||
allow_external_users_to_bypass_lobby="Everyone"
|
||||
)
|
||||
|
||||
check = teams_meeting_external_lobby_bypass_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "People outside the organization can bypass the lobby."
|
||||
)
|
||||
assert result[0].resource == teams_client.global_meeting_policy.dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Teams Meetings Global (Org-wide default) Policy"
|
||||
)
|
||||
assert result[0].resource_id == "teamsMeetingsGlobalPolicy"
|
||||
|
||||
def test_only_internal_users_can_bypass_lobby(self):
|
||||
teams_client = mock.MagicMock()
|
||||
teams_client.audited_tenant = "audited_tenant"
|
||||
teams_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import (
|
||||
teams_meeting_external_lobby_bypass_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import (
|
||||
GlobalMeetingPolicy,
|
||||
)
|
||||
|
||||
teams_client.global_meeting_policy = GlobalMeetingPolicy(
|
||||
allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests"
|
||||
)
|
||||
|
||||
check = teams_meeting_external_lobby_bypass_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Only people in the organization can bypass the lobby."
|
||||
)
|
||||
assert result[0].resource == teams_client.global_meeting_policy.dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Teams Meetings Global (Org-wide default) Policy"
|
||||
)
|
||||
assert result[0].resource_id == "teamsMeetingsGlobalPolicy"
|
||||
|
||||
def test_organizer_only_can_bypass_lobby(self):
|
||||
teams_client = mock.MagicMock()
|
||||
teams_client.audited_tenant = "audited_tenant"
|
||||
teams_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import (
|
||||
teams_meeting_external_lobby_bypass_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import (
|
||||
GlobalMeetingPolicy,
|
||||
)
|
||||
|
||||
teams_client.global_meeting_policy = GlobalMeetingPolicy(
|
||||
allow_external_users_to_bypass_lobby="OrganizerOnly"
|
||||
)
|
||||
|
||||
check = teams_meeting_external_lobby_bypass_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Only people in the organization can bypass the lobby."
|
||||
)
|
||||
assert result[0].resource == teams_client.global_meeting_policy.dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Teams Meetings Global (Org-wide default) Policy"
|
||||
)
|
||||
assert result[0].resource_id == "teamsMeetingsGlobalPolicy"
|
||||
|
||||
def test_invited_users_can_bypass_lobby(self):
|
||||
teams_client = mock.MagicMock()
|
||||
teams_client.audited_tenant = "audited_tenant"
|
||||
teams_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_meeting_external_lobby_bypass_disabled.teams_meeting_external_lobby_bypass_disabled import (
|
||||
teams_meeting_external_lobby_bypass_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import (
|
||||
GlobalMeetingPolicy,
|
||||
)
|
||||
|
||||
teams_client.global_meeting_policy = GlobalMeetingPolicy(
|
||||
allow_external_users_to_bypass_lobby="InvitedUsers"
|
||||
)
|
||||
|
||||
check = teams_meeting_external_lobby_bypass_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Only people in the organization can bypass the lobby."
|
||||
)
|
||||
assert result[0].resource == teams_client.global_meeting_policy.dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Teams Meetings Global (Org-wide default) Policy"
|
||||
)
|
||||
assert result[0].resource_id == "teamsMeetingsGlobalPolicy"
|
||||
@@ -28,6 +28,7 @@ def mock_get_global_meeting_policy(_):
|
||||
return GlobalMeetingPolicy(
|
||||
allow_anonymous_users_to_join_meeting=False,
|
||||
allow_anonymous_users_to_start_meeting=False,
|
||||
allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests",
|
||||
)
|
||||
|
||||
|
||||
@@ -122,5 +123,6 @@ class Test_Teams_Service:
|
||||
assert teams_client.global_meeting_policy == GlobalMeetingPolicy(
|
||||
allow_anonymous_users_to_join_meeting=False,
|
||||
allow_anonymous_users_to_start_meeting=False,
|
||||
allow_external_users_to_bypass_lobby="EveryoneInCompanyExcludingGuests",
|
||||
)
|
||||
teams_client.powershell.close()
|
||||
|
||||
Reference in New Issue
Block a user