Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"Microsoft.Build.NoTargets": "3.7.56"
},
"sdk": {
"version": "9.0.107",
"version": "8.0.117",
"rollForward": "latestFeature"
}
}
158 changes: 134 additions & 24 deletions src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Abstractions;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Client;

namespace Microsoft.Identity.Web
Expand Down Expand Up @@ -582,11 +583,50 @@ public Task<HttpResponseMessage> CallApiForAppAsync(
{
Logger.UnauthenticatedApiCall(_logger, null);
}
if (!string.IsNullOrEmpty(effectiveOptions.AcceptHeader))
{
httpRequestMessage.Headers.Accept.ParseAdd(effectiveOptions.AcceptHeader);
}
// Opportunity to change the request message
if (!string.IsNullOrEmpty(effectiveOptions.AcceptHeader))
{
httpRequestMessage.Headers.Accept.ParseAdd(effectiveOptions.AcceptHeader);
}

// Add extra headers if specified directly on DownstreamApiOptions
var extraHeaders = GetExtraHeaderParameters(effectiveOptions);
if (extraHeaders != null)
{
foreach (var header in extraHeaders)
{
httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}

// Add extra query parameters if specified directly on DownstreamApiOptions
var extraQueryParams = GetExtraQueryParameters(effectiveOptions);
if (extraQueryParams != null && extraQueryParams.Count > 0)
{
var uriBuilder = new UriBuilder(httpRequestMessage.RequestUri!);
var existingQuery = uriBuilder.Query;
var queryString = new StringBuilder(existingQuery);

foreach (var queryParam in extraQueryParams)
{
if (queryString.Length > 1) // if there are existing query parameters
{
queryString.Append('&');
}
else if (queryString.Length == 0)
{
queryString.Append('?');
}

queryString.Append(Uri.EscapeDataString(queryParam.Key));
queryString.Append('=');
queryString.Append(Uri.EscapeDataString(queryParam.Value));
}

uriBuilder.Query = queryString.ToString().TrimStart('?');
httpRequestMessage.RequestUri = uriBuilder.Uri;
}

// Opportunity to change the request message
effectiveOptions.CustomizeHttpRequestMessage?.Invoke(httpRequestMessage);
}

Expand All @@ -608,7 +648,77 @@ private static void AddCallerSDKTelemetry(DownstreamApiOptions effectiveOptions)
CallerSDKDetails["caller-sdk-id"];
effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"] =
CallerSDKDetails["caller-sdk-ver"];
}
}
}
}
}

/// <summary>
/// Gets the extra header parameters from DownstreamApiOptions if they exist.
/// This method uses reflection to check if the property exists to maintain compatibility
/// with different versions of Microsoft.Identity.Abstractions package.
/// Checks for both "ExtraHeaderParameters" and "ExtraHeadersParameters" for compatibility.
/// </summary>
/// <param name="options">The DownstreamApiOptions instance.</param>
/// <returns>Extra header parameters if they exist, null otherwise.</returns>
private static IDictionary<string, string>? GetExtraHeaderParameters(DownstreamApiOptions options)
{
try
{
// First try "ExtraHeaderParameters" (preferred naming)
var propertyInfo = options.GetType().GetProperty("ExtraHeaderParameters");
if (propertyInfo != null)
{
var value = propertyInfo.GetValue(options) as IDictionary<string, string>;
if (value != null && value.Count > 0)
{
return value;
}
}

// Fallback to "ExtraHeadersParameters" (for compatibility)
propertyInfo = options.GetType().GetProperty("ExtraHeadersParameters");
if (propertyInfo != null)
{
var value = propertyInfo.GetValue(options) as IDictionary<string, string>;
if (value != null && value.Count > 0)
{
return value;
}
}
}
catch
{
// If property doesn't exist or any error occurs, return null
}
return null;
}

/// <summary>
/// Gets the extra query parameters from DownstreamApiOptions if they exist.
/// This method uses reflection to check if the property exists to maintain compatibility
/// with different versions of Microsoft.Identity.Abstractions package.
/// </summary>
/// <param name="options">The DownstreamApiOptions instance.</param>
/// <returns>Extra query parameters if they exist, null otherwise.</returns>
private static IDictionary<string, string>? GetExtraQueryParameters(DownstreamApiOptions options)
{
try
{
var propertyInfo = options.GetType().GetProperty("ExtraQueryParameters");
if (propertyInfo != null)
{
var directValue = propertyInfo.GetValue(options) as IDictionary<string, string>;
if (directValue != null && directValue.Count > 0)
{
return directValue;
}
}
}
catch
{
// If property doesn't exist or any error occurs, return null
}

return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
static Microsoft.Identity.Web.DownstreamApi.GetExtraHeaderParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
static Microsoft.Identity.Web.DownstreamApi.GetExtraQueryParameters(Microsoft.Identity.Abstractions.DownstreamApiOptions! options) -> System.Collections.Generic.IDictionary<string!, string!>?
Loading