Skip to content

Commit

Permalink
Add a new provider for Slack
Browse files Browse the repository at this point in the history
  • Loading branch information
mjknowles authored and kevinchalet committed Sep 19, 2015
1 parent 3f58f98 commit a402a45
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 0 deletions.
7 changes: 7 additions & 0 deletions AspNet.Security.OAuth.Providers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Devia
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Spotify", "src\AspNet.Security.OAuth.Spotify\AspNet.Security.OAuth.Spotify.xproj", "{535CD0A4-2117-4576-8552-4188D7E8E3D4}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNet.Security.OAuth.Slack", "src\AspNet.Security.OAuth.Slack\AspNet.Security.OAuth.Slack.xproj", "{95266F79-613A-42C4-96E2-E1435AD9ED6E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -61,6 +63,10 @@ Global
{535CD0A4-2117-4576-8552-4188D7E8E3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{535CD0A4-2117-4576-8552-4188D7E8E3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{535CD0A4-2117-4576-8552-4188D7E8E3D4}.Release|Any CPU.Build.0 = Release|Any CPU
{95266F79-613A-42C4-96E2-E1435AD9ED6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95266F79-613A-42C4-96E2-E1435AD9ED6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95266F79-613A-42C4-96E2-E1435AD9ED6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95266F79-613A-42C4-96E2-E1435AD9ED6E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -74,5 +80,6 @@ Global
{F79E8D15-F296-424C-A50E-AE39EB2C609F} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
{9E09DCBC-20DB-4CD8-8A6D-5FA1958EEF14} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
{535CD0A4-2117-4576-8552-4188D7E8E3D4} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
{95266F79-613A-42C4-96E2-E1435AD9ED6E} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions samples/Mvc.Client/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"AspNet.Security.OAuth.DeviantArt": "1.0.0-*",
"AspNet.Security.OAuth.GitHub": "1.0.0-*",
"AspNet.Security.OAuth.LinkedIn": "1.0.0-*",
"AspNet.Security.OAuth.Slack": "1.0.0-*",
"AspNet.Security.OAuth.Spotify": "1.0.0-*",
"AspNet.Security.OAuth.WordPress": "1.0.0-*",
"AspNet.Security.OAuth.Yahoo": "1.0.0-*",
Expand Down
20 changes: 20 additions & 0 deletions src/AspNet.Security.OAuth.Slack/AspNet.Security.OAuth.Slack.xproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>

<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>95266f79-613a-42c4-96e2-e1435ad9ed6e</ProjectGuid>
<RootNamespace>AspNet.Security.OAuth.Slack</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>

<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
51 changes: 51 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationDefaults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using Microsoft.AspNet.Authentication;
using Microsoft.AspNet.Authentication.OAuth;

namespace AspNet.Security.OAuth.Slack {
/// <summary>
/// Default values used by the Slack authentication middleware.
/// </summary>
public static class SlackAuthenticationDefaults {
/// <summary>
/// Default value for <see cref="AuthenticationOptions.AuthenticationScheme"/>.
/// </summary>
public const string AuthenticationScheme = "Slack";

/// <summary>
/// Default value for <see cref="OAuthOptions.Caption"/>.
/// </summary>
public const string Caption = "Slack";

/// <summary>
/// Default value for <see cref="OAuthOptions.ClaimsIssuer"/>.
/// </summary>
public const string Issuer = "Slack";

/// <summary>
/// Default value for <see cref="OAuthOptions.CallbackPath"/>.
/// </summary>
public const string CallbackPath = "/signin-slack";

/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public const string AuthorizationEndpoint = "https://slack.com/oauth/authorize";

/// <summary>
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
/// </summary>
public const string TokenEndpoint = "https://slack.com/api/oauth.access";

/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
/// For more info about this endpoint, see https://api.slack.com/methods/auth.test.
/// </summary>
public const string UserInformationEndpoint = "https://slack.com/api/auth.test";
}
}
32 changes: 32 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using System;
using AspNet.Security.OAuth.Slack;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;

namespace Microsoft.AspNet.Builder {
public static class SlackAuthenticationExtensions {
public static IServiceCollection ConfigureSlackAuthentication(
[NotNull] this IServiceCollection services,
[NotNull] Action<SlackAuthenticationOptions> configuration) {
return services.Configure(configuration);
}

public static IApplicationBuilder UseSlackAuthentication([NotNull] this IApplicationBuilder app) {
return app.UseMiddleware<SlackAuthenticationMiddleware>();
}

public static IApplicationBuilder UseSlackAuthentication(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<SlackAuthenticationOptions> configuration) {
return app.UseMiddleware<SlackAuthenticationMiddleware>(
new ConfigureOptions<SlackAuthenticationOptions>(configuration));
}
}
}
55 changes: 55 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OAuth.Extensions;
using Microsoft.AspNet.Authentication;
using Microsoft.AspNet.Authentication.OAuth;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.Framework.Internal;
using Newtonsoft.Json.Linq;
using System;

namespace AspNet.Security.OAuth.Slack {
public class SlackAuthenticationHandler : OAuthHandler<SlackAuthenticationOptions> {
public SlackAuthenticationHandler([NotNull] HttpClient client)
: base(client) {
}

protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull] ClaimsIdentity identity,
[NotNull] AuthenticationProperties properties, [NotNull] OAuthTokenResponse tokens) {
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint + "?token=" + Uri.EscapeDataString(tokens.AccessToken));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
response.EnsureSuccessStatusCode();

var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

identity.AddOptionalClaim(ClaimTypes.NameIdentifier, SlackAuthenticationHelper.GetUserIdentifier(payload), Options.ClaimsIssuer)
.AddOptionalClaim(ClaimTypes.Name, SlackAuthenticationHelper.GetUserName(payload), Options.ClaimsIssuer)
.AddOptionalClaim("urn:slack:team_id", SlackAuthenticationHelper.GetTeamIdentifier(payload), Options.ClaimsIssuer)
.AddOptionalClaim("urn:slack:team_name", SlackAuthenticationHelper.GetTeamName(payload), Options.ClaimsIssuer)
.AddOptionalClaim("urn:slack:team_url", SlackAuthenticationHelper.GetTeamLink(payload), Options.ClaimsIssuer);

var context = new OAuthAuthenticatedContext(Context, Options, Backchannel, tokens, payload) {
Principal = new ClaimsPrincipal(identity),
Properties = properties
};

await Options.Events.Authenticated(context);

if (context.Principal?.Identity == null) {
return null;
}

return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme);
}
}
}
41 changes: 41 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using Microsoft.Framework.Internal;
using Newtonsoft.Json.Linq;

