// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using Microsoft.SqlServer.Management.Smo; using Azure.Storage.Blobs; using Azure.Storage; using Azure.Storage.Sas; using Microsoft.SqlTools.ServiceLayer.AzureBlob.Contracts; using System.Globalization; namespace Microsoft.SqlTools.ServiceLayer.AzureBlob { class SharedAccessSignatureCreator { private Server sqlServer; public SharedAccessSignatureCreator(Server sqlServer) { this.sqlServer = sqlServer; } public string CreateSqlSASCredential(string accountName, string accountKey, string containerUri, string expirationDateString) { DateTimeOffset? expirationDate = null; if (!String.IsNullOrEmpty(expirationDateString)) { expirationDate = DateTimeOffset.Parse(expirationDateString, CultureInfo.InvariantCulture); } var containerClient = new BlobContainerClient(new Uri(containerUri), new StorageSharedKeyCredential(accountName, accountKey)); Uri secretStringUri = GetServiceSasUriForContainer(containerClient, null, expirationDate); string secretString = secretStringUri.ToString().Split('?')[1]; string identity = "Shared Access Signature"; WriteSASCredentialToSqlServer(containerUri, identity, secretString); return secretString; } /// /// Create sql sas credential with the given credential name /// /// Name of sas credential, here is the same of the full container url. /// Identity for credential, here is fixed as "Shared Access Signature" /// Secret of credential, which is sharedAccessSignatureForContainer /// The newly created SAS credential public Credential WriteSASCredentialToSqlServer(string credentialName, string identity, string secretString) { try { // Format of Sql SAS credential: // CREATE CREDENTIAL [https://.blob.core.windows.net/] WITH IDENTITY = N'Shared Access Signature', // SECRET = N'sv=2014-02-14&sr=c&sig=lxb2aXr%2Bi0Aeygg%2B0a4REZ%2BqsUxxxxxxsqUybg0tVzg%3D&st=2015-10-15T08%3A00%3A00Z&se=2015-11-15T08%3A00%3A00Z&sp=rwdl' // CredentialCollection credentials = sqlServer.Credentials; Credential azureCredential = new Credential(sqlServer, credentialName); // Container can have many SAS credentials coexisting, here we'll always drop existing one once customer choose to create new credential // since sql customer has no way to know its existency and even harder to retrive its secret string. if (credentials.Contains(credentialName)) { Credential oldCredential = credentials[credentialName]; oldCredential.Drop(); } azureCredential.Create(identity, secretString); return azureCredential; } catch (Exception ex) { throw new FailedOperationException(SR.WriteSASCredentialToSqlServerFailed, ex); } } /// /// Create Shared Access Policy for container /// Default Accesss permission is Write/List/Read/Delete /// /// /// /// public Uri GetServiceSasUriForContainer(BlobContainerClient containerClient, string storedPolicyName = null, DateTimeOffset? expiringDate = null) { // Check whether this BlobContainerClient object has been authorized with Shared Key. if (containerClient.CanGenerateSasUri) { // Create a SAS token BlobSasBuilder sasBuilder = new BlobSasBuilder() { BlobContainerName = containerClient.Name, Resource = BlobSasResource.BLOB_CONTAINER }; if (storedPolicyName == null) { sasBuilder.ExpiresOn = (DateTimeOffset)(expiringDate == null ? DateTimeOffset.UtcNow.AddYears(1) : expiringDate); sasBuilder.SetPermissions(BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Delete); } else { sasBuilder.Identifier = storedPolicyName; } Uri sasUri = containerClient.GenerateSasUri(sasBuilder); return sasUri; } else { throw new FailedOperationException(SR.CreateSasForBlobContainerFailed); } } } }