-
Notifications
You must be signed in to change notification settings - Fork 310
Fix OAuth Protected Resource Metadata flows with AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS #1263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix OAuth Protected Resource Metadata flows with AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS #1263
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| using System.CommandLine.Parsing; | ||
| using System.Diagnostics; | ||
| using System.Net; | ||
| using Azure.Core; | ||
| using Azure.Mcp.Core.Areas.Server.Models; | ||
| using Azure.Mcp.Core.Areas.Server.Options; | ||
| using Azure.Mcp.Core.Commands; | ||
|
|
@@ -21,6 +22,7 @@ | |
| using Microsoft.Extensions.Hosting; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using Microsoft.Extensions.Primitives; | ||
| using Microsoft.Identity.Web; | ||
| using OpenTelemetry; | ||
| using OpenTelemetry.Logs; | ||
|
|
@@ -414,7 +416,8 @@ private IHost CreateHttpHost(ServiceStartOptions serverOptions) | |
| if (!context.Response.HasStarted) | ||
| { | ||
| HttpRequest request = context.Request; | ||
| string resourceMetadataUrl = $"{request.Scheme}://{request.Host}/.well-known/oauth-protected-resource"; | ||
| string scheme = GetSchemeForOAuthProtectedResourceMetadata(request); | ||
| string resourceMetadataUrl = $"{scheme}://{request.Host}/.well-known/oauth-protected-resource"; | ||
|
|
||
| // Modify the WWW-Authenticate header to include resource_metadata | ||
| context.Response.Headers.WWWAuthenticate = | ||
|
|
@@ -498,7 +501,8 @@ private IHost CreateHttpHost(ServiceStartOptions serverOptions) | |
| .GetRequiredService<IOptionsMonitor<MicrosoftIdentityOptions>>(); | ||
| MicrosoftIdentityOptions azureAdOptions = azureAdOptionsMonitor.Get(JwtBearerDefaults.AuthenticationScheme); | ||
| HttpRequest request = context.Request; | ||
| string baseUrl = $"{request.Scheme}://{request.Host}"; | ||
| string scheme = GetSchemeForOAuthProtectedResourceMetadata(request); | ||
| string baseUrl = $"{scheme}://{request.Host}"; | ||
| string? clientId = azureAdOptions.ClientId; | ||
| string? tenantId = azureAdOptions.TenantId; | ||
| string instance = azureAdOptions.Instance?.TrimEnd('/') ?? "https://login.microsoftonline.com"; | ||
|
|
@@ -552,6 +556,50 @@ await JsonSerializer.SerializeAsync( | |
| .AllowAnonymous(); | ||
|
|
||
| return app; | ||
|
|
||
| string GetSchemeForOAuthProtectedResourceMetadata(HttpRequest request) | ||
| { | ||
| string scheme = request.Scheme; | ||
|
|
||
| // Default to "false" for enabling forwarded headers. The env var must be present, | ||
| // and it must be parsed to "true". | ||
| bool enableForwardedHeaders = | ||
| bool.TryParse( | ||
| Environment.GetEnvironmentVariable("AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS"), | ||
| out bool parsedEnvVar) | ||
| && parsedEnvVar; | ||
|
|
||
| // Azure Container Apps setups usually use HTTP between the ACA platform's | ||
| // reverse proxy and the application container. Our OAuth claims challenge | ||
| // needs to match what the client will use as a scheme. So only in this | ||
| // case do we use the X-Forwarded-Proto header if present. We're also going | ||
| // to limit specifically to "http" and "https" values and use their | ||
| // lowercase forms rather than the casing in the header. | ||
| // | ||
| // Other reverse proxies or load balancers may also use X-Forwarded-Proto or | ||
| // may use something different. We only special case ACA here because it's | ||
| // part of the samples as of 2.0-beta.5. More thorough logic and any | ||
| // configuration options can be added later if needed, and that could use | ||
| // ASP.NET Core's Forwarded Headers Middleware. See: | ||
| // https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer | ||
| if (enableForwardedHeaders | ||
| && request.Headers.TryGetValue("X-Forwarded-Proto", out StringValues forwardedProto)) | ||
| { | ||
| if (forwardedProto.FirstOrDefault() is string forwardedProtoValue) | ||
| { | ||
| if (string.Equals(forwardedProtoValue, "https", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| scheme = "https"; | ||
| } | ||
| else if (string.Equals(forwardedProtoValue, "http", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| scheme = "http"; | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+585
to
+599
|
||
|
|
||
| return scheme; | ||
| } | ||
|
Comment on lines
+560
to
+602
|
||
| } | ||
|
|
||
| /// <summary> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
using Azure.Core;directive appears to be unused. The only reference toAzure.Corein the file is a string literal comparison ("Azure.Core.Http") at line 872, which doesn't require this import.