Skip to content

Commit 2186bfb

Browse files
authored
Implement support for TokenCredential Auth (Azure#21915)
* Implement support for TokenCredential Auth
1 parent 7d10f16 commit 2186bfb

File tree

133 files changed

+72586
-42
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+72586
-42
lines changed

sdk/tables/Azure.Data.Tables/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Support for Azure Active Directory (AAD) authorization has been added to `TableServiceClient` and `TableClient`. This enables use of `TokenCredential` credentials. Note: Only Azure Storage API endpoints currently support AAD authorization.
8+
79
### Breaking Changes
810

911
### Key Bugs Fixed

sdk/tables/Azure.Data.Tables/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ az cosmosdb table create --name MyTableName --resource-group MyResourceGroup --a
5151

5252
### Authenticate the Client
5353

54-
Learn more about options for authentication _(including Connection Strings, Shared Key, and Shared Key Signatures)_ [in our samples.](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/tables/Azure.Data.Tables/samples/Sample0Auth.md)
54+
Learn more about options for authentication _(including Connection Strings, Shared Key, Shared Key Signatures, and TokenCredentials)_ [in our samples.](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/tables/Azure.Data.Tables/samples/Sample0Auth.md)
5555

5656
## Key concepts
5757

sdk/tables/Azure.Data.Tables/api/Azure.Data.Tables.netstandard2.0.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public TableClient(string connectionString, string tableName) { }
1414
public TableClient(string connectionString, string tableName, Azure.Data.Tables.TableClientOptions options = null) { }
1515
public TableClient(System.Uri endpoint, Azure.AzureSasCredential credential, Azure.Data.Tables.TableClientOptions options = null) { }
1616
public TableClient(System.Uri endpoint, Azure.Data.Tables.TableClientOptions options = null) { }
17+
public TableClient(System.Uri endpoint, string tableName, Azure.Core.TokenCredential tokenCredential, Azure.Data.Tables.TableClientOptions options = null) { }
1718
public TableClient(System.Uri endpoint, string tableName, Azure.Data.Tables.TableSharedKeyCredential credential) { }
1819
public TableClient(System.Uri endpoint, string tableName, Azure.Data.Tables.TableSharedKeyCredential credential, Azure.Data.Tables.TableClientOptions options = null) { }
1920
public virtual string AccountName { get { throw null; } }
@@ -108,6 +109,7 @@ public TableServiceClient(string connectionString) { }
108109
public TableServiceClient(string connectionString, Azure.Data.Tables.TableClientOptions options = null) { }
109110
public TableServiceClient(System.Uri endpoint, Azure.AzureSasCredential credential) { }
110111
public TableServiceClient(System.Uri endpoint, Azure.AzureSasCredential credential, Azure.Data.Tables.TableClientOptions options = null) { }
112+
public TableServiceClient(System.Uri endpoint, Azure.Core.TokenCredential tokenCredential, Azure.Data.Tables.TableClientOptions options = null) { }
111113
public TableServiceClient(System.Uri endpoint, Azure.Data.Tables.TableClientOptions options = null) { }
112114
public TableServiceClient(System.Uri endpoint, Azure.Data.Tables.TableSharedKeyCredential credential) { }
113115
public TableServiceClient(System.Uri endpoint, Azure.Data.Tables.TableSharedKeyCredential credential, Azure.Data.Tables.TableClientOptions options) { }

sdk/tables/Azure.Data.Tables/samples/Sample0Auth.md

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ or
2323

2424
```C# Snippet:TablesAuthConnString
2525
// Construct a new TableClient using a connection string.
26-
2726
var client = new TableClient(
2827
connectionString,
2928
tableName);
3029

3130
// Create the table if it doesn't already exist to verify we've successfully authenticated.
32-
3331
await client.CreateIfNotExistsAsync();
3432
```
3533

@@ -57,14 +55,12 @@ az cosmosdb list-keys --name <account_name> --resource-group <resource_group>
5755

5856
```C# Snippet:TablesAuthSharedKey
5957
// Construct a new TableClient using a TableSharedKeyCredential.
60-
6158
var client = new TableClient(
6259
new Uri(storageUri),
6360
tableName,
6461
new TableSharedKeyCredential(accountName, accountKey));
6562

6663
// Create the table if it doesn't already exist to verify we've successfully authenticated.
67-
6864
await client.CreateIfNotExistsAsync();
6965
```
7066

@@ -83,29 +79,46 @@ account blade.
8379

8480
```C# Snippet:TablesAuthSas
8581
// Construct a new <see cref="TableServiceClient" /> using a <see cref="TableSharedKeyCredential" />.
86-
8782
var credential = new TableSharedKeyCredential(accountName, accountKey);
8883

8984
var serviceClient = new TableServiceClient(
9085
new Uri(storageUri),
9186
credential);
9287

9388
// Build a shared access signature with the Write and Delete permissions and access to all service resource types.
94-
9589
var sasUri = serviceClient.GenerateSasUri(
9690
TableAccountSasPermissions.Write | TableAccountSasPermissions.Delete,
9791
TableAccountSasResourceTypes.All,
9892
new DateTime(2040, 1, 1, 1, 1, 0, DateTimeKind.Utc));
9993

10094
// Create the TableServiceClients using the SAS URI.
101-
10295
var serviceClientWithSas = new TableServiceClient(sasUri);
10396

10497
// Validate that we are able to create a table using the SAS URI with Write and Delete permissions.
105-
10698
await serviceClientWithSas.CreateTableIfNotExistsAsync(tableName);
10799

108100
// Validate that we are able to delete a table using the SAS URI with Write and Delete permissions.
109-
110101
await serviceClientWithSas.DeleteTableAsync(tableName);
111102
```
103+
104+
## TokenCredential
105+
106+
Azure Tables provides integration with Azure Active Directory (Azure AD) for identity-based authentication of requests
107+
to the Table service when targeting a Storage endpoint. With Azure AD, you can use role-based access control (RBAC) to
108+
grant access to your Azure Table resources to users, groups, or applications.
109+
110+
To access a table resource with a `TokenCredential`, the authenticated identity should have either the "Storage Table Data Contributor" or "Storage Table Data Reader" role.
111+
112+
With the `Azure.Identity` package, you can seamlessly authorize requests in both development and production environments.
113+
To learn more about Azure AD integration in Azure Storage, see the [Azure.Identity README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md)
114+
115+
```C# Snippet:TablesAuthTokenCredential
116+
// Construct a new TableClient using a TokenCredential.
117+
var client = new TableClient(
118+
new Uri(storageUri),
119+
tableName,
120+
new DefaultAzureCredential());
121+
122+
// Create the table if it doesn't already exist to verify we've successfully authenticated.
123+
await client.CreateIfNotExistsAsync();
124+
```

sdk/tables/Azure.Data.Tables/src/TableClient.cs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public virtual string AccountName
7979
/// <param name="options">
8080
/// Optional client options that define the transport pipeline policies for authentication, retries, etc., that are applied to every request.
8181
/// </param>
82-
/// <exception cref="ArgumentException"><paramref name="endpoint"/> is not https.</exception>
82+
/// <exception cref="ArgumentException"><paramref name="endpoint"/> does not start with 'https'.</exception>
8383
public TableClient(Uri endpoint, TableClientOptions options = null)
8484
: this(endpoint, null, default, default, options)
8585
{
@@ -102,7 +102,8 @@ public TableClient(Uri endpoint, TableClientOptions options = null)
102102
/// <param name="options">
103103
/// Optional client options that define the transport pipeline policies for authentication, retries, etc., that are applied to every request.
104104
/// </param>
105-
/// <exception cref="ArgumentException"><paramref name="endpoint"/> is not https.</exception>
105+
/// <exception cref="ArgumentException"><paramref name="endpoint"/> does not start with 'https'.</exception>
106+
/// <exception cref="ArgumentNullException"><paramref name="credential"/> is null.</exception>
106107
public TableClient(Uri endpoint, AzureSasCredential credential, TableClientOptions options = null)
107108
: this(endpoint, null, default, credential, options)
108109
{
@@ -123,6 +124,7 @@ public TableClient(Uri endpoint, AzureSasCredential credential, TableClientOptio
123124
/// </param>
124125
/// <param name="tableName">The name of the table with which this client instance will interact.</param>
125126
/// <param name="credential">The shared key credential used to sign requests.</param>
127+
/// <exception cref="ArgumentException"><paramref name="tableName"/> is an empty string.</exception>
126128
/// <exception cref="ArgumentNullException"><paramref name="tableName"/> or <paramref name="credential"/> is null.</exception>
127129
public TableClient(Uri endpoint, string tableName, TableSharedKeyCredential credential)
128130
: this(endpoint, tableName, new TableSharedKeyPipelinePolicy(credential), default, null)
@@ -143,6 +145,7 @@ public TableClient(Uri endpoint, string tableName, TableSharedKeyCredential cred
143145
/// <param name="options">
144146
/// Optional client options that define the transport pipeline policies for authentication, retries, etc., that are applied to every request.
145147
/// </param>
148+
/// <exception cref="ArgumentException"><paramref name="tableName"/> is an empty string.</exception>
146149
/// <exception cref="ArgumentNullException"><paramref name="tableName"/> or <paramref name="credential"/> is null.</exception>
147150
public TableClient(Uri endpoint, string tableName, TableSharedKeyCredential credential, TableClientOptions options = null)
148151
: this(endpoint, tableName, new TableSharedKeyPipelinePolicy(credential), default, options)
@@ -164,6 +167,7 @@ public TableClient(Uri endpoint, string tableName, TableSharedKeyCredential cred
164167
/// Configure Azure Storage connection strings</see>.
165168
/// </param>
166169
/// <param name="tableName">The name of the table with which this client instance will interact.</param>
170+
/// <exception cref="ArgumentNullException"><paramref name="connectionString"/> or <paramref name="tableName"/> is null.</exception>
167171
public TableClient(string connectionString, string tableName)
168172
: this(connectionString, tableName, default)
169173
{ }
@@ -185,9 +189,12 @@ public TableClient(string connectionString, string tableName)
185189
/// <param name="options">
186190
/// Optional client options that define the transport pipeline policies for authentication, retries, etc., that are applied to every request.
187191
/// </param>
192+
/// <exception cref="ArgumentException"><paramref name="tableName"/> is an empty string.</exception>
193+
/// <exception cref="ArgumentNullException"><paramref name="connectionString"/> or <paramref name="tableName"/> is null.</exception>
188194
public TableClient(string connectionString, string tableName, TableClientOptions options = null)
189195
{
190196
Argument.AssertNotNull(connectionString, nameof(connectionString));
197+
Argument.AssertNotNullOrEmpty(tableName, nameof(tableName));
191198

192199
TableConnectionString connString = TableConnectionString.Parse(connectionString);
193200
_accountName = connString._accountName;
@@ -212,6 +219,52 @@ public TableClient(string connectionString, string tableName, TableClientOptions
212219
Name = tableName;
213220
}
214221

222+
/// <summary>
223+
/// Initializes a new instance of the <see cref="TableClient"/> using the specified <see cref="Uri" /> and <see cref="TokenCredential"/>.
224+
/// </summary>
225+
/// <param name="endpoint">
226+
/// A <see cref="Uri"/> referencing the table service account.
227+
/// This is likely to be similar to "https://{account_name}.table.core.windows.net/{table_name}"
228+
/// or "https://{account_name}.table.cosmos.azure.com/{table_name}".
229+
/// </param>
230+
/// <param name="tableName">The name of the table with which this client instance will interact.</param>
231+
/// <param name="tokenCredential">The <see cref="TokenCredential"/> used to authorize requests.</param>
232+
/// <param name="options">
233+
/// Optional client options that define the transport pipeline policies for authentication, retries, etc., that are applied to every request.
234+
/// </param>
235+
/// <exception cref="ArgumentException"><paramref name="endpoint"/> does not start with 'https'. or <paramref name="tableName"/> is an empty string.</exception>
236+
/// <exception cref="ArgumentNullException"><paramref name="tableName"/>, <paramref name="endpoint"/>, or <paramref name="tokenCredential"/> is null.</exception>
237+
public TableClient(Uri endpoint, string tableName, TokenCredential tokenCredential, TableClientOptions options = default)
238+
{
239+
Argument.AssertNotNull(endpoint, nameof(endpoint));
240+
Argument.AssertNotNull(tokenCredential, nameof(tokenCredential));
241+
242+
// If we were provided no tableName, try to parse it from the endpoint.
243+
if (string.IsNullOrEmpty(tableName))
244+
{
245+
tableName = new TableSasBuilder(endpoint).TableName;
246+
}
247+
248+
Argument.AssertNotNullOrEmpty(tableName, nameof(tableName));
249+
250+
_endpoint = endpoint;
251+
_isCosmosEndpoint = TableServiceClient.IsPremiumEndpoint(endpoint);
252+
options ??= TableClientOptions.DefaultOptions;
253+
254+
var perCallPolicies = _isCosmosEndpoint ? new[] { new CosmosPatchTransformPolicy() } : Array.Empty<HttpPipelinePolicy>();
255+
256+
_pipeline = HttpPipelineBuilder.Build(
257+
options,
258+
perCallPolicies,
259+
new[] { new BearerTokenAuthenticationPolicy(tokenCredential, TableConstants.StorageScope) },
260+
new ResponseClassifier());
261+
262+
_version = options.VersionString;
263+
_diagnostics = new TablesClientDiagnostics(options);
264+
_tableOperations = new TableRestClient(_diagnostics, _pipeline, endpoint.AbsoluteUri, _version);
265+
Name = tableName;
266+
}
267+
215268
internal TableClient(Uri endpoint, string tableName, TableSharedKeyPipelinePolicy policy, AzureSasCredential sasCredential, TableClientOptions options)
216269
{
217270
Argument.AssertNotNull(endpoint, nameof(endpoint));

sdk/tables/Azure.Data.Tables/src/TableConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal static class TableConstants
77
{
88
internal const string LegacyCosmosTableDomain = ".table.cosmosdb.";
99
internal const string CosmosTableDomain = ".table.cosmos.";
10+
internal const string StorageScope = "https://storage.azure.com/.default";
1011

1112
internal static class HeaderNames
1213
{

0 commit comments

Comments
 (0)