Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.

Commit 36497ba

Browse files
authored
Support for AAD subject name issue authentication (#788)
* Introduce a new generic cert loader service. * Make ASC use a static http client and move the data provider away from using client secrets and towards using cert based aad authentication. * Update documentation for ASC data provider * Add retry while lookingup certificates to address timing issue caused on local dev environment. * Move MDM Cert loader to use the generic certificate loader * Cleanup cert loaders since respective data provider is now dependent on generic cert loader. * Move Geomaster client to use certificate from generic cert loader. * Support for loading certificates from dev keyvault to computer user store. This helps dev environment without without constant intervention. * Remove unsed namespaces * Add keyvault certificate loader for dev environment to build pipeline * Add support for subject name + issuer authentication for AAD bearer tokens. This eliminated the need to store client secret. Add support for token cache and auto token refresh. * Cleanup Asc token service since it now acquires token via subject name + issuer auth via the generic token service. * Switch Asc client to use generic token service. * SDK for MSAL. * Config for loading certificate used to acquire AAD token. * Move Kusto SDK client to use subject name issuer AAD authentication. * Initialize generic certificate loader and cleanup other certificate loaders+ASC token service. * Add a new Http data provider. Helps test the generic token service enabling move of other data providers to this approach. * Resolve merge conflict * Fix typofor method name * Add mock values for ASC data provider and tests to succeed. * Add a new method fixing the typo in earlier method name. Once this change is deployed, will deprecate the method with typo and by updating detector code. * Fix build error
1 parent 0d494c9 commit 36497ba

34 files changed

Lines changed: 2492 additions & 532 deletions

src/Diagnostics.DataProviders/AscClient.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static string UserAgent
4646
/// </summary>
4747
private readonly DiagnosticsETWProvider logger;
4848

49-
private readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() =>
49+
private static readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() =>
5050
{
5151
var client = new HttpClient();
5252
client.DefaultRequestHeaders.Clear();
@@ -75,13 +75,21 @@ public static string UserAgent
7575
/// </summary>
7676
private string DiagAscHeaderValue;
7777

78+
private string _clientId = string.Empty;
79+
private Uri _aadAuthorityUri;
80+
private string _tokenAudience = string.Empty;
81+
private string _tokenRequestorCertSubjectName = string.Empty;
82+
7883
/// <summary>
7984
/// Initializes a new instance of the <see cref="AscClient"/> class.
8085
/// <param name="config">Config for Asc Data Provider.</param>
8186
/// <param name="appLensRequestId">AppLens Request Id, used for logging.</param>
8287
/// </summary>
8388
public AscClient(AscDataProviderConfiguration config, string appLensRequestId, IHeaderDictionary incomingRequestHeaders)
8489
{
90+
_clientId = config.ClientId;
91+
_aadAuthorityUri = new Uri(config.AADAuthority);
92+
_tokenAudience = config.TokenResource;
8593
baseUri = config.BaseUri;
8694
apiUri = config.ApiUri;
8795
apiVersion = config.ApiVersion;
@@ -96,6 +104,7 @@ public AscClient(AscDataProviderConfiguration config, string appLensRequestId, I
96104
SubscriptionLocationPlacementId = string.Empty;
97105
}
98106
DiagAscHeaderValue = config.DiagAscHeader;
107+
_tokenRequestorCertSubjectName = config.TokenRequestorCertSubjectName;
99108
}
100109

101110
private HttpClient httpClient
@@ -125,7 +134,7 @@ private HttpClient httpClient
125134

126135
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri))
127136
{
128-
requestMessage.Headers.Add("Authorization", await AscTokenService.Instance.GetAuthorizationTokenAsync());
137+
requestMessage.Headers.Add("Authorization", await TokenRequestorFromPFXService.Instance.GetAuthorizationTokenAsync(_clientId, _aadAuthorityUri, _tokenAudience, _tokenRequestorCertSubjectName, true));
129138
requestMessage.Content = new StringContent(jsonPostBody, Encoding.UTF8, "application/json");
130139
return await GetAscResponse<T>(requestMessage, false, cancellationToken);
131140
}
@@ -171,7 +180,7 @@ private HttpClient httpClient
171180

