Skip to content

Commit 1b5ffd2

Browse files
authored
Sync to 172.76.0
1 parent 17b6e32 commit 1b5ffd2

File tree

78 files changed

+1715
-1054
lines changed

Some content is hidden

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

78 files changed

+1715
-1054
lines changed

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
Update this document for externally visible changes. Put most recent changes first.
44
Once we push a new version to nuget.org add a double hash header for that version.
55

6-
# 172.64.0
6+
## 172.76.0
7+
8+
- Fix scripting performance #165
9+
- Add new audit action type INFORMATION_PROTECTION_OPERATION_GROUP
10+
- Add new database level permissions ALTER ANY EXTERNAL MODEL, CREATE EXTERNAL MODEL and ALTER ANY INFORMATION PROTECTION
11+
12+
## 172.64.0
713

814
- Add DesignMode support to `QueryStoreOptions` class
915
- Add Vector data type support
1016

11-
# 172.61.0
17+
## 172.61.0
1218

1319
- Remove major version restriction on Microsoft.Data.SqlClient dependency Fixes [Issue 188](https://github.com/microsoft/sqlmanagementobjects/issues/188)
1420
- Remove net6 binaries

Directory.Packages.props

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,24 @@
22
See https://github.com/Microsoft/MSBuildSdks/tree/main/src/CentralPackageVersions
33
This file lists every nuget package dependency and its required version.
44
Do not put Version attributes on PackageReference tags in individual projects.
5-
Add explicit references to transitive package dependencies if the msbuild binlog shows there
6-
are double writes due to multiple versions of a package being imported.
7-
It's common that we could import packages A and B that both depend on package C but 2 different versions.
8-
Without a PackageReference to C, our build could pick up either version of C in a non-deterministic manner.
95
The binlog viewer will show both versions being copied to the output folder as a double write.
106
-->
117
<Project>
128
<PropertyGroup>
139
<DotNetPackagesVersion>6.0.0</DotNetPackagesVersion>
1410
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
11+
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
1512
</PropertyGroup>
1613
<ItemGroup>
1714
<!--
1815
When adding new package dependencies here, make sure to also add those packages to
1916
Microsoft.SqlServer.Smo.TestUtils.nuspec if they affect any of the related test utilities.
2017
-->
2118
<PackageVersion Include="Azure.Core" Version="1.41.0" />
22-
<PackageVersion Include="Azure.Identity" Version="1.11.4" />
19+
<PackageVersion Include="Azure.Identity" Version="1.12.0" />
2320
<PackageVersion Include="Azure.ResourceManager" Version="1.8.0" />
2421
<PackageVersion Include="Azure.ResourceManager.Storage" Version="1.1.1" />
22+
<PackageVersion Include="Azure.Storage.Blobs" Version="12.20.0" />
2523
<PackageVersion Include="Azure.Security.KeyVault.Secrets" Version="4.4.0" />
2624
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
2725
<PackageVersion Include="Microsoft.Data.SqlClient" Version="$(SqlClientPackageVersion)" />

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "8.0.406",
3+
"version": "8.0.409",
44
"rollForward": "latestMinor"
55
},
66
"msbuild-sdks": {

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
</PropertyGroup>
8585
<PropertyGroup>
8686
<!-- these variables are referenced by packagebuild.proj for inclusion in nuspecs and used by packages.props -->
87-
<SqlParserPackageVersion>172.18.0</SqlParserPackageVersion>
87+
<SqlParserPackageVersion>172.20.0</SqlParserPackageVersion>
8888
<SqlClientPackage>Microsoft.Data.SqlClient</SqlClientPackage>
8989
<SqlClientPackageVersion>5.1.6</SqlClientPackageVersion>
9090
</PropertyGroup>

src/FunctionalTest/Framework/Helpers/AzureKeyVaultHelper.cs

Lines changed: 29 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,17 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Linq;
76
using System.Security;
8-
using System.Security.Cryptography.X509Certificates;
97
using Azure.Identity;
10-
using Azure.ResourceManager;
11-
using Azure.ResourceManager.Storage;
128
using Azure.Security.KeyVault.Secrets;
139
using Microsoft.SqlServer.ADO.Identity;
1410
namespace Microsoft.SqlServer.Test.Manageability.Utils.Helpers
1511
{
1612
/// <summary>
1713
/// Retrieves a decrypted secret from Azure Key Vault or environment using certificate auth or client secret or managed identity
1814
/// </summary>
19-
public class AzureKeyVaultHelper
15+
public class AzureKeyVaultHelper : ICredential
2016
{
21-
/// <summary>
22-
/// The set of certificate thumbprints associated with the service principal.
23-
/// If this collection is non-empty, AzureApplicationId and AzureTenantId must also be set to valid values.
24-
/// Set these properties to use certificate-based authentication without relying on environment variables to specify the certificate.
25-
/// </summary>
26-
public IEnumerable<string> CertificateThumbprints { get; set; }
2717
/// <summary>
2818
/// The Azure application id associated with the service principal
2919
/// </summary>
@@ -39,14 +29,17 @@ public class AzureKeyVaultHelper
3929
/// <summary>
4030
/// The name of the Azure key vault where test secrets are stored.
4131
/// </summary>
42-
public string KeyVaultName { get; private set; }
43-
44-
private static readonly IDictionary<string,SecureString> secretCache = new Dictionary<string, SecureString>();
32+
public string KeyVaultName { get; set; }
33+
34+
/// <summary>
35+
/// The AzureStorageHelper instance used to access the storage account
36+
/// </summary>
37+
public AzureStorageHelper StorageHelper { get; set; }
38+
private static readonly IDictionary<string, SecureString> secretCache = new Dictionary<string, SecureString>();
4539
private static readonly object syncObj = new object();
4640
public static readonly string SSMS_TEST_SECRET_PREFIX = "SQLA-SSMS-Test-";
4741

4842
private SecretClient secretClient = null;
49-
private ArmClient armClient = null;
5043

5144
/// <summary>
5245
/// Constructs a new AzureKeyVaultHelper that relies on an instance of Azure.Identity.DefaultAzureCredential to access the given vault.
@@ -56,7 +49,6 @@ public AzureKeyVaultHelper(string keyVaultName)
5649
{
5750

5851
KeyVaultName = keyVaultName;
59-
CertificateThumbprints = Enumerable.Empty<string>();
6052
}
6153

6254
/// <summary>
@@ -101,7 +93,7 @@ public string GetDecryptedSecret(string secretName)
10193
Console.WriteLine(@"Got Exception fetching secret. Type:{0}, Inner:{1}, Outer:{2}", e.GetType(), e.InnerException, e);
10294
throw;
10395
}
104-
// Note we aren't bothering to cache secrets we found from GetEnvironmentVariable since that API is already fast
96+
// Note we aren't bothering to cache secrets we found from GetEnvironmentVariable since that API is already fast
10597
lock (syncObj)
10698
{
10799
secretCache[secretName] = secret.StringToSecureString();
@@ -110,71 +102,38 @@ public string GetDecryptedSecret(string secretName)
110102
return secret;
111103
}
112104

113-
private Azure.Core.TokenCredential GetCredential()
105+
/// <summary>
106+
/// Returns a TokenCredential that implements Managed Identity, DefaultAzureCredential, and AzurePipelinesCredential in that order.
107+
/// </summary>
108+
/// <returns></returns>
109+
public Azure.Core.TokenCredential GetCredential()
114110
{
111+
TraceHelper.TraceInformation($"Getting credential for Azure in tenant {AzureTenantId}");
115112
// prefer managed identity then local user on dev machine over the certificate
116113
var credentials = new List<Azure.Core.TokenCredential>() { new ManagedIdentityCredential(AzureManagedIdentityClientId), new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeManagedIdentityCredential = true, TenantId = AzureTenantId }) };
117-
foreach (var thumbprint in CertificateThumbprints ?? Enumerable.Empty<string>())
114+
var options = new AzureDevOpsFederatedTokenCredentialOptions() { TenantId = AzureTenantId, ClientId = AzureApplicationId };
115+
if (options.ServiceConnectionId != null)
118116
{
119-
var certificate = FindCertificate(thumbprint);
120-
if (certificate != null)
121-
{
122-
credentials.Add(new ClientCertificateCredential(AzureTenantId, AzureApplicationId, certificate));
123-
}
117+
TraceHelper.TraceInformation($"Adding AzurePipelinesCredential for tenant id {options.TenantId} using service connection {options.ServiceConnectionId}");
118+
credentials.Insert(0, new AzurePipelinesCredential(options.TenantId, options.ClientId, options.ServiceConnectionId, options.SystemAccessToken));
124119
}
125-
credentials.Add(new AzureDevOpsFederatedTokenCredential(new AzureDevOpsFederatedTokenCredentialOptions() { TenantId = AzureTenantId, ClientId = AzureApplicationId }));
126120
return new ChainedTokenCredential(credentials.ToArray());
127121
}
128122

