Source code for pyrit.auth.azure_storage_auth
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
from datetime import datetime, timedelta
from urllib.parse import urlparse
from azure.identity.aio import DefaultAzureCredential
from azure.storage.blob.aio import BlobServiceClient
from azure.storage.blob import ContainerSasPermissions, UserDelegationKey, generate_container_sas
[docs]
class AzureStorageAuth:
"""
A utility class for Azure Storage authentication, providing methods to generate SAS tokens
using user delegation keys.
"""
[docs]
@staticmethod
async def get_user_delegation_key(blob_service_client: BlobServiceClient) -> UserDelegationKey:
"""
Retrieves a user delegation key valid for one day.
Args:
blob_service_client (BlobServiceClient): An instance of BlobServiceClient to interact
with Azure Blob Storage.
Returns:
UserDelegationKey: A user delegation key valid for one day.
"""
delegation_key_start_time = datetime.now()
delegation_key_expiry_time = delegation_key_start_time + timedelta(days=1)
user_delegation_key = await blob_service_client.get_user_delegation_key(
key_start_time=delegation_key_start_time, key_expiry_time=delegation_key_expiry_time
)
return user_delegation_key
[docs]
@staticmethod
async def get_sas_token(container_url: str) -> str:
"""
Generates a SAS token for the specified blob using a user delegation key.
Args:
container_url (str): The URL of the Azure Blob Storage container.
Returns:
str: The generated SAS token.
"""
if not container_url:
raise ValueError(
"Azure Storage Container URL is not provided. The correct format "
"is 'https://storageaccountname.core.windows.net/containername'."
)
parsed_url = urlparse(container_url)
if not parsed_url.scheme or not parsed_url.netloc or not parsed_url.path:
raise ValueError(
"Invalid Azure Storage Container URL."
" The correct format is 'https://storageaccountname.core.windows.net/containername'."
)
account_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
credential = DefaultAzureCredential()
try:
async with BlobServiceClient(account_url=account_url, credential=credential) as blob_service_client:
user_delegation_key = await AzureStorageAuth.get_user_delegation_key(
blob_service_client=blob_service_client
)
container_name = parsed_url.path.lstrip("/")
storage_account_name = parsed_url.netloc.split(".")[0]
# Set start_time 5 minutes before the current time to account for any clock skew
start_time = datetime.now() - timedelta(minutes=5)
expiry_time = start_time + timedelta(days=1)
sas_token = generate_container_sas(
account_name=storage_account_name,
container_name=container_name,
user_delegation_key=user_delegation_key,
permission=ContainerSasPermissions(read=True, write=True, create=True, list=True, delete=True),
expiry=expiry_time,
start=start_time,
)
finally:
await credential.close()
return sas_token