Revert "feat: remove provider_id and adapt logic"

This reverts commit 3d9d118d2c.
This commit is contained in:
HugoPBrito
2025-04-21 17:49:30 +02:00
parent c8567b5d2b
commit b6e1551397
6 changed files with 71 additions and 81 deletions
@@ -62,9 +62,9 @@ class M365BaseException(ProwlerException):
"message": "The provided tenant ID and client ID do not belong to the provided client secret",
"remediation": "Check the tenant ID and client ID and ensure they belong to the provided client secret.",
},
(6014, "M365InvalidTenantDomainError"): {
"message": "The provided tenant domain is not valid",
"remediation": "Check the tenant domain and ensure it is a valid domain.",
(6014, "M365InvalidProviderIdError"): {
"message": "The provided provider_id does not match with the available subscriptions",
"remediation": "Check the provider_id and ensure it is a valid subscription for the given credentials.",
},
(6015, "M365NoAuthenticationMethodError"): {
"message": "No Microsoft 365 authentication method found",
@@ -235,7 +235,7 @@ class M365TenantIdAndClientIdNotBelongingToClientSecretError(M365CredentialsErro
)
class M365InvalidTenantDomainError(M365BaseException):
class M365InvalidProviderIdError(M365BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6014, file=file, original_exception=original_exception, message=message
@@ -115,7 +115,7 @@ class M365PowerShell(PowerShellSession):
# Validate user credentials belong to tenant
user_domain = credentials.user.split("@")[1]
if not credentials.tenant_domain.endswith(user_domain):
if not credentials.provider_id.endswith(user_domain):
raise M365UserNotBelongingToTenantError(
file=os.path.basename(__file__),
message="The provided M365 User does not belong to the specified tenant.",
+21 -34
View File
@@ -38,7 +38,7 @@ from prowler.providers.m365.exceptions.exceptions import (
M365GetTokenIdentityError,
M365HTTPResponseError,
M365InteractiveBrowserCredentialError,
M365InvalidTenantDomainError,
M365InvalidProviderIdError,
M365MissingEnvironmentCredentialsError,
M365NoAuthenticationMethodError,
M365NotTenantIdButClientIdAndClientSecretError,
@@ -201,7 +201,7 @@ class M365Provider(Provider):
self._credentials = self.setup_powershell(
env_auth=env_auth,
m365_credentials=m365_credentials,
tenant_domain=self._identity.tenant_domain,
provider_id=self.identity.tenant_domain,
)
# Audit Config
@@ -373,7 +373,7 @@ class M365Provider(Provider):
@staticmethod
def setup_powershell(
env_auth: bool = False, m365_credentials: dict = {}, tenant_domain: str = None
env_auth: bool = False, m365_credentials: dict = {}, provider_id: str = None
) -> M365Credentials:
"""Gets the M365 credentials.
@@ -393,7 +393,7 @@ class M365Provider(Provider):
client_id=m365_credentials.get("client_id", ""),
client_secret=m365_credentials.get("client_secret", ""),
tenant_id=m365_credentials.get("tenant_id", ""),
tenant_domain=m365_credentials.get("tenant_domain", ""),
provider_id=m365_credentials.get("provider_id", ""),
)
elif env_auth:
m365_user = getenv("M365_USER")
@@ -416,7 +416,7 @@ class M365Provider(Provider):
client_id=client_id,
client_secret=client_secret,
tenant_id=tenant_id,
tenant_domain=tenant_domain,
provider_id=provider_id,
)
if credentials:
@@ -447,11 +447,8 @@ class M365Provider(Provider):
f"M365 Region: {Fore.YELLOW}{self.region_config.name}{Style.RESET_ALL}",
f"M365 Tenant Domain: {Fore.YELLOW}{self._identity.tenant_domain}{Style.RESET_ALL} M365 Tenant ID: {Fore.YELLOW}{self._identity.tenant_id}{Style.RESET_ALL}",
f"M365 Identity Type: {Fore.YELLOW}{self._identity.identity_type}{Style.RESET_ALL} M365 Identity ID: {Fore.YELLOW}{self._identity.identity_id}{Style.RESET_ALL}",
f"M365 User: {Fore.YELLOW}{self.credentials.user}{Style.RESET_ALL}",
]
if self.credentials and self.credentials.user:
report_lines.append(
f"M365 User: {Fore.YELLOW}{self.credentials.user}{Style.RESET_ALL}"
)
report_title = (
f"{Style.BRIGHT}Using the M365 credentials below:{Style.RESET_ALL}"
)
@@ -484,6 +481,7 @@ class M365Provider(Provider):
- client_secret: The M365 client secret
- user: The M365 user email
- encrypted_password: The M365 encrypted password
- provider_id: The M365 provider ID (in this case the Tenant ID).
region_config (M365RegionConfig): The region configuration object.
Returns:
@@ -610,6 +608,7 @@ class M365Provider(Provider):
client_secret=None,
user=None,
encrypted_password=None,
provider_id=None,
) -> Connection:
"""Test connection to M365 subscription.
@@ -628,7 +627,7 @@ class M365Provider(Provider):
client_secret (str): The M365 client secret.
user (str): The M365 user email.
encrypted_password (str): The M365 encrypted_password.
tenant_domain (str): The M365 tenant domain.
provider_id (str): The M365 provider ID (in this case the Tenant ID).
Returns:
@@ -696,30 +695,18 @@ class M365Provider(Provider):
region_config,
)
# Set up the M365 identity
M365Provider.setup_identity(
az_cli_auth,
sp_env_auth,
env_auth,
browser_auth,
client_id,
)
# Set up the M365 GraphServiceClient
GraphServiceClient(credentials=credentials)
logger.info("M365 provider: Connection to MSGraph successful")
# Set up PowerShell credentials
if user and encrypted_password:
M365Provider.setup_powershell(
env_auth,
m365_credentials,
M365Provider.identity.tenant_domain,
)
logger.info("M365 provider: Connection to PowerShell successful")
else:
logger.info("M365 provider: No PowerShell credentials provided")
M365Provider.setup_powershell(
env_auth,
m365_credentials,
provider_id,
)
logger.info("M365 provider: Connection to PowerShell successful")
return Connection(is_connected=True)
@@ -794,14 +781,14 @@ class M365Provider(Provider):
if raise_on_exception:
raise client_secret_error
return Connection(error=client_secret_error)
# Exceptions from tenant_domain validation
except M365InvalidTenantDomainError as invalid_tenant_domain_error:
# Exceptions from provider_id validation
except M365InvalidProviderIdError as invalid_credentials_error:
logger.error(
f"{invalid_tenant_domain_error.__class__.__name__}[{invalid_tenant_domain_error.__traceback__.tb_lineno}]: {invalid_tenant_domain_error}"
f"{invalid_credentials_error.__class__.__name__}[{invalid_credentials_error.__traceback__.tb_lineno}]: {invalid_credentials_error}"
)
if raise_on_exception:
raise invalid_tenant_domain_error
return Connection(error=invalid_tenant_domain_error)
raise invalid_credentials_error
return Connection(error=invalid_credentials_error)
# Exceptions from SubscriptionClient
except HttpResponseError as http_response_error:
logger.error(
+1 -1
View File
@@ -25,7 +25,7 @@ class M365Credentials(BaseModel):
client_id: str = ""
client_secret: str = ""
tenant_id: str = ""
tenant_domain: str = ""
provider_id: str = ""
class M365OutputOptions(ProviderOutputOptions):
@@ -94,7 +94,7 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
tenant_domain="contoso.onmicrosoft.com",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
@@ -144,7 +144,7 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
tenant_domain="contoso.onmicrosoft.com",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
@@ -187,7 +187,7 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
tenant_domain="contoso.onmicrosoft.com",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
+41 -38
View File
@@ -282,9 +282,6 @@ class TestM365Provider:
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_session"
) as mock_setup_session,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity"
) as mock_setup_identity,
patch(
"prowler.providers.m365.m365_provider.GraphServiceClient"
) as mock_graph_client,
@@ -300,16 +297,6 @@ class TestM365Provider:
mock_session = MagicMock()
mock_setup_session.return_value = mock_session
# Mock setup_identity to return a mocked identity object
mock_identity = M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type=IDENTITY_TYPE,
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
location=LOCATION,
)
mock_setup_identity.return_value = mock_identity
# Mock GraphServiceClient to avoid real API calls
mock_client = MagicMock()
mock_graph_client.return_value = mock_client
@@ -333,12 +320,6 @@ class TestM365Provider:
patch(
"prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
) as mock_validate_static_credentials,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity"
) as mock_setup_identity,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_region_config"
) as mock_setup_region_config,
):
# Mock setup_session to return a mocked session object
mock_session = MagicMock()
@@ -347,25 +328,6 @@ class TestM365Provider:
# Mock ValidateStaticCredentials to avoid real API calls
mock_validate_static_credentials.return_value = None
# Mock setup_identity to return a mocked identity object
mock_identity = M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type=IDENTITY_TYPE,
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
location=LOCATION,
)
mock_setup_identity.return_value = mock_identity
# Mock setup_region_config to return a valid region config
mock_region_config = M365RegionConfig(
name="M365Global",
authority=None,
base_url="https://graph.microsoft.com",
credential_scopes=["https://graph.microsoft.com/.default"],
)
mock_setup_region_config.return_value = mock_region_config
test_connection = M365Provider.test_connection(
tenant_id=str(uuid4()),
region="M365Global",
@@ -477,6 +439,47 @@ class TestM365Provider:
in exception.value.args[0]
)
def test_setup_powershell_valid_credentials(self):
credentials_dict = {
"user": "test@example.com",
"encrypted_password": "test_password",
"client_id": "test_client_id",
"tenant_id": "test_tenant_id",
"client_secret": "test_client_secret",
}
with patch(
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.test_credentials",
return_value=True,
):
result = M365Provider.setup_powershell(
env_auth=False, m365_credentials=credentials_dict
)
assert result.user == credentials_dict["user"]
assert result.passwd == credentials_dict["encrypted_password"]
def test_setup_powershell_invalid_env_credentials(self):
credentials = None
with patch(
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell"
) as mock_powershell:
mock_session = MagicMock()
mock_session.test_credentials.return_value = False
mock_powershell.return_value = mock_session
with pytest.raises(M365MissingEnvironmentCredentialsError) as exc_info:
M365Provider.setup_powershell(
env_auth=True, m365_credentials=credentials
)
assert (
"Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication"
in str(exc_info.value)
)
mock_session.test_credentials.assert_not_called()
def test_test_connection_user_not_belonging_to_tenant(
self,
):