Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions conda/conda-reqs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ azure-identity>=1.16.1
azure-keyvault-secrets>=4.0.0
azure-kusto-data<7.0.0,>=4.4.0
azure-mgmt-compute>=4.6.2
azure-mgmt-core>=1.2.1
azure-mgmt-core>=1.6.0
azure-mgmt-keyvault>=2.0.0
azure-mgmt-monitor
azure-mgmt-network>=2.7.0
Expand All @@ -31,7 +31,6 @@ matplotlib>=3.0.0
msal_extensions>=0.3.0
msal>=1.12.0
msrest>=0.6.0
msrestazure>=0.6.0
networkx>=2.2
numpy>=1.15.4
pandas>=1.4.0, <3.0.0
Expand Down
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@
"msal",
"msal_extensions",
"msrest",
"msrestazure",
"msrest.authentication",
"nest_asyncio",
"networkx",
Expand Down
15 changes: 5 additions & 10 deletions msticpy/auth/azure_auth_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
from enum import Enum
from typing import Any, ClassVar

from azure.common.credentials import get_cli_profile
from azure.core.credentials import TokenCredential
from azure.core.credentials import AccessTokenInfo, TokenCredential
from azure.core.exceptions import ClientAuthenticationError
from azure.identity import (
AzureCliCredential,
Expand All @@ -31,7 +30,6 @@
ManagedIdentityCredential,
VisualStudioCodeCredential,
)
from dateutil import parser

from .._version import VERSION
from ..common.exceptions import MsticpyAzureConfigError
Expand Down Expand Up @@ -536,13 +534,10 @@ class AzureCliStatus(Enum):
def check_cli_credentials() -> tuple[AzureCliStatus, str | None]:
"""Check to see if there is a CLI session with a valid AAD token."""
try:
cli_profile = get_cli_profile()
raw_token = cli_profile.get_raw_token()
bearer_token = None
if isinstance(raw_token, tuple) and len(raw_token) == 3 and len(raw_token[0]) == 3:
bearer_token = raw_token[0][2]
if parser.parse(bearer_token.get("expiresOn", datetime.min)) < datetime.now():
raise ValueError("AADSTS70043: The refresh token has expired")
cli_profile: AzureCliCredential = AzureCliCredential()
token: AccessTokenInfo = cli_profile.get_token_info("/.default")
if token.expires_on < datetime.now().timestamp():
raise ValueError("AADSTS70043: The refresh token has expired")

return AzureCliStatus.CLI_OK, "Azure CLI credentials available."
except ImportError:
Expand Down
13 changes: 6 additions & 7 deletions msticpy/context/azure/azure_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
)

