Skip to content

Commit 29137f7

Browse files
authored
Add KOOK provider (#754)
Add KOOK provider.
1 parent aca188a commit 29137f7

12 files changed

+407
-0
lines changed

AspNet.Security.OAuth.Providers.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{C2CA4B38-A
222222
docs\workweixin.md = docs\workweixin.md
223223
docs\xumm.md = docs\xumm.md
224224
docs\zendesk.md = docs\zendesk.md
225+
docs\kook.md = docs\kook.md
225226
EndProjectSection
226227
EndProject
227228
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Basecamp", "src\AspNet.Security.OAuth.Basecamp\AspNet.Security.OAuth.Basecamp.csproj", "{42306484-B2BF-4B52-B950-E0CDFA58B02A}"
@@ -295,6 +296,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Smart
295296
EndProject
296297
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Huawei", "src\AspNet.Security.OAuth.Huawei\AspNet.Security.OAuth.Huawei.csproj", "{E3CF7FFC-56A0-4033-87A9-BB3080CF030E}"
297298
EndProject
299+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.Security.OAuth.Kook", "src\AspNet.Security.OAuth.Kook\AspNet.Security.OAuth.Kook.csproj", "{101681FB-569F-4941-B943-2AD380039BE0}"
298300
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet.Security.OAuth.PingOne", "src\AspNet.Security.OAuth.PingOne\AspNet.Security.OAuth.PingOne.csproj", "{CF8C4235-6AE6-404E-B572-4FF4E85AB5FF}"
299301
EndProject
300302
Global
@@ -679,6 +681,10 @@ Global
679681
{E3CF7FFC-56A0-4033-87A9-BB3080CF030E}.Debug|Any CPU.Build.0 = Debug|Any CPU
680682
{E3CF7FFC-56A0-4033-87A9-BB3080CF030E}.Release|Any CPU.ActiveCfg = Release|Any CPU
681683
{E3CF7FFC-56A0-4033-87A9-BB3080CF030E}.Release|Any CPU.Build.0 = Release|Any CPU
684+
{101681FB-569F-4941-B943-2AD380039BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
685+
{101681FB-569F-4941-B943-2AD380039BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
686+
{101681FB-569F-4941-B943-2AD380039BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
687+
{101681FB-569F-4941-B943-2AD380039BE0}.Release|Any CPU.Build.0 = Release|Any CPU
682688
{CF8C4235-6AE6-404E-B572-4FF4E85AB5FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
683689
{CF8C4235-6AE6-404E-B572-4FF4E85AB5FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
684690
{CF8C4235-6AE6-404E-B572-4FF4E85AB5FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -788,6 +794,7 @@ Global
788794
{8E42EF81-A630-4BDB-B642-3F20C863F9BE} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
789795
{68862DC5-65B7-4517-B909-AB334F9FCF6E} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
790796
{E3CF7FFC-56A0-4033-87A9-BB3080CF030E} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
797+
{101681FB-569F-4941-B943-2AD380039BE0} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
791798
{CF8C4235-6AE6-404E-B572-4FF4E85AB5FF} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
792799
EndGlobalSection
793800
GlobalSection(ExtensibilityGlobals) = postSolution

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ We would love it if you could help contributing to this repository.
6262
* [Ethan Celletti](https://github.com/Gekctek)
6363
* [Floris Westerman](https://github.com/FWest98)
6464
* [Galo](https://github.com/asiffermann)
65+
* [Gehongyan](https://github.com/gehongyan)
6566
* [Igor Simovic](https://github.com/igorsimovic)
6667
* [James Holcomb](https://github.com/jamesholcomb)
6768
* [Jason Loeffler](https://github.com/jmloeffler)
@@ -163,6 +164,7 @@ If a provider you're looking for does not exist, consider making a PR to add one
163164
| KakaoTalk | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.KakaoTalk?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.KakaoTalk/ "Download AspNet.Security.OAuth.KakaoTalk from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.KakaoTalk?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.KakaoTalk "Download AspNet.Security.OAuth.KakaoTalk from MyGet.org") | [Documentation](https://developers.kakao.com/docs/latest/en/kakaologin/common "KakaoTalk developer documentation") |
164165
| Keycloak | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Keycloak?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Keycloak/ "Download AspNet.Security.OAuth.Keycloak from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Keycloak?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Keycloak "Download AspNet.Security.OAuth.Keycloak from MyGet.org") | [Documentation](https://www.keycloak.org/docs/latest/authorization_services/#_service_overview "Keycloak developer documentation") |
165166
| Kloudless | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Kloudless?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Kloudless/ "Download AspNet.Security.OAuth.Kloudless from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Kloudless?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Kloudless "Download AspNet.Security.OAuth.Kloudless from MyGet.org") | [Documentation](https://developers.kloudless.com/docs/v1/authentication "Kloudless developer documentation") |
167+
| KOOK | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Kook?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Kook/ "Download AspNet.Security.OAuth.Kook from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Kook?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Kook "Download AspNet.Security.OAuth.Kook from MyGet.org") | [Documentation](https://developer.kookapp.cn/doc/oauth2 "KOOK developer documentation") |
166168
| Kroger | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Kroger?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Kroger/ "Download AspNet.Security.OAuth.Kroger from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Kroger?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Kroger "Download AspNet.Security.OAuth.Kroger from MyGet.org") | [Documentation](https://developer.kroger.com/reference/#section/Authentication "Kroger developer documentation") |
167169
| Lichess | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Lichess?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Lichess/ "Download AspNet.Security.OAuth.Lichess from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Lichess?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Lichess "Download AspNet.Security.OAuth.Lichess from MyGet.org") | [Documentation](https://lichess.org/api#section/Authentication "Lichess developer documentation") |
168170
| Line | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Line?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Line/ "Download AspNet.Security.OAuth.Line from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Line?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Line "Download AspNet.Security.OAuth.Line from MyGet.org") | [Documentation](https://developers.line.biz/en/docs/line-login/integrate-line-login "Line developer documentation") |

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ covered by the section above.
5656
| Huawei | _Optional_ | [Documentation](huawei.md "Huawei provider documentation") |
5757
| Instagram | _Optional_ | [Documentation](instagram.md "Instagram provider documentation") |
5858
| Kloudless | _Optional_ | [Documentation](kloudless.md "Kloudless provider documentation") |
59+
| KOOK | _Optional_ | [Documentation](kook.md "KOOK provider documentation") |
5960
| Line | _Optional_ | [Documentation](line.md "Line provider documentation") |
6061
| LinkedIn | _Optional_ | [Documentation](linkedin.md "LinkedIn provider documentation") |
6162
| Odnoklassniki | _Optional_ | [Documentation](odnoklassniki.md "Odnoklassniki provider documentation") |

docs/kook.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Integrating the KOOK Provider
2+
3+
## Example
4+
5+
```csharp
6+
services.AddAuthentication(options => /* Auth configuration */)
7+
.AddKook(options =>
8+
{
9+
options.ClientId = "my-client-id";
10+
options.ClientSecret = "my-client-secret";
11+
12+
// The scope get_user_info is added by default.
13+
// Please make sure the scope get_user_info is enabled in your KOOK developer center.
14+
// If you do not want to use the default scope indeed, remove it as shown below:
15+
// options.Scope.Remove("get_user_info");
16+
});
17+
```
18+
19+
## Required Additional Settings
20+
21+
_None._
22+
23+
## Optional Settings
24+
25+
_None._
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
5+
</PropertyGroup>
6+
7+
<!-- TODO Remove once published to NuGet.org -->
8+
<PropertyGroup>
9+
<DisablePackageBaselineValidation>true</DisablePackageBaselineValidation>
10+
<PackageValidationBaselineVersion>7.0.2</PackageValidationBaselineVersion>
11+
</PropertyGroup>
12+
13+
<PropertyGroup>
14+
<Description>ASP.NET Core security middleware enabling KOOK authentication.</Description>
15+
<Authors>Gehongyan</Authors>
16+
<PackageTags>aspnetcore;authentication;kaiheila;kook;kookapp;oauth;security</PackageTags>
17+
</PropertyGroup>
18+
19+
<ItemGroup>
20+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
21+
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
22+
</ItemGroup>
23+
24+
</Project>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
namespace AspNet.Security.OAuth.Kook;
8+
9+
/// <summary>
10+
/// Contains constants specific to the <see cref="KookAuthenticationHandler"/>.
11+
/// </summary>
12+
public static class KookAuthenticationConstants
13+
{
14+
public static class Claims
15+
{
16+
public const string OperatingSystem = "urn:kook:user:operating_system";
17+
public const string AvatarUrl = "urn:kook:user:avatar:url";
18+
public const string BannerUrl = "urn:kook:user:banner:url";
19+
public const string IsMobileVerified = "urn:kook:user:is_mobile_verified";
20+
public const string IdentifyNumber = "urn:kook:user:identify_num";
21+
}
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
namespace AspNet.Security.OAuth.Kook;
8+
9+
/// <summary>
10+
/// Default values used by the Kook authentication middleware.
11+
/// </summary>
12+
public static class KookAuthenticationDefaults
13+
{
14+
/// <summary>
15+
/// Default value for <see cref="Microsoft.AspNetCore.Authentication.AuthenticationScheme.Name"/>.
16+
/// </summary>
17+
public const string AuthenticationScheme = "Kook";
18+
19+
/// <summary>
20+
/// Default value for <see cref="Microsoft.AspNetCore.Authentication.AuthenticationScheme.DisplayName"/>.
21+
/// </summary>
22+
public static readonly string DisplayName = "Kook";
23+
24+
/// <summary>
25+
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
26+
/// </summary>
27+
public static readonly string Issuer = "Kook";
28+
29+
/// <summary>
30+
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
31+
/// </summary>
32+
public static readonly string CallbackPath = "/signin-kook";
33+
34+
/// <summary>
35+
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
36+
/// </summary>
37+
public static readonly string AuthorizationEndpoint = "https://www.kookapp.cn/app/oauth2/authorize";
38+
39+
/// <summary>
40+
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
41+
/// </summary>
42+
public static readonly string TokenEndpoint = "https://www.kookapp.cn/api/oauth2/token";
43+
44+
/// <summary>
45+
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
46+
/// </summary>
47+
public static readonly string UserInformationEndpoint = "https://www.kookapp.cn/api/v3/user/me";
48+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
using AspNet.Security.OAuth.Kook;
8+
9+
namespace Microsoft.Extensions.DependencyInjection;
10+
11+
/// <summary>
12+
/// Extension methods to add Kook authentication capabilities to an HTTP application pipeline.
13+
/// </summary>
14+
public static class KookAuthenticationExtensions
15+
{
16+
/// <summary>
17+
/// Adds <see cref="KookAuthenticationHandler"/> to the specified
18+
/// <see cref="AuthenticationBuilder"/>, which enables Kook authentication capabilities.
19+
/// </summary>
20+
/// <param name="builder">The authentication builder.</param>
21+
/// <returns>A reference to this instance after the operation has completed.</returns>
22+
public static AuthenticationBuilder AddKook([NotNull] this AuthenticationBuilder builder)
23+
{
24+
return builder.AddKook(KookAuthenticationDefaults.AuthenticationScheme, options => { });
25+
}
26+
27+
/// <summary>
28+
/// Adds <see cref="KookAuthenticationHandler"/> to the specified
29+
/// <see cref="AuthenticationBuilder"/>, which enables Kook authentication capabilities.
30+
/// </summary>
31+
/// <param name="builder">The authentication builder.</param>
32+
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
33+
/// <returns>A reference to this instance after the operation has completed.</returns>
34+
public static AuthenticationBuilder AddKook(
35+
[NotNull] this AuthenticationBuilder builder,
36+
[NotNull] Action<KookAuthenticationOptions> configuration)
37+
{
38+
return builder.AddKook(KookAuthenticationDefaults.AuthenticationScheme, configuration);
39+
}
40+
41+
/// <summary>
42+
/// Adds <see cref="KookAuthenticationHandler"/> to the specified
43+
/// <see cref="AuthenticationBuilder"/>, which enables Kook authentication capabilities.
44+
/// </summary>
45+
/// <param name="builder">The authentication builder.</param>
46+
/// <param name="scheme">The authentication scheme associated with this instance.</param>
47+
/// <param name="configuration">The delegate used to configure the Kook options.</param>
48+
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
49+
public static AuthenticationBuilder AddKook(
50+
[NotNull] this AuthenticationBuilder builder,
51+
[NotNull] string scheme,
52+
[NotNull] Action<KookAuthenticationOptions> configuration)
53+
{
54+
return builder.AddKook(scheme, KookAuthenticationDefaults.DisplayName, configuration);
55+
}
56+
57+
/// <summary>
58+
/// Adds <see cref="KookAuthenticationHandler"/> to the specified
59+
/// <see cref="AuthenticationBuilder"/>, which enables Kook authentication capabilities.
60+
/// </summary>
61+
/// <param name="builder">The authentication builder.</param>
62+
/// <param name="scheme">The authentication scheme associated with this instance.</param>
63+
/// <param name="caption">The optional display name associated with this instance.</param>
64+
/// <param name="configuration">The delegate used to configure the Kook options.</param>
65+
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
66+
public static AuthenticationBuilder AddKook(
67+
[NotNull] this AuthenticationBuilder builder,
68+
[NotNull] string scheme,
69+
[CanBeNull] string caption,
70+
[NotNull] Action<KookAuthenticationOptions> configuration)
71+
{
72+
return builder.AddOAuth<KookAuthenticationOptions, KookAuthenticationHandler>(scheme, caption, configuration);
73+
}
74+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
using System.Net.Http.Headers;
8+
using System.Security.Claims;
9+
using System.Text.Encodings.Web;
10+
using System.Text.Json;
11+
using Microsoft.Extensions.Logging;
12+
using Microsoft.Extensions.Options;
13+
14+
namespace AspNet.Security.OAuth.Kook;
15+
16+
public partial class KookAuthenticationHandler : OAuthHandler<KookAuthenticationOptions>
17+
{
18+
public KookAuthenticationHandler(
19+
[NotNull] IOptionsMonitor<KookAuthenticationOptions> options,
20+
[NotNull] ILoggerFactory logger,
21+
[NotNull] UrlEncoder encoder,
22+
[NotNull] ISystemClock clock)
23+
: base(options, logger, encoder, clock)
24+
{
25+
}
26+
27+
protected override async Task<AuthenticationTicket> CreateTicketAsync(
28+
[NotNull] ClaimsIdentity identity,
29+
[NotNull] AuthenticationProperties properties,
30+
[NotNull] OAuthTokenResponse tokens)
31+
{
32+
using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
33+
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
34+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
35+
36+
using var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
37+
if (!response.IsSuccessStatusCode)
38+
{
39+
await Log.UserProfileErrorAsync(Logger, response, Context.RequestAborted);
40+
throw new HttpRequestException("An error occurred while retrieving the user profile.");
41+
}
42+
43+
using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync(Context.RequestAborted));
44+
45+
var code = payload.RootElement.GetProperty("code").GetInt32();
46+
47+
if (code != 0)
48+
{
49+
Log.UserProfileErrorCode(Logger, code, payload.RootElement.GetString("message"));
50+
throw new HttpRequestException("An error occurred while retrieving the user profile.");
51+
}
52+
53+
var principal = new ClaimsPrincipal(identity);
54+
var user = payload.RootElement.GetProperty("data");
55+
56+
var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, user);
57+
context.RunClaimActions();
58+
59+
await Events.CreatingTicket(context);
60+
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
61+
}
62+
63+
private static partial class Log
64+
{
65+
internal static async Task UserProfileErrorAsync(ILogger logger, HttpResponseMessage response, CancellationToken cancellationToken)
66+
{
67+
UserProfileError(
68+
logger,
69+
response.StatusCode,
70+
response.Headers.ToString(),
71+
await response.Content.ReadAsStringAsync(cancellationToken));
72+
}
73+
74+
[LoggerMessage(1, LogLevel.Error, "An error occurred while retrieving the user profile: the remote server returned a {Status} response with the following payload: {Headers} {Body}.")]
75+
private static partial void UserProfileError(
76+
ILogger logger,
77+
System.Net.HttpStatusCode status,
78+
string headers,
79+
string body);
80+
81+
[LoggerMessage(2, LogLevel.Error, "An error occurred while retrieving the user profile: the remote server returned a {Status} response with the following message: {ErrorMessage}.")]
82+
internal static partial void UserProfileErrorCode(
83+
ILogger logger,
84+
int status,
85+
string? errorMessage);
86+
}
87+
}

0 commit comments

Comments
 (0)