namespace AspNet.Security.OAuth.Slack {
/// <summary>
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
/// instance retrieved from Slack after a successful authentication process.
/// </summary>
public static class SlackAuthenticationHelper {
/// <summary>
/// Gets the identifier corresponding to the authenticated user.
/// </summary>
public static string GetUserIdentifier([NotNull] JObject user) => user.Value<string>("user_id");

/// <summary>
/// Gets the login corresponding to the authenticated user.
/// </summary>
public static string GetUserName([NotNull] JObject user) => user.Value<string>("user");

/// <summary>
/// Gets the name corresponding to the authenticated user.
/// </summary>
public static string GetTeamIdentifier([NotNull] JObject user) => user.Value<string>("team_id");

/// <summary>
/// Gets the name corresponding to the authenticated user.
/// </summary>
public static string GetTeamName([NotNull] JObject user) => user.Value<string>("team");

/// <summary>
/// Gets the URL corresponding to the authenticated user.
/// </summary>
public static string GetTeamLink([NotNull] JObject user) => user.Value<string>("url");
}
}
34 changes: 34 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using Microsoft.AspNet.Authentication;
using Microsoft.AspNet.Authentication.OAuth;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.DataProtection;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.WebEncoders;

namespace AspNet.Security.OAuth.Slack {
public class SlackAuthenticationMiddleware : OAuthMiddleware<SlackAuthenticationOptions> {
public SlackAuthenticationMiddleware(
[NotNull] RequestDelegate next,
[NotNull] IDataProtectionProvider dataProtectionProvider,
[NotNull] ILoggerFactory loggerFactory,
[NotNull] IUrlEncoder encoder,
[NotNull] IOptions<SharedAuthenticationOptions> externalOptions,
[NotNull] IOptions<SlackAuthenticationOptions> options,
ConfigureOptions<SlackAuthenticationOptions> configureOptions = null)
: base(next, dataProtectionProvider, loggerFactory,
encoder, externalOptions, options, configureOptions) {
}

protected override AuthenticationHandler<SlackAuthenticationOptions> CreateHandler() {
return new SlackAuthenticationHandler(Backchannel);
}
}
}
29 changes: 29 additions & 0 deletions src/AspNet.Security.OAuth.Slack/SlackAuthenticationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using Microsoft.AspNet.Authentication.OAuth;
using Microsoft.AspNet.Http;

namespace AspNet.Security.OAuth.Slack {
/// <summary>
/// Defines a set of options used by <see cref="SlackAuthenticationHandler"/>.
/// </summary>
public class SlackAuthenticationOptions : OAuthOptions {
public SlackAuthenticationOptions() {
AuthenticationScheme = SlackAuthenticationDefaults.AuthenticationScheme;
Caption = SlackAuthenticationDefaults.Caption;
ClaimsIssuer = SlackAuthenticationDefaults.Issuer;

CallbackPath = new PathString(SlackAuthenticationDefaults.CallbackPath);

AuthorizationEndpoint = SlackAuthenticationDefaults.AuthorizationEndpoint;
TokenEndpoint = SlackAuthenticationDefaults.TokenEndpoint;
UserInformationEndpoint = SlackAuthenticationDefaults.UserInformationEndpoint;

SaveTokensAsClaims = false;
}
}
}
33 changes: 33 additions & 0 deletions src/AspNet.Security.OAuth.Slack/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version": "1.0.0-*",
"description": "ASP.NET 5 security middleware enabling Slack authentication.",
"authors": [ "Michael Knowles" ],
"owners": [ "Kévin Chalet", "Jerrie Pelser" ],

"projectUrl": "https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html",

"dependencies": {
"AspNet.Security.OAuth.Extensions": {
"type": "build",
"version": "1.0.0-*"
},

"Microsoft.AspNet.Authentication.OAuth": "1.0.0-*",

"Microsoft.Framework.NotNullAttribute.Internal": {
"type": "build",
"version": "1.0.0-*"
}
},

"frameworks": {
"dnx451": { },

"dnxcore50": {
"dependencies": {
"System.Security.Claims": "4.0.1-*"
}
}
}
}

0 comments on commit a402a45

Please sign in to comment.