172181
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri))
173182
{
174-
requestMessage.Headers.Add("Authorization", await AscTokenService.Instance.GetAuthorizationTokenAsync());
183+
requestMessage.Headers.Add("Authorization", await TokenRequestorFromPFXService.Instance.GetAuthorizationTokenAsync(_clientId, _aadAuthorityUri, _tokenAudience, _tokenRequestorCertSubjectName, true));
175184
return await GetAscResponse<T>(requestMessage, false, cancellationToken);
176185
}
177186
}

src/Diagnostics.DataProviders/ConfigurationFactory.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,32 @@ protected override string GetValue(string prefix, string name)
137137
return string.Empty;
138138
}
139139
}
140+
else if (prefix == "AzureSupportCenter")
141+
{
142+
switch (name)
143+
{
144+
case "BaseUri":
145+
return "https://api.diagnostics.msftcloudes.com";
146+
break;
147+
case "ApiUri":
148+
return "/api/diagnosis/";
149+
break;
150+
case "ApiVersion":
151+
return "2018-02-01";
152+
break;
153+
case "UserAgent":
154+
return "AppLensClient";
155+
break;
156+
case "AADAuthority":
157+
return "https://login.microsoftonline.com/MSAzureCloud.onmicrosoft.com";
158+
break;
159+
case "TokenResource":
160+
return "https://msazurecloud.onmicrosoft.com/azurediagnostic";
161+
break;
162+
default:
163+
return string.Empty;
164+
}
165+
}
140166

141167
return string.Empty;
142168
}

src/Diagnostics.DataProviders/DataProviderConfigurations/ASCDataProviderConfiguration.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,9 @@ public class AscDataProviderConfiguration : DataProviderConfigurationBase, IData
6363
/// </summary>
6464
[ConfigurationName("DiagAscHeader")]
6565
public string DiagAscHeader { get; set; }
66+
67+
[ConfigurationName("TokenRequestorCertSubjectName")]
68+
[Required]
69+
public string TokenRequestorCertSubjectName { get; set; }
6670
}
6771
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.DataAnnotations;
4+
5+
6+
namespace Diagnostics.DataProviders.DataProviderConfigurations
7+
{
8+
[DataSourceConfiguration("HttpProvider")]
9+
public class HttpDataProviderConfiguration : DataProviderConfigurationBase, IDataProviderConfiguration
10+
{
11+
/// <summary>
12+
/// Subject name of the certificate that will be used by default to acquire token from AAD while sending HTTP requests.
13+
/// </summary>
14+
[ConfigurationName("DefaultTokenRequestorCertSubjectName")]
15+
[Required]
16+
public string DefaultTokenRequestorCertSubjectName { get; set; }
17+
18+
/// <summary>
19+
/// Subject name of the certificate that will be sent as client certificate along with the HTTP request to support certificate based authentication.
20+
/// </summary>
21+
[ConfigurationName("DefaultClientCertAuthSubjectName")]
22+
[Required]
23+
public string DefaultClientCertAuthSubjectName { get; set; }
24+
25+
/// <summary>
26+
/// User Agent value passed to external endpoint.
27+
/// </summary>
28+
[ConfigurationName("UserAgent")]
29+
[Required]
30+
public string UserAgent { get; set; }
31+
32+
/// <summary>
33+
/// Domain URI of the AAD Tenant where the aad app resides.
34+
/// </summary>
35+
[ConfigurationName("DefaultAADAuthority")]
36+
[Required]
37+
public string DefaultAADAuthority { get; set; }
38+
39+
private Uri _defaultAADAuthorityUri = default(Uri);
40+
41+
public Uri DefaultAADAuthorityUri
42+
{
43+
get {
44+
if (_defaultAADAuthorityUri == null)
45+
{
46+
_defaultAADAuthorityUri = new Uri(DefaultAADAuthority);
47+
}
48+
return _defaultAADAuthorityUri;
49+
}
50+
}
51+
52+
/// <summary>
53+
/// Client id of of the aad app to request the token from.
54+
/// </summary>
55+
[ConfigurationName("DefaultAADClientId")]
56+
[Required]
57+
public string DefaultAADClientId { get; set; }
58+
59+
/// <summary>
60+
/// Timeout value in milliseconds for all outbound requests.
61+
/// </summary>
62+
[ConfigurationName("DefaultRequestTimeOutInMilliSeconds")]
63+
[Required]
64+
public int DefaultRequestTimeOutInMilliSeconds { get; set; }
65+
66+
/// <summary>
67+
/// Number of connections that are open simultaneously to a given destination URL.
68+
/// </summary>
69+
[ConfigurationName("MaxConnectionsPerServer")]
70+
[Required]
71+
public int MaxConnectionsPerServer { get; set; }
72+
73+
/// <summary>
74+
/// Comma seperated list of headers that are prohibited to include in outgoiung HTTP calls
75+
/// </summary>
76+
[ConfigurationName("ProhibitedHeadersCSV")]
77+
[Required]
78+
public string ProhibitedHeaders { get; set; }
79+
80+
private List<string> _prohibitedHeadersList = new List<string>();
81+
public List<string> ProhibitedHeadersList
82+
{
83+
get
84+
{
85+
if (_prohibitedHeadersList.Count < 1 && !string.IsNullOrWhiteSpace(ProhibitedHeaders))
86+
{
87+
foreach (string currHeaderName in ProhibitedHeaders.Split(','))
88+
{
89+
if (!string.IsNullOrWhiteSpace(currHeaderName))
90+
{
91+
_prohibitedHeadersList.Add(currHeaderName.Trim());
92+
}
93+
}
94+
}
95+
return _prohibitedHeadersList;
96+
}
97+
}
98+
}
99+
}

