Skip to content

Commit d228848

Browse files
FehintolaObafemitimayabi2020peombwazengincnotin
committed
Adding AT PoP skeleton (#2511)
* adding "-AT PoP" option to "Set-MgGraphOptions" * Adding AT PoP skeleton --------- Co-authored-by: Tim <[email protected]> Co-authored-by: Peter Ombwa <[email protected]> Co-authored-by: Peter Ombwa <[email protected]> Co-authored-by: Mustafa Zengin <[email protected]> Co-authored-by: Clément Notin <[email protected]> Co-authored-by: Microsoft Graph DevX Tooling <[email protected]> Co-authored-by: Vincent Biret <[email protected]> Co-authored-by: Vincent Biret <[email protected]> Co-authored-by: Subhajit Ray (from Dev Box) <[email protected]>
1 parent 007369d commit d228848

File tree

5 files changed

+129
-12
lines changed

5 files changed

+129
-12
lines changed

docs/authentication.md

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ Before using the provided `-AccessToken` to get Microsoft Graph resources, custo
116116

117117
AT PoP is a security mechanism that binds an access token to a cryptographic key that only the intended recipient has. This prevents unauthorized use of the token by malicious actors. AT PoP enhances data protection, reduces token replay attacks, and enables fine-grained authorization policies.
118118

119+
Note: AT PoP requires WAM to function.
120+
119121
Microsoft Graph PowerShell module supports AT PoP in the following scenario:
120122

121123
- To enable AT PoP on supported devices

src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<Import Project="$(MSBuildThisFileDirectory)..\..\..\Repo.props" />
33
<PropertyGroup>
44
<LangVersion>9.0</LangVersion>
55
<TargetFrameworks>netstandard2.0;net6.0;net472</TargetFrameworks>
66
<RootNamespace>Microsoft.Graph.PowerShell.Authentication.Core</RootNamespace>
7-
<Version>2.6.1</Version>
7+
<Version>2.12.0</Version>
88
</PropertyGroup>
99
<PropertyGroup>
1010
<EnableNETAnalyzers>true</EnableNETAnalyzers>
1111
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
1212
</PropertyGroup>
1313
<ItemGroup>
14-
<PackageReference Include="Azure.Identity" Version="1.11.0" />
15-
<PackageReference Include="Azure.Identity.Broker" Version="1.0.0-beta.5" />
16-
<PackageReference Include="Azure.Identity.BrokeredAuthentication" Version="1.0.0-beta.3" />
17-
<PackageReference Include="Microsoft.Graph.Core" Version="3.0.9" />
18-
<PackageReference Include="Microsoft.Identity.Client" Version="4.56.0" />
19-
<PackageReference Include="Microsoft.Identity.Client.Broker" Version="4.56.0" />
14+
<PackageReference Include="Azure.Identity" Version="1.11.0-beta.1" />
15+
<PackageReference Include="Azure.Core" Version="1.38.0" />
16+
<PackageReference Include="Azure.Identity.Broker" Version="1.1.0-beta.1" />
17+
<PackageReference Include="Microsoft.Graph.Core" Version="3.1.8" />
18+
<PackageReference Include="Microsoft.Identity.Client" Version="4.59.0" />
19+
<PackageReference Include="Microsoft.Identity.Client.Broker" Version="4.59.0" />
2020
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
2121
</ItemGroup>
2222
<Target Name="CopyFiles" AfterTargets="Build">

src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs

+29-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// ------------------------------------------------------------------------------
44
using Azure.Core;
55
using Azure.Core.Diagnostics;
6+
using Azure.Core.Pipeline;
67
using Azure.Identity;
78
using Azure.Identity.Broker;
89
using Microsoft.Graph.Authentication;
@@ -86,6 +87,12 @@ private static bool IsWamSupported()
8687
return GraphSession.Instance.GraphOption.EnableWAMForMSGraph && SharedUtilities.IsWindowsPlatform();
8788
}
8889

