Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2058c9f
Generated code
weirongw23-msft May 27, 2026
be05b4d
Redact sensitive session info for recorded tests / changelogs
weirongw23-msft May 28, 2026
5eeb392
Rewrite
weirongw23-msft May 31, 2026
a4b0379
WIP
weirongw23-msft Jun 1, 2026
49ad7dc
GG
weirongw23-msft Jun 1, 2026
19b3f75
Removed comments
weirongw23-msft Jun 1, 2026
4a8ef92
More stuff
weirongw23-msft Jun 1, 2026
75744d1
More tests
weirongw23-msft Jun 2, 2026
75a2bd7
Format
weirongw23-msft Jun 2, 2026
0eb242a
Added one more test
weirongw23-msft Jun 2, 2026
b7c4ef9
One more assert
weirongw23-msft Jun 2, 2026
48faaec
API changes
weirongw23-msft Jun 2, 2026
a63e45e
BOOM BOOM
weirongw23-msft Jun 2, 2026
24ffd97
Async
weirongw23-msft Jun 2, 2026
1e9171b
Async tests
weirongw23-msft Jun 2, 2026
c7c77af
Feature not enabled
weirongw23-msft Jun 3, 2026
6a1492d
Feedback
weirongw23-msft Jun 3, 2026
d86b2d9
Got rid of broad except
weirongw23-msft Jun 3, 2026
8c66a4d
Merge branch 'main' into weirongw23/sessions-private
weirongw23-msft Jun 3, 2026
27003eb
black
weirongw23-msft Jun 3, 2026
e13d8d5
Rename
weirongw23-msft Jun 4, 2026
47dfd8c
More feedback
weirongw23-msft Jun 4, 2026
9f3796c
Passing pipeline directly
weirongw23-msft Jun 4, 2026
edb67d3
Removed the use_session kwarg in policies
weirongw23-msft Jun 4, 2026
8cce524
Actually retry on 401
weirongw23-msft Jun 4, 2026
e5c7ee7
Factored out helper methods in test files
weirongw23-msft Jun 4, 2026
d752e8b
Merge branch 'main' into weirongw23/sessions-private
weirongw23-msft Jun 4, 2026
ffe44db
Refactoring
weirongw23-msft Jun 4, 2026
7f9d2c0
More refactoring
weirongw23-msft Jun 4, 2026
e247fe7
invalidate update
weirongw23-msft Jun 4, 2026
5eacfb8
Inline resolve session
weirongw23-msft Jun 4, 2026
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
5 changes: 5 additions & 0 deletions sdk/storage/azure-storage-blob/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## 12.31.0b1 (Unreleased)

### Features Added
- Added opt-in session-based authentication for `ContainerClient` via the new
`use_session` keyword argument. When enabled, it must be used with a
`TokenCredential`. Eligible GET requests issued through the client
are authenticated using a short-lived session credential obtained from the
service instead of the bearer token.
Comment thread
weirongw23-msft marked this conversation as resolved.

