Skip to content

Commit 034dc35

Browse files
serberkevinchalet
authored andcommitted
Add a Vkontakte provider
1 parent d5f4d40 commit 034dc35

10 files changed

+366
-1
lines changed

AspNet.Security.OAuth.Providers.sln

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 14
4-
VisualStudioVersion = 14.0.23107.0
4+
VisualStudioVersion = 14.0.25123.0
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}"
77
EndProject
@@ -63,6 +63,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Sales
6363
EndProject
6464
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Gitter", "src\AspNet.Security.OAuth.Gitter\AspNet.Security.OAuth.Gitter.xproj", "{EDD1BA76-D656-4513-BC65-FEC688CBB9F8}"
6565
EndProject
66+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Vkontakte", "src\AspNet.Security.OAuth.Vkontakte\AspNet.Security.OAuth.Vkontakte.xproj", "{B332222F-43B4-4B3E-8EB3-9BCE29901043}"
67+
EndProject
6668
Global
6769
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6870
Debug|Any CPU = Debug|Any CPU
@@ -181,6 +183,10 @@ Global
181183
{EDD1BA76-D656-4513-BC65-FEC688CBB9F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
182184
{EDD1BA76-D656-4513-BC65-FEC688CBB9F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
183185
{EDD1BA76-D656-4513-BC65-FEC688CBB9F8}.Release|Any CPU.Build.0 = Release|Any CPU
186+
{B332222F-43B4-4B3E-8EB3-9BCE29901043}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
187+
{B332222F-43B4-4B3E-8EB3-9BCE29901043}.Debug|Any CPU.Build.0 = Debug|Any CPU
188+
{B332222F-43B4-4B3E-8EB3-9BCE29901043}.Release|Any CPU.ActiveCfg = Release|Any CPU
189+
{B332222F-43B4-4B3E-8EB3-9BCE29901043}.Release|Any CPU.Build.0 = Release|Any CPU
184190
EndGlobalSection
185191
GlobalSection(SolutionProperties) = preSolution
186192
HideSolutionNode = FALSE
@@ -214,5 +220,6 @@ Global
214220
{1302E67D-5448-407B-8B8D-709A0BA458E8} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
215221
{5881BB63-89BD-4397-A61C-69B1844F7615} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
216222
{EDD1BA76-D656-4513-BC65-FEC688CBB9F8} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
223+
{B332222F-43B4-4B3E-8EB3-9BCE29901043} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
217224
EndGlobalSection
218225
EndGlobal

samples/Mvc.Client/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"AspNet.Security.OAuth.Spotify": { "target": "project" },
4040
"AspNet.Security.OAuth.Twitch": { "target": "project" },
4141
"AspNet.Security.OAuth.Vimeo": { "target": "project" },
42+
"AspNet.Security.OAuth.Vkontakte": { "target": "project" },
4243
"AspNet.Security.OAuth.WordPress": { "target": "project" },
4344
"AspNet.Security.OAuth.Yahoo": { "target": "project" },
4445
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0-*",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6+
</PropertyGroup>
7+
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
8+
<PropertyGroup Label="Globals">
9+
<ProjectGuid>b332222f-43b4-4b3e-8eb3-9bce29901043</ProjectGuid>
10+
<RootNamespace>AspNet.Security.OAuth.Vkontakte</RootNamespace>
11+
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
12+
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
13+
</PropertyGroup>
14+
<PropertyGroup>
15+
<SchemaVersion>2.0</SchemaVersion>
16+
</PropertyGroup>
17+
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
18+
</Project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 Microsoft.AspNetCore.Builder;
8+
9+
namespace AspNet.Security.OAuth.Vkontakte {
10+
/// <summary>
11+
/// Default values used by the Vkontakte authentication middleware.
12+
/// </summary>
13+
public static class VkontakteAuthenticationDefault {
14+
/// <summary>
15+
/// Default value for <see cref="AuthenticationOptions.AuthenticationScheme"/>.
16+
/// </summary>
17+
public const string AuthenticationScheme = "Vkontakte";
18+
19+
/// <summary>
20+
/// Default value for <see cref="RemoteAuthenticationOptions.DisplayName"/>.
21+
/// </summary>
22+
public const string DisplayName = "Vkontakte";
23+
24+
/// <summary>
25+
/// Default value for <see cref="AuthenticationOptions.ClaimsIssuer"/>.
26+
/// </summary>
27+
public const string Issuer = "Vkontakte";
28+
29+
/// <summary>
30+
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
31+
/// </summary>
32+
public const string CallbackPath = "/signin-vkontakte";
33+
34+
/// <summary>
35+
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
36+
/// </summary>
37+
public const string AuthorizationEndpoint = "https://oauth.vk.com/authorize";
38+
39+
/// <summary>
40+
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
41+
/// </summary>
42+
public const string TokenEndpoint = "https://oauth.vk.com/access_token";
43+
44+
/// <summary>
45+
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
46+
/// </summary>
47+
public const string UserInformationEndpoint = "https://api.vk.com/method/users.get.json";
48+
}
49+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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;
8+
using AspNet.Security.OAuth.Vkontakte;
9+
using JetBrains.Annotations;
10+
using Microsoft.Extensions.Options;
11+
12+
namespace Microsoft.AspNetCore.Builder {
13+
/// <summary>
14+
/// Extension methods to add Vkontakte authentication capabilities to an HTTP application pipeline.
15+
/// </summary>
16+
public static class VkontakteAuthenticationExtensions {
17+
/// <summary>
18+
/// Adds the <see cref="VkontakteAuthenticationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Vkontakte authentication capabilities.
19+
/// </summary>
20+
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
21+
/// <param name="options">A <see cref="VkontakteAuthenticationOptions"/> that specifies options for the middleware.</param>
22+
/// <returns>A reference to this instance after the operation has completed.</returns>
23+
public static IApplicationBuilder UseVkontakteAuthentication(
24+
[NotNull] this IApplicationBuilder app,
25+
[NotNull] VkontakteAuthenticationOptions options) {
26+
if (app == null) {
27+
throw new ArgumentNullException(nameof(app));
28+
}
29+
30+
if (options == null) {
31+
throw new ArgumentNullException(nameof(options));
32+
}
33+
34+
return app.UseMiddleware<VkontakteAuthenticationMiddleware>(Options.Create(options));
35+
}
36+
37+
/// <summary>
38+
/// Adds the <see cref="VkontakteAuthenticationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Vkontakte authentication capabilities.
39+
/// </summary>
40+
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
41+
/// <param name="configuration">An action delegate to configure the provided <see cref="VkontakteAuthenticationOptions"/>.</param>
42+
/// <returns>A reference to this instance after the operation has completed.</returns>
43+
public static IApplicationBuilder UseLinkedInAuthentication(
44+
[NotNull] this IApplicationBuilder app,
45+
[NotNull] Action<VkontakteAuthenticationOptions> configuration) {
46+
if (app == null) {
47+
throw new ArgumentNullException(nameof(app));
48+
}
49+
50+
if (configuration == null) {
51+
throw new ArgumentNullException(nameof(configuration));
52+
}
53+
54+
var options = new VkontakteAuthenticationOptions();
55+
configuration(options);
56+
57+
return app.UseMiddleware<VkontakteAuthenticationMiddleware>(Options.Create(options));
58+
}
59+
}
60+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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;
8+
using System.Security.Claims;
9+
using System.Threading.Tasks;
10+
using AspNet.Security.OAuth.Extensions;
11+
using JetBrains.Annotations;
12+
using Microsoft.AspNetCore.Authentication;
13+
using Microsoft.AspNetCore.Authentication.OAuth;
14+
using Microsoft.AspNetCore.Http.Authentication;
15+
using Microsoft.AspNetCore.WebUtilities;
16+
using Microsoft.Extensions.Logging;
17+
using Newtonsoft.Json.Linq;
18+
19+
namespace AspNet.Security.OAuth.Vkontakte {
20+
public class VkontakteAuthenticationHandler : OAuthHandler<VkontakteAuthenticationOptions> {
21+
public VkontakteAuthenticationHandler(HttpClient client)
22+
: base(client) {
23+
}
24+
25+
protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull] ClaimsIdentity identity, [NotNull] AuthenticationProperties properties, [NotNull] OAuthTokenResponse tokens) {
26+
var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, "access_token", tokens.AccessToken);
27+
28+
if (Options.Fields.Count != 0) {
29+
address = QueryHelpers.AddQueryString(address, "fields", string.Join(",", Options.Fields));
30+
}
31+
32+
var response = await Backchannel.GetAsync(address, Context.RequestAborted);
33+
if (!response.IsSuccessStatusCode) {
34+
Logger.LogError("An error occurred when retrieving the user profile: the remote server " +
35+
"returned a {Status} response with the following payload: {Headers} {Body}.",
36+
/* Status: */ response.StatusCode,
37+
/* Headers: */ response.Headers.ToString(),
38+
/* Body: */ await response.Content.ReadAsStringAsync());
39+
40+
throw new HttpRequestException("An error occurred when retrieving the user profile.");
41+
}
42+
43+
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
44+
var user = (JObject) payload["response"][0];
45+
46+
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
47+
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, user);
48+
49+
identity.AddOptionalClaim(ClaimTypes.NameIdentifier, VkontakteAuthenticationHelper.GetId(user), Options.ClaimsIssuer)
50+
.AddOptionalClaim(ClaimTypes.GivenName, VkontakteAuthenticationHelper.GetFirstName(user), Options.ClaimsIssuer)
51+
.AddOptionalClaim(ClaimTypes.Surname, VkontakteAuthenticationHelper.GetLastName(user), Options.ClaimsIssuer)
52+
.AddOptionalClaim(ClaimTypes.Name, VkontakteAuthenticationHelper.GetScreenName(user), Options.ClaimsIssuer)
53+
.AddOptionalClaim("urn:vkontakte:link", VkontakteAuthenticationHelper.GetPhoto(user), Options.ClaimsIssuer);
54+
55+
await Options.Events.CreatingTicket(context);
56+
57+
return context.Ticket;
58+
}
59+
}
60+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 JetBrains.Annotations;
8+
using Newtonsoft.Json.Linq;
9+
10+
namespace AspNet.Security.OAuth.Vkontakte {
11+
/// <summary>
12+
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
13+
/// instance retrieved from Vkontakte after a successful authentication process.
14+
/// </summary>
15+
public static class VkontakteAuthenticationHelper {
16+
/// <summary>
17+
/// Gets the identifier associated with the logged in user.
18+
/// </summary>
19+
public static string GetId([NotNull] JObject user) => user.Value<string>("uid");
20+
21+
/// <summary>
22+
/// Gets the first name associated with the logged in user.
23+
/// </summary>
24+
public static string GetFirstName([NotNull] JObject user) => user.Value<string>("first_name");
25+
26+
/// <summary>
27+
/// Gets the last name associated with the logged in user.
28+
/// </summary>
29+
public static string GetLastName([NotNull] JObject user) => user.Value<string>("last_name");
30+
31+
/// <summary>
32+
/// Gets the screen name associated with the logged in user.
33+
/// </summary>
34+
public static string GetScreenName([NotNull] JObject user) => user.Value<string>("screen_name");
35+
36+
/// <summary>
37+
/// Gets the photo associated with the logged in user.
38+
/// </summary>
39+
public static string GetPhoto([NotNull] JObject user) => user.Value<string>("photo_50");
40+
}
41+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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.Text.Encodings.Web;
8+
using JetBrains.Annotations;
9+
using Microsoft.AspNetCore.Authentication;
10+
using Microsoft.AspNetCore.Authentication.OAuth;
11+
using Microsoft.AspNetCore.DataProtection;
12+
using Microsoft.AspNetCore.Http;
13+
using Microsoft.Extensions.Logging;
14+
using Microsoft.Extensions.Options;
15+
16+
namespace AspNet.Security.OAuth.Vkontakte {
17+
public class VkontakteAuthenticationMiddleware : OAuthMiddleware<VkontakteAuthenticationOptions> {
18+
public VkontakteAuthenticationMiddleware(
19+
[NotNull] RequestDelegate next,
20+
[NotNull] IOptions<VkontakteAuthenticationOptions> options,
21+
[NotNull] IDataProtectionProvider dataProtectionProvider,
22+
[NotNull] ILoggerFactory loggerFactory,
23+
[NotNull] UrlEncoder encoder,
24+
[NotNull] IOptions<SharedAuthenticationOptions> sharedOptions)
25+
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options) {
26+
}
27+
28+
protected override AuthenticationHandler<VkontakteAuthenticationOptions> CreateHandler() {
29+
return new VkontakteAuthenticationHandler(Backchannel);
30+
}
31+
}
32+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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.Collections.Generic;
8+
using Microsoft.AspNetCore.Builder;
9+
using Microsoft.AspNetCore.Http;
10+
11+
namespace AspNet.Security.OAuth.Vkontakte {
12+
/// <summary>
13+
/// Configuration options for <see cref="VkontakteAuthenticationMiddleware"/>.
14+
/// </summary>
15+
public class VkontakteAuthenticationOptions : OAuthOptions {
16+
/// <summary>
17+
/// Initializes a new <see cref="VkontakteAuthenticationOptions"/>.
18+
/// </summary>
19+
public VkontakteAuthenticationOptions() {
20+
AuthenticationScheme = VkontakteAuthenticationDefault.AuthenticationScheme;
21+
DisplayName = VkontakteAuthenticationDefault.DisplayName;
22+
ClaimsIssuer = VkontakteAuthenticationDefault.Issuer;
23+
24+
CallbackPath = new PathString("/signin-vkontakte");
25+
26+
AuthorizationEndpoint = VkontakteAuthenticationDefault.AuthorizationEndpoint;
27+
TokenEndpoint = VkontakteAuthenticationDefault.TokenEndpoint;
28+
UserInformationEndpoint = VkontakteAuthenticationDefault.UserInformationEndpoint;
29+
}
30+
31+
/// <summary>
32+
/// Gets the list of fields to retrieve from the user information endpoint.
33+
/// See https://vk.com/dev/fields for more information.
34+
/// </summary>
35+
public ICollection<string> Fields { get; } = new HashSet<string> {
36+
"uid",
37+
"first_name",
38+
"last_name",
39+
"screen_name",
40+
"photo_50"
41+
};
42+
}
43+
}

0 commit comments

Comments
 (0)