Skip to content

Commit a75f056

Browse files
Add AuthorizeRequestDelegate to allow service module to adjust token audience (#15989)
* Add Erich's DataPlane code * Add Erich's DataPlane code * Add Erich's DataPlane code * Update the code Co-authored-by: wyunchi-ms <[email protected]> Co-authored-by: dingmeng-xue <[email protected]>
1 parent ace17b5 commit a75f056

File tree

5 files changed

+91
-5
lines changed

5 files changed

+91
-5
lines changed

src/Accounts/Accounts/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020

2121
## Upcoming Release
22+
* Added AuthorizeRequestDelegate to allow service module to adjust token audience.
2223
* Utilized [AssemblyLoadContext](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext) to resolve assembly conflict issues in PowerShell.
2324
* Updated Azure.Core from 1.16.0 to 1.19.0.
2425

src/Accounts/Accounts/CommonModule/ContextAdapter.cs

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace Microsoft.Azure.Commands.Common
3232
using NextDelegate = Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>;
3333
using SignalDelegate = Func<string, CancellationToken, Func<EventArgs>, Task>;
3434
using PipelineChangeDelegate = Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>;
35+
using TokenAudienceConverterDelegate = Func<string, string, string, string, Uri, string>;
3536

3637
/// <summary>
3738
/// Perform authentication and parameter completion based on the value of the context
@@ -74,6 +75,51 @@ public void OnNewRequest(InvocationInfo invocationInfo, string correlationId, st
7475
appendStep(this.SendHandler(GetDefaultContext(_provider, invocationInfo), AzureEnvironment.Endpoint.ResourceManager));
7576
}
7677

78+
internal void AddRequestUserAgentHandler(
79+
InvocationInfo invocationInfo,
80+
string correlationId,
81+
string processRecordId,
82+
PipelineChangeDelegate prependStep,
83+
PipelineChangeDelegate appendStep)
84+
{
85+
appendStep(new UserAgent(invocationInfo).SendAsync);
86+
}
87+
88+
internal void AddPatchRequestUriHandler(
89+
InvocationInfo invocationInfo,
90+
string correlationId,
91+
string processRecordId,
92+
PipelineChangeDelegate prependStep,
93+
PipelineChangeDelegate appendStep)
94+
{
95+
appendStep(
96+
async (request, cancelToken, cancelAction, signal, next) =>
97+
{
98+
var context = GetDefaultContext(_provider, invocationInfo);
99+
PatchRequestUri(context, request);
100+
return await next(request, cancelToken, cancelAction, signal);
101+
});
102+
}
103+
104+
internal void AddAuthorizeRequestHandler(
105+
InvocationInfo invocationInfo,
106+
string endpointResourceIdKey,
107+
string endpointSuffixKey,
108+
PipelineChangeDelegate prependStep,
109+
PipelineChangeDelegate appendStep,
110+
TokenAudienceConverterDelegate tokenAudienceConverter,
111+
IDictionary<string, object> extensibleParameters = null)
112+
{
113+
appendStep(
114+
async (request, cancelToken, cancelAction, signal, next) =>
115+
{
116+
endpointResourceIdKey = endpointResourceIdKey ?? AzureEnvironment.Endpoint.ResourceManager;
117+
var context = GetDefaultContext(_provider, invocationInfo);
118+
await AuthorizeRequest(context, request, cancelToken, endpointResourceIdKey, endpointSuffixKey, tokenAudienceConverter);
119+
return await next(request, cancelToken, cancelAction, signal);
120+
});
121+
}
122+
77123
/// <summary>
78124
/// Called for well-known parameters that require argument completers
79125
/// </summary>
@@ -156,7 +202,7 @@ internal Func<HttpRequestMessage, CancellationToken, Action, SignalDelegate, Nex
156202
return async (request, cancelToken, cancelAction, signal, next) =>
157203
{
158204
PatchRequestUri(context, request);
159-
await AuthorizeRequest(context, resourceId, request, cancelToken);
205+
await AuthorizeRequest(context, request, cancelToken, resourceId, resourceId);
160206
return await next(request, cancelToken, cancelAction, signal);
161207
};
162208
}
@@ -165,11 +211,12 @@ internal Func<HttpRequestMessage, CancellationToken, Action, SignalDelegate, Nex
165211
/// Pipeline step for authenticating requests
166212
/// </summary>
167213
/// <param name="context"></param>
168-
/// <param name="resourceId"></param>
214+
/// <param name="endpointResourceIdKey"></param>
169215
/// <param name="request"></param>
170216
/// <param name="outerToken"></param>
171217
/// <returns></returns>
172-
internal async Task AuthorizeRequest(IAzureContext context, string resourceId, HttpRequestMessage request, CancellationToken outerToken)
218+
internal async Task AuthorizeRequest(IAzureContext context, HttpRequestMessage request, CancellationToken outerToken, string endpointResourceIdKey,
219+
string endpointSuffixKey, TokenAudienceConverterDelegate tokenAudienceConverter = null, IDictionary<string, object> extensibleParamters = null)
173220
{
174221
if (context == null || context.Account == null || context.Environment == null)
175222
{
@@ -178,12 +225,29 @@ internal async Task AuthorizeRequest(IAzureContext context, string resourceId, H
178225

179226
await Task.Run(() =>
180227
{
181-
resourceId = context?.Environment?.GetAudienceFromRequestUri(request.RequestUri) ?? resourceId;
182-
var authToken = _authenticator.Authenticate(context.Account, context.Environment, context.Tenant.Id, null, "Never", null, resourceId);
228+
if (tokenAudienceConverter != null)
229+
{
230+
var info = GetEndpointInfo(context.Environment, endpointResourceIdKey, endpointSuffixKey);
231+
var tokenAudience = tokenAudienceConverter.Invoke(info.CurEnvEndpointResourceId, info.CurEnvEndpointSuffix, info.BaseEnvEndpointResourceId, info.BaseEnvEndpointSuffix, request.RequestUri);
232+
endpointResourceIdKey = tokenAudience ?? endpointResourceIdKey;
233+
}
234+
var authToken = _authenticator.Authenticate(context.Account, context.Environment, context.Tenant.Id, null, "Never", null, endpointResourceIdKey);
183235
authToken.AuthorizeRequest((type, token) => request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(type, token));
184236
}, outerToken);
185237
}
186238

239+
private (string CurEnvEndpointResourceId, string CurEnvEndpointSuffix, string BaseEnvEndpointResourceId, string BaseEnvEndpointSuffix) GetEndpointInfo(IAzureEnvironment environment, string endpointResourceIdKey, string endpointSuffixKey)
240+
{
241+
var baseEnvironment = AzureEnvironment.PublicEnvironments[EnvironmentName.AzureCloud];
242+
243+
string curEnvEndpointResourceId = environment?.GetEndpoint(endpointResourceIdKey);
244+
string curEnvEndpointSuffix = environment?.GetEndpoint(endpointSuffixKey);
245+
string baseEnvEndpointResourceId = baseEnvironment?.GetEndpoint(endpointResourceIdKey);
246+
string baseEnvEndpointSuffix = baseEnvironment?.GetEndpoint(endpointSuffixKey);
247+
248+
return (curEnvEndpointResourceId, curEnvEndpointSuffix, baseEnvEndpointResourceId, baseEnvEndpointSuffix); ;
249+
}
250+
187251
internal void PatchRequestUri(IAzureContext context, HttpRequestMessage request)
188252
{
189253
var requestUri = context?.Environment?.GetUriFromBaseRequestUri(request.RequestUri);

src/Accounts/Accounts/CommonModule/EnvironmentExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public static Uri GetUriFromBaseRequestUri(this IAzureEnvironment environment, U
103103
return baseEndpoint;
104104
}
105105

106+
////TODO: Update to support all data plane audience
106107
/// <summary>
107108
/// Determien the inteneded audience of a request
108109
/// </summary>

src/Accounts/Accounts/CommonModule/RegisterAzModule.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ protected override void ProcessRecord()
5454
// this gets called before the generated cmdlet makes a call across the wire (allows you to change the HTTP pipeline)
5555
OnNewRequest = ContextAdapter.Instance.OnNewRequest,
5656

57+
//OnNewRequest = AddRequestUserAgentHandler + AddPatchRequestUriHandler + AddAuthorizeRequestHandler
58+
AddRequestUserAgentHandler = ContextAdapter.Instance.AddRequestUserAgentHandler,
59+
60+
AddPatchRequestUriHandler = ContextAdapter.Instance.AddPatchRequestUriHandler,
61+
62+
AddAuthorizeRequestHandler = ContextAdapter.Instance.AddAuthorizeRequestHandler,
63+
5764
// Called for well-known parameters that require argument completers
5865
ArgumentCompleter = ContextAdapter.Instance.CompleteArgument,
5966

src/Accounts/Accounts/CommonModule/VTable.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ namespace Microsoft.Azure.Commands.Common
2424
using ModuleLoadPipelineDelegate = Action<string, string, Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>, Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>>;
2525
using NewRequestPipelineDelegate = Action<System.Management.Automation.InvocationInfo, string, string, Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>, Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>>;
2626
using ArgumentCompleterDelegate = Func<string, System.Management.Automation.InvocationInfo, string, string[], string[], string[]>;
27+
using AuthorizeRequestDelegate = global::System.Action<System.Management.Automation.InvocationInfo,
28+
string,
29+
string,
30+
global::System.Action<global::System.Func<global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken, global::System.Action, global::System.Func<string, global::System.Threading.CancellationToken, global::System.Func<global::System.EventArgs>, global::System.Threading.Tasks.Task>, global::System.Func<global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken, global::System.Action, global::System.Func<string, global::System.Threading.CancellationToken, global::System.Func<global::System.EventArgs>, global::System.Threading.Tasks.Task>, global::System.Threading.Tasks.Task<global::System.Net.Http.HttpResponseMessage>>, global::System.Threading.Tasks.Task<global::System.Net.Http.HttpResponseMessage>>>,
31+
global::System.Action<global::System.Func<global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken, global::System.Action, global::System.Func<string, global::System.Threading.CancellationToken, global::System.Func<global::System.EventArgs>, global::System.Threading.Tasks.Task>, global::System.Func<global::System.Net.Http.HttpRequestMessage, global::System.Threading.CancellationToken, global::System.Action, global::System.Func<string, global::System.Threading.CancellationToken, global::System.Func<global::System.EventArgs>, global::System.Threading.Tasks.Task>, global::System.Threading.Tasks.Task<global::System.Net.Http.HttpResponseMessage>>, global::System.Threading.Tasks.Task<global::System.Net.Http.HttpResponseMessage>>>,
32+
global::System.Func<string, string, string, string, global::System.Uri, string>,
33+
System.Collections.Generic.IDictionary<string, object>>;
2734

2835
/// <summary>
2936
/// The Virtual Call table of the functions to be exported to the generated module
@@ -74,6 +81,12 @@ public class VTable
7481
/// <param name="appendStep">a delegate which allows the module to append a step in the HTTP Pipeline</param>
7582
public NewRequestPipelineDelegate OnNewRequest;
7683

84+
public NewRequestPipelineDelegate AddRequestUserAgentHandler;
85+
86+
public NewRequestPipelineDelegate AddPatchRequestUriHandler;
87+
88+
public AuthorizeRequestDelegate AddAuthorizeRequestHandler;
89+
7790
/// <summary>
7891
/// Called for well-known parameters that require argument completers
7992
/// </summary>

0 commit comments

Comments
 (0)