Browse Source

Add Basecamp to the list of supported providers

pull/1737/head
Kévin Chalet 3 years ago
parent
commit
c85fa3f774
  1. 62
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Authentication.cs
  2. 50
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs
  3. 7
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
  4. 3
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
  5. 27
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
  6. 12
      src/OpenIddict.Client/OpenIddictClientEvents.Exchange.cs

62
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Authentication.cs

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System.Collections.Immutable;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration;
public static partial class OpenIddictClientWebIntegrationHandlers
{
public static class Authentication
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create(
/*
* Authorization request preparation:
*/
MapNonStandardRequestParameters.Descriptor);
/// <summary>
/// Contains the logic responsible for mapping non-standard request parameters
/// to their standard equivalent for the providers that require it.
/// </summary>
public sealed class MapNonStandardRequestParameters : IOpenIddictClientHandler<PrepareAuthorizationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareAuthorizationRequestContext>()
.UseSingletonHandler<MapNonStandardRequestParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareAuthorizationRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// Some providers implement old drafts of the OAuth 2.0 specification that didn't support
// the "response_type" parameter but relied on a "type" parameter to determine the type
// of flow (web server or user agent-based). Since the "user_agent" value more or less
// corresponds to the legacy OAuth 2.0-only implicit flow, it is deliberately not
// supported, so the only supported value is "web_server" (aka authorization code flow).
if (context.Registration.ProviderName is Providers.Basecamp)
{
context.Request["type"] = "web_server";
context.Request.ResponseType = null;
}
return default;
}
}
}
}

50
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs

@ -26,6 +26,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/*
* Token request preparation:
*/
MapNonStandardRequestParameters.Descriptor,
AttachNonStandardBasicAuthenticationCredentials.Descriptor,
AttachNonStandardRequestHeaders.Descriptor,
AttachNonStandardQueryStringParameters.Descriptor,
@ -36,6 +37,51 @@ public static partial class OpenIddictClientWebIntegrationHandlers
*/
MapNonStandardResponseParameters.Descriptor);
/// <summary>
/// Contains the logic responsible for mapping non-standard request parameters
/// to their standard equivalent for the providers that require it.
/// </summary>
public sealed class MapNonStandardRequestParameters : IOpenIddictClientHandler<PrepareTokenRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareTokenRequestContext>()
.UseSingletonHandler<MapNonStandardRequestParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareTokenRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// Some providers implement old drafts of the OAuth 2.0 specification that
// didn't support the "response_type" parameter but relied on a "type"
// parameter to determine the type of request (web server or refresh).
if (context.Registration.ProviderName is Providers.Basecamp)
{
context.Request["type"] = context.Request.GrantType switch
{
GrantTypes.AuthorizationCode => "web_server",
GrantTypes.RefreshToken => "refresh",
_ => null
};
context.Request.GrantType = null;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible for attaching the client credentials to the HTTP Authorization
/// header using a non-standard construction logic for the providers that require it.
@ -259,8 +305,8 @@ public static partial class OpenIddictClientWebIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for attaching non-standard query string
/// parameters to the token request for the providers that require it.
/// Contains the logic responsible for mapping non-standard response parameters
/// to their standard equivalent for the providers that require it.
/// </summary>
public sealed class MapNonStandardResponseParameters : IOpenIddictClientHandler<ExtractTokenResponseContext>
{

7
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs

@ -257,6 +257,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.Response = context.Registration.ProviderName switch
{
// Basecamp returns a nested "identity" object and a collection of "accounts".
Providers.Basecamp => new(context.Response["identity"]?.GetNamedParameters() ??
throw new InvalidOperationException(SR.FormatID0334("identity")))
{
["accounts"] = context.Response["accounts"]
},
// Fitbit returns a nested "user" object.
Providers.Fitbit => new(context.Response["user"]?.GetNamedParameters() ??
throw new InvalidOperationException(SR.FormatID0334("user"))),

3
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

@ -41,6 +41,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
FormatNonStandardScopeParameter.Descriptor,
IncludeStateParameterInRedirectUri.Descriptor,
AttachAdditionalChallengeParameters.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Discovery.DefaultHandlers)
.AddRange(Exchange.DefaultHandlers)
.AddRange(Protection.DefaultHandlers)
@ -881,7 +882,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// By default, Google doesn't return a refresh token but allows sending an "access_type"
// parameter to retrieve one (but it is only returned during the first authorization dance).
if (context.Registration.ProviderName is Providers.Google)
else if (context.Registration.ProviderName is Providers.Google)
{
var options = context.Registration.GetGoogleOptions();

27
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

@ -86,6 +86,33 @@
<Environment Issuer="https://app.asana.com/api/1.0" />
</Provider>
<!--
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
██ ▄▄▀█ ▄▄▀██ ▄▄▄ ██ ▄▄▄██ ▄▄▀█ ▄▄▀██ ▄▀▄ ██ ▄▄ ██
██ ▄▄▀█ ▀▀ ██▄▄▄▀▀██ ▄▄▄██ ████ ▀▀ ██ █ █ ██ ▀▀ ██
██ ▀▀ █ ██ ██ ▀▀▀ ██ ▀▀▀██ ▀▀▄█ ██ ██ ███ ██ █████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
-->
<Provider Name="Basecamp" Documentation="https://github.com/basecamp/api/blob/master/sections/authentication.md">
<!--
Note: Basecamp implements an old draft of the OAuth 2.0 specification and doesn't support the
"response_type" and "grant_type" parameters adopted in the final version of the standard.
To work around that, these parameters are dynamically mapped to "type=web_server" or "type=refresh"
depending on the desired flow (and whether the request is an authorization or token request).
-->
<Environment Issuer="https://launchpad.37signals.com/">
<Configuration AuthorizationEndpoint="https://launchpad.37signals.com/authorization/new"
TokenEndpoint="https://launchpad.37signals.com/authorization/token"
UserinfoEndpoint="https://launchpad.37signals.com/authorization.json">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
</Environment>
</Provider>
<!--
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
██ ▄▄▀█ ▄▄▀█▄▄ ▄▄█▄▄ ▄▄██ █████ ▄▄▄█████ ▀██ ██ ▄▄▄█▄▄ ▄▄██

12
src/OpenIddict.Client/OpenIddictClientEvents.Exchange.cs

@ -36,12 +36,20 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the grant type sent to the token endpoint.
/// </summary>
public string? GrantType { get; set; }
public string? GrantType
{
get => Request.GrantType;
set => Request.GrantType = value;
}
/// <summary>
/// Gets or sets the authorization code sent to the token endpoint, if applicable.
/// </summary>
public string? AuthorizationCode { get; set; }
public string? AuthorizationCode
{
get => Request.Code;
set => Request.Code = value;
}
}
/// <summary>

Loading…
Cancel
Save