123+
/// <summary>
124+
/// Returns the account access key for the given storage account resource id.
125+
/// </summary>
126+
/// <param name="storageAccountResourceId"></param>
127+
/// <returns></returns>
129128
public string GetStorageAccountAccessKey(string storageAccountResourceId)
130129
{
131130
TraceHelper.TraceInformation($"Fetching storage access key for {storageAccountResourceId}");
132-
if (armClient == null)
133-
{
134-
armClient = new ArmClient(GetCredential());
135-
}
136-
var storageAccount = armClient.GetStorageAccountResource(new Azure.Core.ResourceIdentifier(storageAccountResourceId));
137-
return storageAccount.GetKeys().First().Value;
131+
return new AzureStorageHelper(storageAccountResourceId, this).GetStorageAccountAccessKey(storageAccountResourceId);
138132
}
133+
}
139134

140-
private static X509Certificate2 FindCertificate(string thumbprint)
141-
{
142-
X509Certificate2 certificate = null;
143-
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
144-
{
145-
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
146-
try
147-
{
148-
store.Open(OpenFlags.ReadOnly);
149-
X509Certificate2Collection certificateCollection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: false);
150-
if (certificateCollection.Count == 0)
151-
{
152-
TraceHelper.TraceInformation("Couldn't find Smo cert {0} in local machine. Looking in current user", thumbprint);
153-
var userStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
154-
userStore.Open(OpenFlags.ReadOnly);
155-
try
156-
{
157-
certificateCollection = userStore.Certificates.Find(X509FindType.FindByThumbprint,
158-
thumbprint, validOnly: false);
159-
}
160-
finally
161-
{
162-
userStore.Close();
163-
}
164-
}
165-
if (certificateCollection.Count != 0)
166-
{
167-
TraceHelper.TraceInformation("Found cert {0}", thumbprint);
168-
certificate = certificateCollection[0];
169-
}
170-
}
171-
finally
172-
{
173-
store.Close();
174-
}
175-
}
176-
return certificate;
177-
}
178-
135+
public interface ICredential
136+
{
137+
Azure.Core.TokenCredential GetCredential();
179138
}
180139
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
5+
using System;
6+
using System.IO;
7+
using System.Linq;
8+
using Azure.ResourceManager;
9+
using Azure.ResourceManager.Storage;
10+
using Azure.Storage.Blobs;
11+
using Microsoft.SqlServer.Management.Smo;
12+
13+
namespace Microsoft.SqlServer.Test.Manageability.Utils.Helpers
14+
{
15+
/// <summary>
16+
/// Contains methods for configuring Azure storage access by SQL instances
17+
/// </summary>
18+
public class AzureStorageHelper
19+
{
20+
private ArmClient ArmClient => new ArmClient(CredentialProvider.GetCredential());
21+
22+
public string Id { get; private set; }
23+
public ICredential CredentialProvider { get; }
24+
25+
public AzureStorageHelper(string id, ICredential credentialProvider)
26+
{
27+
Id = id.Trim();
28+
CredentialProvider = credentialProvider;
29+
}
30+
31+
public string StorageAccountName => Id.Substring(Id.LastIndexOf('/') + 1);
32+
public Credential EnsureCredential(Management.Smo.Server server)
33+
{
34+
var credential = new Credential(server, StorageAccountName + Guid.NewGuid());
35+
credential.Create(StorageAccountName, GetStorageAccountAccessKey(Id));
36+
return credential;
37+
}
38+
39+
public string GetStorageAccountAccessKey(string storageAccountResourceId)
40+
{
41+
TraceHelper.TraceInformation($"Fetching storage access key for {storageAccountResourceId}");
42+
var storageAccount = ArmClient.GetStorageAccountResource(new Azure.Core.ResourceIdentifier(storageAccountResourceId));
43+
return storageAccount.GetKeys().First().Value;
44+
}
45+
46+
/// <summary>
47+
/// Downloads a blob from the given blob URL in Azure storage
48+
/// </summary>
49+
/// <param name="blobUrl"></param>
50+
/// <returns></returns>
51+
public string DownloadBlob(string blobUrl)
52+
{
53+
var ext = Path.GetExtension(blobUrl);
54+
var path = Path.GetTempFileName();
55+
var finalPath = Path.ChangeExtension(path, ext);
56+
File.Move(path, finalPath);
57+
var blobClient = new BlobClient(new Uri(blobUrl), CredentialProvider.GetCredential());
58+
using (var rsp = blobClient.DownloadTo(finalPath))
59+
{
60+
if (rsp.IsError)
61+
{
62+
throw new InvalidOperationException($"Unable to download blob '{blobUrl}'. Error: {rsp.ReasonPhrase}");
63+
}
64+
}
65+
return finalPath;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)