Skip to content

Commit

Permalink
cleanupcleanup and added revocation
Browse files Browse the repository at this point in the history
  • Loading branch information
mozts2005 committed Nov 20, 2024
1 parent 411f3d2 commit 7bea78e
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 27 deletions.
45 changes: 26 additions & 19 deletions sandbox/OpenIddict.Sandbox.Console.Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@
.SetProductInformation(typeof(Program).Assembly);
// Add a client registration matching the client application definition in the server project.
options.AddRegistration(new OpenIddictClientRegistration
{
Issuer = new Uri("https://localhost:44395/", UriKind.Absolute),
ProviderName = "Local",
ProviderDisplayName = "Local authorization server",
//options.AddRegistration(new OpenIddictClientRegistration
//{
// Issuer = new Uri("https://localhost:44395/", UriKind.Absolute),
// ProviderName = "Local",
// ProviderDisplayName = "Local authorization server",
ClientId = "console",
// ClientId = "console",
PostLogoutRedirectUri = new Uri("callback/logout/local", UriKind.Relative),
RedirectUri = new Uri("callback/login/local", UriKind.Relative),
// PostLogoutRedirectUri = new Uri("callback/logout/local", UriKind.Relative),
// RedirectUri = new Uri("callback/login/local", UriKind.Relative),
Scopes = { Scopes.Email, Scopes.Profile, Scopes.OfflineAccess, "demo_api" }
});
// Scopes = { Scopes.Email, Scopes.Profile, Scopes.OfflineAccess, "demo_api" }
//});
// Register the Web providers integrations.
//
Expand All @@ -90,17 +90,24 @@
// parameter containing their URL as part of authorization responses. For more information,
// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
options.UseWebProviders()
.AddGitHub(options =>
.AddZendesk(options =>
{
options.SetClientId("992372d088f8676a7945")
.SetClientSecret("1f18c22f766e44d7bd4ea4a6510b9e337d48ab38")
.SetRedirectUri("callback/login/github");
})
.AddTwitter(options =>
{
options.SetClientId("bXgwc0U3N3A3YWNuaWVsdlRmRWE6MTpjaQ")
.SetRedirectUri("callback/login/twitter");
options.SetTenant("csharpapi")
.SetClientId("openiddict_testing")
.SetRedirectUri("callback/login/zendesk")
.AddScopes(["read", "write"]);
});
//.AddGitHub(options =>
//{
// options.SetClientId("992372d088f8676a7945")
// .SetClientSecret("1f18c22f766e44d7bd4ea4a6510b9e337d48ab38")
// .SetRedirectUri("callback/login/github");
//})
//.AddTwitter(options =>
//{
// options.SetClientId("bXgwc0U3N3A3YWNuaWVsdlRmRWE6MTpjaQ")
// .SetRedirectUri("callback/login/twitter");
//});
});
// Register the worker responsible for creating the database used to store tokens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

using System.Collections.Immutable;
using System.Net.Http;
using System.Net.Http.Headers;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlerFilters;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.UserInfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;

namespace OpenIddict.Client.WebIntegration;
Expand All @@ -17,12 +19,99 @@ public static partial class OpenIddictClientWebIntegrationHandlers
public static class Revocation
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([

/*
* Revocation request preparation:
*/
OverrideHttpMethod.Descriptor,
AttachAccessTokenParameter.Descriptor,
/*
* Revocation response extraction:
*/
NormalizeContentType.Descriptor
]);

/// <summary>
/// Contains the logic responsible for overriding the HTTP method for the providers that require it.
/// </summary>
public sealed class OverrideHttpMethod : IOpenIddictClientHandler<PrepareRevocationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareRevocationRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<OverrideHttpMethod>()
.SetOrder(PreparePostHttpRequest<PrepareRevocationRequestContext>.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();

/// <inheritdoc/>
public ValueTask HandleAsync(PrepareRevocationRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}

// This handler only applies to System.Net.Http requests. If the HTTP request cannot be resolved,
// this may indicate that the request was incorrectly processed by another client stack.
var request = context.Transaction.GetHttpRequestMessage() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0173));

request.Method = context.Registration.ProviderType switch
{

ProviderTypes.Zendesk => HttpMethod.Delete,

_ => request.Method
};

return default;
}
}

/// <summary>
/// Contains the logic responsible for attaching the access token
/// parameter to the request for the providers that require it.
/// </summary>
public sealed class AttachAccessTokenParameter : IOpenIddictClientHandler<PrepareRevocationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareRevocationRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<AttachAccessTokenParameter>()
.SetOrder(AttachBearerAccessToken.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();

/// <inheritdoc/>
public ValueTask HandleAsync(PrepareRevocationRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}

// This handler only applies to System.Net.Http requests. If the HTTP request cannot be resolved,
// this may indicate that the request was incorrectly processed by another client stack.
var request = context.Transaction.GetHttpRequestMessage() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0173));

