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] SAS Credential in Storage. #17646

Merged
merged 32 commits into from
Jan 11, 2021

Conversation

kasobol-msft
Copy link
Contributor

@kasobol-msft kasobol-msft commented Dec 18, 2020

In this PR:

  • Usage of AzureSasCredential in Storage

Remarks

  • This PR builds on the top of Add AzureSasCredential #17636 and must wait until referenced PR goes first. Please post comments related to SAS credentials in that PR.

@ghost ghost added Azure.Core Storage Storage Service (Queues, Blobs, Files) labels Dec 18, 2020
@@ -111,6 +111,28 @@ public BlobChangeFeedClient(Uri serviceUri, StorageSharedKeyCredential credentia
_blobServiceClient = new BlobServiceClient(serviceUri, credential, options);
}

/// <summary>
/// Initializes a new instance of the <see cref="BlobChangeFeedClient"/>
/// class.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a blurb to all these doc comments telling people to only use this overload if they need to roll SAS signatures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added remarks.

Comment on lines 51 to 52
=> new ArgumentException($"The resource URI {uri} must not contain SAS if AzureSasCredential is used." +
$" You can use BlobUriBuilder to strip SAS from the resource URI before instantiating clients.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about something like?

Suggested change
=> new ArgumentException($"The resource URI {uri} must not contain SAS if AzureSasCredential is used." +
$" You can use BlobUriBuilder to strip SAS from the resource URI before instantiating clients.");
=> new ArgumentException(
$"You cannot use {nameof(AzureSasCredential)} when the resource URI also contains a Shared Access Signature: {uri}\n" +
$"You can remove the shared access signature by creating a {nameof(BlobUriBuilder)}, setting {nameof(BlobUriBuilder.Sas)} to null, and calling {nameof(BlobUriBuilder.ToUri)}.");

Anyone getting this exception is probably going to be confused. I'd like to put the URI after the core of the message so it's not lost behind a very long string.

Copy link
Contributor Author

@kasobol-msft kasobol-msft Dec 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds Good.

/// <returns>An authentication policy.</returns>
public static HttpPipelinePolicy AsPolicy(this AzureSasCredential credential, Uri serviceUri)
{
var queryParameters = serviceUri.GetQueryParameters();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to check if serviceUri is null? I think this will get called before validation in base(...) for some .ctors. Consider also taking in the name of the URI param so you can throw the most helpful exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could. However, after writing test for that and wrapping this piece of code in null check I found that NullReferenceException is thrown here.
Maybe we should add Argument.AssertNotNull in both AsPolicy and ctros ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added validations.

@@ -61,7 +61,24 @@ public static void AssertExpectedException<T>(Action action, T expectedException

public static void AssertExpectedException<T>(Action action, Func<T, bool> predicate = null)
where T : Exception
=> AssertExpectedException(action, default, GetDefaultExceptionAssertion<T>((_, a) => predicate(a)));
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you flip it around and make the other version call this then with a predicate: _ => true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which other version do you mean? The one that takes expectedException?

The problem here was that existing implementation of this overload ended up in this line attempting to assert exception message, which was deemed to always fail... This overload of AssertExpectedException had zero callers because of that problem.

@kasobol-msft kasobol-msft marked this pull request as ready for review January 5, 2021 17:30
Copy link
Member

@seanmcc-msft seanmcc-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Blob Batch?

@kasobol-msft
Copy link
Contributor Author

What about Blob Batch?

The Batch should work without change as long as underlying service client is created with AzureSASCredential. Added test for that.

@@ -228,6 +231,7 @@ public partial class DataLakePathClient
public DataLakePathClient(string connectionString, string fileSystemName, string path) { }
public DataLakePathClient(string connectionString, string fileSystemName, string path, Azure.Storage.Files.DataLake.DataLakeClientOptions options) { }
public DataLakePathClient(System.Uri pathUri) { }
public DataLakePathClient(System.Uri pathUri, Azure.AzureSasCredential credential, Azure.Storage.Files.DataLake.DataLakeClientOptions options = null) { }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a different ctor parameter pattern for the TokenCredential (3 overloads instead of defaulted options). Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less code. I was trying to understand why do we have such pattern in place, but nobody would recall why. From user POV there shouldn't be a difference (unless I'm missing something subtle here).

You can observe similar inconsistencies in APIs implementations. Some would come with multiple overloads, some will use optional parameters. I think those with multiple overloads approach are older.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the goal of all of these is to make mainline APIs look simpler. We've noticed that customers get scared of methods with many parameters even if they are all optional so opted for having overloads in important scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. I'll make it consistent then.

Copy link
Contributor

@pakrym pakrym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@KrzysztofCwalina KrzysztofCwalina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general looks good. Just a couple of nits and a question about the impact of using generic methods (where we don't have to) on AOT scenarios.

@@ -47,6 +47,12 @@ public static InvalidOperationException StreamMustBeAtPosition0()
public static InvalidOperationException TokenCredentialsRequireHttps()
=> new InvalidOperationException("Use of token credentials requires HTTPS");

public static ArgumentException SasCredentialRequiresUriWithoutSas<TUriBuilder>(Uri uri)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas, how does it affect AOT scenarios? Would it be better to pass the type as a method parameter (object or Type)?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic arguments are better than passing Type around. It is not just AOT, it is also a for IL trimming. Passing System.Type around is a potential problem for IL trimming and may sometime need annotations to work well with it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this specific case, it should not really matter since the typeof usage is trivial and the method is small. https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs in the CoreLib uses both patterns.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. so this stays I guess.

throw Errors.SasCredentialRequiresUriWithoutSas<TUriBuilder>(resourceUri);
}
return new AzureSasCredentialSynchronousPolicy(
credential ?? throw Errors.ArgumentNull(nameof(credential)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to check preconditions at the beginning of the method body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

/// A <see cref="Uri"/> referencing the directory that includes the
/// name of the account, the name of the file system, and the path of the
/// directory.
/// Must not contain shared access signature.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add ", which should be passed in the second (following) parameter" ... or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@kasobol-msft kasobol-msft merged commit e2fad94 into Azure:master Jan 11, 2021
minnieliu pushed a commit to minnieliu/azure-sdk-for-net that referenced this pull request Jan 23, 2021
* Add AzureSasCredential

* corner case.

* api.

* core as project ref (todo undo this)

* first client.

* hack azure core in webjobs for now.

* api.

* constructors.

* blob tests.

* datalake tests.

* share tests + take out sas on share and service clients as there isn't much APIs that would work with sas there.

* queues tests.

* well that works. nvm.

* remarks.

* error message.

* predicate shouldn't be optional.

* post-merge tweaks.

* message about right UriBuilder.

* added uri validation.

* changelog.

* user delegation sas change.

* batch.

* this test doesn't work well in playback mode.

* pr feedback.

* comments.

* validation.

* undo project references workaround.

* undo webjobs project ref workaround.
annelo-msft pushed a commit to annelo-msft/azure-sdk-for-net that referenced this pull request Feb 17, 2021
* Add AzureSasCredential

* corner case.

* api.

* core as project ref (todo undo this)

* first client.

* hack azure core in webjobs for now.

* api.

* constructors.

* blob tests.

* datalake tests.

* share tests + take out sas on share and service clients as there isn't much APIs that would work with sas there.

* queues tests.

* well that works. nvm.

* remarks.

* error message.

* predicate shouldn't be optional.

* post-merge tweaks.

* message about right UriBuilder.

* added uri validation.

* changelog.

* user delegation sas change.

* batch.

* this test doesn't work well in playback mode.

* pr feedback.

* comments.

* validation.

* undo project references workaround.

* undo webjobs project ref workaround.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Storage Storage Service (Queues, Blobs, Files)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants