Skip to content

Commit 2a653c8

Browse files
resolving PR comments
1 parent ad63199 commit 2a653c8

File tree

8 files changed

+40
-51
lines changed

8 files changed

+40
-51
lines changed

src/Authentication/Authentication.Core/Common/GraphSession.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class GraphSession : IGraphSession
5959
/// <summary>
6060
/// Temporarily stores the user's Graph request details such as Method and Uri. Essential as part of the Proof of Possession efforts.
6161
/// </summary>
62-
public IGraphRequestProofofPossession GraphRequestProofofPossession { get; set; }
62+
public IGraphRequestPopContext GraphRequestPopContext { get; set; }
6363

6464
/// <summary>
6565
/// Represents a collection of Microsoft Graph PowerShell meta-info.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
namespace Microsoft.Graph.PowerShell.Authentication
1111
{
12-
public interface IGraphRequestProofofPossession
12+
public interface IGraphRequestPopContext
1313
{
1414
Uri Uri { get; set; }
1515
HttpMethod HttpMethod { get; set; }
1616
AccessToken AccessToken { get; set; }
1717
string ProofofPossessionNonce { get; set; }
1818
PopTokenRequestContext PopTokenContext { get; set; }
1919
Request Request { get; set; }
20-
InteractiveBrowserCredential BrowserCredential { get; set; }
20+
InteractiveBrowserCredential PopInteractiveBrowserCredential { get; set; }
2121
}
2222
}

src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public interface IGraphSession
1212
IDataStore DataStore { get; set; }
1313
IRequestContext RequestContext { get; set; }
1414
IGraphOption GraphOption { get; set; }
15-
IGraphRequestProofofPossession GraphRequestProofofPossession { get; set; }
15+
IGraphRequestPopContext GraphRequestPopContext { get; set; }
1616
}
1717
}

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

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System.IO;
1717
using System.Linq;
1818
using System.Net.Http;
19+
using System.Net.Http.Headers;
1920
using System.Security.Cryptography.X509Certificates;
2021
using System.Threading;
2122
using System.Threading.Tasks;
@@ -88,12 +89,6 @@ private static bool IsWamSupported()
8889
return GraphSession.Instance.GraphOption.EnableWAMForMSGraph && SharedUtilities.IsWindowsPlatform();
8990
}
9091

91-
//Check to see if ATPoP is Supported
92-
public static bool IsATPoPSupported()
93-
{
94-
return GraphSession.Instance.GraphOption.EnableATPoPForMSGraph;
95-
}
96-
9792
private static async Task<TokenCredential> GetClientSecretCredentialAsync(IAuthContext authContext)
9893
{
9994
if (authContext is null)
@@ -130,27 +125,24 @@ private static async Task<InteractiveBrowserCredential> GetInteractiveBrowserCre
130125
interactiveOptions.TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext);
131126

132127
var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions);
133-
if (IsATPoPSupported())
128+
if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph)
134129
{
135-
GraphSession.Instance.GraphRequestProofofPossession.PopTokenContext = CreatePopTokenRequestContext(authContext);
136-
GraphSession.Instance.GraphRequestProofofPossession.BrowserCredential = interactiveBrowserCredential;
130+
GraphSession.Instance.GraphRequestPopContext.PopTokenContext = await CreatePopTokenRequestContext(authContext);
131+
GraphSession.Instance.GraphRequestPopContext.PopInteractiveBrowserCredential = interactiveBrowserCredential;
137132
}
138133