## 12.29.0 (2026-05-14)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"azure.storage.blob.models.CorsRule": null,
"azure.storage.blob.models.CpkInfo": null,
"azure.storage.blob.models.CpkScopeInfo": null,
"azure.storage.blob.models.CreateSessionConfiguration": null,
"azure.storage.blob.models.CreateSessionResponse": null,
"azure.storage.blob.models.DelimitedTextConfiguration": null,
"azure.storage.blob.models.FilterBlobItem": null,
"azure.storage.blob.models.FilterBlobSegment": null,
Expand All @@ -46,6 +48,7 @@
"azure.storage.blob.models.QuerySerialization": null,
"azure.storage.blob.models.RetentionPolicy": null,
"azure.storage.blob.models.SequenceNumberAccessConditions": null,
"azure.storage.blob.models.SessionCredentials": null,
"azure.storage.blob.models.SignedIdentifier": null,
"azure.storage.blob.models.SourceCpkInfo": null,
"azure.storage.blob.models.SourceModifiedAccessConditions": null,
Expand All @@ -68,6 +71,7 @@
"azure.storage.blob.models.RehydratePriority": null,
"azure.storage.blob.models.BlobImmutabilityPolicyMode": null,
"azure.storage.blob.models.GeoReplicationStatusType": null,
"azure.storage.blob.models.AuthenticationType": null,
"azure.storage.blob.models.PremiumPageBlobAccessTier": null,
"azure.storage.blob.models.AccessTierOptional": null,
"azure.storage.blob.models.FileShareTokenIntent": null,
Expand Down Expand Up @@ -134,6 +138,8 @@
"azure.storage.blob.aio.operations.ContainerOperations.list_blob_hierarchy_segment": null,
"azure.storage.blob.operations.ContainerOperations.get_account_info": null,
"azure.storage.blob.aio.operations.ContainerOperations.get_account_info": null,
"azure.storage.blob.operations.ContainerOperations.create_session": null,
"azure.storage.blob.aio.operations.ContainerOperations.create_session": null,
"azure.storage.blob.operations.BlobOperations.download": null,
"azure.storage.blob.aio.operations.BlobOperations.download": null,
"azure.storage.blob.operations.BlobOperations.get_properties": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
:keyword str audience: The audience to use when requesting tokens for Azure Active Directory
authentication. Only has an effect when credential is of type TokenCredential. The value could be
https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net.
:keyword bool use_session: If True, enable session-based authentication for this container.
When enabled, eligible GET requests issued by this client will be authenticated using
a short-lived session credential obtained from the service instead
of the provided TokenCredential. Only supported with a TokenCredential;
ValueError is raised otherwise. Defaults to False.

.. admonition:: Example:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
max_single_get_size: int = 32 * 1024 * 1024,
max_chunk_get_size: int = 4 * 1024 * 1024,
audience: Optional[str] = None,
use_session: bool = False,
**kwargs: Any
) -> None: ...
def __enter__(self) -> Self: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pyli
:keyword str audience: The audience to use when requesting tokens for Azure Active Directory
authentication. Only has an effect when credential is of type TokenCredential. The value could be
https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net.
:keyword bool use_session: If True, enable session-based authentication for this container.
When enabled, eligible GET requests issued by this client will be authenticated using
a short-lived session credential obtained from the service instead
of the provided TokenCredential. Only supported with a TokenCredential;
ValueError is raised otherwise. Defaults to False.

.. admonition:: Example:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin):
max_single_get_size: int = 32 * 1024 * 1024,
min_large_block_upload_threshold: int = 4 * 1024 * 1024 + 1,
use_byte_buffer: Optional[bool] = None,
use_session: bool = False,
**kwargs: Any,
) -> None: ...
def __enter__(self) -> Self: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
build_break_lease_request,
build_change_lease_request,
build_create_request,
build_create_session_request,
build_delete_request,
build_filter_blobs_request,
build_get_access_policy_request,
Expand Down Expand Up @@ -1861,3 +1862,82 @@ async def get_account_info(

if cls:
return cls(pipeline_response, None, response_headers) # type: ignore

@distributed_trace_async
async def create_session(
self,
create_session_configuration: _models.CreateSessionConfiguration,
timeout: Optional[int] = None,
request_id_parameter: Optional[str] = None,
**kwargs: Any
) -> _models.CreateSessionResponse:
"""The Create Session operation enables users to create a session scoped to a container.

:param create_session_configuration: Required.
:type create_session_configuration: ~azure.storage.blob.models.CreateSessionConfiguration
:param timeout: The timeout parameter is expressed in seconds. For more information, see
:code:`<a
href="https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations">Setting
Timeouts for Blob Service Operations.</a>`. Default value is None.
:type timeout: int
:param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character
limit that is recorded in the analytics logs when storage analytics logging is enabled. Default
value is None.
:type request_id_parameter: str
:return: CreateSessionResponse or the result of cls(response)
:rtype: ~azure.storage.blob.models.CreateSessionResponse
:raises ~azure.core.exceptions.HttpResponseError:
"""
error_map: MutableMapping = {
401: ClientAuthenticationError,
404: ResourceNotFoundError,
409: ResourceExistsError,
304: ResourceNotModifiedError,
}
error_map.update(kwargs.pop("error_map", {}) or {})

_headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})