// Zendesk requires using the token that is going to be revoked
if (context.Registration.ProviderType is ProviderTypes.Zendesk)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.Token);
}

return default;
}
}

/// <summary>
/// Contains the logic responsible for normalizing the returned content
/// type of revocation responses for the providers that require it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,9 @@ public ValueTask HandleAsync(ProcessAuthenticationContext context)

// Shopify returns the email address as a custom "associated_user/email" node in token responses:
ProviderTypes.Shopify => (string?) context.TokenResponse?["associated_user"]?["email"],

// Zendesk returns the emails address as a custom "user/email" node:
ProviderTypes.Zendesk => (string?) context.UserInfoResponse?["user"]?["email"],

_ => context.MergedPrincipal.GetClaim(ClaimTypes.Email)
});
Expand Down Expand Up @@ -1441,6 +1444,9 @@ ProviderTypes.Spotify or ProviderTypes.StackExchange or ProviderTypes.Zoom
// Typeform returns the username as a custom "alias" node:
ProviderTypes.Typeform => (string?) context.UserInfoResponse?["alias"],

// Zendesk returns the username as a custom "user/name" node:
ProviderTypes.Zendesk => (string?) context.UserInfoResponse?["user"]?["name"],

// Zoho returns the username as a custom "Display_Name" node:
ProviderTypes.Zoho => (string?) context.UserInfoResponse?["Display_Name"],

Expand Down Expand Up @@ -1529,6 +1535,9 @@ ProviderTypes.Twitter or ProviderTypes.Weibo or ProviderTypes.Zoom
// WordPress returns the user identifier as a custom "ID" node:
ProviderTypes.WordPress => (string?) context.UserInfoResponse?["ID"],

// Zendesk returns the user identifier as a custom "user/id" node:
ProviderTypes.Zendesk => (string?) context.UserInfoResponse?["user"]?["id"],

// WordPress returns the user identifier as a custom "ZUID" node:
ProviderTypes.Zoho => (string?) context.UserInfoResponse?["ZUID"],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2153,7 +2153,7 @@
<Environment Issuer="https://api.login.yahoo.com/" />
</Provider>

<Provider Name="Zendesk" Id="5577b117-1f3d-464f-b987-aabf7c0ab3f7" Documentation="https://developer.zendesk.com/api-reference/introduction/security-and-auth/#oauth-access-token">
<Provider Name="Zendesk" Id="5577b117-1f3d-464f-b987-aabf7c0ab3f7" Documentation="https://support.zendesk.com/hc/en-us/articles/4408845965210-Using-OAuth-authentication-with-your-application">

<!--Note: Zendesk is a multitenant provider that relies on subdomains to identify instances.
As such, the following URLs all include a {settings.Tenant} placeholder that will be dynamically
Expand All @@ -2162,16 +2162,12 @@
<Environment Issuer="https://{settings.Tenant}.zendesk.com/">
<Configuration AuthorizationEndpoint="https://{settings.Tenant}.zendesk.com/oauth/authorizations/new"
TokenEndpoint="https://{settings.Tenant}.zendesk.com/oauth/tokens"
UserInfoEndpoint="https://{settings.Tenant}.zendesk.com/api/v2/users/me">
UserInfoEndpoint="https://{settings.Tenant}.zendesk.com/api/v2/users/me"
RevocationEndpoint="https://{settings.Tenant}.zendesk.com/api/v2/oauth/tokens/current.json">
<CodeChallengeMethod Value="S256" />
<GrantType Value="authorization_code" />

</Configuration>
</Environment>
<Setting PropertyName="Tenant" ParameterName="tenant" Type="String" Required="true"
Description="Gets or sets the tenant used to identify the Zendesk instance." />
<Setting PropertyName="ClientType" ParameterName="kind" Type="String" Required="false"
DefaultValue="confidential" Description="Client Type: public or confidential. Public OAuth clients are applications that run in environments where credentials cannot be securely stored, such as mobile and web apps. These clients are required to use PKCE. Confidential OAuth clients run on secure servers where their credentials can be kept secure. These clients can use PKCE, client secret, or both." />
<Setting PropertyName="Tenant" ParameterName="tenant" Type="String" Required="true" Description="Gets or sets the tenant used to identify the Zendesk instance" />
</Provider>

<!--
Expand Down

0 comments on commit 7bea78e

Please sign in to comment.