-
Notifications
You must be signed in to change notification settings - Fork 183
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use Azure cli or PowerShell credentials for devops and oss service (#…
…8298) * Use Azure cli or PowerShell credentials for devops and oss service * Move alias caching into GitHubToAADConverter and update pipelines * Stop retrying on 404s * Use new app ID for OSS portal * Skip tests for notification tool
- Loading branch information
Showing
18 changed files
with
140 additions
and
286 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 61 additions & 50 deletions
111
tools/identity-resolution/Helpers/GitHubToAADConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,107 @@ | ||
using System; | ||
using System.Net; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Azure.Core; | ||
using Azure.Identity; | ||
using Microsoft.Extensions.Logging; | ||
using Models.OpenSourcePortal; | ||
using Newtonsoft.Json; | ||
|
||
namespace Azure.Sdk.Tools.NotificationConfiguration.Helpers | ||
{ | ||
/// <summary> | ||
/// Utility class for converting GitHub usernames to AAD user principal names. | ||
/// </summary> | ||
/// <remarks> | ||
/// A map of GitHub usernames to AAD user principal names is cached in memory to avoid making multiple calls to the | ||
/// OpenSource portal API. The cache is initialized with the full alias list on the first call to | ||
/// GetUserPrincipalNameFromGithubAsync. | ||
/// </remarks> | ||
public class GitHubToAADConverter | ||
{ | ||
private readonly TokenCredential credential; | ||
private readonly ILogger<GitHubToAADConverter> logger; | ||
private readonly SemaphoreSlim cacheLock = new(1); | ||
private Dictionary<string, string> lookupCache; | ||
|
||
/// <summary> | ||
/// GitHubToAadConverter constructor for generating new token, and initialize http client. | ||
/// </summary> | ||
/// <param name="credential">The aad token auth class.</param> | ||
/// <param name="logger">Logger</param> | ||
public GitHubToAADConverter( | ||
ClientSecretCredential credential, | ||
ILogger<GitHubToAADConverter> logger) | ||
public GitHubToAADConverter(TokenCredential credential, ILogger<GitHubToAADConverter> logger) | ||
{ | ||
this.credential = credential; | ||
this.logger = logger; | ||
var opsAuthToken = ""; | ||
|
||
} | ||
|
||
public async Task<string> GetUserPrincipalNameFromGithubAsync(string gitHubUserName) | ||
{ | ||
await EnsureCacheExistsAsync(); | ||
|
||
if (this.lookupCache.TryGetValue(gitHubUserName, out string aadUserPrincipalName)) | ||
{ | ||
return aadUserPrincipalName; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public async Task EnsureCacheExistsAsync() | ||
{ | ||
await this.cacheLock.WaitAsync(); | ||
try | ||
{ | ||
// This is aad scope of opensource rest API. | ||
string[] scopes = new string[] | ||
if (this.lookupCache == null) | ||
{ | ||
"api://2789159d-8d8b-4d13-b90b-ca29c1707afd/.default" | ||
}; | ||
opsAuthToken = credential.GetToken(new TokenRequestContext(scopes)).Token; | ||
var peopleLinks = await GetPeopleLinksAsync(); | ||
this.lookupCache = peopleLinks.ToDictionary( | ||
x => x.GitHub.Login, | ||
x => x.Aad.UserPrincipalName, | ||
StringComparer.OrdinalIgnoreCase); | ||
} | ||
} | ||
catch (Exception ex) | ||
finally | ||
{ | ||
logger.LogError("Failed to generate aad token. " + ex.Message); | ||
this.cacheLock.Release(); | ||
} | ||
client = new HttpClient(); | ||
client.DefaultRequestHeaders.Add("content_type", "application/json"); | ||
client.DefaultRequestHeaders.Add("api-version", "2019-10-01"); | ||
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {opsAuthToken}"); | ||
} | ||
|
||
private readonly HttpClient client; | ||
private readonly ILogger<GitHubToAADConverter> logger; | ||
|
||
/// <summary> | ||
/// Get the user principal name from github. User principal name is in format of ms email. | ||
/// </summary> | ||
/// <param name="githubUserName">github user name</param> | ||
/// <returns>Aad user principal name</returns> | ||
public string GetUserPrincipalNameFromGithub(string githubUserName) | ||
private async Task<UserLink[]> GetPeopleLinksAsync() | ||
{ | ||
return GetUserPrincipalNameFromGithubAsync(githubUserName).Result; | ||
} | ||
AccessToken opsAuthToken; | ||
|
||
public async Task<string> GetUserPrincipalNameFromGithubAsync(string githubUserName) | ||
{ | ||
try | ||
{ | ||
var responseJsonString = await client.GetStringAsync($"https://repos.opensource.microsoft.com/api/people/links/github/{githubUserName}"); | ||
dynamic contentJson = JsonConvert.DeserializeObject(responseJsonString); | ||
return contentJson.aad.userPrincipalName; | ||
} | ||
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) | ||
{ | ||
logger.LogWarning("Github username {Username} not found", githubUserName); | ||
// This is aad scope of opensource rest API. | ||
string[] scopes = new [] { "api://66b6ea26-954d-4b68-8f48-71e3faec7ad1/.default" }; | ||
opsAuthToken = await credential.GetTokenAsync(new TokenRequestContext(scopes), CancellationToken.None); | ||
} | ||
catch (Exception ex) | ||
{ | ||
logger.LogError(ex.Message); | ||
this.logger.LogError("Failed to generate aad token. {ExceptionMessage}", ex.Message); | ||
throw; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public async Task<UserLink[]> GetPeopleLinksAsync() | ||
{ | ||
try | ||
{ | ||
logger.LogInformation("Calling GET https://repos.opensource.microsoft.com/api/people/links"); | ||
var responseJsonString = await client.GetStringAsync($"https://repos.opensource.microsoft.com/api/people/links"); | ||
var allLinks = JsonConvert.DeserializeObject<UserLink[]>(responseJsonString); | ||
using HttpClient client = new (); | ||
client.DefaultRequestHeaders.Add("content_type", "application/json"); | ||
client.DefaultRequestHeaders.Add("api-version", "2019-10-01"); | ||
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {opsAuthToken.Token}"); | ||
|
||
return allLinks; | ||
this.logger.LogInformation("Calling GET https://repos.opensource.microsoft.com/api/people/links"); | ||
string responseJsonString = await client.GetStringAsync($"https://repos.opensource.microsoft.com/api/people/links"); | ||
return JsonConvert.DeserializeObject<UserLink[]>(responseJsonString); | ||
} | ||
catch (Exception ex) | ||
{ | ||
logger.LogError(ex.Message); | ||
this.logger.LogError(ex, "Error getting people links from opensource.microsoft.com: {ExceptionMessage}", ex.Message); | ||
throw; | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.