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

Commit

Permalink
Support for AAD subject name issue authentication (#788)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
nmallick1 authored Feb 26, 2022
1 parent 0d494c9 commit 36497ba
Show file tree
Hide file tree
Showing 34 changed files with 2,492 additions and 532 deletions.
15 changes: 12 additions & 3 deletions src/Diagnostics.DataProviders/AscClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static string UserAgent
/// </summary>
private readonly DiagnosticsETWProvider logger;

private readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() =>
private static readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() =>
{
var client = new HttpClient();
client.DefaultRequestHeaders.Clear();
Expand Down Expand Up @@ -75,13 +75,21 @@ public static string UserAgent
/// </summary>
private string DiagAscHeaderValue;

private string _clientId = string.Empty;
private Uri _aadAuthorityUri;
private string _tokenAudience = string.Empty;
private string _tokenRequestorCertSubjectName = string.Empty;

/// <summary>
/// Initializes a new instance of the <see cref="AscClient"/> class.
/// <param name="config">Config for Asc Data Provider.</param>
/// <param name="appLensRequestId">AppLens Request Id, used for logging.</param>
/// </summary>
public AscClient(AscDataProviderConfiguration config, string appLensRequestId, IHeaderDictionary incomingRequestHeaders)
{
_clientId = config.ClientId;
_aadAuthorityUri = new Uri(config.AADAuthority);
_tokenAudience = config.TokenResource;
baseUri = config.BaseUri;
apiUri = config.ApiUri;
apiVersion = config.ApiVersion;
Expand All @@ -96,6 +104,7 @@ public AscClient(AscDataProviderConfiguration config, string appLensRequestId, I
SubscriptionLocationPlacementId = string.Empty;
}
DiagAscHeaderValue = config.DiagAscHeader;
_tokenRequestorCertSubjectName = config.TokenRequestorCertSubjectName;
}

private HttpClient httpClient
Expand Down Expand Up @@ -125,7 +134,7 @@ private HttpClient httpClient

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

using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
requestMessage.Headers.Add("Authorization", await AscTokenService.Instance.GetAuthorizationTokenAsync());
requestMessage.Headers.Add("Authorization", await TokenRequestorFromPFXService.Instance.GetAuthorizationTokenAsync(_clientId, _aadAuthorityUri, _tokenAudience, _tokenRequestorCertSubjectName, true));
return await GetAscResponse<T>(requestMessage, false, cancellationToken);
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/Diagnostics.DataProviders/ConfigurationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ protected override string GetValue(string prefix, string name)
return string.Empty;
}
}
else if (prefix == "AzureSupportCenter")
{
switch (name)
{
case "BaseUri":
return "https://api.diagnostics.msftcloudes.com";
break;
case "ApiUri":
return "/api/diagnosis/";
break;
case "ApiVersion":
return "2018-02-01";
break;
case "UserAgent":
return "AppLensClient";
break;
case "AADAuthority":
return "https://login.microsoftonline.com/MSAzureCloud.onmicrosoft.com";
break;
case "TokenResource":
return "https://msazurecloud.onmicrosoft.com/azurediagnostic";
break;
default:
return string.Empty;
}
}

return string.Empty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,9 @@ public class AscDataProviderConfiguration : DataProviderConfigurationBase, IData
/// </summary>
[ConfigurationName("DiagAscHeader")]
public string DiagAscHeader { get; set; }

[ConfigurationName("TokenRequestorCertSubjectName")]
[Required]
public string TokenRequestorCertSubjectName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;


namespace Diagnostics.DataProviders.DataProviderConfigurations
{
[DataSourceConfiguration("HttpProvider")]
public class HttpDataProviderConfiguration : DataProviderConfigurationBase, IDataProviderConfiguration
{
/// <summary>
/// Subject name of the certificate that will be used by default to acquire token from AAD while sending HTTP requests.
/// </summary>
[ConfigurationName("DefaultTokenRequestorCertSubjectName")]
[Required]
public string DefaultTokenRequestorCertSubjectName { get; set; }

/// <summary>
/// Subject name of the certificate that will be sent as client certificate along with the HTTP request to support certificate based authentication.
/// </summary>
[ConfigurationName("DefaultClientCertAuthSubjectName")]
[Required]
public string DefaultClientCertAuthSubjectName { get; set; }

/// <summary>
/// User Agent value passed to external endpoint.
/// </summary>
[ConfigurationName("UserAgent")]
[Required]
public string UserAgent { get; set; }

/// <summary>
/// Domain URI of the AAD Tenant where the aad app resides.
/// </summary>
[ConfigurationName("DefaultAADAuthority")]
[Required]
public string DefaultAADAuthority { get; set; }

private Uri _defaultAADAuthorityUri = default(Uri);

public Uri DefaultAADAuthorityUri
{
get {
if (_defaultAADAuthorityUri == null)
{
_defaultAADAuthorityUri = new Uri(DefaultAADAuthority);
}
return _defaultAADAuthorityUri;
}
}

/// <summary>
/// Client id of of the aad app to request the token from.
/// </summary>
[ConfigurationName("DefaultAADClientId")]
[Required]
public string DefaultAADClientId { get; set; }

/// <summary>
/// Timeout value in milliseconds for all outbound requests.
/// </summary>
[ConfigurationName("DefaultRequestTimeOutInMilliSeconds")]
[Required]
public int DefaultRequestTimeOutInMilliSeconds { get; set; }

/// <summary>
/// Number of connections that are open simultaneously to a given destination URL.
/// </summary>
[ConfigurationName("MaxConnectionsPerServer")]
[Required]
public int MaxConnectionsPerServer { get; set; }

/// <summary>
/// Comma seperated list of headers that are prohibited to include in outgoiung HTTP calls
/// </summary>
[ConfigurationName("ProhibitedHeadersCSV")]
[Required]
public string ProhibitedHeaders { get; set; }

private List<string> _prohibitedHeadersList = new List<string>();
public List<string> ProhibitedHeadersList
{
get
{
if (_prohibitedHeadersList.Count < 1 && !string.IsNullOrWhiteSpace(ProhibitedHeaders))
{
foreach (string currHeaderName in ProhibitedHeaders.Split(','))
{
if (!string.IsNullOrWhiteSpace(currHeaderName))
{
_prohibitedHeadersList.Add(currHeaderName.Trim());
}
}
}
return _prohibitedHeadersList;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public class KustoDataProviderConfiguration : DataProviderConfigurationBase, IDa
public string ClientId { get; set; }

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

/// <summary>
/// DB Name
Expand Down
3 changes: 3 additions & 0 deletions src/Diagnostics.DataProviders/DataProviders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class DataProviders
public ILogAnalyticsDataProvider K8SELogAnalytics;
public Func<MdmDataSource, IMdmDataProvider> Mdm;
public Func<GenericMdmDataProviderConfiguration, IMdmDataProvider> MdmGeneric;
public IHttpDataProvider Http;

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

Expand Down Expand Up @@ -64,6 +65,8 @@ public DataProviders(DataProviderContext context)
{
return GetOrAddDataProvider(new MdmLogDecorator(context, new MdmDataProvider(_cache, new GenericMdmDataProviderConfigurationWrapper(config), context.RequestId, context.receivedHeaders)));
};

Http = GetOrAddDataProvider(new HttpDataProviderLogDecorator(context, new HttpDataProvider(_cache, context.Configuration.HttpDataProviderConfiguration, context)));
}

private T GetOrAddDataProvider<T>(T dataProvider) where T : LogDecoratorBase
Expand Down
Loading

0 comments on commit 36497ba

Please sign in to comment.