Skip to content

Commit cc8bdfc

Browse files
Tables aad (Azure#19299)
closes Azure#19244
1 parent 22cc32f commit cc8bdfc

File tree

40 files changed

+7166
-33
lines changed

40 files changed

+7166
-33
lines changed

sdk/tables/azure-data-tables/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 12.0.1 (Unreleased)
44

55
### Features Added
6+
* Storage Accounts only: `TableClient` and `TableServiceClient`s can now use `azure-identity` credentials for authentication. Note: A `TableClient` authenticated with a `TokenCredential` cannot use the `get_table_access_policy` or `set_table_access_policy` methods.
67

78
### Breaking Changes
89

sdk/tables/azure-data-tables/azure/data/tables/_base_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ def format_query_string(sas_token, credential):
394394
"You cannot use AzureSasCredential when the resource URI also contains a Shared Access Signature.")
395395
if sas_token and not credential:
396396
query_str += sas_token
397-
elif isinstance(credential, (AzureSasCredential, AzureNamedKeyCredential)):
397+
elif credential:
398398
return "", credential
399399
return query_str.rstrip("?&"), None
400400

sdk/tables/azure-data-tables/azure/data/tables/_table_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
7272
:param str table_name: The table name.
7373
:keyword credential:
7474
The credentials with which to authenticate. This is optional if the
75-
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential
76-
or AzureSasCredential from azure-core.
75+
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential (azure-core),
76+
AzureSasCredential (azure-core), or TokenCredentials from azure-identity.
7777
:paramtype credential:
7878
:class:`~azure.core.credentials.AzureNamedKeyCredential` or
79-
:class:`~azure.core.credentials.AzureSasCredential`
79+
:class:`~azure.core.credentials.AzureSasCredential` or
80+
:class:`~azure.core.credentials.TokenCredential`
8081
:returns: None
8182
"""
8283
if not table_name:

sdk/tables/azure-data-tables/azure/data/tables/_table_service_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ class TableServiceClient(TablesBaseClient):
4444
authenticated with a SAS token.
4545
:keyword credential:
4646
The credentials with which to authenticate. This is optional if the
47-
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential
48-
or AzureSasCredential from azure-core.
47+
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential (azure-core),
48+
AzureSasCredential (azure-core), or TokenCredentials from azure-identity.
4949
:paramtype credential:
5050
:class:`~azure.core.credentials.AzureNamedKeyCredential` or
51-
:class:`~azure.core.credentials.AzureSasCredential`
51+
:class:`~azure.core.credentials.AzureSasCredential` or
52+
:class:`~azure.core.credentials.TokenCredential`
5253
:keyword str api_version:
5354
The Storage API version to use for requests. Default value is '2019-02-02'.
5455
Setting to an older version may result in reduced feature compatibility.

sdk/tables/azure-data-tables/azure/data/tables/aio/_table_client_async.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential
6161
:param str table_name: The table name.
6262
:keyword credential:
6363
The credentials with which to authenticate. This is optional if the
64-
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential
65-
or AzureSasCredential from azure-core.
64+
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential (azure-core),
65+
AzureSasCredential (azure-core), or TokenCredentials from azure-identity.
6666
:paramtype credential:
6767
:class:`~azure.core.credentials.AzureNamedKeyCredential` or
68-
:class:`~azure.core.credentials.AzureSasCredential`
68+
:class:`~azure.core.credentials.AzureSasCredential` or
69+
:class:`~azure.core.credentials.TokenCredential`
6970
7071
:returns: None
7172
"""

sdk/tables/azure-data-tables/azure/data/tables/aio/_table_service_client_async.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ class TableServiceClient(AsyncTablesBaseClient):
4747
authenticated with a SAS token.
4848
:keyword credential:
4949
The credentials with which to authenticate. This is optional if the
50-
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential
51-
or AzureSasCredential from azure-core.
50+
account URL already has a SAS token. The value can be one of AzureNamedKeyCredential (azure-core),
51+
AzureSasCredential (azure-core), or TokenCredentials from azure-identity.
5252
:paramtype credential:
5353
:class:`~azure.core.credentials.AzureNamedKeyCredential` or
54-
:class:`~azure.core.credentials.AzureSasCredential`
54+
:class:`~azure.core.credentials.AzureSasCredential` or
55+
:class:`~azure.core.credentials.TokenCredential`
5556
:keyword str api_version:
5657
The Storage API version to use for requests. Default value is '2019-02-02'.
5758
Setting to an older version may result in reduced feature compatibility.

sdk/tables/azure-data-tables/tests/_shared/asynctestcase.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
EdmType,
1717
)
1818
from azure.data.tables.aio import TableServiceClient
19+
from azure.identity.aio import DefaultAzureCredential
1920

2021
from devtools_testutils import is_live
2122

@@ -38,6 +39,11 @@ async def get_token(self, *args):
3839

3940

4041
class AsyncTableTestCase(TableTestCase):
42+
def get_token_credential(self):
43+
if is_live():
44+
return DefaultAzureCredential()
45+
return self.generate_fake_token()
46+
4147
def generate_fake_token(self):
4248
return AsyncFakeTokenCredential()
4349

@@ -116,9 +122,9 @@ async def _insert_random_entity(self, pk=None, rk=None):
116122
metadata = await self.table.create_entity(entity=entity)
117123
return entity, metadata["etag"]
118124

119-
async def _set_up(self, account_name, account_key, url="table"):
125+
async def _set_up(self, account_name, credential, url="table"):
120126
account_url = self.account_url(account_name, url)
121-
self.ts = TableServiceClient(account_url, credential=account_key)
127+
self.ts = TableServiceClient(account_url, credential=credential)
122128
self.table_name = self.get_resource_name("uttable")
123129
self.table = self.ts.get_table_client(self.table_name)
124130
if self.is_live:

