-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathHttpClientPushedAuthorizationExtensions.cs
More file actions
97 lines (86 loc) · 4.89 KB
/
HttpClientPushedAuthorizationExtensions.cs
File metadata and controls
97 lines (86 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright (c) Duende Software. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Duende.IdentityModel.Internal;
namespace Duende.IdentityModel.Client;
/// <summary>
/// HttpClient extensions for OIDC discovery
/// </summary>
public static class HttpClientPushedAuthorizationExtensions
{
/// <summary>
/// Sends a pushed authorization request
/// </summary>
/// <param name="client">The HTTP client.</param>
/// <param name="request"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public static Task<PushedAuthorizationResponse> PushAuthorizationAsync(this HttpClient client, PushedAuthorizationRequest request, CancellationToken cancellationToken = default)
{
if (request.Parameters.ContainsKey(OidcConstants.AuthorizeRequest.RequestUri))
{
throw new ArgumentException("request_uri cannot be used in a pushed authorization request", "request_uri");
}
var clone = request.Clone();
// client id is always required, and will be added by the call to
// Prepare() for other client credential styles.
if (request.ClientCredentialStyle == ClientCredentialStyle.AuthorizationHeader)
{
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ClientId, request.ClientId);
}
if (request.Request.IsPresent() || request.Parameters.ContainsKey(OidcConstants.AuthorizeRequest.Request))
{
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.Request, request.Request);
}
else
{
clone.Parameters.AddRequired(OidcConstants.AuthorizeRequest.ResponseType, request.ResponseType);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Scope, request.Scope);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.RedirectUri, request.RedirectUri);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.State, request.State);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Nonce, request.Nonce);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.LoginHint, request.LoginHint);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.AcrValues, request.AcrValues);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Prompt, request.Prompt);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.ResponseMode, request.ResponseMode);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.CodeChallenge, request.CodeChallenge);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.CodeChallengeMethod, request.CodeChallengeMethod);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Display, request.Display);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.MaxAge, request.MaxAge.ToString());
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.UiLocales, request.UiLocales);
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.IdTokenHint, request.IdTokenHint);
foreach (var resource in request.Resource ?? [])
{
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.Resource, resource, allowDuplicates: true);
}
clone.Parameters.AddOptional(OidcConstants.AuthorizeRequest.DPoPKeyThumbprint, request.DPoPKeyThumbprint);
}
return PushAuthorizationAsync(client, clone, cancellationToken);
}
internal static async Task<PushedAuthorizationResponse> PushAuthorizationAsync(this HttpMessageInvoker client, ProtocolRequest request, CancellationToken cancellationToken = default)
{
// If a factory is set, invoke it to get a fresh assertion for this attempt and
// store it on Options so that DPoP retry handlers can invoke it again on each
// subsequent attempt. The factory always takes precedence over a fixed ClientAssertion value.
if (request.ClientAssertionFactory != null)
{
request.ClientAssertion = await request.ClientAssertionFactory().ConfigureAwait();
request.Options.Set(ProtocolRequestOptions.ClientAssertionFactory, request.ClientAssertionFactory);
}
request.Prepare();
request.Method = HttpMethod.Post;
HttpResponseMessage response;
try
{
response = await client.SendAsync(request, cancellationToken).ConfigureAwait();
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
return ProtocolResponse.FromException<PushedAuthorizationResponse>(ex);
}
return await ProtocolResponse.FromHttpResponseAsync<PushedAuthorizationResponse>(response).ConfigureAwait();
}
}