try:
from azure.common.exceptions import CloudError
from azure.core.exceptions import ClientAuthenticationError
from azure.core.exceptions import ClientAuthenticationError, HttpResponseError
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.subscription import SubscriptionClient
Expand Down Expand Up @@ -198,7 +197,7 @@ def connect(

Raises
------
CloudError
ClientAuthenticationError
If no valid credentials are found or if subscription client can't be created

See Also
Expand All @@ -220,7 +219,7 @@ def connect(
)
if not self.credentials:
err_msg: str = "Could not obtain credentials."
raise CloudError(err_msg)
raise ClientAuthenticationError(err_msg)
if only_interactive_cred(self.credentials.modern) and not silent:
logger.warning("Check your default browser for interactive sign-in prompt.")

Expand All @@ -231,7 +230,7 @@ def connect(
)
if not self.sub_client:
err_msg = "Could not create a Subscription client."
raise CloudError(err_msg)
raise ClientAuthenticationError(err_msg)
logger.info("Connected to Azure Subscription Client")
self.connected = True

Expand Down Expand Up @@ -454,7 +453,7 @@ def get_resources(
"2019-08-01",
).properties

except CloudError:
except HttpResponseError:
props = self.resource_client.resources.get_by_id(
resource.id,
self._get_api(resource_id=resource.id, sub_id=sub_id),
Expand Down Expand Up @@ -1023,7 +1022,7 @@ def _check_client(self: Self, client_name: str, sub_id: str | None = None) -> No

if getattr(self, client_name) is None:
err_msg = "Could not create client"
raise CloudError(err_msg)
raise ClientAuthenticationError(err_msg)

def _legacy_auth(self: Self, client_name: str, sub_id: str | None = None) -> None:
"""
Expand Down
49 changes: 43 additions & 6 deletions msticpy/context/azure/sentinel_analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@

import httpx
import pandas as pd
from azure.common.exceptions import CloudError
from azure.core.exceptions import (
ClientAuthenticationError,
HttpResponseError,
ResourceExistsError,
ResourceNotFoundError,
ResourceNotModifiedError,
)
from IPython.display import display
from typing_extensions import Self

Expand Down Expand Up @@ -190,7 +196,11 @@ def create_analytic_rule( # pylint: disable=too-many-arguments, too-many-locals
------
MsticpyUserError
If template provided isn't found.
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
ResourceNotModifiedError
HttpResponseError
If the API returns an error.

"""
Expand Down Expand Up @@ -250,7 +260,18 @@ def create_analytic_rule( # pylint: disable=too-many-arguments, too-many-locals
timeout=get_http_timeout(),
)
if not response.is_success:
raise CloudError(response=response)
match response.status_code:
case httpx.codes.UNAUTHORIZED:
raise ClientAuthenticationError()
case httpx.codes.NOT_FOUND:
raise ResourceNotFoundError()
case httpx.codes.CONFLICT:
raise ResourceExistsError()
case httpx.codes.NOT_MODIFIED:
raise ResourceNotModifiedError()
case _:
err_msg = f"Received HTTP return code {response.status_code}: {response.text}"
raise HttpResponseError(err_msg)
logger.info("Analytic Created.")
return response.json().get("name")

Expand Down Expand Up @@ -305,7 +326,10 @@ def delete_analytic_rule(

Raises
------
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
HttpResponseError
If the API returns an error.

"""
Expand All @@ -323,7 +347,16 @@ def delete_analytic_rule(
timeout=get_http_timeout(),
)
if response.is_error:
raise CloudError(response=response)
match response.status_code:
case httpx.codes.UNAUTHORIZED:
raise ClientAuthenticationError()
case httpx.codes.NOT_FOUND:
raise ResourceNotFoundError()
case httpx.codes.CONFLICT:
raise ResourceExistsError()
case _:
err_msg = f"Received HTTP return code {response.status_code}: {response.text}"
raise HttpResponseError(err_msg)
logger.info("Analytic Deleted.")

def list_analytic_templates(self) -> pd.DataFrame:
Expand All @@ -337,7 +370,11 @@ def list_analytic_templates(self) -> pd.DataFrame:

Raises
------
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
ResourceNotModifiedError
HttpResponseError
If a valid result is not returned.

"""
Expand Down
52 changes: 46 additions & 6 deletions msticpy/context/azure/sentinel_bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@

import httpx
import pandas as pd
from azure.common.exceptions import CloudError
from azure.core.exceptions import (
ClientAuthenticationError,
HttpResponseError,
ResourceExistsError,
ResourceNotFoundError,
ResourceNotModifiedError,
)
from IPython.display import display
from typing_extensions import Self

Expand Down Expand Up @@ -79,7 +85,11 @@ def create_bookmark( # noqa:PLR0913

Raises
------
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
ResourceNotModifiedError
HttpResponseError
If API returns an error.

"""
Expand Down Expand Up @@ -112,7 +122,20 @@ def create_bookmark( # noqa:PLR0913
if response.is_success:
logger.info("Bookmark created.")
return response.json().get("name")
raise CloudError(response=response)
match response.status_code:
case httpx.codes.UNAUTHORIZED:
raise ClientAuthenticationError()
case httpx.codes.NOT_FOUND:
raise ResourceNotFoundError()
case httpx.codes.CONFLICT:
raise ResourceExistsError()
case httpx.codes.NOT_MODIFIED:
raise ResourceNotModifiedError()
case _:
err_msg = (
f"Received HTTP return code {response.status_code}: {response.text}"
)
raise HttpResponseError(err_msg)

def delete_bookmark(
self: Self,
Expand All @@ -128,7 +151,11 @@ def delete_bookmark(

Raises
------
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
ResourceNotModifiedError
HttpResponseError
If the API returns an error.

"""
Expand All @@ -147,8 +174,21 @@ def delete_bookmark(
)
if response.is_success:
logger.info("Bookmark deleted.")
else:
raise CloudError(response=response)
return
match response.status_code:
case httpx.codes.UNAUTHORIZED:
raise ClientAuthenticationError()
case httpx.codes.NOT_FOUND:
raise ResourceNotFoundError()
case httpx.codes.CONFLICT:
raise ResourceExistsError()
case httpx.codes.NOT_MODIFIED:
raise ResourceNotModifiedError()
case _:
err_msg = (
f"Received HTTP return code {response.status_code}: {response.text}"
)
raise HttpResponseError(err_msg)

def _get_bookmark_id(self: Self, bookmark: str) -> str:
"""
Expand Down
6 changes: 5 additions & 1 deletion msticpy/context/azure/sentinel_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,11 @@ def list_data_connectors(self: Self) -> pd.DataFrame:

Raises
------
CloudError
ClientAuthenticationError
ResourceNotFoundError
ResourceExistsError
ResourceNotModifiedError
HttpResponseError
If a valid result is not returned.

"""
Expand Down
Loading
Loading