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

Respect Sas token in conn string #8940

Merged
merged 4 commits into from
Dec 3, 2019

Conversation

JoshLove-msft
Copy link
Member

@JoshLove-msft JoshLove-msft commented Nov 28, 2019

  • Update StorageConnectionString to include Sas token in the various Endpoint properties.
  • Remove ctors from StorageConnectionString that are only used in tests, and instead add corresponding factory methods to TestExtensions
  • Remove Table related code in StorageConnectionString and tests as this SDK doesn't support table endpoints.

Fixes #8859

if ((services & AccountSasServices.Files) == AccountSasServices.Files)
{
sb.Append(Constants.Sas.AccountServices.File);
}
if ((services & AccountSasServices.Queues) == AccountSasServices.Queues)
Copy link
Member Author

@JoshLove-msft JoshLove-msft Nov 28, 2019

Choose a reason for hiding this comment

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

Moved this down for consistency with the ordering the Portal uses when constructing the Sas signature. Otherwise we get a sig mismatch error when using a copy+pasted conn string with sas token from the portal.

Copy link
Member

Choose a reason for hiding this comment

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

Mind adding a comment in the source explaining why the order's important?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

Copy link
Member

@jongio jongio left a comment

Choose a reason for hiding this comment

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

Thank you Josh!