90+
//Check to see if ATPoP is Supported
91+
private static bool IsATPoPSupported()
92+
{
93+
return GraphSession.Instance.GraphOption.EnableATPoPForMSGraph;
94+
}
95+
8996
private static async Task<TokenCredential> GetClientSecretCredentialAsync(IAuthContext authContext)
9097
{
9198
if (authContext is null)
@@ -125,11 +132,29 @@ private static async Task<InteractiveBrowserCredential> GetInteractiveBrowserCre
125132
var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions);
126133
if (IsWamSupported())
127134
{
128-
authRecord = await Task.Run(() =>
135+
// Adding a scenario to account for Access Token Proof of Possession
136+
if (IsATPoPSupported())
129137
{
130-
// Run the thread in MTA.
131-
return interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken);
132-
});
138+
// Logic to implement ATPoP Authentication
139+
var client = new PopClient(interactiveBrowserCredential, authContext, new PopClientOptions()
140+
{
141+
Diagnostics =
142+
{
143+
IsLoggingContentEnabled = true,
144+
LoggedHeaderNames = { "Authorization" }
145+
}
146+
});
147+
//var response = client.Get(new Uri("https://20.190.132.47/beta/me"), CancellationToken.None);
148+
authRecord = client.GetAuthRecord();
149+
}
150+
else
151+
{
152+
authRecord = await Task.Run(() =>
153+
{
154+
// Run the thread in MTA.
155+
return interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken);
156+
});
157+
}
133158
}
134159
else
135160
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.IdentityModel;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Azure;
6+
using Azure.Core;
7+
using Azure.Core.Pipeline;
8+
using Azure.Identity;
9+
using Azure.Identity.Broker;
10+
using Microsoft.Identity.Client.NativeInterop;
11+
12+
namespace Microsoft.Graph.PowerShell.Authentication.Core.Utilities
13+
{
14+
public class PopClient
15+
{
16+
private readonly HttpPipeline _pipeline;
17+
private AuthenticationRecord _authenticationRecord;
18+
private readonly InteractiveBrowserCredential _interactiveBrowserCredential;
19+
20+
public PopClient(TokenCredential credential, IAuthContext authContext, ClientOptions options = null)
21+
{
22+
//_interactiveBrowserCredential = (InteractiveBrowserCredential)credential;
23+
_interactiveBrowserCredential = new InteractiveBrowserCredential(new InteractiveBrowserCredentialBrokerOptions(WindowHandleUtlities.GetConsoleOrTerminalWindow()));
24+
25+
if (!(credential is ISupportsProofOfPossession))
26+
{
27+
throw new ArgumentException("The provided TokenCredential does not support proof of possession.", nameof(credential));
28+
}
29+
30+
var pipelineOptions = new HttpPipelineOptions(options);
31+
pipelineOptions.PerRetryPolicies.Add(new InteractivePopTokenAuthenticationPolicy(_interactiveBrowserCredential, "https://graph.microsoft.com/.default", () => _authenticationRecord));
32+
33+
_pipeline = HttpPipelineBuilder.Build(pipelineOptions);
34+
}
35+
36+
public async ValueTask<Response> GetAsync(Uri uri, CancellationToken cancellationToken = default)
37+
{
38+
using var request = _pipeline.CreateRequest();
39+
request.Method = RequestMethod.Get;
40+
request.Uri.Reset(uri);
41+
return await _pipeline.SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
42+
}
43+
44+
public Response Get(Uri uri, CancellationToken cancellationToken = default)
45+
{
46+
using var request = _pipeline.CreateRequest();
47+
request.Method = RequestMethod.Get;
48+
request.Uri.Reset(uri);
49+
return _pipeline.SendRequest(request, cancellationToken);
50+
}
51+
52+
public async ValueTask<AuthenticationRecord> GetAuthRecordAsync()
53+
{
54+
_authenticationRecord ??= await _interactiveBrowserCredential.AuthenticateAsync();
55+
return _authenticationRecord;
56+
}
57+
58+
public AuthenticationRecord GetAuthRecord()
59+
{
60+
_authenticationRecord ??= _interactiveBrowserCredential.Authenticate();
61+
return _authenticationRecord;
62+
}
63+
}
64+
65+
public class InteractivePopTokenAuthenticationPolicy : PopTokenAuthenticationPolicy
66+
{
67+
private readonly InteractiveBrowserCredential _interactiveBrowserCredential;
68+
private readonly Func<AuthenticationRecord> _getAuthRecord;
69+
70+
public InteractivePopTokenAuthenticationPolicy(InteractiveBrowserCredential credential, string scope, Func<AuthenticationRecord> getAuthRecord)
71+
: base(credential, scope)
72+
{
73+
_interactiveBrowserCredential = credential;
74+
_getAuthRecord = getAuthRecord;
75+
}
76+
77+
protected override ValueTask AuthorizeRequestAsync(HttpMessage message)
78+
{
79+
var authRecord = _getAuthRecord();
80+
if (authRecord != null)
81+
{
82+
_interactiveBrowserCredential.AuthenticateAsync(new TokenRequestContext(new[] { "https://graph.microsoft.com/.default" })).ConfigureAwait(false);
83+
}
84+
85+
return base.AuthorizeRequestAsync(message);
86+
}
87+
}
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
using Azure.Core;
2+
public class PopClientOptions : ClientOptions { }

0 commit comments

Comments
 (0)