-
Notifications
You must be signed in to change notification settings - Fork 14
Feature/pushed authorization requests #73
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
Open
andrewclymer
wants to merge
30
commits into
release/3.0.0
Choose a base branch
from
feature/PushedAuthorizationRequests
base: release/3.0.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
87951c6
feat: add Pushed Authorization skeleton endpoint and corresponding tests
andrewclymer 8005f8f
feat: Added invoking validation
andrewclymer 95412a3
feat: PAR endpoint handler simple path complete
andrewclymer 69e672b
feat: initial PushedAuthorizationEndpoint logging done
andrewclymer bf3e4d9
feat: implement PushedAuthorizationRequestValidator with validation l…
andrewclymer 6701fd4
feat: add PAR discovery document generation
andrewclymer ced3617
feat: adjust formatting in DiscoveryResponseGenerator for clarity
andrewclymer 374e516
feat: rename PushedAuthorizationEndpoint to PushedAuthorizationReques…
andrewclymer f058de2
feat: add client secret validation to PushedAuthorizationRequestEndpo…
andrewclymer bb56026
Store abstraction and response generator. Logging outstanding
richardblewett 14b3cd9
Midway through wiring up the Authorization flow with request_uri. Nee…
andrewclymer 50ddc56
Refactored to store NameValueColllection rather than trying to save a…
andrewclymer 4d0c288
First end to end implementation done. still requires logging to be added
andrewclymer 1e5bc73
Supports checking client_id is the same for both the PAR and the auth…
andrewclymer 541896b
Add/updated copyright messages
andrewclymer b57bd96
Removed some whitepsace
andrewclymer d2d7899
Rebased off 2.0 main
andrewclymer 3a38f4c
Added telemetry
andrewclymer 8c3a649
Additional logging
andrewclymer e6b5399
Refactored to put a service layer between the response generator and …
andrewclymer a999fb0
Ensure no sensitive authentication parameters are persisted
andrewclymer 5837600
Refactored the PAR service to send a request_uri hash to the store as…
andrewclymer ce4d5c4
Refactored namespace for test and removed commented out code
andrewclymer ff81325
Fixes PAR path in discovery document, adding an additional //connect
andrewclymer bfc86d5
Refactor Pushed Authorization components for improved readability and…
andrewclymer fa97881
Reorganize Pushed Authorization request handling in discovery respons…
andrewclymer 0915db4
Add cache control header to Pushed Authorization response and impleme…
andrewclymer 26f2707
Used extension method for SetNoCache rather than explictly setting th…
andrewclymer d33f4b6
Forgot to push the test
andrewclymer 4290750
Reverted project reference back to a package reference
andrewclymer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -141,4 +141,9 @@ public class IdentityServerOptions | |
| /// Gets or sets the enable authorise response issuer param option | ||
| /// </summary> | ||
| public bool EnableAuthorizeResponseIssuerParam { get; set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// PAR authorization options | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't match the rest of the file |
||
| /// </summary> | ||
| public PushedAuthorizationOptions PushedAuthorization {get;} = new PushedAuthorizationOptions(); | ||
| } | ||
21 changes: 21 additions & 0 deletions
21
...dentityServer/src/Configuration/DependencyInjection/Options/PushedAuthorizationOptions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) 2026, Rock Solid Knowledge Ltd | ||
| // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
| using System; | ||
|
|
||
| namespace Open.IdentityServer.Configuration; | ||
|
|
||
| /// <summary> | ||
| /// PAR options | ||
| /// </summary> | ||
| public class PushedAuthorizationOptions | ||
| { | ||
| /// <summary> | ||
| /// Enforce PAR for all authorization requests | ||
| /// </summary> | ||
| public bool Required { get; set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// The lifetime of a PAR request_uri | ||
| /// </summary> | ||
| public TimeSpan Expiration { get; set; } = TimeSpan.FromSeconds(60); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
src/Open.IdentityServer/src/Endpoints/PushedAuthorizationEndpoint.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| // Copyright (c) 2026, Rock Solid Knowledge Ltd | ||
| // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Specialized; | ||
| using System.Net; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Http; | ||
| using Microsoft.Extensions.Logging; | ||
| using Open.IdentityServer.Configuration; | ||
| using Open.IdentityServer.Endpoints.Results; | ||
| using Open.IdentityServer.Hosting; | ||
| using Open.IdentityServer.Extensions; | ||
| using Open.IdentityServer.ResponseHandling; | ||
| using Open.IdentityServer.Services; | ||
| using Open.IdentityServer.Validation; | ||
|
|
||
| #nullable enable | ||
| namespace Open.IdentityServer.Endpoints; | ||
|
|
||
| internal class PushedAuthorizationRequestEndpoint( | ||
| IdentityServerOptions options, | ||
| IClientSecretValidator clientSecretValidator, | ||
| IPushedAuthorizationRequestValidator validator , | ||
| IPushedAuthorizationResponseGenerator responseGenerator, | ||
| ITelemetryService telemetry, | ||
| ILogger<PushedAuthorizationRequestEndpoint> logger) : IEndpointHandler | ||
| { | ||
| public async Task<IEndpointResult> ProcessAsync(HttpContext requestContext) | ||
| { | ||
| using ITrace trace = telemetry.Trace(TelemetryConstants.TraceCategories.Basic, this); | ||
|
|
||
| if (options.Endpoints.EnablePushedAuthorizationRequestEndpoint == false) | ||
| { | ||
| return new StatusCodeResult(HttpStatusCode.NotFound); | ||
| } | ||
|
|
||
| logger.LogDebug("Start processing pushed authorization request"); | ||
| if (!HttpMethods.IsPost(requestContext.Request.Method)) | ||
| { | ||
| return Error(OidcConstants.TokenErrors.InvalidRequest); | ||
| } | ||
|
|
||
| ClientSecretValidationResult? clientValidationResult = await clientSecretValidator.ValidateAsync(requestContext); | ||
|
andrewclymer marked this conversation as resolved.
|
||
| if (clientValidationResult.IsError) | ||
| { | ||
| return Error(OidcConstants.TokenErrors.InvalidClient); | ||
| } | ||
|
|
||
| trace?.AddTag(TelemetryConstants.TagConstants.Client, clientValidationResult.Client.ClientId); | ||
|
|
||
| NameValueCollection? parParameters = await ParseForm(requestContext.Request); | ||
| if (parParameters == null) | ||
| { | ||
| return Error(OidcConstants.TokenErrors.InvalidRequest); | ||
| } | ||
| var validationContext = new PushedAuthorizationRequestValidationContext(parParameters); | ||
| return await ProcessRequest(requestContext, validationContext); | ||
| } | ||
|
|
||
| private async Task<IEndpointResult> ProcessRequest( | ||
| HttpContext requestContext, | ||
| PushedAuthorizationRequestValidationContext validationContext) | ||
| { | ||
| PushAuthorizationRequestValidationResult result = await validator | ||
| .ValidateAsync(validationContext, requestContext.RequestAborted); | ||
|
|
||
| telemetry.CountPushedAuthorizationRequest( | ||
| result.ValidatedAuthorizeRequest.ClientId , | ||
| result.IsError ? result.Error : null); | ||
|
|
||
| if (result.IsError) | ||
| { | ||
| logger.LogError("Bad PAR request from {0}: {1}", | ||
| result.ValidatedAuthorizeRequest.ClientId, | ||
| result.Error); | ||
|
|
||
| return new BadRequestResult(result.Error, result.ErrorDescription); | ||
| } | ||
|
|
||
| PushedAuthorizationResponse response = await responseGenerator | ||
| .CreateResponseAsync(result.ValidatedAuthorizeRequest); | ||
|
|
||
| logger.LogTrace("End processing pushed authorization request"); | ||
| return new PushedAuthorizationResult(response); | ||
| } | ||
|
|
||
| private async Task<NameValueCollection?> ParseForm(HttpRequest request) | ||
| { | ||
| try | ||
| { | ||
| IFormCollection form = await request.ReadFormAsync(); | ||
| NameValueCollection parParameters = form.AsNameValueCollection(); | ||
|
|
||
| return parParameters; | ||
| } | ||
| catch (InvalidOperationException ) | ||
| { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| private TokenErrorResult Error(string error, string? errorDescription = null, Dictionary<string, object>? custom = null) | ||
| { | ||
| var response = new TokenErrorResponse | ||
| { | ||
| Error = error, | ||
| ErrorDescription = errorDescription, | ||
| Custom = custom | ||
| }; | ||
|
|
||
| logger.LogError("PushedAuthorizationRequest error: {error}:{errorDescriptions}", error, error ?? "-no message-"); | ||
|
|
||
| return new TokenErrorResult(response); | ||
| } | ||
| } | ||
22 changes: 22 additions & 0 deletions
22
src/Open.IdentityServer/src/Endpoints/Results/PushedAuthorizationResult.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright (c) 2026, Rock Solid Knowledge Ltd | ||
| // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
|
||
| using System.Threading.Tasks; | ||
| using Microsoft.AspNetCore.Http; | ||
| using Open.IdentityServer.Extensions; | ||
| using Open.IdentityServer.Hosting; | ||
| using Open.IdentityServer.ResponseHandling; | ||
|
|
||
| namespace Open.IdentityServer.Endpoints.Results; | ||
|
|
||
| internal record PushedAuthorizationResult(PushedAuthorizationResponse Response) : IEndpointResult | ||
| { | ||
| public async Task ExecuteAsync(HttpContext context) | ||
|
andrewclymer marked this conversation as resolved.
|
||
| { | ||
| context.Response.StatusCode = StatusCodes.Status201Created; | ||
| context.Response.ContentType = "application/json"; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is already set by WriteAsJsonAsync |
||
| context.Response.SetNoCache(); | ||
|
|
||
| await context.Response.WriteAsJsonAsync(Response); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
spacing