restype: Literal["container"] = kwargs.pop("restype", _params.pop("restype", "container"))
comp: Literal["session"] = kwargs.pop("comp", _params.pop("comp", "session"))
content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/xml"))
cls: ClsType[_models.CreateSessionResponse] = kwargs.pop("cls", None)

_content = self._serialize.body(create_session_configuration, "CreateSessionConfiguration", is_xml=True)

_request = build_create_session_request(
url=self._config.url,
version=self._config.version,
timeout=timeout,
request_id_parameter=request_id_parameter,
restype=restype,
comp=comp,
content_type=content_type,
content=_content,
headers=_headers,
params=_params,
)
_request.url = self._client.format_url(_request.url)

_stream = False
pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access
_request, stream=_stream, **kwargs
)

response = pipeline_response.http_response

if response.status_code not in [201]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize.failsafe_deserialize(
_models.StorageError,
pipeline_response,
)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize("CreateSessionResponse", pipeline_response.http_response)

if cls:
return cls(pipeline_response, deserialized, {}) # type: ignore

return deserialized # type: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
CorsRule,
CpkInfo,
CpkScopeInfo,
CreateSessionConfiguration,
CreateSessionResponse,
DelimitedTextConfiguration,
FilterBlobItem,
FilterBlobSegment,
Expand All @@ -59,6 +61,7 @@
QuerySerialization,
RetentionPolicy,
SequenceNumberAccessConditions,
SessionCredentials,
SignedIdentifier,
SourceCpkInfo,
SourceModifiedAccessConditions,
Expand All @@ -75,6 +78,7 @@
AccessTierRequired,
AccountKind,
ArchiveStatus,
AuthenticationType,
BlobCopySourceTags,
BlobExpiryOptions,
BlobImmutabilityPolicyMode,
Expand Down Expand Up @@ -129,6 +133,8 @@
"CorsRule",
"CpkInfo",
"CpkScopeInfo",
"CreateSessionConfiguration",
"CreateSessionResponse",
"DelimitedTextConfiguration",
"FilterBlobItem",
"FilterBlobSegment",
Expand All @@ -149,6 +155,7 @@
"QuerySerialization",
"RetentionPolicy",
"SequenceNumberAccessConditions",
"SessionCredentials",
"SignedIdentifier",
"SourceCpkInfo",
"SourceModifiedAccessConditions",
Expand All @@ -162,6 +169,7 @@
"AccessTierRequired",
"AccountKind",
"ArchiveStatus",
"AuthenticationType",
"BlobCopySourceTags",
"BlobExpiryOptions",
"BlobImmutabilityPolicyMode",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ class ArchiveStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta):
REHYDRATE_PENDING_TO_SMART = "rehydrate-pending-to-smart"


class AuthenticationType(str, Enum, metaclass=CaseInsensitiveEnumMeta):
"""The type of authentication required to create the session. The only type currently supported is
HMAC.
"""

HMAC = "HMAC"


class BlobCopySourceTags(str, Enum, metaclass=CaseInsensitiveEnumMeta):
"""BlobCopySourceTags."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,84 @@ def __init__(self, *, encryption_scope: Optional[str] = None, **kwargs: Any) ->
self.encryption_scope = encryption_scope


class CreateSessionConfiguration(_serialization.Model):
"""CreateSessionConfiguration.

All required parameters must be populated in order to send to server.