sdk/tables/azure-data-tables/tests/_shared/testcase.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,22 @@
2323
TableMetrics,
2424
TableServiceClient,
2525
)
26+
from azure.identity import DefaultAzureCredential
2627

2728
from devtools_testutils import is_live
2829

2930
SLEEP_DELAY = 30
3031

3132
TEST_TABLE_PREFIX = "pytablesync"
3233

34+
SERVICE_UNAVAILABLE_RESP_BODY = '<?xml version="1.0" encoding="utf-8"?><StorageServiceStats><GeoReplication><Status' \
35+
'>unavailable</Status><LastSyncTime></LastSyncTime></GeoReplication' \
36+
'></StorageServiceStats> '
37+
38+
SERVICE_LIVE_RESP_BODY = '<?xml version="1.0" encoding="utf-8"?><StorageServiceStats><GeoReplication><Status' \
39+
'>live</Status><LastSyncTime>Wed, 19 Jan 2021 22:28:43 GMT</LastSyncTime></GeoReplication' \
40+
'></StorageServiceStats> '
41+
3342

3443
class FakeTokenCredential(object):
3544
"""Protocol for classes able to provide OAuth tokens.
@@ -81,6 +90,11 @@ def generate_sas_token(self):
8190
expiry=datetime.now() + timedelta(days=8),
8291
)
8392

93+
def get_token_credential(self):
94+
if is_live():
95+
return DefaultAzureCredential()
96+
return self.generate_fake_token()
97+
8498
def generate_fake_token(self):
8599
return FakeTokenCredential()
86100

@@ -421,10 +435,10 @@ def _insert_random_entity(self, pk=None, rk=None):
421435
metadata = self.table.create_entity(entity)
422436
return entity, metadata["etag"]
423437

424-
def _set_up(self, account_name, account_key, url="table"):
438+
def _set_up(self, account_name, credential, url="table"):
425439
self.table_name = self.get_resource_name("uttable")
426440
self.ts = TableServiceClient(
427-
self.account_url(account_name, url), credential=account_key, table_name=self.table_name
441+
self.account_url(account_name, url), credential=credential, table_name=self.table_name
428442
)
429443
self.table = self.ts.get_table_client(self.table_name)
430444
if self.is_live:
@@ -449,6 +463,13 @@ def _assert_stats_unavailable(self, stats):
449463
assert stats["geo_replication"]["status"] == "unavailable"
450464
assert stats["geo_replication"]["last_sync_time"] is None
451465

466+
@staticmethod
467+
def override_response_body_with_unavailable_status(response):
468+
response.http_response.text = lambda _: SERVICE_UNAVAILABLE_RESP_BODY
469+
470+
@staticmethod
471+
def override_response_body_with_live_status(response):
472+
response.http_response.text = lambda _: SERVICE_LIVE_RESP_BODY
452473

453474
class ResponseCallback(object):
454475
def __init__(self, status=None, new_status=None):
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- application/xml
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Date:
12+
- Thu, 17 Jun 2021 16:53:03 GMT
13+
User-Agent:
14+
- azsdk-python-data-tables/12.0.1 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
15+
x-ms-date:
16+
- Thu, 17 Jun 2021 16:53:03 GMT
17+
x-ms-version:
18+
- '2019-02-02'
19+
method: GET
20+
uri: https://fake_table_account.table.core.windows.net/pytablesync7b551169?comp=acl
21+
response:
22+
body:
23+
string: '<?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code>ResourceNotFound</m:code><m:message
24+
xml:lang="en-US">The specified resource does not exist.
25+
26+
RequestId:7c3b01c2-0002-006a-1999-63305d000000
27+
28+
Time:2021-06-17T16:53:05.6341722Z</m:message></m:error>'
29+
headers:
30+
content-length:
31+
- '322'
32+
content-type:
33+
- application/xml
34+
date:
35+
- Thu, 17 Jun 2021 16:53:04 GMT
36+
server:
37+
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
38+
x-ms-error-code:
39+
- ResourceNotFound
40+
x-ms-version:
41+
- '2019-02-02'
42+
status:
43+
code: 404
44+
message: The specified resource does not exist.
45+
- request:
46+
body: null
47+
headers:
48+
Accept:
49+
- application/xml
50+
Accept-Encoding:
51+
- gzip, deflate
52+
Connection:
53+
- keep-alive
54+
Content-Length:
55+
- '0'
56+
Content-Type:
57+
- application/xml
58+
Date:
59+
- Thu, 17 Jun 2021 16:53:04 GMT
60+
User-Agent:
61+
- azsdk-python-data-tables/12.0.1 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
62+
x-ms-date:
63+
- Thu, 17 Jun 2021 16:53:04 GMT
64+
x-ms-version:
65+
- '2019-02-02'
66+
method: PUT
67+
uri: https://fake_table_account.table.core.windows.net/pytablesync7b551169?comp=acl
68+
response:
69+
body:
70+
string: '<?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code>ResourceNotFound</m:code><m:message
71+
xml:lang="en-US">The specified resource does not exist.
72+
73+
RequestId:7c3b0201-0002-006a-5499-63305d000000
74+
75+
Time:2021-06-17T16:53:05.7602607Z</m:message></m:error>'
76+
headers:
77+
content-length:
78+
- '322'
79+
content-type:
80+
- application/xml
81+
date:
82+
- Thu, 17 Jun 2021 16:53:04 GMT
83+
server:
84+
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
85+
x-ms-error-code:
86+
- ResourceNotFound
87+
x-ms-version:
88+
- '2019-02-02'
89+
status:
90+
code: 404
91+
message: The specified resource does not exist.
92+
version: 1

0 commit comments

Comments
 (0)