src/Diagnostics.DataProviders/DataProviderConfigurations/KustoDataProviderConfiguration.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ public class KustoDataProviderConfiguration : DataProviderConfigurationBase, IDa
2121
public string ClientId { get; set; }
2222

2323
/// <summary>
24-
/// App Key
24+
/// Subject name of the certificate that will be sent to AAD for token acquisition.
2525
/// </summary>
26-
[ConfigurationName("AppKey")]
26+
[ConfigurationName("TokenRequestorCertSubjectName")]
2727
[Required]
28-
public string AppKey { get; set; }
28+
public string TokenRequestorCertSubjectName { get; set; }
2929

3030
/// <summary>
3131
/// DB Name

src/Diagnostics.DataProviders/DataProviders.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class DataProviders
2020
public ILogAnalyticsDataProvider K8SELogAnalytics;
2121
public Func<MdmDataSource, IMdmDataProvider> Mdm;
2222
public Func<GenericMdmDataProviderConfiguration, IMdmDataProvider> MdmGeneric;
23+
public IHttpDataProvider Http;
2324

2425
private readonly List<LogDecoratorBase> _dataProviderList = new List<LogDecoratorBase>();
2526

@@ -64,6 +65,8 @@ public DataProviders(DataProviderContext context)
6465
{
6566
return GetOrAddDataProvider(new MdmLogDecorator(context, new MdmDataProvider(_cache, new GenericMdmDataProviderConfigurationWrapper(config), context.RequestId, context.receivedHeaders)));
6667
};
68+
69+
Http = GetOrAddDataProvider(new HttpDataProviderLogDecorator(context, new HttpDataProvider(_cache, context.Configuration.HttpDataProviderConfiguration, context)));
6770
}
6871

6972
private T GetOrAddDataProvider<T>(T dataProvider) where T : LogDecoratorBase

0 commit comments

Comments
 (0)