diff --git a/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs b/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs
index 4b1e1c42..b1c85eec 100644
--- a/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs
+++ b/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs
@@ -1,4 +1,5 @@
using System.Security.Claims;
+using System.Text;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
@@ -74,6 +75,103 @@ internal static class OpenIddictHelpers
}
}
+ ///
+ /// Adds a query string parameter to the specified .
+ ///
+ /// The address, to which the query string parameter will be appended.
+ /// The name of the query string parameter to append.
+ /// The value of the query string parameter to append.
+ /// The final instance, with the specified parameter appended.
+ public static Uri AddQueryStringParameter(Uri address, string name, string? value)
+ {
+ if (address is null)
+ {
+ throw new ArgumentNullException(nameof(address));
+ }
+
+ var builder = new StringBuilder(address.Query);
+ if (builder.Length > 0)
+ {
+ builder.Append('&');
+ }
+
+ builder.Append(Uri.EscapeDataString(name));
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ builder.Append('=');
+ builder.Append(Uri.EscapeDataString(value));
+ }
+
+ return new UriBuilder(address) { Query = builder.ToString() }.Uri;
+ }
+
+ ///
+ /// Adds query string parameters to the specified .
+ ///
+ /// The address, to which the query string parameters will be appended.
+ /// The query string parameters to append.
+ /// The final instance, with the specified parameters appended.
+ /// is .
+ /// is .
+ public static Uri AddQueryStringParameters(Uri address, IReadOnlyDictionary parameters)
+ {
+ if (address is null)
+ {
+ throw new ArgumentNullException(nameof(address));
+ }
+
+ if (parameters is null)
+ {
+ throw new ArgumentNullException(nameof(parameters));
+ }
+
+ if (parameters.Count is 0)
+ {
+ return address;
+ }
+
+ var builder = new StringBuilder(address.Query);
+
+ foreach (var parameter in parameters)
+ {
+ // If the parameter doesn't include any string value,
+ // only append the parameter key to the query string.
+ if (parameter.Value.Count is 0)
+ {
+ if (builder.Length > 0)
+ {
+ builder.Append('&');
+ }
+
+ builder.Append(Uri.EscapeDataString(parameter.Key));
+ }
+
+ // Otherwise, iterate the string values and create
+ // a new "name=value" pair for each iterated value.
+ else
+ {
+ foreach (var value in parameter.Value)
+ {
+ if (builder.Length > 0)
+ {
+ builder.Append('&');
+ }
+
+ builder.Append(Uri.EscapeDataString(parameter.Key));
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ builder.Append('=');
+ builder.Append(Uri.EscapeDataString(value));
+ }
+ }
+ }
+ }
+
+ return new UriBuilder(address) { Query = builder.ToString() }.Uri;
+ }
+
///
/// Extracts the parameters from the specified query string.
///
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj b/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
index e8f9bd3e..01c39ecb 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddict.Client.SystemNetHttp.csproj
@@ -38,6 +38,10 @@
+
+
+
+
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
index 6dc5c3bc..5d973d8c 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
@@ -10,10 +10,10 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO.Compression;
using System.Net.Http.Headers;
-using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
+using OpenIddict.Extensions;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpConstants;
namespace OpenIddict.Client.SystemNetHttp;
@@ -226,28 +226,10 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
return default;
}
- var builder = new StringBuilder();
-
- foreach (var (key, value) in
- from parameter in context.Transaction.Request.GetParameters()
- let values = (string?[]?) parameter.Value
- where values is not null
- from value in values
- where !string.IsNullOrEmpty(value)
- select (parameter.Key, Value: value))
- {
- if (builder.Length > 0)
- {
- builder.Append('&');
- }
-
- builder.Append(Uri.EscapeDataString(key));
- builder.Append('=');
- builder.Append(Uri.EscapeDataString(value));
- }
-
- // Compute the final request URI using the base address and the query string.
- request.RequestUri = new UriBuilder(request.RequestUri) { Query = builder.ToString() }.Uri;
+ request.RequestUri = OpenIddictHelpers.AddQueryStringParameters(request.RequestUri,
+ context.Transaction.Request.GetParameters().ToDictionary(
+ parameter => parameter.Key,
+ parameter => new StringValues((string?[]?) parameter.Value)));
return default;
}
@@ -286,11 +268,10 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
request.Content = new FormUrlEncodedContent(
from parameter in context.Transaction.Request.GetParameters()
- let values = (string[]?) parameter.Value
+ let values = (string?[]?) parameter.Value
where values is not null
from value in values
- where !string.IsNullOrEmpty(value)
- select new KeyValuePair(parameter.Key, value));
+ select new KeyValuePair(parameter.Key, value));
return default;
}
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddict.Client.WebIntegration.csproj b/src/OpenIddict.Client.WebIntegration/OpenIddict.Client.WebIntegration.csproj
index 18dd3dca..756051da 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddict.Client.WebIntegration.csproj
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddict.Client.WebIntegration.csproj
@@ -27,6 +27,10 @@
+
+
+
+
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
index e8e7955f..7e7ec84a 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
@@ -8,6 +8,7 @@ using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.Json;
using static OpenIddict.Client.OpenIddictClientHandlers.Userinfo;
+using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlerFilters;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
@@ -39,6 +40,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
///
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .AddFilter()
.UseSingletonHandler()
.SetOrder(AttachBearerAccessToken.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
@@ -82,6 +84,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
///
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .AddFilter()
.UseSingletonHandler()
.SetOrder(PopulateClaims.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
diff --git a/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj b/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
index dd958561..eb75f378 100644
--- a/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
+++ b/src/OpenIddict.Validation.SystemNetHttp/OpenIddict.Validation.SystemNetHttp.csproj
@@ -38,6 +38,10 @@
+
+
+
+
diff --git a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
index f017716b..b0b045bc 100644
--- a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
+++ b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
@@ -10,10 +10,10 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO.Compression;
using System.Net.Http.Headers;
-using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
+using OpenIddict.Extensions;
using static OpenIddict.Validation.SystemNetHttp.OpenIddictValidationSystemNetHttpConstants;
namespace OpenIddict.Validation.SystemNetHttp;
@@ -227,28 +227,10 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
return default;
}
- var builder = new StringBuilder();
-
- foreach (var (key, value) in
- from parameter in context.Transaction.Request.GetParameters()
- let values = (string?[]?) parameter.Value
- where values is not null
- from value in values
- where !string.IsNullOrEmpty(value)
- select (parameter.Key, Value: value))
- {
- if (builder.Length > 0)
- {
- builder.Append('&');
- }
-
- builder.Append(Uri.EscapeDataString(key));
- builder.Append('=');
- builder.Append(Uri.EscapeDataString(value));
- }
-
- // Compute the final request URI using the base address and the query string.
- request.RequestUri = new UriBuilder(request.RequestUri) { Query = builder.ToString() }.Uri;
+ request.RequestUri = OpenIddictHelpers.AddQueryStringParameters(request.RequestUri,
+ context.Transaction.Request.GetParameters().ToDictionary(
+ parameter => parameter.Key,
+ parameter => new StringValues((string?[]?) parameter.Value)));
return default;
}
@@ -287,11 +269,10 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
request.Content = new FormUrlEncodedContent(
from parameter in context.Transaction.Request.GetParameters()
- let values = (string[]?) parameter.Value
+ let values = (string?[]?) parameter.Value
where values is not null
from value in values
- where !string.IsNullOrEmpty(value)
- select new KeyValuePair(parameter.Key, value));
+ select new KeyValuePair(parameter.Key, value));
return default;
}
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddict.Server.IntegrationTests.csproj b/test/OpenIddict.Server.IntegrationTests/OpenIddict.Server.IntegrationTests.csproj
index 2c94cec3..4e8a7a8c 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddict.Server.IntegrationTests.csproj
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddict.Server.IntegrationTests.csproj
@@ -33,6 +33,10 @@
+
+
+
+
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTestClient.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTestClient.cs
index e32e720d..d0c2ed3e 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTestClient.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTestClient.cs
@@ -5,10 +5,9 @@
*/
using System.Net.Http.Json;
-using System.Text;
-using System.Text.Encodings.Web;
using AngleSharp.Html.Parser;
using Microsoft.Extensions.Primitives;
+using OpenIddict.Extensions;
namespace OpenIddict.Server.IntegrationTests;
@@ -235,71 +234,28 @@ public class OpenIddictServerIntegrationTestClient : IAsyncDisposable
private HttpRequestMessage CreateRequestMessage(OpenIddictRequest request, HttpMethod method, Uri uri)
{
- // Note: a dictionary is deliberately not used here to allow multiple parameters with the
- // same name to be specified. While initially not allowed by the core OAuth2 specification,
- // this is required for derived drafts like the OAuth2 token exchange specification.
- var parameters = new List>();
-
- foreach (var parameter in request.GetParameters())
+ if (!uri.IsAbsoluteUri)
{
- // If the parameter is null or empty, send an empty value.
- if (OpenIddictParameter.IsNullOrEmpty(parameter.Value))
- {
- parameters.Add(new KeyValuePair(parameter.Key, string.Empty));
-
- continue;
- }
-
- var values = (string?[]?) parameter.Value;
- if (values is not { Length: > 0 })
- {
- continue;
- }
-
- foreach (var value in values)
- {
- parameters.Add(new KeyValuePair(parameter.Key, value));
- }
+ uri = new Uri(HttpClient.BaseAddress!, uri);
}
- if (method == HttpMethod.Get && parameters.Count is not 0)
+ var message = new HttpRequestMessage(method, uri);
+ if (message.Method == HttpMethod.Get && request.Count is not 0)
{
- var builder = new StringBuilder();
-
- foreach (var parameter in parameters)
- {
- if (string.IsNullOrEmpty(parameter.Key))
- {
- continue;
- }
-
- if (builder.Length is not 0)
- {
- builder.Append('&');
- }
-
- builder.Append(UrlEncoder.Default.Encode(parameter.Key));
-
- if (!string.IsNullOrEmpty(parameter.Value))
- {
- builder.Append('=');
- builder.Append(UrlEncoder.Default.Encode(parameter.Value));
- }
- }
-
- if (!uri.IsAbsoluteUri)
- {
- uri = new Uri(HttpClient.BaseAddress!, uri);
- }
-
- uri = new UriBuilder(uri) { Query = builder.ToString() }.Uri;
+ message.RequestUri = OpenIddictHelpers.AddQueryStringParameters(message.RequestUri!,
+ request.GetParameters().ToDictionary(
+ parameter => parameter.Key,
+ parameter => new StringValues((string?[]?) parameter.Value)));
}
- var message = new HttpRequestMessage(method, uri);
-
- if (method != HttpMethod.Get)
+ if (message.Method != HttpMethod.Get)
{
- message.Content = new FormUrlEncodedContent(parameters);
+ message.Content = new FormUrlEncodedContent(
+ from parameter in request.GetParameters()
+ let values = (string?[]?) parameter.Value
+ where values is not null
+ from value in values
+ select new KeyValuePair(parameter.Key, value));
}
return message;
diff --git a/test/OpenIddict.Validation.IntegrationTests/OpenIddict.Validation.IntegrationTests.csproj b/test/OpenIddict.Validation.IntegrationTests/OpenIddict.Validation.IntegrationTests.csproj
index f2ea1e0e..0b2c218a 100644
--- a/test/OpenIddict.Validation.IntegrationTests/OpenIddict.Validation.IntegrationTests.csproj
+++ b/test/OpenIddict.Validation.IntegrationTests/OpenIddict.Validation.IntegrationTests.csproj
@@ -32,6 +32,10 @@
+
+
+
+
diff --git a/test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTestClient.cs b/test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTestClient.cs
index afcc5f70..d1c2ae19 100644
--- a/test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTestClient.cs
+++ b/test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTestClient.cs
@@ -5,10 +5,9 @@
*/
using System.Net.Http.Json;
-using System.Text;
-using System.Text.Encodings.Web;
using AngleSharp.Html.Parser;
using Microsoft.Extensions.Primitives;
+using OpenIddict.Extensions;
namespace OpenIddict.Validation.IntegrationTests;
@@ -235,71 +234,28 @@ public class OpenIddictValidationIntegrationTestClient : IAsyncDisposable
private HttpRequestMessage CreateRequestMessage(OpenIddictRequest request, HttpMethod method, Uri uri)
{
- // Note: a dictionary is deliberately not used here to allow multiple parameters with the
- // same name to be specified. While initially not allowed by the core OAuth2 specification,
- // this is required for derived drafts like the OAuth2 token exchange specification.
- var parameters = new List>();
-
- foreach (var parameter in request.GetParameters())
+ if (!uri.IsAbsoluteUri)
{
- // If the parameter is null or empty, send an empty value.
- if (OpenIddictParameter.IsNullOrEmpty(parameter.Value))
- {
- parameters.Add(new KeyValuePair(parameter.Key, string.Empty));
-
- continue;
- }
-
- var values = (string?[]?) parameter.Value;
- if (values is not { Length: > 0 })
- {
- continue;
- }
-
- foreach (var value in values)
- {
- parameters.Add(new KeyValuePair(parameter.Key, value));
- }
+ uri = new Uri(HttpClient.BaseAddress!, uri);
}
- if (method == HttpMethod.Get && parameters.Count is not 0)
+ var message = new HttpRequestMessage(method, uri);
+ if (message.Method == HttpMethod.Get && request.Count is not 0)
{
- var builder = new StringBuilder();
-
- foreach (var parameter in parameters)
- {
- if (string.IsNullOrEmpty(parameter.Key))
- {
- continue;
- }
-
- if (builder.Length is not 0)
- {
- builder.Append('&');
- }
-
- builder.Append(UrlEncoder.Default.Encode(parameter.Key));
-
- if (!string.IsNullOrEmpty(parameter.Value))
- {
- builder.Append('=');
- builder.Append(UrlEncoder.Default.Encode(parameter.Value));
- }
- }
-
- if (!uri.IsAbsoluteUri)
- {
- uri = new Uri(HttpClient.BaseAddress!, uri);
- }
-
- uri = new UriBuilder(uri) { Query = builder.ToString() }.Uri;
+ message.RequestUri = OpenIddictHelpers.AddQueryStringParameters(message.RequestUri!,
+ request.GetParameters().ToDictionary(
+ parameter => parameter.Key,
+ parameter => new StringValues((string?[]?) parameter.Value)));
}
- var message = new HttpRequestMessage(method, uri);
-
- if (method != HttpMethod.Get)
+ if (message.Method != HttpMethod.Get)
{
- message.Content = new FormUrlEncodedContent(parameters);
+ message.Content = new FormUrlEncodedContent(
+ from parameter in request.GetParameters()
+ let values = (string?[]?) parameter.Value
+ where values is not null
+ from value in values
+ select new KeyValuePair(parameter.Key, value));
}
return message;