var sasBuilder = new AccountSasBuilder
{
ExpiresOn = Recording.UtcNow.AddHours(1),
Services = AccountSasServices.All,
Copy link
Member

Choose a reason for hiding this comment

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

Do we have tests that cover only Blob, Files, and Queues. Or since this is just for blobs, should test for Blobs and All?

Copy link
Member

Choose a reason for hiding this comment

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

Blobs and All should be sufficient for this file. Adding additional tests in the Files and Queue test projects might be a good idea.

{
ExpiresOn = Recording.UtcNow.AddHours(1),
Services = AccountSasServices.All,
ResourceTypes = AccountSasResourceTypes.All,
Copy link
Member

Choose a reason for hiding this comment

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

Can we also test individually for Container, Object, Service?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

ResourceTypes = AccountSasResourceTypes.All,
Protocol = SasProtocol.Https,
};
sasBuilder.SetPermissions(AccountSasPermissions.All);
Copy link
Member

Choose a reason for hiding this comment

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

If not done already would be good to have coverage for Read only and Write only.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a Read-only

Copy link
Member Author

Choose a reason for hiding this comment

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

And a Write, Delete

/// <param name="storageCredentials">A StorageCredentials object.</param>
/// <param name="useHttps"><c>true</c> to use HTTPS to connect to storage service endpoints; otherwise, <c>false</c>.</param>
/// <remarks>Using HTTPS to connect to the storage services is recommended.</remarks>
internal static StorageConnectionString CreateStorageConnectionString(object storageCredentials, bool useHttps) =>
Copy link
Member

Choose a reason for hiding this comment

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

Should this param be of type object or restricted to an interface?

Copy link
Member Author

Choose a reason for hiding this comment

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

As an FYI, this and the bodies of the other new factory methods were extracted as-is from StorageConnectionString constructors, which were only used by tests.

The parameter is object, because it can be either a SharedAccessSignatureCredentials or a StorageSharedKeyCredential. We probably didn't have them inherit from a common type so as to avoid adding types that customers wouldn't actually need to use.

Copy link
Member

Choose a reason for hiding this comment

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

Azure.Core didn't want to add a base Credential type so we're stuck with object.

{
accountName = sharedKeyCredentials.AccountName;
}
else
Copy link
Member

Choose a reason for hiding this comment

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

Should we use else if here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure

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

var protocol = useHttps ? "https" : "http";
Copy link
Member

Choose a reason for hiding this comment

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

Technically when discussing URIs, this part is called the scheme, not protocol.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated

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.

Looks good.

Copy link
Member

@tg-msft tg-msft left a comment

Choose a reason for hiding this comment

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

Please get escrow approval before merging this change.

if ((services & AccountSasServices.Files) == AccountSasServices.Files)
{
sb.Append(Constants.Sas.AccountServices.File);
}
if ((services & AccountSasServices.Queues) == AccountSasServices.Queues)
Copy link
Member

Choose a reason for hiding this comment

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

Mind adding a comment in the source explaining why the order's important?

{
var builder = new UriBuilder(endpoint)
{
Query = sasToken
Copy link
Member

Choose a reason for hiding this comment

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

Do we know for sure the endpoint will never have any query params? Especially since connection strings aren't well defined anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

Would you recommend using HttpUtility.ParseQueryString to append sasToken?

Copy link
Member

Choose a reason for hiding this comment

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

No, I don't think we need to parse it - I just don't want to stomp any values. I'd create the builder first without setting Query. If sasToken isn't null/empty, then we can check whether builder.Query has a value before appending (and possibly squeezing in a &).

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated

endpointSuffix);

return (new Uri(primaryUri), new Uri(secondaryUri));
return (primaryUriBuilder.Uri, secondaryUriBuilder.Uri);
Copy link
Member

Choose a reason for hiding this comment

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

Nit - is it worth sharing a single builder and just changing the host between Uri creation?

/// <param name="storageCredentials">A StorageCredentials object.</param>
/// <param name="useHttps"><c>true</c> to use HTTPS to connect to storage service endpoints; otherwise, <c>false</c>.</param>
/// <remarks>Using HTTPS to connect to the storage services is recommended.</remarks>
internal static StorageConnectionString CreateStorageConnectionString(object storageCredentials, bool useHttps) =>
Copy link
Member

Choose a reason for hiding this comment

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

Azure.Core didn't want to add a base Credential type so we're stuck with object.

@tg-msft
Copy link
Member

tg-msft commented Dec 2, 2019

Also - do we need to verify HTTPS if a SAS is used via connection string now?

@JoshLove-msft
Copy link
Member Author

Also - do we need to verify HTTPS if a SAS is used via connection string now?

We should add this for SAS in general, not just for connection string, but let's do it in a separate PR.

@JoshLove-msft
Copy link
Member Author

Also - do we need to verify HTTPS if a SAS is used via connection string now?

We should add this for SAS in general, not just for connection string, but let's do it in a separate PR.

Ended up adding this in here.

@JoshLove-msft JoshLove-msft changed the title Respect Sas token in conn string Respect Sas token in conn string and prevent sending Sas over HTTP Dec 3, 2019
/// The transport pipeline used to send every request.
/// </param>
/// <param name="clientDiagnostics"></param>
internal ShareServiceClient(Uri serviceUri, HttpPipeline pipeline, ClientDiagnostics clientDiagnostics)
Copy link
Member Author

Choose a reason for hiding this comment

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

This ctor is unused.

/// The transport pipeline used to send every request.
/// </param>
/// <param name="clientDiagnostics"></param>
internal QueueServiceClient(Uri serviceUri, HttpPipeline pipeline, ClientDiagnostics clientDiagnostics)
Copy link
Member Author

Choose a reason for hiding this comment

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

Unused

@JoshLove-msft
Copy link
Member Author

Also - do we need to verify HTTPS if a SAS is used via connection string now?

We should add this for SAS in general, not just for connection string, but let's do it in a separate PR.

Ended up adding this in here.

Backing this out. This needs more discussion.

@JoshLove-msft JoshLove-msft changed the title Respect Sas token in conn string and prevent sending Sas over HTTP Respect Sas token in conn string Dec 3, 2019
@JoshLove-msft JoshLove-msft merged commit a9f3c47 into Azure:master Dec 3, 2019
@JoshLove-msft JoshLove-msft deleted the sas-conn-string branch December 3, 2019 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Azure Blob Storage: Connection String SAS
4 participants