Skip to content

Commit 21751ca

Browse files
authored
Merge pull request #67 from mjcheetham/msauth-inproc
Move Microsoft authentication in-proc
2 parents 08b5df0 + d2703ae commit 21751ca

File tree

23 files changed

+325
-576
lines changed

23 files changed

+325
-576
lines changed

.azure-pipelines/templates/windows/pack.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
steps:
22
- script: |
33
xcopy "out\windows\Installer.Windows\bin\$(configuration)\net461" "$(Build.StagingDirectory)\publish\"
4-
xcopy "out\windows\Payload.Windows\bin\$(configuration)\net461\win-x86" "$(Build.StagingDirectory)\publish\payload\"
4+
xcopy "out\windows\Payload.Windows\bin\$(configuration)\net461\win-x64" "$(Build.StagingDirectory)\publish\payload\"
55
mkdir "$(Build.StagingDirectory)\publish\payload.sym\"
66
move "$(Build.StagingDirectory)\publish\payload\*.pdb" "$(Build.StagingDirectory)\publish\payload.sym\"
77
displayName: Prepare final build artifact

Git-Credential-Manager.sln

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestInfrastructure", "src\s
2121
EndProject
2222
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitHub", "src\shared\GitHub\GitHub.csproj", "{3C840B06-A595-4FD9-9A76-56CD45B14780}"
2323
EndProject
24-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Authentication.Helper.Windows", "src\windows\Microsoft.Authentication.Helper.Windows\Microsoft.Authentication.Helper.Windows.csproj", "{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}"
25-
EndProject
26-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Authentication.Helper.Windows.Tests", "src\windows\Microsoft.Authentication.Helper.Windows.Tests\Microsoft.Authentication.Helper.Windows.Tests.csproj", "{E0391B02-16D5-4B49-9C33-349B25717011}"
27-
EndProject
2824
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{D5277A0E-997E-453A-8CB9-4EFCC8B16A29}"
2925
EndProject
3026
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Tests", "src\shared\GitHub.Tests\GitHub.Tests.csproj", "{3E524EA8-D31A-4394-997C-14B522E3D6FD}"
@@ -160,22 +156,6 @@ Global
160156
{3C840B06-A595-4FD9-9A76-56CD45B14780}.MacDebug|Any CPU.Build.0 = Debug|Any CPU
161157
{3C840B06-A595-4FD9-9A76-56CD45B14780}.MacRelease|Any CPU.ActiveCfg = Release|Any CPU
162158
{3C840B06-A595-4FD9-9A76-56CD45B14780}.MacRelease|Any CPU.Build.0 = Release|Any CPU
163-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
164-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.Release|Any CPU.ActiveCfg = Release|Any CPU
165-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.WindowsDebug|Any CPU.ActiveCfg = Debug|Any CPU
166-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.WindowsDebug|Any CPU.Build.0 = Debug|Any CPU
167-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.WindowsRelease|Any CPU.ActiveCfg = Release|Any CPU
168-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
169-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.MacDebug|Any CPU.ActiveCfg = Debug|Any CPU
170-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4}.MacRelease|Any CPU.ActiveCfg = Release|Any CPU
171-
{E0391B02-16D5-4B49-9C33-349B25717011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
172-
{E0391B02-16D5-4B49-9C33-349B25717011}.Release|Any CPU.ActiveCfg = Release|Any CPU
173-
{E0391B02-16D5-4B49-9C33-349B25717011}.WindowsDebug|Any CPU.ActiveCfg = Debug|Any CPU
174-
{E0391B02-16D5-4B49-9C33-349B25717011}.WindowsDebug|Any CPU.Build.0 = Debug|Any CPU
175-
{E0391B02-16D5-4B49-9C33-349B25717011}.WindowsRelease|Any CPU.ActiveCfg = Release|Any CPU
176-
{E0391B02-16D5-4B49-9C33-349B25717011}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
177-
{E0391B02-16D5-4B49-9C33-349B25717011}.MacDebug|Any CPU.ActiveCfg = Debug|Any CPU
178-
{E0391B02-16D5-4B49-9C33-349B25717011}.MacRelease|Any CPU.ActiveCfg = Release|Any CPU
179159
{3E524EA8-D31A-4394-997C-14B522E3D6FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
180160
{3E524EA8-D31A-4394-997C-14B522E3D6FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
181161
{3E524EA8-D31A-4394-997C-14B522E3D6FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -242,7 +222,6 @@ Global
242222
EndGlobalSection
243223
GlobalSection(NestedProjects) = preSolution
244224
{66722747-1B61-40E4-A89B-1AC8E6D62EA9} = {A7FC1234-95E3-4496-B5F7-4306F41E6A0E}
245-
{8B984F78-4EAF-4BC0-A34E-BA3949700ED4} = {66722747-1B61-40E4-A89B-1AC8E6D62EA9}
246225
{D5277A0E-997E-453A-8CB9-4EFCC8B16A29} = {A7FC1234-95E3-4496-B5F7-4306F41E6A0E}
247226
{28F06D44-AB25-4CF5-93F9-978C23FAA9D6} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
248227
{3C840B06-A595-4FD9-9A76-56CD45B14780} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
@@ -251,7 +230,6 @@ Global
251230
{97DC6241-1240-4A85-8035-F8404A983A82} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
252231
{AD41FA1E-51F5-4E4F-B7DA-32F921491313} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
253232
{5A7D9E8B-C1D2-4C5C-BE98-648C41D1F8BD} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
254-
{E0391B02-16D5-4B49-9C33-349B25717011} = {66722747-1B61-40E4-A89B-1AC8E6D62EA9}
255233
{3E524EA8-D31A-4394-997C-14B522E3D6FD} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
256234
{3D279E2D-E011-45CF-8EA8-3D71D1300443} = {A7FC1234-95E3-4496-B5F7-4306F41E6A0E}
257235
{206430B1-CEED-4C84-8D49-D0A399632202} = {3D279E2D-E011-45CF-8EA8-3D71D1300443}

src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp2.1</TargetFramework>
6-
<TargetFramework Condition="'$(OSPlatform)'=='windows'">net461</TargetFramework>
7-
<RuntimeIdentifiers>win-x86;osx-x64</RuntimeIdentifiers>
5+
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
6+
<TargetFrameworks Condition="'$(OSPlatform)'=='windows'">net461;netcoreapp2.1</TargetFrameworks>
7+
<RuntimeIdentifiers>win-x64;osx-x64</RuntimeIdentifiers>
88
<AssemblyName>git-credential-manager-core</AssemblyName>
99
<RootNamespace>Microsoft.Git.CredentialManager</RootNamespace>
1010
<ApplicationIcon>$(RepoAssetsPath)gcmicon.ico</ApplicationIcon>
@@ -13,12 +13,6 @@
1313
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
1414
</PropertyGroup>
1515

16-
<!-- On Windows we target 32-bit because the WinForms authentication helpers are 32-bit
17-
and also need to use the native libgit2 library (we use the 32-bit version on Windows) -->
18-
<PropertyGroup Condition="'$(OSPlatform)'=='windows'">
19-
<Prefer32Bit>true</Prefer32Bit>
20-
</PropertyGroup>
21-
2216
<ItemGroup>
2317
<ProjectReference Include="..\GitHub\GitHub.csproj" />
2418
<ProjectReference Include="..\Microsoft.AzureRepos\Microsoft.AzureRepos.csproj" />

src/shared/Microsoft.AzureRepos.Tests/AzureDevOpsApiTests.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
using System.Threading.Tasks;
1010
using Microsoft.Git.CredentialManager;
1111
using Microsoft.Git.CredentialManager.Tests.Objects;
12+
using Microsoft.IdentityModel.JsonWebTokens;
1213
using Newtonsoft.Json;
1314
using Xunit;
15+
using static Microsoft.Git.CredentialManager.Tests.TestHelpers;
1416

1517
namespace Microsoft.AzureRepos.Tests
1618
{
@@ -223,7 +225,7 @@ public async Task AzureDevOpsRestApi_CreatePersonalAccessTokenAsync_ReturnsPAT()
223225
var orgUri = new Uri("https://dev.azure.com/org/");
224226

225227
const string expectedPat = "PERSONAL-ACCESS-TOKEN";
226-
const string accessToken = "ACCESS-TOKEN";
228+
JsonWebToken accessToken = CreateJwt();
227229
IEnumerable<string> scopes = new[] {AzureDevOpsConstants.PersonalAccessTokenScopes.ReposWrite};
228230

229231
var identityServiceUri = new Uri("https://identity.example.com/");
@@ -262,7 +264,7 @@ public async Task AzureDevOpsRestApi_CreatePersonalAccessTokenAsync_LocSvcReturn
262264
var context = new TestCommandContext();
263265
var orgUri = new Uri("https://dev.azure.com/org/");
264266

265-
const string accessToken = "ACCESS-TOKEN";
267+
JsonWebToken accessToken = CreateJwt();
266268
IEnumerable<string> scopes = new[] {AzureDevOpsConstants.PersonalAccessTokenScopes.ReposWrite};
267269

268270
var locSvcRequestUri = new Uri(orgUri, ExpectedLocationServicePath);
@@ -282,7 +284,7 @@ public async Task AzureDevOpsRestApi_CreatePersonalAccessTokenAsync_IdentSvcRetu
282284
var context = new TestCommandContext();
283285
var orgUri = new Uri("https://dev.azure.com/org/");
284286

285-
const string accessToken = "ACCESS-TOKEN";
287+
JsonWebToken accessToken = CreateJwt();
286288
IEnumerable<string> scopes = new[] {AzureDevOpsConstants.PersonalAccessTokenScopes.ReposWrite};
287289

288290
var identityServiceUri = new Uri("https://identity.example.com/");
@@ -315,7 +317,7 @@ public async Task AzureDevOpsRestApi_CreatePersonalAccessTokenAsync_IdentSvcRetu
315317
var context = new TestCommandContext();
316318
var orgUri = new Uri("https://dev.azure.com/org/");
317319

318-
const string accessToken = "ACCESS-TOKEN";
320+
JsonWebToken accessToken = CreateJwt();
319321
IEnumerable<string> scopes = new[] {AzureDevOpsConstants.PersonalAccessTokenScopes.ReposWrite};
320322

321323
var identityServiceUri = new Uri("https://identity.example.com/");
@@ -400,12 +402,12 @@ private static void AssertAcceptJson(HttpRequestMessage request)
400402
Assert.Contains(Constants.Http.MimeTypeJson, acceptMimeTypes);
401403
}
402404

403-
private static void AssertBearerToken(HttpRequestMessage request, string bearerToken)
405+
private static void AssertBearerToken(HttpRequestMessage request, JsonWebToken bearerToken)
404406
{
405407
AuthenticationHeaderValue authHeader = request.Headers.Authorization;
406408
Assert.NotNull(authHeader);
407409
Assert.Equal("Bearer", authHeader.Scheme);
408-
Assert.Equal(bearerToken, authHeader.Parameter);
410+
Assert.Equal(bearerToken.EncodedToken, authHeader.Parameter);
409411
}
410412

411413
private static HttpResponseMessage CreateLocationServiceResponse(Uri identityServiceUri)

src/shared/Microsoft.AzureRepos.Tests/AzureReposHostProviderTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.Git.CredentialManager.Tests.Objects;
99
using Moq;
1010
using Xunit;
11+
using static Microsoft.Git.CredentialManager.Tests.TestHelpers;
1112

1213
namespace Microsoft.AzureRepos.Tests
1314
{
@@ -151,7 +152,7 @@ public async Task AzureReposProvider_GetCredentialAsync_ReturnsCredential()
151152
var expectedClientId = AzureDevOpsConstants.AadClientId;
152153
var expectedRedirectUri = AzureDevOpsConstants.AadRedirectUri;
153154
var expectedResource = AzureDevOpsConstants.AadResourceId;
154-
var accessToken = "ACCESS-TOKEN";
155+
var accessToken = CreateJwt("john.doe");
155156
var personalAccessToken = "PERSONAL-ACCESS-TOKEN";
156157

157158
var context = new TestCommandContext();
@@ -163,7 +164,7 @@ public async Task AzureReposProvider_GetCredentialAsync_ReturnsCredential()
163164
.ReturnsAsync(personalAccessToken);
164165

165166
var msAuthMock = new Mock<IMicrosoftAuthentication>();
166-
msAuthMock.Setup(x => x.GetAccessTokenAsync(authorityUrl, expectedClientId, expectedRedirectUri, expectedResource, remoteUri))
167+
msAuthMock.Setup(x => x.GetAccessTokenAsync(authorityUrl, expectedClientId, expectedRedirectUri, expectedResource, remoteUri, null))
167168
.ReturnsAsync(accessToken);
168169

169170
var provider = new AzureReposHostProvider(context, azDevOpsMock.Object, msAuthMock.Object);

src/shared/Microsoft.AzureRepos/AzureDevOpsRestApi.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
using System.Text.RegularExpressions;
1010
using System.Threading.Tasks;
1111
using Microsoft.Git.CredentialManager;
12+
using Microsoft.IdentityModel.JsonWebTokens;
1213

1314
namespace Microsoft.AzureRepos
1415
{
1516
public interface IAzureDevOpsRestApi : IDisposable
1617
{
1718
Task<string> GetAuthorityAsync(Uri organizationUri);
18-
Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, string accessToken, IEnumerable<string> scopes);
19+
Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, JsonWebToken accessToken, IEnumerable<string> scopes);
1920
}
2021

2122
public class AzureDevOpsRestApi : IAzureDevOpsRestApi
@@ -84,7 +85,7 @@ public async Task<string> GetAuthorityAsync(Uri organizationUri)
8485
return commonAuthority;
8586
}
8687

87-
public async Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, string accessToken, IEnumerable<string> scopes)
88+
public async Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, JsonWebToken accessToken, IEnumerable<string> scopes)
8889
{
8990
const string sessionTokenUrl = "_apis/token/sessiontokens?api-version=1.0&tokentype=compact";
9091

@@ -93,7 +94,7 @@ public async Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, st
9394
{
9495
throw new ArgumentException($"Provided URI '{organizationUri}' is not a valid Azure DevOps hostname", nameof(organizationUri));
9596
}
96-
EnsureArgument.NotNullOrWhiteSpace(accessToken, nameof(accessToken));
97+
EnsureArgument.NotNull(accessToken, nameof(accessToken));
9798

9899
_context.Trace.WriteLine("Getting Azure DevOps Identity Service endpoint...");
99100
Uri identityServiceUri = await GetIdentityServiceUriAsync(organizationUri, accessToken);
@@ -134,7 +135,7 @@ public async Task<string> CreatePersonalAccessTokenAsync(Uri organizationUri, st
134135

135136
#region Private Methods
136137

137-
private async Task<Uri> GetIdentityServiceUriAsync(Uri organizationUri, string accessToken)
138+
private async Task<Uri> GetIdentityServiceUriAsync(Uri organizationUri, JsonWebToken accessToken)
138139
{
139140
const string locationServicePath = "_apis/ServiceDefinitions/LocationService2/951917AC-A960-4999-8464-E3F0AA25B381";
140141
const string locationServiceQuery = "api-version=1.0";
@@ -273,7 +274,7 @@ private static StringContent CreateAccessTokenRequestJson(Uri organizationUri, I
273274
/// <param name="content">Optional request content.</param>
274275
/// <param name="bearerToken">Optional bearer token for authorization.</param>
275276
/// <returns>HTTP request message.</returns>
276-
private static HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri uri, HttpContent content = null, string bearerToken = null)
277+
private static HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri uri, HttpContent content = null, JsonWebToken bearerToken = null)
277278
{
278279
var request = new HttpRequestMessage(method, uri);
279280

@@ -282,9 +283,9 @@ private static HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri ur
282283
request.Content = content;
283284
}
284285

285-
if (!string.IsNullOrWhiteSpace(bearerToken))
286+
if (bearerToken != null)
286287
{
287-
request.Headers.Authorization = new AuthenticationHeaderValue(Constants.Http.WwwAuthenticateBearerScheme, bearerToken);
288+
request.Headers.Authorization = new AuthenticationHeaderValue(Constants.Http.WwwAuthenticateBearerScheme, bearerToken.EncodedToken);
288289
}
289290

290291
return request;

src/shared/Microsoft.AzureRepos/AzureReposHostProvider.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading.Tasks;
66
using Microsoft.Git.CredentialManager;
77
using Microsoft.Git.CredentialManager.Authentication;
8+
using Microsoft.IdentityModel.JsonWebTokens;
89
using KnownGitCfg = Microsoft.Git.CredentialManager.Constants.GitConfiguration;
910

1011
namespace Microsoft.AzureRepos
@@ -73,13 +74,15 @@ public override async Task<ICredential> GenerateCredentialAsync(InputArguments i
7374

7475
// Get an AAD access token for the Azure DevOps SPS
7576
Context.Trace.WriteLine("Getting Azure AD access token...");
76-
string accessToken = await _msAuth.GetAccessTokenAsync(
77+
JsonWebToken accessToken = await _msAuth.GetAccessTokenAsync(
7778
authAuthority,
7879
AzureDevOpsConstants.AadClientId,
7980
AzureDevOpsConstants.AadRedirectUri,
8081
AzureDevOpsConstants.AadResourceId,
81-
remoteUri);
82-
Context.Trace.WriteLineSecrets("Acquired access token. Token='{0}'", new object[] {accessToken});
82+
remoteUri,
83+
null);
84+
string atUser = accessToken.GetAzureUserName();
85+
Context.Trace.WriteLineSecrets($"Acquired Azure access token. User='{atUser}' Token='{{0}}'", new object[] {accessToken.EncodedToken});
8386

8487
// Ask the Azure DevOps instance to create a new PAT
8588
var patScopes = new[]

0 commit comments

Comments
 (0)