139134
if (!File.Exists(Constants.AuthRecordPath))
140135
{
141136
AuthenticationRecord authRecord;
142-
//var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions);
143137
if (IsWamSupported())
144138
{
145139
// Adding a scenario to account for Access Token Proof of Possession
146-
if (IsATPoPSupported())
140+
if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph)
147141
{
148-
// Logic to implement ATPoP Authentication
149142
authRecord = await Task.Run(() =>
150143
{
151144
// Run the thread in MTA.
152-
//GraphSession.Instance.GraphRequestProofofPossession.AccessToken = interactiveBrowserCredential.GetTokenAsync(GraphSession.Instance.GraphRequestProofofPossession.PopTokenContext, cancellationToken).Result;
153-
return interactiveBrowserCredential.AuthenticateAsync(GraphSession.Instance.GraphRequestProofofPossession.PopTokenContext, cancellationToken);
145+
return interactiveBrowserCredential.AuthenticateAsync(GraphSession.Instance.GraphRequestPopContext.PopTokenContext, cancellationToken);
154146
});
155147
}
156148
else
@@ -478,19 +470,16 @@ public static Task DeleteAuthRecordAsync()
478470
return Task.CompletedTask;
479471
}
480472

481-
public static PopTokenRequestContext CreatePopTokenRequestContext(IAuthContext authContext)
473+
private static async Task<PopTokenRequestContext> CreatePopTokenRequestContext(IAuthContext authContext)
482474
{
483475
// Creating a httpclient that would handle all pop calls
484-
Uri popResourceUri = GraphSession.Instance.GraphRequestProofofPossession.Uri ?? new Uri("https://graph.microsoft.com/beta/organization"); //PPE (https://graph.microsoft-ppe.com) or Canary (https://canary.graph.microsoft.com) or (https://20.190.132.47/beta/me)
476+
Uri popResourceUri = GraphSession.Instance.GraphRequestPopContext.Uri ?? new Uri("https://graph.microsoft.com/beta/organization"); //PPE (https://graph.microsoft-ppe.com) or Canary (https://canary.graph.microsoft.com) or (https://20.190.132.47/beta/me)
485477
HttpClient popHttpClient = new(new HttpClientHandler());
486478

487-
// Find the WWW-Authenticate header in the response.
488-
var popMethod = GraphSession.Instance.GraphRequestProofofPossession.HttpMethod ?? HttpMethod.Get;
489-
var popResponse = popHttpClient.SendAsync(new HttpRequestMessage(popMethod, popResourceUri)).Result;
490-
var popChallenge = popResponse.Headers.WwwAuthenticate.First(wa => wa.Scheme == "PoP");
491-
var nonceStart = popChallenge.Parameter.IndexOf("nonce=\"") + "nonce=\"".Length;
492-
var nonceEnd = popChallenge.Parameter.IndexOf('"', nonceStart);
493-
GraphSession.Instance.GraphRequestProofofPossession.ProofofPossessionNonce = popChallenge.Parameter.Substring(nonceStart, nonceEnd - nonceStart);
479+
// Find the nonce in the WWW-Authenticate header in the response.
480+
var popMethod = GraphSession.Instance.GraphRequestPopContext.HttpMethod ?? HttpMethod.Get;
481+
var popResponse = await popHttpClient.SendAsync(new HttpRequestMessage(popMethod, popResourceUri));
482+
GraphSession.Instance.GraphRequestPopContext.ProofofPossessionNonce = WwwAuthenticateParameters.CreateFromAuthenticationHeaders(popResponse.Headers, "Pop").Nonce;
494483

495484
// Refresh token logic --- start
496485
var popPipelineOptions = new HttpPipelineOptions(new PopClientOptions()
@@ -499,12 +488,12 @@ public static PopTokenRequestContext CreatePopTokenRequestContext(IAuthContext a
499488
});
500489

501490
var _popPipeline = HttpPipelineBuilder.Build(popPipelineOptions, new HttpPipelineTransportOptions());
502-
GraphSession.Instance.GraphRequestProofofPossession.Request = _popPipeline.CreateRequest();
503-
GraphSession.Instance.GraphRequestProofofPossession.Request.Method = ConvertToAzureRequestMethod(popMethod);
504-
GraphSession.Instance.GraphRequestProofofPossession.Request.Uri.Reset(popResourceUri);
491+
GraphSession.Instance.GraphRequestPopContext.Request = _popPipeline.CreateRequest();
492+
GraphSession.Instance.GraphRequestPopContext.Request.Method = ConvertToAzureRequestMethod(popMethod);
493+
GraphSession.Instance.GraphRequestPopContext.Request.Uri.Reset(popResourceUri);
505494

506495
// Refresh token logic --- end
507-
var popContext = new PopTokenRequestContext(authContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: GraphSession.Instance.GraphRequestProofofPossession.ProofofPossessionNonce, request: GraphSession.Instance.GraphRequestProofofPossession.Request);
496+
var popContext = new PopTokenRequestContext(authContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: GraphSession.Instance.GraphRequestPopContext.ProofofPossessionNonce, request: GraphSession.Instance.GraphRequestPopContext.Request);
508497
return popContext;
509498
}
510499
public static RequestMethod ConvertToAzureRequestMethod(HttpMethod httpMethod)

