Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Storage] Fixed bug where connection string with account name not set in Storage Client #48636

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions sdk/storage/Azure.Storage.Blobs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
### Breaking Changes

### Bugs Fixed
- Fixed bug where a `BlobServiceClient`, `BlobContainerClient`, `BlobBaseClient` created with a connection string with an account name specified (e.g. "AccountName=..;"), the account name was not populated on the Storage Clients if the account name was not also specified in the endpoint. (#42925)

### Other Changes

Expand Down
10 changes: 7 additions & 3 deletions sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ public BlobBaseClient(string connectionString, string blobContainerName, string
BlobName = blobName
};
_uri = builder.ToUri();
_accountName = conn.AccountName;
_containerName = blobContainerName;
_name = blobName;

_clientConfiguration = new BlobClientConfiguration(
pipeline: options.Build(conn.Credentials),
Expand Down Expand Up @@ -278,6 +281,7 @@ public BlobBaseClient(Uri blobUri, StorageSharedKeyCredential credential, BlobCl
sasCredential: null,
tokenCredential: null)
{
_accountName ??= credential?.AccountName;
}

/// <summary>
Expand Down Expand Up @@ -605,9 +609,9 @@ private void SetNameFieldsIfNull()
if (_name == null || _containerName == null || _accountName == null)
{
var builder = new BlobUriBuilder(Uri, ClientConfiguration.TrimBlobNameSlashes);
_name = builder.BlobName;
_containerName = builder.BlobContainerName;
_accountName = builder.AccountName;
_name ??= builder.BlobName;
_containerName ??= builder.BlobContainerName;
_accountName ??= builder.AccountName;
}
}

Expand Down
7 changes: 5 additions & 2 deletions sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ public BlobContainerClient(string connectionString, string blobContainerName, Bl
BlobContainerName = blobContainerName
};
_uri = builder.ToUri();
_name = blobContainerName;
_accountName = conn.AccountName;
options ??= new BlobClientOptions();

_clientConfiguration = new BlobClientConfiguration(
Expand Down Expand Up @@ -275,6 +277,7 @@ public BlobContainerClient(Uri blobContainerUri, StorageSharedKeyCredential cred
Argument.AssertNotNull(blobContainerUri, nameof(blobContainerUri));
HttpPipelinePolicy authPolicy = credential.AsPolicy();
_uri = blobContainerUri;
_accountName = credential.AccountName;
_authenticationPolicy = authPolicy;
options ??= new BlobClientOptions();

Expand Down Expand Up @@ -623,8 +626,8 @@ private void SetNameFieldsIfNull()
if (_name == null || _accountName == null)
{
var builder = new BlobUriBuilder(Uri, ClientConfiguration.TrimBlobNameSlashes);
_name = builder.BlobContainerName;
_accountName = builder.AccountName;
_name ??= builder.BlobContainerName;
_accountName ??= builder.AccountName;
}
}

Expand Down
1 change: 1 addition & 0 deletions sdk/storage/Azure.Storage.Blobs/src/BlobServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public BlobServiceClient(string connectionString, BlobClientOptions options)
_uri = conn.BlobEndpoint;
options ??= new BlobClientOptions();
_authenticationPolicy = StorageClientOptions.GetAuthenticationPolicy(conn.Credentials);
_accountName = conn.AccountName;

_clientConfiguration = new BlobClientConfiguration(
pipeline: options.Build(_authenticationPolicy),
Expand Down
22 changes: 22 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ public void Ctor_ConnectionString()
Assert.AreEqual("accountName", builder2.AccountName);
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

var containerName = "containername";
var blobName = "blobname";

BlobBaseClient blobClient = new BlobBaseClient(connectionString.ToString(true), containerName, blobName);

Assert.AreEqual(containerName, blobClient.BlobContainerName);
Assert.AreEqual(blobName, blobClient.Name);
Assert.AreEqual(accountName, blobClient.AccountName);
}

[RecordedTest]
public async Task Ctor_ConnectionStringEscapeBlobName()
{
Expand Down
24 changes: 24 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,30 @@ public void Ctor_ConnectionString()
Assert.AreEqual(accountName, builder.AccountName);
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

var containerName = "containername";

BlobContainerClient container = new BlobContainerClient(connectionString.ToString(true), containerName);

var builder = new BlobUriBuilder(container.Uri);

Assert.AreEqual(containerName, builder.BlobContainerName);
Assert.AreEqual("", builder.BlobName);
Assert.AreEqual(containerName, container.Name);
Assert.AreEqual(accountName, container.AccountName);
}

[RecordedTest]
[TestCase(true)] // https://github.com/Azure/azure-sdk-for-net/issues/9110
[TestCase(false)]
Expand Down
17 changes: 17 additions & 0 deletions sdk/storage/Azure.Storage.Blobs/tests/ServiceClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ public void Ctor_ConnectionString()
Assert.AreEqual(accountName, builder2.AccountName);
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

BlobServiceClient service = new BlobServiceClient(connectionString.ToString(true));

Assert.AreEqual(accountName, service.AccountName);
}

[RecordedTest]
public void Ctor_Uri()
{
Expand Down
1 change: 1 addition & 0 deletions sdk/storage/Azure.Storage.Common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Fixed bug to ensure that the accumulated disposables within the internal `StorageWriteStream` are disposed properly in the event that an exception is thrown during the disposal process. (#47781)
- Fixed bug to Redact SAS credentials from Error.SasCredentialRequiresUriWithoutSas message.
- Fixed bug where LazyLoadingReadOnlyStream overprovisions the default buffer memory for OpenRead
- Fixed bug where a client created with a connection string with an account name specified (e.g. "AccountName=..;"), the account name was not populated on the Storage Clients if the account name was not also specified in the endpoint. (#42925)

### Other Changes
- Implemented IAsyncDisposable in StorageWriteStream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ public static StorageConnectionString DevelopmentStorageAccount
public object Credentials { get; set; }

/// <summary>
/// Private record of the account name for use in ToString(bool).
/// Gets the account name.
/// </summary>
internal string _accountName;
public string AccountName;

/// <summary>
/// Parses a connection string and returns a <see cref="StorageConnectionString"/> created
Expand Down Expand Up @@ -516,7 +516,7 @@ static Uri CreateUri(string endpoint, string sasToken)
Settings = s_validCredentials(settings)
};

accountInformation._accountName = settingOrDefault(Constants.ConnectionStrings.AccountNameSetting);
accountInformation.AccountName = settingOrDefault(Constants.ConnectionStrings.AccountNameSetting);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ internal static StorageConnectionString CreateStorageConnectionString(
throw Errors.ArgumentNull(nameof(accountName));
}

conn._accountName = accountName;
conn.AccountName = accountName;
var sasToken = (storageCredentials is SharedAccessSignatureCredentials sasCredentials) ? sasCredentials.SasToken : default;

var scheme = useHttps ? Constants.Https : Constants.Http;
Expand Down Expand Up @@ -205,9 +205,9 @@ internal static string ToString(this StorageConnectionString conn, bool exportSe
listOfSettings.Add(ToString(conn.Credentials, exportSecrets));
}

if (!string.IsNullOrWhiteSpace(conn._accountName) && (conn.Credentials is StorageSharedKeyCredential sharedKeyCredentials ? string.IsNullOrWhiteSpace(sharedKeyCredentials.AccountName) : true))
if (!string.IsNullOrWhiteSpace(conn.AccountName) && (conn.Credentials is StorageSharedKeyCredential sharedKeyCredentials ? string.IsNullOrWhiteSpace(sharedKeyCredentials.AccountName) : true))
{
listOfSettings.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", Constants.ConnectionStrings.AccountNameSetting, conn._accountName));
listOfSettings.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", Constants.ConnectionStrings.AccountNameSetting, conn.AccountName));
}

return string.Join(";", listOfSettings);
Expand Down
1 change: 1 addition & 0 deletions sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
### Breaking Changes

### Bugs Fixed
- Fixed bug where a `DataLakeServiceClient`, `DataLakeFileSystemClient`, `DataLakeDirectoryClient`, `DataLakeFileClient`, `DataLakePathClient` created with a connection string with an account name specified (e.g. "AccountName=..;"), the account name was not populated on the Storage Clients if the account name was not also specified in the endpoint. (#42925)

### Other Changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Files.DataLake.Models;
using Metadata = System.Collections.Generic.IDictionary<string, string>;
using System.Text.Json;
using System.Collections.Generic;
using Azure.Storage.Shared;
using Azure.Storage.Sas;
using System.ComponentModel;
using static Azure.Storage.Constants.Sas;
using Azure.Storage.Common;

#pragma warning disable SA1402 // File may only contain a single type
Expand Down Expand Up @@ -237,6 +233,7 @@ public DataLakeFileSystemClient(string connectionString, string fileSystemName,
_uri = uriBuilder.ToUri();
_blobUri = uriBuilder.ToBlobUri();
_dfsUri = uriBuilder.ToDfsUri();
_accountName = conn.AccountName;

_clientConfiguration = new DataLakeClientConfiguration(
pipeline: options.Build(conn.Credentials),
Expand Down Expand Up @@ -594,8 +591,8 @@ private void SetNameFieldsIfNull()
if (_name == null || _accountName == null)
{
var builder = new DataLakeUriBuilder(Uri);
_name = builder.FileSystemName;
_accountName = builder.AccountName;
_name ??= builder.FileSystemName;
_accountName ??= builder.AccountName;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ public DataLakePathClient(
_uri = uriBuilder.ToUri();
_blobUri = uriBuilder.ToBlobUri();
_dfsUri = uriBuilder.ToDfsUri();
_accountName = conn.AccountName;
_path = path;

_clientConfiguration = new DataLakeClientConfiguration(
pipeline: options.Build(conn.Credentials),
Expand Down Expand Up @@ -763,10 +765,10 @@ internal virtual void SetNameFieldsIfNull()
|| _name == null)
{
var builder = new DataLakeUriBuilder(Uri);
_fileSystemName = builder.FileSystemName;
_accountName = builder.AccountName;
_path = builder.DirectoryOrFilePath;
_name = builder.LastDirectoryOrFileName;
_fileSystemName ??= builder.FileSystemName;
_accountName ??= builder.AccountName;
_path ??= builder.DirectoryOrFilePath;
_name ??= builder.LastDirectoryOrFileName;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
Expand Down Expand Up @@ -177,6 +176,7 @@ public DataLakeServiceClient(string connectionString, DataLakeClientOptions opti
customerProvidedKey: options.CustomerProvidedKey);

_uri = conn.BlobEndpoint;
_accountName = conn.AccountName;
_blobUri = new DataLakeUriBuilder(_uri).ToBlobUri();

_blobServiceClient = BlobServiceClientInternals.Create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@ public async Task Ctor_ConnectionString_GenerateSas()
}
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

var filesystemName = "filesystemName";

DataLakeFileSystemClient container = new DataLakeFileSystemClient(connectionString.ToString(true), filesystemName);

Assert.AreEqual(filesystemName, container.Name);
Assert.AreEqual(accountName, container.AccountName);
}

[RecordedTest]
public void Ctor_TokenCredential_Http()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,28 @@ public async Task Ctor_ConnectionString_GenerateSas()
await sasPathClient.GetAccessControlAsync();
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

var filesystemName = "filesystemName";
var pathName = "pathName";

DataLakePathClient pathClient = new DataLakePathClient(connectionString.ToString(true), filesystemName, pathName);

Assert.AreEqual(filesystemName, pathClient.FileSystemName);
Assert.AreEqual(pathName, pathClient.Name);
Assert.AreEqual(accountName, pathClient.AccountName);
}

[RecordedTest]
public void Ctor_TokenCredential_Http()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@ public async Task Ctor_ConnectionString_GenerateSas()
}
}

[Test]
public void Ctor_ConnectionString_CustomUri()
{
var accountName = "accountName";
var accountKey = Convert.ToBase64String(new byte[] { 0, 1, 2, 3, 4, 5 });

var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobEndpoint = new Uri("http://customdomain/" + accountName);
var blobSecondaryEndpoint = new Uri("http://customdomain/" + accountName + "-secondary");

var connectionString = new StorageConnectionString(credentials, blobStorageUri: (blobEndpoint, blobSecondaryEndpoint));

DataLakeServiceClient service = new DataLakeServiceClient(connectionString.ToString(true));

Assert.AreEqual(accountName, service.AccountName);
}

[RecordedTest]
public void Ctor_TokenCredential_Http()
{
Expand Down
1 change: 1 addition & 0 deletions sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
### Breaking Changes

### Bugs Fixed
- Fixed bug where a `ShareServiceClient`, `ShareClient`, `ShareDirectoryClient`, `ShareFileClient` created with a connection string with an account name specified (e.g. "AccountName=..;"), the account name was not populated on the Storage Clients if the account name was not also specified in the endpoint. (#42925)

### Other Changes

Expand Down
Loading