From 4100b2aa132e6031aeb663e37e4a7140e63ca523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Thu, 28 May 2026 17:12:01 +0300 Subject: [PATCH 1/6] GD2-4811 packages update --- src/Directory.Build.targets | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 8a9cab353..043ae849b 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -2,15 +2,15 @@ net8.0 - 8.0.19 + 8.0.27 - - - - + + + + @@ -40,19 +40,19 @@ - + - + - + - - - - - + + + + + From f5778dcad144f85a283f958721c27ff57c718e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Thu, 28 May 2026 18:03:42 +0300 Subject: [PATCH 2/6] GD2-4811 editor config --- .editorconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 547eadea8..164295049 100644 --- a/.editorconfig +++ b/.editorconfig @@ -383,7 +383,7 @@ resharper_csharp_align_multiline_argument=false resharper_csharp_align_multiline_expression=false resharper_csharp_align_multiline_parameter=false resharper_csharp_align_multiple_declaration=false -resharper_csharp_max_line_length=120 +resharper_csharp_max_line_length=160 resharper_csharp_naming_rule.enum_member=AaBb resharper_csharp_naming_rule.method_property_event=AaBb resharper_csharp_naming_rule.other=AaBb @@ -412,7 +412,7 @@ resharper_format_leading_spaces_decl=false resharper_html_attribute_indent=align_by_first_attribute resharper_html_linebreak_before_elements=body,div,p,form,h1,h2,h3 resharper_html_max_blank_lines_between_tags=2 -resharper_html_max_line_length=120 +resharper_html_max_line_length=160 resharper_html_pi_attribute_style=on_single_line resharper_html_space_before_self_closing=false resharper_html_wrap_lines=true @@ -619,7 +619,7 @@ resharper_vb_align_multiline_argument=true resharper_vb_align_multiline_expression=true resharper_vb_align_multiline_parameter=true resharper_vb_align_multiple_declaration=true -resharper_vb_max_line_length=120 +resharper_vb_max_line_length=160 resharper_vb_place_field_attribute_on_same_line=true resharper_vb_place_method_attribute_on_same_line=false resharper_vb_place_type_attribute_on_same_line=false @@ -659,7 +659,7 @@ resharper_wrap_verbatim_interpolated_strings=no_wrap resharper_xmldoc_attribute_indent=single_indent resharper_xmldoc_linebreak_before_elements=summary,remarks,example,returns,param,typeparam,value,para resharper_xmldoc_max_blank_lines_between_tags=0 -resharper_xmldoc_max_line_length=120 +resharper_xmldoc_max_line_length=160 resharper_xmldoc_pi_attribute_style=do_not_touch resharper_xmldoc_space_before_self_closing=true resharper_xmldoc_wrap_lines=true @@ -668,7 +668,7 @@ resharper_xmldoc_wrap_text=true resharper_xml_attribute_indent=align_by_first_attribute resharper_xml_linebreak_before_elements= resharper_xml_max_blank_lines_between_tags=2 -resharper_xml_max_line_length=120 +resharper_xml_max_line_length=160 resharper_xml_pi_attribute_style=do_not_touch resharper_xml_space_before_self_closing=true resharper_xml_wrap_lines=true From 325886160d684ef79d4bff44ae922139c3a87084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Thu, 28 May 2026 18:05:10 +0300 Subject: [PATCH 3/6] GD2-4811 IdentityExceptionHandleMiddleware --- ...entityServerServiceCollectionExtensions.cs | 4 +- ...ntityServerApplicationBuilderExtensions.cs | 2 + .../src/Extensions/ExceptionExtensions.cs | 23 +++ .../IdentityExceptionHandleMiddleware.cs | 156 ++++++++++++++++++ .../ExceptionHandling/Rfc/RfcException.cs | 68 ++++++++ .../ExceptionHandling/Rfc/RfcExtensions.cs | 14 ++ .../ExceptionHandling/Rfc/RfcHelper.cs | 60 +++++++ .../Hosting/ExceptionHandling/Rfc/RfcTypes.cs | 51 ++++++ 8 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 src/IdentityServer4/src/Extensions/ExceptionExtensions.cs create mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs create mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs create mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs create mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs create mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs diff --git a/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs b/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs index ca0ba41b5..92291ab8a 100644 --- a/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs +++ b/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using IdentityServer4.Configuration; using Microsoft.Extensions.Configuration; using System; +using IdentityServer4.Hosting.ExceptionHandling; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authentication.OpenIdConnect; @@ -44,7 +45,8 @@ public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection s .AddValidators() .AddResponseGenerators() .AddDefaultSecretParsers() - .AddDefaultSecretValidators(); + .AddDefaultSecretValidators() + .AddIdentityExceptionHandling(); // provide default in-memory implementation, not suitable for most production scenarios builder.AddInMemoryPersistedGrants(); diff --git a/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs b/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs index 9b8831640..0f8861957 100644 --- a/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs +++ b/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs @@ -12,6 +12,7 @@ using System; using System.Reflection; using System.Threading.Tasks; +using IdentityServer4.Hosting.ExceptionHandling; namespace Microsoft.AspNetCore.Builder; @@ -29,6 +30,7 @@ public static class IdentityServerApplicationBuilderExtensions public static IApplicationBuilder UseIdentityServer(this IApplicationBuilder app, IdentityServerMiddlewareOptions options = null) { app.Validate(); + app.UseIdentityExceptionHandling(); app.UseMiddleware(); diff --git a/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs b/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs new file mode 100644 index 000000000..a0027371f --- /dev/null +++ b/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace IdentityServer4.Extensions; + +internal static class ExceptionExtensions +{ + public static IEnumerable GetInnerExceptions(this Exception exception, int count = 5) + { + ArgumentNullException.ThrowIfNull(exception); + + var innerException = exception; + do + { + yield return innerException; + + innerException = innerException.InnerException; + count--; + } while (innerException is not null && count > 0); + } +} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs new file mode 100644 index 000000000..a07673d73 --- /dev/null +++ b/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs @@ -0,0 +1,156 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using IdentityServer4.Extensions; +using IdentityServer4.Hosting.ExceptionHandling.Rfc; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace IdentityServer4.Hosting.ExceptionHandling; + +public sealed class IdentityExceptionHandleMiddleware(ILogger logger, IWebHostEnvironment environment) : IMiddleware +{ + private const int Status499ClientClosedRequest = 499; + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var cToken = context.RequestAborted; + + try + { + await next(context); + } + catch (Exception exception) + { + // rfc problem + var rfcProblem = exception.ToProblemDetails(); + + // rfc code + rfcProblem.Status ??= ResolveHttpStatusCode(exception); + + // rfc type + rfcProblem.Type ??= ResolveRfcTypeByHttpStatusCode(rfcProblem.Status.Value); + + // rfc stackTrace + if (string.IsNullOrEmpty(exception.StackTrace) is false && environment.IsProduction() is false) + rfcProblem.Extensions[RfcExtensions.StackTrace] = string.Join(Environment.NewLine, + exception.GetInnerExceptions().Select(x => x.StackTrace)); + + // rfc traceId + rfcProblem.Extensions[RfcExtensions.TraceId] = Activity.Current?.Id ?? context.TraceIdentifier; + + // rfc Instance + rfcProblem.Instance = GetRfcInstance(context.Request); + + var responseJson = JsonSerializer.Serialize(rfcProblem); + if (rfcProblem.Status >= StatusCodes.Status500InternalServerError) + logger.LogError(exception, "Request failed"); + else + logger.LogWarning(exception, "Request complete with warning. {MiddlewareResponse}", responseJson); + + try + { + context.Response.StatusCode = rfcProblem.Status.Value; + context.Response.ContentType = "application/json"; + + await context.Response.WriteAsync(responseJson, cToken); + } + catch (ObjectDisposedException) + { + // ignore + } + catch (InvalidOperationException e) when (e.Message.Contains("response has already started", StringComparison.CurrentCultureIgnoreCase)) + { + // ignore + } + } + } + + private static int ResolveHttpStatusCode(Exception exception) => exception switch + { + UnauthorizedAccessException => StatusCodes.Status403Forbidden, + ArgumentException or ValidationException => StatusCodes.Status400BadRequest, + OperationCanceledException => Status499ClientClosedRequest, + _ => StatusCodes.Status500InternalServerError + }; + + private static string ResolveRfcTypeByHttpStatusCode(int statusCode) => statusCode switch + { + // 4xx Client Errors + StatusCodes.Status400BadRequest => RfcTypes.BadRequest, + StatusCodes.Status401Unauthorized => RfcTypes.Unauthorized, + StatusCodes.Status402PaymentRequired => RfcTypes.PaymentError, + StatusCodes.Status403Forbidden => RfcTypes.Forbidden, + StatusCodes.Status404NotFound => RfcTypes.NotFound, + StatusCodes.Status405MethodNotAllowed => RfcTypes.MethodNotAllowed, + StatusCodes.Status406NotAcceptable => RfcTypes.NotAcceptable, + StatusCodes.Status407ProxyAuthenticationRequired => RfcTypes.Unauthorized, + StatusCodes.Status408RequestTimeout => RfcTypes.Timeout, + StatusCodes.Status409Conflict => RfcTypes.Conflict, + StatusCodes.Status410Gone => RfcTypes.Gone, + StatusCodes.Status411LengthRequired => RfcTypes.LengthRequired, + StatusCodes.Status412PreconditionFailed => RfcTypes.PreconditionFailed, + StatusCodes.Status413PayloadTooLarge => RfcTypes.PayloadTooLarge, + StatusCodes.Status414UriTooLong => RfcTypes.UriTooLong, + StatusCodes.Status415UnsupportedMediaType => RfcTypes.UnsupportedMediaType, + StatusCodes.Status416RangeNotSatisfiable => RfcTypes.RangeNotSatisfiable, + StatusCodes.Status417ExpectationFailed => RfcTypes.ExpectationFailed, + StatusCodes.Status418ImATeapot => "☕🤦‍♂️", + StatusCodes.Status421MisdirectedRequest => RfcTypes.MisdirectedRequest, + StatusCodes.Status422UnprocessableEntity => RfcTypes.ValidationError, + StatusCodes.Status423Locked => RfcTypes.Locked, + StatusCodes.Status424FailedDependency => RfcTypes.FailedDependency, + 425 => RfcTypes.TooEarly, + StatusCodes.Status426UpgradeRequired => RfcTypes.UpgradeRequired, + StatusCodes.Status428PreconditionRequired => RfcTypes.PreconditionRequired, + StatusCodes.Status429TooManyRequests => RfcTypes.TooManyRequests, + StatusCodes.Status431RequestHeaderFieldsTooLarge => RfcTypes.RequestHeaderTooLarge, + StatusCodes.Status451UnavailableForLegalReasons => RfcTypes.UnavailableForLegalReasons, + + // 5xx Server Errors + StatusCodes.Status500InternalServerError => RfcTypes.InternalServerError, + StatusCodes.Status501NotImplemented => RfcTypes.NotImplemented, + StatusCodes.Status502BadGateway => RfcTypes.BadGateway, + StatusCodes.Status503ServiceUnavailable => RfcTypes.ServiceUnavailable, + StatusCodes.Status504GatewayTimeout => RfcTypes.GatewayTimeout, + StatusCodes.Status505HttpVersionNotsupported => RfcTypes.HttpVersionNotSupported, + StatusCodes.Status506VariantAlsoNegotiates => RfcTypes.VariantAlsoNegotiates, + StatusCodes.Status507InsufficientStorage => RfcTypes.InsufficientStorage, + StatusCodes.Status508LoopDetected => RfcTypes.LoopDetected, + StatusCodes.Status510NotExtended => RfcTypes.NotExtended, + StatusCodes.Status511NetworkAuthenticationRequired => RfcTypes.NetworkAuthenticationRequired, + + _ => "unknown" + }; + + private static string GetRfcInstance(HttpRequest contextRequest) + { + var instance = new + { + Path = contextRequest.Path.ToString(), + Query = contextRequest.QueryString.ToString() + }; + + return JsonSerializer.Serialize(instance); + } +} + +public static class IdentityExceptionHandleMiddlewareExtensions +{ + public static IIdentityServerBuilder AddIdentityExceptionHandling(this IIdentityServerBuilder identityServer) + { + identityServer.Services.AddSingleton(); + return identityServer; + } + + public static IApplicationBuilder UseIdentityExceptionHandling(this IApplicationBuilder app) => app.UseMiddleware(); +} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs new file mode 100644 index 000000000..17e60a7bc --- /dev/null +++ b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.AspNetCore.Http; + +namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; + +/// +/// Represents an application exception that can be converted to +/// an RFC 7807 / HTTP API error response. +/// +/// +/// Use this contract for domain and application exceptions that should be +/// exposed to API clients in a stable and predictable format. +/// +/// The values returned by this interface are used to populate +/// . +/// +/// +internal interface IRfcException +{ + protected internal static readonly ImmutableDictionary NoExtensions = ImmutableDictionary.Create(); + + /// + /// Gets the HTTP status code that should be returned to the client. + /// + /// + /// A valid HTTP status code, for example + /// , + /// , + /// . + /// + int StatusCode { get; } + + /// + /// Gets the stable problem type identifier. + /// + /// + /// A stable URI or URI-like string that identifies the category of the problem, + /// for example /problems/not-found or /problems/validation-error. + /// + /// + /// This value should describe the problem category, not the .NET exception type. + /// + string RfcType { get; } + + /// + /// Gets the short, human-readable summary of the problem type. + /// + /// + /// A stable title such as Resource not found, + /// Validation failed, or Conflict. + /// + string Title { get; } + + /// + /// Gets the human-readable explanation specific to the current occurrence. + /// + /// + /// Additional details for the current error instance. + /// This value may be when no extra details should be exposed. + /// + /// + /// Do not put stack traces, secrets, connection strings, or other internal diagnostics here. + /// + string? Detail { get; } + + IDictionary RfcExtensions => NoExtensions; +} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs new file mode 100644 index 000000000..e5ac6b756 --- /dev/null +++ b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs @@ -0,0 +1,14 @@ +namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; + +#pragma warning disable 1591 + +internal static class RfcExtensions +{ + public const int DefaultExtensionsCapacity = 4; + + // default + public const string ExceptionType = "exceptionType"; + public const string ExceptionData = "exceptionData"; + public const string StackTrace = "stackTrace"; + public const string TraceId = "traceId"; +} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs new file mode 100644 index 000000000..dff185ffb --- /dev/null +++ b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; + +namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; + +/// +/// Provides helper methods for converting exceptions to . +/// +internal static class RfcHelper +{ + /// + /// Converts the specified exception to a instance. + /// + /// + /// The exception type. + /// + /// + /// The exception to convert. + /// + /// + /// A instance. + /// + public static ProblemDetails ToProblemDetails(this T exception) where T : Exception + { + ArgumentNullException.ThrowIfNull(exception); + + var extensions = new Dictionary(RfcExtensions.DefaultExtensionsCapacity) + { + [RfcExtensions.ExceptionType] = exception.GetType().Name.Replace("`1", string.Empty, StringComparison.Ordinal) + }; + + if (exception.Data.Count > 0) + extensions[RfcExtensions.ExceptionData] = exception.Data; + + if (exception is not IRfcException rfcException) + return new ProblemDetails + { + Title = "Unexpected error occurred", + Detail = exception.Message, + Extensions = extensions + }; + + // custom rfc extensions + if (rfcException.RfcExtensions.Count > 0) + foreach (var rfcExtension in rfcException.RfcExtensions) + extensions[rfcExtension.Key] = rfcExtension.Value; + + var problemDetails = new ProblemDetails + { + Type = rfcException.RfcType, + Title = rfcException.Title, + Status = rfcException.StatusCode, + Detail = rfcException.Detail, + Extensions = extensions + }; + + return problemDetails; + } +} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs new file mode 100644 index 000000000..fafaa8c0e --- /dev/null +++ b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs @@ -0,0 +1,51 @@ +namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; + +/// +/// RFC 7807 problem type identifiers. +/// +internal static class RfcTypes +{ + // 4xx + public const string BadRequest = "/problems/bad-request"; + public const string Unauthorized = "/problems/unauthorized"; + public const string Forbidden = "/problems/forbidden"; + public const string NotFound = "/problems/not-found"; + public const string MethodNotAllowed = "/problems/method-not-allowed"; + public const string NotAcceptable = "/problems/not-acceptable"; + public const string Conflict = "/problems/conflict"; + public const string Gone = "/problems/gone"; + public const string LengthRequired = "/problems/length-required"; + public const string PreconditionFailed = "/problems/precondition-failed"; + public const string PayloadTooLarge = "/problems/payload-too-large"; + public const string UriTooLong = "/problems/uri-too-long"; + public const string UnsupportedMediaType = "/problems/unsupported-media-type"; + public const string RangeNotSatisfiable = "/problems/range-not-satisfiable"; + public const string ExpectationFailed = "/problems/expectation-failed"; + public const string MisdirectedRequest = "/problems/misdirected-request"; + public const string ValidationError = "/problems/validation-error"; + public const string Locked = "/problems/locked"; + public const string FailedDependency = "/problems/failed-dependency"; + public const string TooEarly = "/problems/too-early"; + public const string UpgradeRequired = "/problems/upgrade-required"; + public const string PreconditionRequired = "/problems/precondition-required"; + public const string TooManyRequests = "/problems/too-many-requests"; + public const string RequestHeaderTooLarge = "/problems/request-header-fields-too-large"; + public const string UnavailableForLegalReasons = "/problems/unavailable-for-legal-reasons"; + + // 5xx + public const string InternalServerError = "/problems/internal-server-error"; + public const string NotImplemented = "/problems/not-implemented"; + public const string BadGateway = "/problems/bad-gateway"; + public const string ServiceUnavailable = "/problems/service-unavailable"; + public const string GatewayTimeout = "/problems/gateway-timeout"; + public const string HttpVersionNotSupported = "/problems/http-version-not-supported"; + public const string VariantAlsoNegotiates = "/problems/variant-also-negotiates"; + public const string InsufficientStorage = "/problems/insufficient-storage"; + public const string LoopDetected = "/problems/loop-detected"; + public const string NotExtended = "/problems/not-extended"; + public const string NetworkAuthenticationRequired = "/problems/network-authentication-required"; + + // Domain / business + public const string PaymentError = "/problems/payment-error"; + public const string Timeout = "/problems/timeout"; +} \ No newline at end of file From a9a381389908871fd536d9336d285b49b5e52376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Thu, 28 May 2026 18:23:11 +0300 Subject: [PATCH 4/6] GD2-4811 test fix overlapping_identity_scopes_and_api_scopes_should_show_error_page --- .../Endpoints/Authorize/AuthorizeTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IdentityServer4/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs b/src/IdentityServer4/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs index c04f38037..16c046b41 100644 --- a/src/IdentityServer4/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs +++ b/src/IdentityServer4/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs @@ -1058,8 +1058,8 @@ public async Task overlapping_identity_scopes_and_api_scopes_should_show_error_p "123_state", "123_nonce"); - Func a = () => _mockPipeline.BrowserClient.GetAsync(url, TestContext.Current.CancellationToken); - await a.Should().ThrowAsync(); + var response = await _mockPipeline.BrowserClient.GetAsync(url, TestContext.Current.CancellationToken); + response.StatusCode.Should().Be(HttpStatusCode.InternalServerError); } [Fact] From 0fbc309799f1e88605f05130a46deb690c578e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Wed, 3 Jun 2026 13:22:51 +0300 Subject: [PATCH 5/6] =?UTF-8?q?GD2-4811=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=20Dex.RfcExceptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...entityServerServiceCollectionExtensions.cs | 14 +- ...ntityServerApplicationBuilderExtensions.cs | 34 ++-- .../IdentityExceptionHandleMiddleware.cs | 156 ------------------ .../ExceptionHandling/Rfc/RfcException.cs | 68 -------- .../ExceptionHandling/Rfc/RfcExtensions.cs | 14 -- .../ExceptionHandling/Rfc/RfcHelper.cs | 60 ------- .../Hosting/ExceptionHandling/Rfc/RfcTypes.cs | 51 ------ .../src/IdentityServer4.csproj | 1 + 8 files changed, 30 insertions(+), 368 deletions(-) delete mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs delete mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs delete mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs delete mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs delete mode 100644 src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs diff --git a/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs b/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs index 92291ab8a..81405f295 100644 --- a/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs +++ b/src/IdentityServer4/src/Configuration/DependencyInjection/IdentityServerServiceCollectionExtensions.cs @@ -5,7 +5,7 @@ using IdentityServer4.Configuration; using Microsoft.Extensions.Configuration; using System; -using IdentityServer4.Hosting.ExceptionHandling; +using Dex.RfcExceptionsHandler.Extensions; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.AspNetCore.Authentication.OpenIdConnect; @@ -34,6 +34,8 @@ public static IIdentityServerBuilder AddIdentityServerBuilder(this IServiceColle /// public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection services) { + services.AddDefaultRfcExceptionHandleMiddleware(); + var builder = services.AddIdentityServerBuilder(); builder @@ -45,8 +47,7 @@ public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection s .AddValidators() .AddResponseGenerators() .AddDefaultSecretParsers() - .AddDefaultSecretValidators() - .AddIdentityExceptionHandling(); + .AddDefaultSecretValidators(); // provide default in-memory implementation, not suitable for most production scenarios builder.AddInMemoryPersistedGrants(); @@ -85,10 +86,9 @@ public static IIdentityServerBuilder AddIdentityServer(this IServiceCollection s /// The schemes to configure. If none provided, then all OpenIdConnect schemes will use the cache. public static IServiceCollection AddOidcStateDataFormatterCache(this IServiceCollection services, params string[] schemes) { - services.AddSingleton>( - svcs => new ConfigureOpenIdConnectOptions( - schemes, - svcs.GetRequiredService()) + services.AddSingleton>(svcs => new ConfigureOpenIdConnectOptions( + schemes, + svcs.GetRequiredService()) ); return services; diff --git a/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs b/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs index 0f8861957..76aa46abb 100644 --- a/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs +++ b/src/IdentityServer4/src/Configuration/IdentityServerApplicationBuilderExtensions.cs @@ -12,7 +12,7 @@ using System; using System.Reflection; using System.Threading.Tasks; -using IdentityServer4.Hosting.ExceptionHandling; +using Dex.RfcExceptionsHandler.Extensions; namespace Microsoft.AspNetCore.Builder; @@ -30,7 +30,7 @@ public static class IdentityServerApplicationBuilderExtensions public static IApplicationBuilder UseIdentityServer(this IApplicationBuilder app, IdentityServerMiddlewareOptions options = null) { app.Validate(); - app.UseIdentityExceptionHandling(); + app.UseRfcExceptionHandleMiddleware(); app.UseMiddleware(); @@ -56,21 +56,26 @@ internal static void Validate(this IApplicationBuilder app) if (loggerFactory == null) throw new ArgumentNullException(nameof(loggerFactory)); var logger = loggerFactory.CreateLogger("IdentityServer4.Startup"); - logger.LogInformation("Starting IdentityServer4 version {version}", typeof(IdentityServerMiddleware).Assembly.GetCustomAttribute().InformationalVersion); + logger.LogInformation("Starting IdentityServer4 version {version}", + typeof(IdentityServerMiddleware).Assembly.GetCustomAttribute().InformationalVersion); var scopeFactory = app.ApplicationServices.GetService(); using var scope = scopeFactory.CreateScope(); var serviceProvider = scope.ServiceProvider; - TestService(serviceProvider, typeof(IPersistedGrantStore), logger, "No storage mechanism for grants specified. Use the 'AddInMemoryPersistedGrants' extension method to register a development version."); - TestService(serviceProvider, typeof(IClientStore), logger, "No storage mechanism for clients specified. Use the 'AddInMemoryClients' extension method to register a development version."); - TestService(serviceProvider, typeof(IResourceStore), logger, "No storage mechanism for resources specified. Use the 'AddInMemoryIdentityResources' or 'AddInMemoryApiResources' extension method to register a development version."); + TestService(serviceProvider, typeof(IPersistedGrantStore), logger, + "No storage mechanism for grants specified. Use the 'AddInMemoryPersistedGrants' extension method to register a development version."); + TestService(serviceProvider, typeof(IClientStore), logger, + "No storage mechanism for clients specified. Use the 'AddInMemoryClients' extension method to register a development version."); + TestService(serviceProvider, typeof(IResourceStore), logger, + "No storage mechanism for resources specified. Use the 'AddInMemoryIdentityResources' or 'AddInMemoryApiResources' extension method to register a development version."); var persistedGrants = serviceProvider.GetService(typeof(IPersistedGrantStore)); if (persistedGrants.GetType().FullName == typeof(InMemoryPersistedGrantStore).FullName) { - logger.LogInformation("You are using the in-memory version of the persisted grant store. This will store consent decisions, authorization codes, refresh and reference tokens in memory only. If you are using any of those features in production, you want to switch to a different store implementation."); + logger.LogInformation( + "You are using the in-memory version of the persisted grant store. This will store consent decisions, authorization codes, refresh and reference tokens in memory only. If you are using any of those features in production, you want to switch to a different store implementation."); } var options = serviceProvider.GetRequiredService(); @@ -87,7 +92,8 @@ private static async Task ValidateAsync(IServiceProvider services, ILogger logge if (await schemes.GetDefaultAuthenticateSchemeAsync() == null && options.Authentication.CookieAuthenticationScheme == null) { - logger.LogWarning("No authentication scheme has been set. Setting either a default authentication scheme or a CookieAuthenticationScheme on IdentityServerOptions is required."); + logger.LogWarning( + "No authentication scheme has been set. Setting either a default authentication scheme or a CookieAuthenticationScheme on IdentityServerOptions is required."); } else { @@ -96,7 +102,8 @@ private static async Task ValidateAsync(IServiceProvider services, ILogger logge if (options.Authentication.CookieAuthenticationScheme != null) { authenticationScheme = await schemes.GetSchemeAsync(options.Authentication.CookieAuthenticationScheme); - logger.LogInformation("Using explicitly configured authentication scheme {scheme} for IdentityServer", options.Authentication.CookieAuthenticationScheme); + logger.LogInformation("Using explicitly configured authentication scheme {scheme} for IdentityServer", + options.Authentication.CookieAuthenticationScheme); } else { @@ -106,7 +113,9 @@ private static async Task ValidateAsync(IServiceProvider services, ILogger logge if (!typeof(IAuthenticationSignInHandler).IsAssignableFrom(authenticationScheme.HandlerType)) { - logger.LogInformation("Authentication scheme {scheme} is configured for IdentityServer, but it is not a scheme that supports signin (like cookies). If you support interactive logins via the browser, then a cookie-based scheme should be used.", authenticationScheme.Name); + logger.LogInformation( + "Authentication scheme {scheme} is configured for IdentityServer, but it is not a scheme that supports signin (like cookies). If you support interactive logins via the browser, then a cookie-based scheme should be used.", + authenticationScheme.Name); } logger.LogDebug("Using {scheme} as default ASP.NET Core scheme for authentication", (await schemes.GetDefaultAuthenticateSchemeAsync())?.Name); @@ -120,7 +129,7 @@ private static async Task ValidateAsync(IServiceProvider services, ILogger logge private static void ValidateOptions(IdentityServerOptions options, ILogger logger) { if (options.IssuerUri.IsPresent()) logger.LogDebug("Custom IssuerUri set to {0}", options.IssuerUri); - + // todo: perhaps different logging messages? //if (options.UserInteraction.LoginUrl.IsMissing()) throw new InvalidOperationException("LoginUrl is not configured"); //if (options.UserInteraction.LoginReturnUrlParameter.IsMissing()) throw new InvalidOperationException("LoginReturnUrlParameter is not configured"); @@ -130,7 +139,8 @@ private static void ValidateOptions(IdentityServerOptions options, ILogger logge if (options.UserInteraction.ErrorIdParameter.IsMissing()) throw new InvalidOperationException("ErrorIdParameter is not configured"); if (options.UserInteraction.ConsentUrl.IsMissing()) throw new InvalidOperationException("ConsentUrl is not configured"); if (options.UserInteraction.ConsentReturnUrlParameter.IsMissing()) throw new InvalidOperationException("ConsentReturnUrlParameter is not configured"); - if (options.UserInteraction.CustomRedirectReturnUrlParameter.IsMissing()) throw new InvalidOperationException("CustomRedirectReturnUrlParameter is not configured"); + if (options.UserInteraction.CustomRedirectReturnUrlParameter.IsMissing()) + throw new InvalidOperationException("CustomRedirectReturnUrlParameter is not configured"); if (options.Authentication.CheckSessionCookieName.IsMissing()) throw new InvalidOperationException("CheckSessionCookieName is not configured"); diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs deleted file mode 100644 index a07673d73..000000000 --- a/src/IdentityServer4/src/Hosting/ExceptionHandling/IdentityExceptionHandleMiddleware.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using System.Text.Json; -using System.Threading.Tasks; -using IdentityServer4.Extensions; -using IdentityServer4.Hosting.ExceptionHandling.Rfc; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -namespace IdentityServer4.Hosting.ExceptionHandling; - -public sealed class IdentityExceptionHandleMiddleware(ILogger logger, IWebHostEnvironment environment) : IMiddleware -{ - private const int Status499ClientClosedRequest = 499; - - public async Task InvokeAsync(HttpContext context, RequestDelegate next) - { - var cToken = context.RequestAborted; - - try - { - await next(context); - } - catch (Exception exception) - { - // rfc problem - var rfcProblem = exception.ToProblemDetails(); - - // rfc code - rfcProblem.Status ??= ResolveHttpStatusCode(exception); - - // rfc type - rfcProblem.Type ??= ResolveRfcTypeByHttpStatusCode(rfcProblem.Status.Value); - - // rfc stackTrace - if (string.IsNullOrEmpty(exception.StackTrace) is false && environment.IsProduction() is false) - rfcProblem.Extensions[RfcExtensions.StackTrace] = string.Join(Environment.NewLine, - exception.GetInnerExceptions().Select(x => x.StackTrace)); - - // rfc traceId - rfcProblem.Extensions[RfcExtensions.TraceId] = Activity.Current?.Id ?? context.TraceIdentifier; - - // rfc Instance - rfcProblem.Instance = GetRfcInstance(context.Request); - - var responseJson = JsonSerializer.Serialize(rfcProblem); - if (rfcProblem.Status >= StatusCodes.Status500InternalServerError) - logger.LogError(exception, "Request failed"); - else - logger.LogWarning(exception, "Request complete with warning. {MiddlewareResponse}", responseJson); - - try - { - context.Response.StatusCode = rfcProblem.Status.Value; - context.Response.ContentType = "application/json"; - - await context.Response.WriteAsync(responseJson, cToken); - } - catch (ObjectDisposedException) - { - // ignore - } - catch (InvalidOperationException e) when (e.Message.Contains("response has already started", StringComparison.CurrentCultureIgnoreCase)) - { - // ignore - } - } - } - - private static int ResolveHttpStatusCode(Exception exception) => exception switch - { - UnauthorizedAccessException => StatusCodes.Status403Forbidden, - ArgumentException or ValidationException => StatusCodes.Status400BadRequest, - OperationCanceledException => Status499ClientClosedRequest, - _ => StatusCodes.Status500InternalServerError - }; - - private static string ResolveRfcTypeByHttpStatusCode(int statusCode) => statusCode switch - { - // 4xx Client Errors - StatusCodes.Status400BadRequest => RfcTypes.BadRequest, - StatusCodes.Status401Unauthorized => RfcTypes.Unauthorized, - StatusCodes.Status402PaymentRequired => RfcTypes.PaymentError, - StatusCodes.Status403Forbidden => RfcTypes.Forbidden, - StatusCodes.Status404NotFound => RfcTypes.NotFound, - StatusCodes.Status405MethodNotAllowed => RfcTypes.MethodNotAllowed, - StatusCodes.Status406NotAcceptable => RfcTypes.NotAcceptable, - StatusCodes.Status407ProxyAuthenticationRequired => RfcTypes.Unauthorized, - StatusCodes.Status408RequestTimeout => RfcTypes.Timeout, - StatusCodes.Status409Conflict => RfcTypes.Conflict, - StatusCodes.Status410Gone => RfcTypes.Gone, - StatusCodes.Status411LengthRequired => RfcTypes.LengthRequired, - StatusCodes.Status412PreconditionFailed => RfcTypes.PreconditionFailed, - StatusCodes.Status413PayloadTooLarge => RfcTypes.PayloadTooLarge, - StatusCodes.Status414UriTooLong => RfcTypes.UriTooLong, - StatusCodes.Status415UnsupportedMediaType => RfcTypes.UnsupportedMediaType, - StatusCodes.Status416RangeNotSatisfiable => RfcTypes.RangeNotSatisfiable, - StatusCodes.Status417ExpectationFailed => RfcTypes.ExpectationFailed, - StatusCodes.Status418ImATeapot => "☕🤦‍♂️", - StatusCodes.Status421MisdirectedRequest => RfcTypes.MisdirectedRequest, - StatusCodes.Status422UnprocessableEntity => RfcTypes.ValidationError, - StatusCodes.Status423Locked => RfcTypes.Locked, - StatusCodes.Status424FailedDependency => RfcTypes.FailedDependency, - 425 => RfcTypes.TooEarly, - StatusCodes.Status426UpgradeRequired => RfcTypes.UpgradeRequired, - StatusCodes.Status428PreconditionRequired => RfcTypes.PreconditionRequired, - StatusCodes.Status429TooManyRequests => RfcTypes.TooManyRequests, - StatusCodes.Status431RequestHeaderFieldsTooLarge => RfcTypes.RequestHeaderTooLarge, - StatusCodes.Status451UnavailableForLegalReasons => RfcTypes.UnavailableForLegalReasons, - - // 5xx Server Errors - StatusCodes.Status500InternalServerError => RfcTypes.InternalServerError, - StatusCodes.Status501NotImplemented => RfcTypes.NotImplemented, - StatusCodes.Status502BadGateway => RfcTypes.BadGateway, - StatusCodes.Status503ServiceUnavailable => RfcTypes.ServiceUnavailable, - StatusCodes.Status504GatewayTimeout => RfcTypes.GatewayTimeout, - StatusCodes.Status505HttpVersionNotsupported => RfcTypes.HttpVersionNotSupported, - StatusCodes.Status506VariantAlsoNegotiates => RfcTypes.VariantAlsoNegotiates, - StatusCodes.Status507InsufficientStorage => RfcTypes.InsufficientStorage, - StatusCodes.Status508LoopDetected => RfcTypes.LoopDetected, - StatusCodes.Status510NotExtended => RfcTypes.NotExtended, - StatusCodes.Status511NetworkAuthenticationRequired => RfcTypes.NetworkAuthenticationRequired, - - _ => "unknown" - }; - - private static string GetRfcInstance(HttpRequest contextRequest) - { - var instance = new - { - Path = contextRequest.Path.ToString(), - Query = contextRequest.QueryString.ToString() - }; - - return JsonSerializer.Serialize(instance); - } -} - -public static class IdentityExceptionHandleMiddlewareExtensions -{ - public static IIdentityServerBuilder AddIdentityExceptionHandling(this IIdentityServerBuilder identityServer) - { - identityServer.Services.AddSingleton(); - return identityServer; - } - - public static IApplicationBuilder UseIdentityExceptionHandling(this IApplicationBuilder app) => app.UseMiddleware(); -} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs deleted file mode 100644 index 17e60a7bc..000000000 --- a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcException.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.AspNetCore.Http; - -namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; - -/// -/// Represents an application exception that can be converted to -/// an RFC 7807 / HTTP API error response. -/// -/// -/// Use this contract for domain and application exceptions that should be -/// exposed to API clients in a stable and predictable format. -/// -/// The values returned by this interface are used to populate -/// . -/// -/// -internal interface IRfcException -{ - protected internal static readonly ImmutableDictionary NoExtensions = ImmutableDictionary.Create(); - - /// - /// Gets the HTTP status code that should be returned to the client. - /// - /// - /// A valid HTTP status code, for example - /// , - /// , - /// . - /// - int StatusCode { get; } - - /// - /// Gets the stable problem type identifier. - /// - /// - /// A stable URI or URI-like string that identifies the category of the problem, - /// for example /problems/not-found or /problems/validation-error. - /// - /// - /// This value should describe the problem category, not the .NET exception type. - /// - string RfcType { get; } - - /// - /// Gets the short, human-readable summary of the problem type. - /// - /// - /// A stable title such as Resource not found, - /// Validation failed, or Conflict. - /// - string Title { get; } - - /// - /// Gets the human-readable explanation specific to the current occurrence. - /// - /// - /// Additional details for the current error instance. - /// This value may be when no extra details should be exposed. - /// - /// - /// Do not put stack traces, secrets, connection strings, or other internal diagnostics here. - /// - string? Detail { get; } - - IDictionary RfcExtensions => NoExtensions; -} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs deleted file mode 100644 index e5ac6b756..000000000 --- a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; - -#pragma warning disable 1591 - -internal static class RfcExtensions -{ - public const int DefaultExtensionsCapacity = 4; - - // default - public const string ExceptionType = "exceptionType"; - public const string ExceptionData = "exceptionData"; - public const string StackTrace = "stackTrace"; - public const string TraceId = "traceId"; -} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs deleted file mode 100644 index dff185ffb..000000000 --- a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcHelper.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; - -/// -/// Provides helper methods for converting exceptions to . -/// -internal static class RfcHelper -{ - /// - /// Converts the specified exception to a instance. - /// - /// - /// The exception type. - /// - /// - /// The exception to convert. - /// - /// - /// A instance. - /// - public static ProblemDetails ToProblemDetails(this T exception) where T : Exception - { - ArgumentNullException.ThrowIfNull(exception); - - var extensions = new Dictionary(RfcExtensions.DefaultExtensionsCapacity) - { - [RfcExtensions.ExceptionType] = exception.GetType().Name.Replace("`1", string.Empty, StringComparison.Ordinal) - }; - - if (exception.Data.Count > 0) - extensions[RfcExtensions.ExceptionData] = exception.Data; - - if (exception is not IRfcException rfcException) - return new ProblemDetails - { - Title = "Unexpected error occurred", - Detail = exception.Message, - Extensions = extensions - }; - - // custom rfc extensions - if (rfcException.RfcExtensions.Count > 0) - foreach (var rfcExtension in rfcException.RfcExtensions) - extensions[rfcExtension.Key] = rfcExtension.Value; - - var problemDetails = new ProblemDetails - { - Type = rfcException.RfcType, - Title = rfcException.Title, - Status = rfcException.StatusCode, - Detail = rfcException.Detail, - Extensions = extensions - }; - - return problemDetails; - } -} \ No newline at end of file diff --git a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs b/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs deleted file mode 100644 index fafaa8c0e..000000000 --- a/src/IdentityServer4/src/Hosting/ExceptionHandling/Rfc/RfcTypes.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace IdentityServer4.Hosting.ExceptionHandling.Rfc; - -/// -/// RFC 7807 problem type identifiers. -/// -internal static class RfcTypes -{ - // 4xx - public const string BadRequest = "/problems/bad-request"; - public const string Unauthorized = "/problems/unauthorized"; - public const string Forbidden = "/problems/forbidden"; - public const string NotFound = "/problems/not-found"; - public const string MethodNotAllowed = "/problems/method-not-allowed"; - public const string NotAcceptable = "/problems/not-acceptable"; - public const string Conflict = "/problems/conflict"; - public const string Gone = "/problems/gone"; - public const string LengthRequired = "/problems/length-required"; - public const string PreconditionFailed = "/problems/precondition-failed"; - public const string PayloadTooLarge = "/problems/payload-too-large"; - public const string UriTooLong = "/problems/uri-too-long"; - public const string UnsupportedMediaType = "/problems/unsupported-media-type"; - public const string RangeNotSatisfiable = "/problems/range-not-satisfiable"; - public const string ExpectationFailed = "/problems/expectation-failed"; - public const string MisdirectedRequest = "/problems/misdirected-request"; - public const string ValidationError = "/problems/validation-error"; - public const string Locked = "/problems/locked"; - public const string FailedDependency = "/problems/failed-dependency"; - public const string TooEarly = "/problems/too-early"; - public const string UpgradeRequired = "/problems/upgrade-required"; - public const string PreconditionRequired = "/problems/precondition-required"; - public const string TooManyRequests = "/problems/too-many-requests"; - public const string RequestHeaderTooLarge = "/problems/request-header-fields-too-large"; - public const string UnavailableForLegalReasons = "/problems/unavailable-for-legal-reasons"; - - // 5xx - public const string InternalServerError = "/problems/internal-server-error"; - public const string NotImplemented = "/problems/not-implemented"; - public const string BadGateway = "/problems/bad-gateway"; - public const string ServiceUnavailable = "/problems/service-unavailable"; - public const string GatewayTimeout = "/problems/gateway-timeout"; - public const string HttpVersionNotSupported = "/problems/http-version-not-supported"; - public const string VariantAlsoNegotiates = "/problems/variant-also-negotiates"; - public const string InsufficientStorage = "/problems/insufficient-storage"; - public const string LoopDetected = "/problems/loop-detected"; - public const string NotExtended = "/problems/not-extended"; - public const string NetworkAuthenticationRequired = "/problems/network-authentication-required"; - - // Domain / business - public const string PaymentError = "/problems/payment-error"; - public const string Timeout = "/problems/timeout"; -} \ No newline at end of file diff --git a/src/IdentityServer4/src/IdentityServer4.csproj b/src/IdentityServer4/src/IdentityServer4.csproj index 66b44a667..896d5a338 100644 --- a/src/IdentityServer4/src/IdentityServer4.csproj +++ b/src/IdentityServer4/src/IdentityServer4.csproj @@ -41,6 +41,7 @@ + From c2c2d08d6d1fff68c687c72cdfa71180aa462ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Wed, 3 Jun 2026 13:24:50 +0300 Subject: [PATCH 6/6] GD2-4811 cleanup --- .../src/Extensions/ExceptionExtensions.cs | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/IdentityServer4/src/Extensions/ExceptionExtensions.cs diff --git a/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs b/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs deleted file mode 100644 index a0027371f..000000000 --- a/src/IdentityServer4/src/Extensions/ExceptionExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; - -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - -namespace IdentityServer4.Extensions; - -internal static class ExceptionExtensions -{ - public static IEnumerable GetInnerExceptions(this Exception exception, int count = 5) - { - ArgumentNullException.ThrowIfNull(exception); - - var innerException = exception; - do - { - yield return innerException; - - innerException = innerException.InnerException; - count--; - } while (innerException is not null && count > 0); - } -} \ No newline at end of file