src/Authentication/Authentication/Cmdlets/InvokeMgGraphRequest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,8 +1023,8 @@ private async Task ProcessRecordAsync()
10231023
try
10241024
{
10251025
PrepareSession();
1026-
GraphSession.Instance.GraphRequestProofofPossession.Uri = Uri;
1027-
GraphSession.Instance.GraphRequestProofofPossession.HttpMethod = GetHttpMethod(Method);
1026+
GraphSession.Instance.GraphRequestPopContext.Uri = Uri;
1027+
GraphSession.Instance.GraphRequestPopContext.HttpMethod = GetHttpMethod(Method);
10281028
var client = HttpHelpers.GetGraphHttpClient();
10291029
ValidateRequestUri();
10301030
using (var httpRequestMessage = GetRequest(client, Uri))

src/Authentication/Authentication/Common/GraphSessionInitializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal static GraphSession CreateInstance(IDataStore dataStore = null)
4848
DataStore = dataStore ?? new DiskDataStore(),
4949
RequestContext = new RequestContext(),
5050
GraphOption = graphOptions ?? new GraphOption(),
51-
GraphRequestProofofPossession = new GraphRequestProofofPossession()
51+
GraphRequestPopContext = new GraphRequestPopContext()
5252
};
5353
}
5454
/// <summary>

src/Authentication/Authentication/Handlers/AuthenticationHandler.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.Graph.Authentication;
88
using Microsoft.Graph.PowerShell.Authentication.Core.Utilities;
99
using Microsoft.Graph.PowerShell.Authentication.Extensions;
10+
using Microsoft.Identity.Client;
1011
using System;
1112
using System.Collections.Generic;
1213
using System.Linq;
@@ -23,6 +24,7 @@ internal class AuthenticationHandler : DelegatingHandler
2324
{
2425
private const string ClaimsKey = "claims";
2526
private const string BearerAuthenticationScheme = "Bearer";
27+
private const string PopAuthenticationScheme = "Pop";
2628
private int MaxRetry { get; set; } = 1;
2729

2830
public AzureIdentityAccessTokenProvider AuthenticationProvider { get; set; }
@@ -47,6 +49,13 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
4749

4850
HttpResponseMessage response = await base.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false);
4951

