Browse Source

Add LinkedIn support

pull/1535/head
Kévin Chalet 4 years ago
parent
commit
d92307add7
  1. 68
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
  2. 25
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

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

@ -19,6 +19,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/* /*
* Authentication processing: * Authentication processing:
*/ */
HandleNonStandardFrontchannelErrorResponse.Descriptor,
AttachNonStandardClientAssertionTokenClaims.Descriptor, AttachNonStandardClientAssertionTokenClaims.Descriptor,
AttachTokenRequestNonStandardClientCredentials.Descriptor, AttachTokenRequestNonStandardClientCredentials.Descriptor,
AttachAdditionalUserinfoRequestParameters.Descriptor, AttachAdditionalUserinfoRequestParameters.Descriptor,
@ -32,6 +33,61 @@ public static partial class OpenIddictClientWebIntegrationHandlers
.AddRange(Protection.DefaultHandlers) .AddRange(Protection.DefaultHandlers)
.AddRange(Userinfo.DefaultHandlers); .AddRange(Userinfo.DefaultHandlers);
/// <summary>
/// Contains the logic responsible for handling non-standard
/// authorization errors for the providers that require it.
/// </summary>
public class HandleNonStandardFrontchannelErrorResponse : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<HandleNonStandardFrontchannelErrorResponse>()
.SetOrder(HandleFrontchannelErrorResponse.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessAuthenticationContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// Note: some providers are known to return non-standard errors.
// To normalize the set of errors handled by the OpenIddict client,
// the non-standard errors are mapped to their standard equivalent.
//
// Errors that are not handled here will be automatically handled
// by the standard handler present in the core OpenIddict client.
if (context.Registration.ProviderName is Providers.LinkedIn)
{
var error = (string?) context.Request[Parameters.Error];
if (string.IsNullOrEmpty(error))
{
return default;
}
if (string.Equals(error, "user_cancelled_authorize", StringComparison.Ordinal) ||
string.Equals(error, "user_cancelled_login", StringComparison.Ordinal))
{
context.Reject(
error: Errors.AccessDenied,
description: SR.GetResourceString(SR.ID2149),
uri: SR.FormatID8000(SR.ID2149));
return default;
}
}
return default;
}
}
/// <summary> /// <summary>
/// Contains the logic responsible for amending the client /// Contains the logic responsible for amending the client
/// assertion methods for the providers that require it. /// assertion methods for the providers that require it.
@ -148,7 +204,17 @@ public static partial class OpenIddictClientWebIntegrationHandlers
Debug.Assert(context.UserinfoRequest is not null, SR.GetResourceString(SR.ID4008)); Debug.Assert(context.UserinfoRequest is not null, SR.GetResourceString(SR.ID4008));
if (context.Registration.ProviderName is Providers.StackExchange) if (context.Registration.ProviderName is Providers.LinkedIn)
{
var options = context.Registration.GetLinkedInOptions();
// By default, LinkedIn returns all the basic fields except the profile image.
// To retrieve the profile image, a projection parameter must be sent with
// all the parameters that should be returned from the userinfo endpoint.
context.UserinfoRequest["projection"] = string.Concat("(", string.Join(",", options.Fields), ")");
}
else if (context.Registration.ProviderName is Providers.StackExchange)
{ {
var options = context.Registration.GetStackExchangeOptions(); var options = context.Registration.GetStackExchangeOptions();

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

@ -25,6 +25,31 @@
<Environment Issuer="https://accounts.google.com/" /> <Environment Issuer="https://accounts.google.com/" />
</Provider> </Provider>
<Provider Name="LinkedIn" Documentation="https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin">
<Environment Issuer="https://www.linkedin.com/">
<Configuration AuthorizationEndpoint="https://www.linkedin.com/oauth/v2/authorization"
TokenEndpoint="https://www.linkedin.com/oauth/v2/accessToken"
UserinfoEndpoint="https://api.linkedin.com/v2/me" />
<!--
Note: LinkedIn requires sending at least one scope element. If no scope is set, an error is
returned to the caller. To prevent that, the "r_liteprofile" scope (that is required by the
userinfo endpoint) is always added even if another scope was explicitly registered by the user.
-->
<Scope Name="r_liteprofile" Default="true" Required="true" />
</Environment>
<Setting PropertyName="Fields" ParameterName="fields" Collection="true" Type="String"
Description="The fields that should be retrieved from the userinfo endpoint (by default, all known basic fields are requested)">
<CollectionItem Value="firstName" Default="true" Required="false" />
<CollectionItem Value="id" Default="true" Required="false" />
<CollectionItem Value="lastName" Default="true" Required="false" />
<CollectionItem Value="localizedFirstName" Default="true" Required="false" />
<CollectionItem Value="localizedLastName" Default="true" Required="false" />
<CollectionItem Value="profilePicture(displayImage~:playableStreams)" Default="true" Required="false" />
</Setting>
</Provider>
<Provider Name="Microsoft" Documentation="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc"> <Provider Name="Microsoft" Documentation="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc">
<!-- <!--
Note: Microsoft is a multitenant provider that relies on virtual paths to identify instances. Note: Microsoft is a multitenant provider that relies on virtual paths to identify instances.

Loading…
Cancel
Save