:ivar authentication_type: The type of authentication required to create the session. The only
type currently supported is HMAC. Required. "HMAC"
:vartype authentication_type: str or ~azure.storage.blob.models.AuthenticationType
"""

_validation = {
"authentication_type": {"required": True},
}

_attribute_map = {
"authentication_type": {"key": "AuthenticationType", "type": "str"},
}
_xml_map = {"name": "CreateSessionRequest"}

def __init__(self, *, authentication_type: Union[str, "_models.AuthenticationType"], **kwargs: Any) -> None:
"""
:keyword authentication_type: The type of authentication required to create the session. The
only type currently supported is HMAC. Required. "HMAC"
:paramtype authentication_type: str or ~azure.storage.blob.models.AuthenticationType
"""
super().__init__(**kwargs)
self.authentication_type = authentication_type


class CreateSessionResponse(_serialization.Model):
"""CreateSessionResponse.

:ivar id: A unique identifier for the created session.
:vartype id: str
:ivar expiration: The time when the session will expire. The format follows RFC 1123.
:vartype expiration: ~datetime.datetime
:ivar authentication_type: The type of authentication required to create the session. The only
type currently supported is HMAC. "HMAC"
:vartype authentication_type: str or ~azure.storage.blob.models.AuthenticationType
:ivar credentials:
:vartype credentials: ~azure.storage.blob.models.SessionCredentials
"""

_attribute_map = {
"id": {"key": "Id", "type": "str"},
"expiration": {"key": "Expiration", "type": "rfc-1123"},
"authentication_type": {"key": "AuthenticationType", "type": "str"},
"credentials": {"key": "Credentials", "type": "SessionCredentials"},
}
_xml_map = {"name": "CreateSessionResult"}

def __init__(
self,
*,
id: Optional[str] = None, # pylint: disable=redefined-builtin
expiration: Optional[datetime.datetime] = None,
authentication_type: Optional[Union[str, "_models.AuthenticationType"]] = None,
credentials: Optional["_models.SessionCredentials"] = None,
**kwargs: Any
) -> None:
"""
:keyword id: A unique identifier for the created session.
:paramtype id: str
:keyword expiration: The time when the session will expire. The format follows RFC 1123.
:paramtype expiration: ~datetime.datetime
:keyword authentication_type: The type of authentication required to create the session. The
only type currently supported is HMAC. "HMAC"
:paramtype authentication_type: str or ~azure.storage.blob.models.AuthenticationType
:keyword credentials:
:paramtype credentials: ~azure.storage.blob.models.SessionCredentials
"""
super().__init__(**kwargs)
self.id = id
self.expiration = expiration
self.authentication_type = authentication_type
self.credentials = credentials


class DelimitedTextConfiguration(_serialization.Model):
"""Groups the settings used for interpreting the blob data if the blob is delimited text
formatted.
Expand Down Expand Up @@ -2483,6 +2561,39 @@ def __init__(
self.if_sequence_number_equal_to = if_sequence_number_equal_to


class SessionCredentials(_serialization.Model):
"""SessionCredentials.

:ivar session_token: An opaque token used to authorize subsequent requests in the session. Must
be treated as a security credential.
:vartype session_token: str
:ivar session_key: Only returned when AuthenticationType is HMAC. A symmetric encryption key
used to sign requests in the session using the Shared Key protocol.
:vartype session_key: str
"""

_attribute_map = {
"session_token": {"key": "SessionToken", "type": "str"},
"session_key": {"key": "SessionKey", "type": "str"},
}
_xml_map = {"name": "Credentials"}

def __init__(
self, *, session_token: Optional[str] = None, session_key: Optional[str] = None, **kwargs: Any
) -> None:
"""
:keyword session_token: An opaque token used to authorize subsequent requests in the session.
Must be treated as a security credential.
:paramtype session_token: str
:keyword session_key: Only returned when AuthenticationType is HMAC. A symmetric encryption key
used to sign requests in the session using the Shared Key protocol.
:paramtype session_key: str
"""
super().__init__(**kwargs)
self.session_token = session_token
self.session_key = session_key


class SignedIdentifier(_serialization.Model):
"""signed identifier.

Expand Down
Loading