52+
// Continuous nonce extraction on each request
53+
if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph)
54+
{
55+
GraphSession.Instance.GraphRequestPopContext.ProofofPossessionNonce = WwwAuthenticateParameters.CreateFromAuthenticationHeaders(response.Headers, PopAuthenticationScheme).Nonce;
56+
GraphSession.Instance.GraphRequestPopContext.PopTokenContext = new PopTokenRequestContext(GraphSession.Instance.AuthContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: GraphSession.Instance.GraphRequestPopContext.ProofofPossessionNonce, request: GraphSession.Instance.GraphRequestPopContext.Request);
57+
}
58+
5059
// Check if response is a 401 & is not a streamed body (is buffered)
5160
if (response.StatusCode == HttpStatusCode.Unauthorized && httpRequestMessage.IsBuffered())
5261
{
@@ -65,17 +74,17 @@ private async Task AuthenticateRequestAsync(HttpRequestMessage httpRequestMessag
6574
{
6675
if (AuthenticationProvider != null)
6776
{
68-
if (AuthenticationHelpers.IsATPoPSupported())
77+
if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph)
6978
{
70-
GraphSession.Instance.GraphRequestProofofPossession.Request.Method = AuthenticationHelpers.ConvertToAzureRequestMethod(httpRequestMessage.Method);
71-
GraphSession.Instance.GraphRequestProofofPossession.Request.Uri.Reset(httpRequestMessage.RequestUri);
79+
GraphSession.Instance.GraphRequestPopContext.Request.Method = AuthenticationHelpers.ConvertToAzureRequestMethod(httpRequestMessage.Method);
80+
GraphSession.Instance.GraphRequestPopContext.Request.Uri.Reset(httpRequestMessage.RequestUri);
7281
foreach (var header in httpRequestMessage.Headers)
7382
{
74-
GraphSession.Instance.GraphRequestProofofPossession.Request.Headers.Add(header.Key, header.Value.First());
83+
GraphSession.Instance.GraphRequestPopContext.Request.Headers.Add(header.Key, header.Value.First());
7584
}
7685

77-
var accessToken = GraphSession.Instance.GraphRequestProofofPossession.BrowserCredential.GetTokenAsync(GraphSession.Instance.GraphRequestProofofPossession.PopTokenContext, cancellationToken).Result;
78-
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Pop", accessToken.Token);
86+
var accessToken = await GraphSession.Instance.GraphRequestPopContext.PopInteractiveBrowserCredential.GetTokenAsync(GraphSession.Instance.GraphRequestPopContext.PopTokenContext, cancellationToken).ConfigureAwait(false);
87+
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(PopAuthenticationScheme, accessToken.Token);
7988
}
8089
else
8190
{
@@ -104,15 +113,6 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage httpR
104113
}
105114
await DrainAsync(httpResponseMessage).ConfigureAwait(false);
106115

107-
if (AuthenticationHelpers.IsATPoPSupported())
108-
{
109-
var popChallenge = httpResponseMessage.Headers.WwwAuthenticate.First(wa => wa.Scheme == "PoP");
110-
var nonceStart = popChallenge.Parameter.IndexOf("nonce=\"") + "nonce=\"".Length;
111-
var nonceEnd = popChallenge.Parameter.IndexOf('"', nonceStart);
112-
GraphSession.Instance.GraphRequestProofofPossession.ProofofPossessionNonce = popChallenge.Parameter.Substring(nonceStart, nonceEnd - nonceStart);
113-
GraphSession.Instance.GraphRequestProofofPossession.PopTokenContext = new PopTokenRequestContext(GraphSession.Instance.AuthContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: GraphSession.Instance.GraphRequestProofofPossession.ProofofPossessionNonce, request: GraphSession.Instance.GraphRequestProofofPossession.Request);
114-
}
115-
116116
// Authenticate request using auth provider
117117
await AuthenticateRequestAsync(newRequest, additionalRequestInfo, cancellationToken).ConfigureAwait(false);
118118
httpResponseMessage = await base.SendAsync(newRequest, cancellationToken);

src/Authentication/Authentication/Models/GraphRequestProofofPossession.cs renamed to src/Authentication/Authentication/Models/GraphRequestPopContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010

1111
namespace Microsoft.Graph.PowerShell.Authentication
1212
{
13-
internal class GraphRequestProofofPossession : IGraphRequestProofofPossession
13+
internal class GraphRequestPopContext : IGraphRequestPopContext
1414
{
1515
public Uri Uri { get; set; }
1616
public HttpMethod HttpMethod { get; set; }
1717
public AccessToken AccessToken { get; set; }
1818
public string ProofofPossessionNonce { get; set; }
1919
public PopTokenRequestContext PopTokenContext { get; set; }
2020
public Request Request { get; set; }
21-
public InteractiveBrowserCredential BrowserCredential { get; set; }
21+
public InteractiveBrowserCredential PopInteractiveBrowserCredential { get; set; }
2222
}
2323

2424
}

0 commit comments

Comments
 (0)