Compare commits

...

17 Commits

Author SHA1 Message Date
Tommy Parnell
d07c280377 bump version 2016-12-09 07:59:02 -05:00
jasondaicoder
f5ccfa5fdf added provider for wso2 (#194)
* added provider for wso2

* corrected some wrong comments

* fixed wrong pacakges reference path issues

* Provided enough comments for the extension methods
2016-12-09 07:57:58 -05:00
Kevin Boyle
5b4c7a9621 Write out the full exception with stacktrace (#195) 2016-12-09 07:57:34 -05:00
Tommy Parnell
03bca9ac2c Merge branch 'YuriPetskus-patch-1' 2016-11-21 17:29:56 -05:00
Tommy Parnell
52ab5c2571 bump version 2016-11-21 17:29:30 -05:00
Tommy Parnell
4112051063 put email behind if wall 2016-11-21 17:25:59 -05:00
Tommy Parnell
e0b97f3bb5 Merge branch 'patch-1' of git://github.com/YuriPetskus/OwinOAuthProviders into YuriPetskus-patch-1 2016-11-21 17:22:52 -05:00
Tommy Parnell
6d999ec41a Update README.md 2016-11-11 17:26:48 -05:00
Tommy Parnell
2642736548 bump version 2016-11-01 18:14:18 -04:00
MartinPaulLippert
6cfab46b9d Added LinkedInAuthentication ApplyRedirect (#187)
* Added ApplyRedirect to LinkedInAuthentication Provider
Changed LinkedInAuthenticationHandler to use ApplyRedirect
Added LinkedInApplyRedirectContext

Changes allow a developer to override the authorization endpoint
2016-11-01 18:12:31 -04:00
Tommy Parnell
2567036747 bump version 2016-10-27 08:17:57 -04:00
Tommy Parnell
2e5561befb Merge pull request #185 from diwu86/sf_scope
add id to scope and mobile_phone to context
2016-10-27 08:16:19 -04:00
Di Wu
202f215c19 add id to scope and mobile_phone to context 2016-10-26 16:48:11 -04:00
Tommy Parnell
28b4edbde9 fix readme (#181) 2016-10-06 16:07:25 -04:00
Tommy Parnell
2eb914597b 2.9 2016-10-06 15:53:55 -04:00
denis32000
ed5615cd9f Added providers for Box and Baidu (#179)
* Added project with provider for Box cloud service
* Added Baidu provider
2016-10-06 15:49:04 -04:00
Yuri Petskus
511a4c1287 Update VKontakteAuthenticationHandler.cs
Email support. VK send it with access_token
2016-05-24 15:53:12 +06:00
57 changed files with 3019 additions and 226 deletions

3
.gitignore vendored
View File

@@ -70,6 +70,9 @@ ipch/
# Guidance Automation Toolkit
*.gpState
# CodeRush is a .NET coding add-in
.cr/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper

View File

@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.ArcGISOnline", "src\Owin.Security.Providers.ArcGISOnline\Owin.Security.Providers.ArcGISOnline.csproj", "{8A49FAEF-D365-4D25-942C-1CAD03845A5E}"
EndProject
@@ -100,6 +100,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.Gen
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.MyHeritage", "src\Owin.Security.Providers.MyHeritage\Owin.Security.Providers.MyHeritage.csproj", "{84795078-31B5-4369-BD1B-F960165F8C71}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.Box", "src\Owin.Security.Providers.Box\Owin.Security.Providers.Box.csproj", "{1AEF8813-E1F9-41E1-BC8D-732960595E9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.Baidu", "src\Owin.Security.Providers.Baidu\Owin.Security.Providers.Baidu.csproj", "{E2759807-4D7C-4288-AAC8-F5B7B4616680}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.WSO2", "src\Owin.Security.Providers.WSO2\Owin.Security.Providers.WSO2.csproj", "{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -302,6 +308,18 @@ Global
{84795078-31B5-4369-BD1B-F960165F8C71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84795078-31B5-4369-BD1B-F960165F8C71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84795078-31B5-4369-BD1B-F960165F8C71}.Release|Any CPU.Build.0 = Release|Any CPU
{1AEF8813-E1F9-41E1-BC8D-732960595E9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AEF8813-E1F9-41E1-BC8D-732960595E9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AEF8813-E1F9-41E1-BC8D-732960595E9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1AEF8813-E1F9-41E1-BC8D-732960595E9F}.Release|Any CPU.Build.0 = Release|Any CPU
{E2759807-4D7C-4288-AAC8-F5B7B4616680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2759807-4D7C-4288-AAC8-F5B7B4616680}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2759807-4D7C-4288-AAC8-F5B7B4616680}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2759807-4D7C-4288-AAC8-F5B7B4616680}.Release|Any CPU.Build.0 = Release|Any CPU
{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -3,9 +3,6 @@ using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
//using Owin.Security.Providers.Orcid;
//using Owin.Security.Providers.Discord;
namespace OwinOAuthProvidersDemo
{
public partial class Startup
@@ -21,266 +18,277 @@ namespace OwinOAuthProvidersDemo
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
//app.UseDeviantArtAuthentication("id", "secret");
//app.UseUntappdAuthentication("id", "secret");
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseDeviantArtAuthentication("id", "secret");
//app.UseUntappdAuthentication("id", "secret");
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication();
//app.UseGoogleAuthentication();
//app.UseLinkedInAuthentication("", "");
//app.UseLinkedInAuthentication("", "");
//app.UseYahooAuthentication("", "");
//app.UseYahooAuthentication("", "");
//app.UseTripItAuthentication("", "");
//app.UseTripItAuthentication("", "");
//app.UseGitHubAuthentication("", "");
//app.UseGitHubAuthentication("", "");
//app.UseBufferAuthentication("", "");
//app.UseBufferAuthentication("", "");
//app.UseRedditAuthentication("", "");
//app.UseRedditAuthentication("", "");
//app.UseStackExchangeAuthentication(
// clientId: "",
// clientSecret: "",
// key: "");
//app.UseStackExchangeAuthentication(
// clientId: "",
// clientSecret: "",
// key: "");
//app.UseInstagramInAuthentication("", "");
//app.UseInstagramInAuthentication("", "");
//var options = new GooglePlusAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// RequestOfflineAccess = true,
// Provider = new GooglePlusAuthenticationProvider
// {
// OnAuthenticated = async context => System.Diagnostics.Debug.WriteLine(String.Format("Refresh Token: {0}", context.RefreshToken))
// }
//};
//options.MomentTypes.Add("http://schemas.google.com/AddActivity");
//options.MomentTypes.Add("http://schemas.google.com/CheckInActivity");
//options.MomentTypes.Add("http://schemas.google.com/BuyActivity");
//app.UseGooglePlusAuthentication(options);
//var options = new GooglePlusAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// RequestOfflineAccess = true,
// Provider = new GooglePlusAuthenticationProvider
// {
// OnAuthenticated = async context => System.Diagnostics.Debug.WriteLine(String.Format("Refresh Token: {0}", context.RefreshToken))
// }
//};
//options.MomentTypes.Add("http://schemas.google.com/AddActivity");
//options.MomentTypes.Add("http://schemas.google.com/CheckInActivity");
//options.MomentTypes.Add("http://schemas.google.com/BuyActivity");
//app.UseGooglePlusAuthentication(options);
/*
/*
* Twitch sign-ins use /signin-Twitch as the URL for authentication
*
*/
////Simple Twitch Sign-in
//app.UseTwitchAuthentication("", "");
////Simple Twitch Sign-in
//app.UseTwitchAuthentication("", "");
////More complex Twitch Sign-in
//var opt = new TwitchAuthenticationOptions()
//{
// ClientId = "",
// ClientSecret = "",
// Provider = new TwitchAuthenticationProvider()
// {
// OnAuthenticated = async z =>
// {
//// Getting the twitch users picture
// z.Identity.AddClaim(new Claim("Picture", z.User.GetValue("logo").ToString()));
// }
//// You should be able to access these claims with HttpContext.GetOwinContext().Authentication.GetExternalLoginInfoAsync().Claims in your Account Controller
// // Commonly used in the ExternalLoginCallback() in AccountController.cs
// /*
////More complex Twitch Sign-in
//var opt = new TwitchAuthenticationOptions()
//{
// ClientId = "",
// ClientSecret = "",
// Provider = new TwitchAuthenticationProvider()
// {
// OnAuthenticated = async z =>
// {
//// Getting the twitch users picture
// z.Identity.AddClaim(new Claim("Picture", z.User.GetValue("logo").ToString()));
// }
//// You should be able to access these claims with HttpContext.GetOwinContext().Authentication.GetExternalLoginInfoAsync().Claims in your Account Controller
// // Commonly used in the ExternalLoginCallback() in AccountController.cs
// /*
// if (user != null)
// {
// var claim = (await AuthenticationManager.GetExternalLoginInfoAsync()).ExternalIdentity.Claims.First(
// a => a.Type == "Picture");
// user.Claims.Add(new IdentityUserClaim() { ClaimType = claim.Type, ClaimValue = claim.Value });
// await SignInAsync(user, isPersistent: false);
// return RedirectToLocal(returnUrl);
// }
// */
// }
//};
//app.UseTwitchAuthentication(opt);
// if (user != null)
// {
// var claim = (await AuthenticationManager.GetExternalLoginInfoAsync()).ExternalIdentity.Claims.First(
// a => a.Type == "Picture");
// user.Claims.Add(new IdentityUserClaim() { ClaimType = claim.Type, ClaimValue = claim.Value });
// await SignInAsync(user, isPersistent: false);
// return RedirectToLocal(returnUrl);
// }
// */
// }
//};
//app.UseTwitchAuthentication(opt);
//app.UseOpenIDAuthentication("http://me.yahoo.com/", "Yahoo");
//app.UseOpenIDAuthentication("http://me.yahoo.com/", "Yahoo");
//app.UseOpenIDAuthentication("https://openid.stackexchange.com/", "StackExchange");
//app.UseOpenIDAuthentication("https://openid.stackexchange.com/", "StackExchange");
//app.UseOpenIDAuthentication("https://www.google.com/accounts/o8/id", "Google");
//app.UseOpenIDAuthentication("https://www.google.com/accounts/o8/id", "Google");
//app.UseSteamAuthentication(applicationKey: "");
//app.UseSteamAuthentication(applicationKey: "");
//app.UseOpenIDAuthentication("http://orange.fr", "Orange");
// Use OpenId provider login uri instead of discovery uri
//app.UseOpenIDAuthentication("http://openid.orange.fr/server", "Orange", true);
//app.UseOpenIDAuthentication("http://orange.fr", "Orange");
// Use OpenId provider login uri instead of discovery uri
//app.UseOpenIDAuthentication("http://openid.orange.fr/server", "Orange", true);
//app.UseSalesforceAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseSalesforceAuthentication(
// clientId: "",
// clientSecret: "");
//in scenarios where a sandbox URL needs to be used
//var salesforceOptions = new SalesforceAuthenticationOptions
//{
// Endpoints =
// new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints
// {
// AuthorizationEndpoint =
// "https://ap1.salesforce.com/services/oauth2/authorize",
// TokenEndpoint = "https://ap1.salesforce.com/services/oauth2/token"
// },
// ClientId = "",
// ClientSecret = "",
// Provider = new SalesforceAuthenticationProvider()
// {
// OnAuthenticated = async context =>
// {
// System.Diagnostics.Debug.WriteLine(context.AccessToken);
// System.Diagnostics.Debug.WriteLine(context.RefreshToken);
// System.Diagnostics.Debug.WriteLine(context.OrganizationId);
// }
// }
//};
//app.UseSalesforceAuthentication(salesforceOptions);
//in scenarios where a sandbox URL needs to be used
//var salesforceOptions = new SalesforceAuthenticationOptions
//{
// Endpoints =
// new SalesforceAuthenticationOptions.SalesforceAuthenticationEndpoints
// {
// AuthorizationEndpoint =
// "https://ap1.salesforce.com/services/oauth2/authorize",
// TokenEndpoint = "https://ap1.salesforce.com/services/oauth2/token"
// },
// ClientId = "",
// ClientSecret = "",
// Provider = new SalesforceAuthenticationProvider()
// {
// OnAuthenticated = async context =>
// {
// System.Diagnostics.Debug.WriteLine(context.AccessToken);
// System.Diagnostics.Debug.WriteLine(context.RefreshToken);
// System.Diagnostics.Debug.WriteLine(context.OrganizationId);
// }
// }
//};
//app.UseSalesforceAuthentication(salesforceOptions);
////app.UseShopifyAuthentication("", "");
////app.UseShopifyAuthentication("", "");
//app.UseArcGISOnlineAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseArcGISOnlineAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseWordPressAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseWordPressAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseDropboxAuthentication(
// appKey: "",
// appSecret: "");
//app.UseDropboxAuthentication(
// appKey: "",
// appSecret: "");
//app.UseHealthGraphAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseHealthGraphAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseBattleNetAuthentication(new BattleNetAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = ""
//});
//app.UseBattleNetAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseBoxAuthentication(
// appKey: "",
// appSecret: "");
//app.UseAsanaAuthentication("", "");
//app.UseBaiduAuthentication(
// apiKey: "",
// secretKey: "");
//app.UseEveOnlineAuthentication("", "");
//app.UseBattleNetAuthentication(new BattleNetAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = ""
//});
//app.UseBattleNetAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseSoundCloudAuthentication("", "");
//app.UseAsanaAuthentication("", "");
//app.UseFoursquareAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseEveOnlineAuthentication("", "");
//app.UsePayPalAuthentication(
// clientId: "",
// clientSecret: "",
// isSandbox: false);
//app.UseSoundCloudAuthentication("", "");
//app.UseWargamingAccountAuthentication("", WargamingAuthenticationOptions.Region.NorthAmerica);
//app.UseFoursquareAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseFlickrAuthentication("", "");
//app.UseVisualStudioAuthentication(
// appId: "",
// appSecret: "");
//app.UsePayPalAuthentication(
// clientId: "",
// clientSecret: "",
// isSandbox: false);
//app.UseSpotifyAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseWargamingAccountAuthentication("", WargamingAuthenticationOptions.Region.NorthAmerica);
//var options = new SlackAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// TeamId = "" // optional
//};
//options.Scope.Add("identify");
//app.UseSlackAuthentication(options);
//app.UseFlickrAuthentication("", "");
//app.UseVisualStudioAuthentication(
// appId: "",
// appSecret: "");
//app.UseGitterAuthentication(
// clientId: "",
// clientSecret: ""
//);
//app.UseSpotifyAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseImgurAuthentication(
// new ImgurAuthenticationOptions
// {
// ClientId = "",
// ClientSecret = ""
// });
//var options = new SlackAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// TeamId = "" // optional
//};
//options.Scope.Add("identify");
//app.UseSlackAuthentication(options);
//var options = new BacklogAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// ContractName = "",
// CallbackPath = new PathString(""), // ex.new PathString("/OauthTokenRequest")
// Provider = new BacklogAuthenticationProvider
// {
// OnAuthenticated = async context => await System.Threading.Tasks.Task.Run(()=> { System.Diagnostics.Debug.WriteLine(String.Format("Refresh Token: {0}", context.RefreshToken)); })
// }
//};
//app.UseGitterAuthentication(
// clientId: "",
// clientSecret: ""
//);
//app.UseBacklogAuthentication(options);
//app.UseImgurAuthentication(
// new ImgurAuthenticationOptions
// {
// ClientId = "",
// ClientSecret = ""
// });
//var cosignOptions = new CosignAuthenticationOptions
//{
// AuthenticationType = "Cosign",
// SignInAsAuthenticationType = signInAsType,
// CosignServer = "weblogin.umich.edu",
// CosignServicePort = 6663,
// IdentityServerHostInstance = "core1",
// ClientServer = "cosignservername"
//};
//app.UseCosignAuthentication(cosignOptions);
//var options = new BacklogAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = "",
// ContractName = "",
// CallbackPath = new PathString(""), // ex.new PathString("/OauthTokenRequest")
// Provider = new BacklogAuthenticationProvider
// {
// OnAuthenticated = async context => await System.Threading.Tasks.Task.Run(()=> { System.Diagnostics.Debug.WriteLine(String.Format("Refresh Token: {0}", context.RefreshToken)); })
// }
//};
//app.UseVimeoAuthentication("", "");
//app.UseBacklogAuthentication(options);
//app.UseFitbitAuthentication(new FitbitAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = ""
//});
//var cosignOptions = new CosignAuthenticationOptions
//{
// AuthenticationType = "Cosign",
// SignInAsAuthenticationType = signInAsType,
// CosignServer = "weblogin.umich.edu",
// CosignServicePort = 6663,
// IdentityServerHostInstance = "core1",
// ClientServer = "cosignservername"
//};
//app.UseCosignAuthentication(cosignOptions);
//app.UseOnshapeAuthentication(
// appKey: "",
// appSecret: "");
//
//
//app.UseOnshapeAuthentication(new OnshapeAuthenticationOptions()
//{
// AppKey = "",
// AppSecret = "",
// CallbackPath = new PathString("/oauthRedirect"),
// Hostname = "partner.dev.onshape.com"
//});
//app.UseVimeoAuthentication("", "");
//app.UseVKontakteAuthentication("", "");
//app.UseFitbitAuthentication(new FitbitAuthenticationOptions
//{
// ClientId = "",
// ClientSecret = ""
//});
//app.UseXingAuthentication("", "");
//app.UseOnshapeAuthentication(
// appKey: "",
// appSecret: "");
//
//
//app.UseOnshapeAuthentication(new OnshapeAuthenticationOptions()
//{
// AppKey = "",
// AppSecret = "",
// CallbackPath = new PathString("/oauthRedirect"),
// Hostname = "partner.dev.onshape.com"
//});
//app.UseDoYouBuzzAuthentication("", "");
//app.("", "");
//app.UseOrcidAuthentication("","");
//app.UseVKontakteAuthentication("", "");
//app.UseDiscordAuthentication("", "");
//app.UseGeniAuthentication("", "");
//app.UseMyHeritageAuthentication("", "");
}
}
//app.UseXingAuthentication("", "");
//app.UseDoYouBuzzAuthentication("", "");
//app.("", "");
//app.UseOrcidAuthentication("","");
//app.UseDiscordAuthentication("", "");
//app.UseGeniAuthentication("", "");
//app.UseMyHeritageAuthentication("", "");
//app.UseWSO2Authentication("", "", "");
}
}
}

View File

@@ -52,7 +52,9 @@ Provides a set of extra authentication providers for OWIN ([Project Katana](http
- Wargaming
## Implementation Guides
For above listed provider implementation guide, visit Jerrie Pelser's blog - [oauthforaspnet](http://www.oauthforaspnet.com)
Take a look at the [samples project](https://github.com/TerribleDev/OwinOAuthProviders/blob/master/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs#L39).
## Installation
@@ -84,7 +86,7 @@ A big thanks goes out to all these contributors without whom this would not have
* Ben Foster (https://github.com/benfoster)
* Jonathan Peterson (https://github.com/eonasdan)
For most accurate and up to date list of contributors please see https://github.com/RockstarLabs/OwinOAuthProviders/graphs/contributors
For most accurate and up to date list of contributors please see https://github.com/TerribleDev/OwinOAuthProviders/graphs/contributors
## License

View File

@@ -15,7 +15,7 @@ PACKAGES = File.expand_path("packages")
TOOLS = File.expand_path("tools")
NUGET = File.expand_path("#{TOOLS}/nuget")
NUGET_EXE = File.expand_path("#{TOOLS}/nuget/nuget.exe")
@version = "2.8.0"
@version = "2.12.0"
PROJECTS = Dir.glob('src/*').select{|dir| File.directory? dir }
desc 'Retrieve things'

View File

@@ -16,9 +16,7 @@
There are many individual providers, this package is a meta package that has a dependency on all of them.
</summary>
<releaseNotes>
Version 2.3
- Added Geni, and discord providers.
- Retarget to .net 4.5 from 4.5.2
View the release notes on github
</releaseNotes>
<copyright>Copyright 2013 - 2016</copyright>
<tags>owin katana oauth LinkedIn Yahoo Google+ GitHub Reddit Instagram StackExchange SalesForce TripIt Buffer ArcGIS Dropbox Wordpress Battle.NET Yammer OpenID Steam Twitch</tags>

View File

@@ -19,11 +19,9 @@
Also adds generic OpenID 2.0 providers as well implementations for Steam and Wargaming.
</summary>
<releaseNotes>
Version 2.3
- Added Geni, and discord providers.
- Retarget to .net 4.5 from 4.5.2
View the release notes on github
</releaseNotes>
<copyright>Copyright 2013 - 2016</copyright>
<tags>owin katana oauth LinkedIn Yahoo Google+ GitHub Reddit Instagram StackExchange SalesForce TripIt Buffer ArcGIS Dropbox Wordpress Battle.NET Yammer OpenID Steam Twitch</tags>
<tags>owin katana oauth LinkedIn Yahoo Google+ GitHub Reddit Instagram StackExchange SalesForce TripIt Buffer ArcGIS Dropbox Wordpress Battle.NET Yammer OpenID Steam Twitch Box Baidu</tags>
</metadata>
</package>

View File

@@ -0,0 +1,29 @@
using System;
namespace Owin.Security.Providers.Baidu
{
public static class BaiduAuthenticationExtensions
{
public static IAppBuilder UseBaiduAuthentication(this IAppBuilder app,
BaiduAuthenticationOptions options)
{
if (app == null)
throw new ArgumentNullException(nameof(app));
if (options == null)
throw new ArgumentNullException(nameof(options));
app.Use(typeof(BaiduAuthenticationMiddleware), app, options);
return app;
}
public static IAppBuilder UseBaiduAuthentication(this IAppBuilder app, string apiKey, string secretKey)
{
return app.UseBaiduAuthentication(new BaiduAuthenticationOptions
{
ApiKey = apiKey,
SecretKey = secretKey
});
}
}
}

View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
namespace Owin.Security.Providers.Baidu
{
public class BaiduAuthenticationHandler : AuthenticationHandler<BaiduAuthenticationOptions>
{
private const string StateCookie = "_BaiduState";
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string TokenEndpoint = "https://openapi.baidu.com/oauth/2.0/token";
private const string UserInfoEndpoint = "https://openapi.baidu.com/rest/2.0/passport/users/getInfo";
private const string AuthEndpoint = "http://openapi.baidu.com/oauth/2.0/authorize";
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public BaiduAuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
string code = null;
var query = Request.Query;
var values = query.GetValues("code");
if (values != null && values.Count == 1)
{
code = values[0];
}
var state = Request.Cookies[StateCookie];
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
return null;
}
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
// Check for error
if (Request.Query.Get("error") != null)
return new AuthenticationTicket(null, properties);
var requestPrefix = Request.Scheme + "://" + Request.Host;
var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirectUri),
new KeyValuePair<string, string>("client_id", Options.ApiKey),
new KeyValuePair<string, string>("client_secret", Options.SecretKey)
};
// Request the token
var tokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
tokenResponse.EnsureSuccessStatusCode();
var text = await tokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
// Get the Baidu user
// http://developer.baidu.com/wiki/index.php?title=docs/oauth/rest/file_data_apis_list#.E8.BF.94.E5.9B.9E.E7.94.A8.E6.88.B7.E8.AF.A6.E7.BB.86.E8.B5.84.E6.96.99
var userResponse = await _httpClient.GetAsync(
UserInfoEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled);
userResponse.EnsureSuccessStatusCode();
text = await userResponse.Content.ReadAsStringAsync();
var user = JObject.Parse(text);
var context = new BaiduAuthenticatedContext(Context, user, accessToken)
{
Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType)
};
if (!string.IsNullOrEmpty(context.Userid))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Userid, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.UserName))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName, XmlSchemaString, Options.AuthenticationType));
}
context.Properties = properties;
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
}
return new AuthenticationTicket(null, properties);
}
protected override Task ApplyResponseChallengeAsync()
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge == null) return Task.FromResult<object>(null);
var baseUri =
Request.Scheme +
Uri.SchemeDelimiter +
Request.Host +
Request.PathBase;
var currentUri =
baseUri +
Request.Path +
Request.QueryString;
var redirectUri =
baseUri +
Options.CallbackPath;
var properties = challenge.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
// comma separated
var scope = string.Join(" ", Options.Scope);
var state = Options.StateDataFormat.Protect(properties);
var authorizationEndpoint =
AuthEndpoint +
"?response_type=code" +
"&client_id=" + Uri.EscapeDataString(Options.ApiKey) +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
"&scope=" + Uri.EscapeDataString(scope) +
"&state=" + Uri.EscapeDataString(state);
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Secure = Request.IsSecure
};
Response.StatusCode = 302;
Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(properties), cookieOptions);
Response.Headers.Set("Location", authorizationEndpoint);
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
if (!Options.CallbackPath.HasValue || Options.CallbackPath != Request.Path) return false;
// TODO: error responses
var ticket = await AuthenticateAsync();
if (ticket == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new BaiduReturnEndpointContext(Context, ticket)
{
SignInAsAuthenticationType = Options.SignInAsAuthenticationType,
RedirectUri = ticket.Properties.RedirectUri
};
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null &&
context.Identity != null)
{
var grantIdentity = context.Identity;
if (!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, grantIdentity);
}
if (context.IsRequestCompleted || context.RedirectUri == null) return context.IsRequestCompleted;
var redirectUri = context.RedirectUri;
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied");
}
Response.Redirect(redirectUri);
context.RequestCompleted();
return context.IsRequestCompleted;
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Globalization;
using System.Net.Http;
using Microsoft.Owin;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler;
using Microsoft.Owin.Security.DataProtection;
using Microsoft.Owin.Security.Infrastructure;
namespace Owin.Security.Providers.Baidu
{
public class BaiduAuthenticationMiddleware : AuthenticationMiddleware<BaiduAuthenticationOptions>
{
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public BaiduAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app,
BaiduAuthenticationOptions options)
: base(next, options)
{
if (string.IsNullOrWhiteSpace(Options.ApiKey))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Resources.Exception_OptionMustBeProvided, nameof(Options.ApiKey)));
if (string.IsNullOrWhiteSpace(Options.SecretKey))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Resources.Exception_OptionMustBeProvided, nameof(Options.SecretKey)));
_logger = app.CreateLogger<BaiduAuthenticationMiddleware>();
if (Options.Provider == null)
Options.Provider = new BaiduAuthenticationProvider();
if (Options.StateDataFormat == null)
{
var dataProtector = app.CreateDataProtector(
typeof (BaiduAuthenticationMiddleware).FullName,
Options.AuthenticationType, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
_httpClient = new HttpClient(ResolveHttpMessageHandler(Options))
{
Timeout = Options.BackchannelTimeout,
MaxResponseContentBufferSize = 1024*1024*10
};
}
/// <summary>
/// Provides the <see cref="T:Microsoft.Owin.Security.Infrastructure.AuthenticationHandler" /> object for processing
/// authentication-related requests.
/// </summary>
/// <returns>
/// An <see cref="T:Microsoft.Owin.Security.Infrastructure.AuthenticationHandler" /> configured with the
/// <see cref="T:Owin.Security.Providers.Baidu.BaiduAuthenticationOptions" /> supplied to the constructor.
/// </returns>
protected override AuthenticationHandler<BaiduAuthenticationOptions> CreateHandler()
{
return new BaiduAuthenticationHandler(_httpClient, _logger);
}
private static HttpMessageHandler ResolveHttpMessageHandler(BaiduAuthenticationOptions options)
{
var handler = options.BackchannelHttpHandler ?? new WebRequestHandler();
// If they provided a validator, apply it or fail.
if (options.BackchannelCertificateValidator == null) return handler;
// Set the cert validate callback
var webRequestHandler = handler as WebRequestHandler;
if (webRequestHandler == null)
{
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
}
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
return handler;
}
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Net.Http;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using System.Collections.Generic;
namespace Owin.Security.Providers.Baidu
{
public class BaiduAuthenticationOptions : AuthenticationOptions
{
/// <summary>
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
/// in back channel communications belong to Baidu
/// </summary>
/// <value>
/// The pinned certificate validator.
/// </value>
/// <remarks>
/// If this property is null then the default certificate checks are performed,
/// validating the subject name and if the signing chain is a trusted party.
/// </remarks>
public ICertificateValidator BackchannelCertificateValidator { get; set; }
/// <summary>
/// The HttpMessageHandler used to communicate with Baidu.
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
/// can be downcast to a WebRequestHandler.
/// </summary>
public HttpMessageHandler BackchannelHttpHandler { get; set; }
/// <summary>
/// Gets or sets timeout value in milliseconds for back channel communications with Baidu.
/// </summary>
/// <value>
/// The back channel timeout in milliseconds.
/// </value>
public TimeSpan BackchannelTimeout { get; set; }
/// <summary>
/// The request path within the application's base path where the user-agent will be returned.
/// The middleware will process this request when it arrives.
/// Default value is "/signin-dropbox".
/// </summary>
public PathString CallbackPath { get; set; }
/// <summary>
/// Get or sets the text that the user can display on a sign in user interface.
/// </summary>
public string Caption
{
get { return Description.Caption; }
set { Description.Caption = value; }
}
/// <summary>
/// Gets or sets the Baidu supplied API Key
/// </summary>
public string ApiKey { get; set; }
/// <summary>
/// Gets or sets the Baidu supplied Secret Key
/// </summary>
public string SecretKey { get; set; }
/// <summary>
/// A list of permissions to request.
/// </summary>
public IList<string> Scope { get; private set; }
/// <summary>
/// Gets or sets the <see cref="IBaiduAuthenticationProvider" /> used in the authentication events
/// </summary>
public IBaiduAuthenticationProvider Provider { get; set; }
/// <summary>
/// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user
/// <see cref="System.Security.Claims.ClaimsIdentity" />.
/// </summary>
public string SignInAsAuthenticationType { get; set; }
/// <summary>
/// Gets or sets the type used to secure data handled by the middleware.
/// </summary>
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
/// <summary>
/// Initializes a new <see cref="BaiduAuthenticationOptions" />
/// </summary>
public BaiduAuthenticationOptions()
: base("Baidu")
{
Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-baidu");
AuthenticationMode = AuthenticationMode.Passive;
Scope = new List<string>
{
"basic"
};
BackchannelTimeout = TimeSpan.FromSeconds(60);
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Owin.Security.Providers.Baidu
{
internal static class Constants
{
public const string DefaultAuthenticationType = "Baidu";
}
}

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E2759807-4D7C-4288-AAC8-F5B7B4616680}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Owin.Security.Providers.Baidu</RootNamespace>
<AssemblyName>Owin.Security.Providers.Baidu</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Constants.cs" />
<Compile Include="BaiduAuthenticationExtensions.cs" />
<Compile Include="BaiduAuthenticationHandler.cs" />
<Compile Include="BaiduAuthenticationMiddleware.cs" />
<Compile Include="BaiduAuthenticationOptions.cs" />
<Compile Include="Provider\BaiduAuthenticatedContext.cs" />
<Compile Include="Provider\BaiduAuthenticationProvider.cs" />
<Compile Include="Provider\BaiduReturnEndpointContext.cs" />
<Compile Include="Provider\IBaiduAuthenticationProvider.cs" />
<Compile Include="Resources.Designer.cs">
<DependentUpon>Resources.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity>
<ItemGroup>
<VersionNumber Include="@(Targets->'%(Version)')" />
</ItemGroup>
</Target>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
PostBuildMacros;
</PostBuildEventDependsOn>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Owin.Security.Providers.Baidu")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Owin.Security.Providers.Baidu")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("AD2018C1-FA82-4DC3-8CD4-BCC4D232A678")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]

View File

@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Security.Claims;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
using Newtonsoft.Json.Linq;
namespace Owin.Security.Providers.Baidu
{
/// <summary>
/// Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.
/// </summary>
public class BaiduAuthenticatedContext : BaseContext
{
/// <summary>
/// Initializes a <see cref="BaiduAuthenticatedContext"/>
/// </summary>
/// <param name="context">The OWIN environment</param>
/// <param name="user">The JSON-serialized user</param>
/// <param name="accessToken">Baidu Access token</param>
public BaiduAuthenticatedContext(IOwinContext context, JObject user, string accessToken)
: base(context)
{
AccessToken = accessToken;
User = user;
Userid = TryGetValue(user, "userid");
UserName = TryGetValue(user, "username");
RealName = TryGetValue(user, "realname");
}
/// <summary>
/// Gets the JSON-serialized user
/// </summary>
/// <remarks>
/// Contains the Baidu user obtained from the endpoint https://api.dropbox.com/1/account/info
/// </remarks>
public JObject User { get; private set; }
/// <summary>
/// Gets the Baidu OAuth access token
/// </summary>
public string AccessToken { get; private set; }
/// <summary>
/// Gets the Baidu user ID
/// </summary>
public string Userid { get; private set; }
/// <summary>
/// The name of the user
/// </summary>
public string UserName { get; private set; }
/// <summary>
/// The real name of the user
/// </summary>
public string RealName { get; private set; }
/// <summary>
/// Gets the <see cref="ClaimsIdentity"/> representing the user
/// </summary>
public ClaimsIdentity Identity { get; set; }
/// <summary>
/// Gets or sets a property bag for common authentication properties
/// </summary>
public AuthenticationProperties Properties { get; set; }
private static string TryGetValue(JObject user, string propertyName)
{
JToken value;
return user.TryGetValue(propertyName, out value) ? value.ToString() : null;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
namespace Owin.Security.Providers.Baidu
{
/// <summary>
/// Default <see cref="IBaiduAuthenticationProvider"/> implementation.
/// </summary>
public class BaiduAuthenticationProvider : IBaiduAuthenticationProvider
{
/// <summary>
/// Initializes a <see cref="BaiduAuthenticationProvider"/>
/// </summary>
public BaiduAuthenticationProvider()
{
OnAuthenticated = context => Task.FromResult<object>(null);
OnReturnEndpoint = context => Task.FromResult<object>(null);
}
/// <summary>
/// Gets or sets the function that is invoked when the Authenticated method is invoked.
/// </summary>
public Func<BaiduAuthenticatedContext, Task> OnAuthenticated { get; set; }
/// <summary>
/// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked.
/// </summary>
public Func<BaiduReturnEndpointContext, Task> OnReturnEndpoint { get; set; }
/// <summary>
/// Invoked whenever Baidu successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task Authenticated(BaiduAuthenticatedContext context)
{
return OnAuthenticated(context);
}
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task ReturnEndpoint(BaiduReturnEndpointContext context)
{
return OnReturnEndpoint(context);
}
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
namespace Owin.Security.Providers.Baidu
{
/// <summary>
/// Provides context information to middleware providers.
/// </summary>
public class BaiduReturnEndpointContext : ReturnEndpointContext
{
/// <summary>
///
/// </summary>
/// <param name="context">OWIN environment</param>
/// <param name="ticket">The authentication ticket</param>
public BaiduReturnEndpointContext(
IOwinContext context,
AuthenticationTicket ticket)
: base(context, ticket)
{
}
}
}

View File

@@ -0,0 +1,24 @@
using System.Threading.Tasks;
namespace Owin.Security.Providers.Baidu
{
/// <summary>
/// Specifies callback methods which the <see cref="BaiduAuthenticationMiddleware"></see> invokes to enable developer control over the authentication process. />
/// </summary>
public interface IBaiduAuthenticationProvider
{
/// <summary>
/// Invoked whenever Baidu successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task Authenticated(BaiduAuthenticatedContext context);
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task ReturnEndpoint(BaiduReturnEndpointContext context);
}
}

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Owin.Security.Providers.Baidu {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Owin.Security.Providers.Baidu.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; option must be provided..
/// </summary>
internal static string Exception_OptionMustBeProvided {
get {
return ResourceManager.GetString("Exception_OptionMustBeProvided", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler..
/// </summary>
internal static string Exception_ValidatorHandlerMismatch {
get {
return ResourceManager.GetString("Exception_ValidatorHandlerMismatch", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Exception_OptionMustBeProvided" xml:space="preserve">
<value>The '{0}' option must be provided.</value>
</data>
<data name="Exception_ValidatorHandlerMismatch" xml:space="preserve">
<value>An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.</value>
</data>
</root>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
</packages>

View File

@@ -0,0 +1,29 @@
using System;
namespace Owin.Security.Providers.Box
{
public static class BoxAuthenticationExtensions
{
public static IAppBuilder UseBoxAuthentication(this IAppBuilder app,
BoxAuthenticationOptions options)
{
if (app == null)
throw new ArgumentNullException(nameof(app));
if (options == null)
throw new ArgumentNullException(nameof(options));
app.Use(typeof(BoxAuthenticationMiddleware), app, options);
return app;
}
public static IAppBuilder UseBoxAuthentication(this IAppBuilder app, string appKey, string appSecret)
{
return app.UseBoxAuthentication(new BoxAuthenticationOptions
{
ClientId = appKey,
ClientSecret = appSecret
});
}
}
}

View File

@@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
namespace Owin.Security.Providers.Box
{
public class BoxAuthenticationHandler : AuthenticationHandler<BoxAuthenticationOptions>
{
private const string StateCookie = "_BoxState";
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string TokenEndpoint = "https://api.box.com/oauth2/token";
private const string UserInfoEndpoint = "https://api.box.com/2.0/users/me";
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public BoxAuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
string code = null;
var query = Request.Query;
var values = query.GetValues("code");
if (values != null && values.Count == 1)
{
code = values[0];
}
var state = Request.Cookies[StateCookie];
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
return null;
}
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
// Check for error
if (Request.Query.Get("error") != null)
return new AuthenticationTicket(null, properties);
var requestPrefix = Request.Scheme + "://" + Request.Host;
var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirectUri),
new KeyValuePair<string, string>("client_id", Options.ClientId),
new KeyValuePair<string, string>("client_secret", Options.ClientSecret)
};
// Request the token
var tokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
tokenResponse.EnsureSuccessStatusCode();
var text = await tokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
// Get the Box user
// https://docs.box.com/reference#get-the-current-users-information
var userRequest = new HttpRequestMessage(HttpMethod.Get, UserInfoEndpoint);
userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var userResponse = await _httpClient.SendAsync(userRequest, Request.CallCancelled);
userResponse.EnsureSuccessStatusCode();
text = await userResponse.Content.ReadAsStringAsync();
var user = JObject.Parse(text);
var context = new BoxAuthenticatedContext(Context, user, accessToken)
{
Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType)
};
if (!string.IsNullOrEmpty(context.Id))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Name))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Name, XmlSchemaString, Options.AuthenticationType));
}
context.Properties = properties;
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
}
return new AuthenticationTicket(null, properties);
}
protected override Task ApplyResponseChallengeAsync()
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge == null) return Task.FromResult<object>(null);
var baseUri =
Request.Scheme +
Uri.SchemeDelimiter +
Request.Host +
Request.PathBase;
var currentUri =
baseUri +
Request.Path +
Request.QueryString;
var redirectUri =
baseUri +
Options.CallbackPath;
var properties = challenge.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
var authorizationEndpoint =
"https://api.box.com/oauth2/authorize" +
"?response_type=code" +
"&client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&state=authenticated" +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri);
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Secure = Request.IsSecure
};
Response.StatusCode = 302;
Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(properties), cookieOptions);
Response.Headers.Set("Location", authorizationEndpoint);
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
if (!Options.CallbackPath.HasValue || Options.CallbackPath != Request.Path) return false;
// TODO: error responses
var ticket = await AuthenticateAsync();
if (ticket == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new BoxReturnEndpointContext(Context, ticket)
{
SignInAsAuthenticationType = Options.SignInAsAuthenticationType,
RedirectUri = ticket.Properties.RedirectUri
};
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null &&
context.Identity != null)
{
var grantIdentity = context.Identity;
if (!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, grantIdentity);
}
if (context.IsRequestCompleted || context.RedirectUri == null) return context.IsRequestCompleted;
var redirectUri = context.RedirectUri;
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied");
}
Response.Redirect(redirectUri);
context.RequestCompleted();
return context.IsRequestCompleted;
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Globalization;
using System.Net.Http;
using Microsoft.Owin;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler;
using Microsoft.Owin.Security.DataProtection;
using Microsoft.Owin.Security.Infrastructure;
namespace Owin.Security.Providers.Box
{
public class BoxAuthenticationMiddleware : AuthenticationMiddleware<BoxAuthenticationOptions>
{
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public BoxAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app,
BoxAuthenticationOptions options)
: base(next, options)
{
if (string.IsNullOrWhiteSpace(Options.ClientId))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Resources.Exception_OptionMustBeProvided, nameof(Options.ClientId)));
if (string.IsNullOrWhiteSpace(Options.ClientSecret))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Resources.Exception_OptionMustBeProvided, nameof(Options.ClientSecret)));
_logger = app.CreateLogger<BoxAuthenticationMiddleware>();
if (Options.Provider == null)
Options.Provider = new BoxAuthenticationProvider();
if (Options.StateDataFormat == null)
{
var dataProtector = app.CreateDataProtector(
typeof (BoxAuthenticationMiddleware).FullName,
Options.AuthenticationType, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
_httpClient = new HttpClient(ResolveHttpMessageHandler(Options))
{
Timeout = Options.BackchannelTimeout,
MaxResponseContentBufferSize = 1024*1024*10
};
}
/// <summary>
/// Provides the <see cref="T:Microsoft.Owin.Security.Infrastructure.AuthenticationHandler" /> object for processing
/// authentication-related requests.
/// </summary>
/// <returns>
/// An <see cref="T:Microsoft.Owin.Security.Infrastructure.AuthenticationHandler" /> configured with the
/// <see cref="T:Owin.Security.Providers.Box.BoxAuthenticationOptions" /> supplied to the constructor.
/// </returns>
protected override AuthenticationHandler<BoxAuthenticationOptions> CreateHandler()
{
return new BoxAuthenticationHandler(_httpClient, _logger);
}
private static HttpMessageHandler ResolveHttpMessageHandler(BoxAuthenticationOptions options)
{
var handler = options.BackchannelHttpHandler ?? new WebRequestHandler();
// If they provided a validator, apply it or fail.
if (options.BackchannelCertificateValidator == null) return handler;
// Set the cert validate callback
var webRequestHandler = handler as WebRequestHandler;
if (webRequestHandler == null)
{
throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch);
}
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
return handler;
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Net.Http;
using Microsoft.Owin;
using Microsoft.Owin.Security;
namespace Owin.Security.Providers.Box
{
public class BoxAuthenticationOptions : AuthenticationOptions
{
/// <summary>
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
/// in back channel communications belong to Box
/// </summary>
/// <value>
/// The pinned certificate validator.
/// </value>
/// <remarks>
/// If this property is null then the default certificate checks are performed,
/// validating the subject name and if the signing chain is a trusted party.
/// </remarks>
public ICertificateValidator BackchannelCertificateValidator { get; set; }
/// <summary>
/// The HttpMessageHandler used to communicate with Box.
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
/// can be downcast to a WebRequestHandler.
/// </summary>
public HttpMessageHandler BackchannelHttpHandler { get; set; }
/// <summary>
/// Gets or sets timeout value in milliseconds for back channel communications with Box.
/// </summary>
/// <value>
/// The back channel timeout in milliseconds.
/// </value>
public TimeSpan BackchannelTimeout { get; set; }
/// <summary>
/// The request path within the application's base path where the user-agent will be returned.
/// The middleware will process this request when it arrives.
/// Default value is "/signin-box".
/// </summary>
public PathString CallbackPath { get; set; }
/// <summary>
/// Get or sets the text that the user can display on a sign in user interface.
/// </summary>
public string Caption
{
get { return Description.Caption; }
set { Description.Caption = value; }
}
/// <summary>
/// Gets or sets the Box supplied Client ID
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// Gets or sets the Box supplied Client Secret
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Gets or sets the <see cref="IBoxAuthenticationProvider" /> used in the authentication events
/// </summary>
public IBoxAuthenticationProvider Provider { get; set; }
/// <summary>
/// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user
/// <see cref="System.Security.Claims.ClaimsIdentity" />.
/// </summary>
public string SignInAsAuthenticationType { get; set; }
/// <summary>
/// Gets or sets the type used to secure data handled by the middleware.
/// </summary>
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
/// <summary>
/// Initializes a new <see cref="BoxAuthenticationOptions" />
/// </summary>
public BoxAuthenticationOptions()
: base("Box")
{
Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-box");
AuthenticationMode = AuthenticationMode.Passive;
BackchannelTimeout = TimeSpan.FromSeconds(60);
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Owin.Security.Providers.Box
{
internal static class Constants
{
public const string DefaultAuthenticationType = "Box";
}
}

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1AEF8813-E1F9-41E1-BC8D-732960595E9F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Owin.Security.Providers.Box</RootNamespace>
<AssemblyName>Owin.Security.Providers.Box</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Constants.cs" />
<Compile Include="BoxAuthenticationExtensions.cs" />
<Compile Include="BoxAuthenticationHandler.cs" />
<Compile Include="BoxAuthenticationMiddleware.cs" />
<Compile Include="BoxAuthenticationOptions.cs" />
<Compile Include="Provider\BoxAuthenticatedContext.cs" />
<Compile Include="Provider\BoxAuthenticationProvider.cs" />
<Compile Include="Provider\BoxReturnEndpointContext.cs" />
<Compile Include="Provider\IBoxAuthenticationProvider.cs" />
<Compile Include="Resources.Designer.cs">
<DependentUpon>Resources.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity>
<ItemGroup>
<VersionNumber Include="@(Targets->'%(Version)')" />
</ItemGroup>
</Target>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
PostBuildMacros;
</PostBuildEventDependsOn>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Owin.Security.Providers.Box")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Owin.Security.Providers.Box")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("1242F9A5-AEF8-44F8-A255-F0D24DAE0A2C")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]

View File

@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Security.Claims;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
using Newtonsoft.Json.Linq;
namespace Owin.Security.Providers.Box
{
/// <summary>
/// Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.
/// </summary>
public class BoxAuthenticatedContext : BaseContext
{
/// <summary>
/// Initializes a <see cref="BoxAuthenticatedContext"/>
/// </summary>
/// <param name="context">The OWIN environment</param>
/// <param name="user">The JSON-serialized user</param>
/// <param name="accessToken">Box Access token</param>
public BoxAuthenticatedContext(IOwinContext context, JObject user, string accessToken)
: base(context)
{
AccessToken = accessToken;
User = user;
Id = TryGetValue(user, "id");
Name = TryGetValue(user, "name");
Login = TryGetValue(user, "login");
}
/// <summary>
/// Gets the JSON-serialized user
/// </summary>
/// <remarks>
/// Contains the Box user obtained from the endpoint https://api.box.com/2.0/users/me
/// </remarks>
public JObject User { get; private set; }
/// <summary>
/// Gets the Box OAuth access token
/// </summary>
public string AccessToken { get; private set; }
/// <summary>
/// Gets the Box user ID
/// </summary>
public string Id { get; private set; }
/// <summary>
/// The name of the user
/// </summary>
public string Name { get; private set; }
/// <summary>
/// The login of the user
/// </summary>
public string Login { get; private set; }
/// <summary>
/// Gets the <see cref="ClaimsIdentity"/> representing the user
/// </summary>
public ClaimsIdentity Identity { get; set; }
/// <summary>
/// Gets or sets a property bag for common authentication properties
/// </summary>
public AuthenticationProperties Properties { get; set; }
private static string TryGetValue(JObject user, string propertyName)
{
JToken value;
return user.TryGetValue(propertyName, out value) ? value.ToString() : null;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
namespace Owin.Security.Providers.Box
{
/// <summary>
/// Default <see cref="IBoxAuthenticationProvider"/> implementation.
/// </summary>
public class BoxAuthenticationProvider : IBoxAuthenticationProvider
{
/// <summary>
/// Initializes a <see cref="BoxAuthenticationProvider"/>
/// </summary>
public BoxAuthenticationProvider()
{
OnAuthenticated = context => Task.FromResult<object>(null);
OnReturnEndpoint = context => Task.FromResult<object>(null);
}
/// <summary>
/// Gets or sets the function that is invoked when the Authenticated method is invoked.
/// </summary>
public Func<BoxAuthenticatedContext, Task> OnAuthenticated { get; set; }
/// <summary>
/// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked.
/// </summary>
public Func<BoxReturnEndpointContext, Task> OnReturnEndpoint { get; set; }
/// <summary>
/// Invoked whenever Box successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task Authenticated(BoxAuthenticatedContext context)
{
return OnAuthenticated(context);
}
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task ReturnEndpoint(BoxReturnEndpointContext context)
{
return OnReturnEndpoint(context);
}
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
namespace Owin.Security.Providers.Box
{
/// <summary>
/// Provides context information to middleware providers.
/// </summary>
public class BoxReturnEndpointContext : ReturnEndpointContext
{
/// <summary>
///
/// </summary>
/// <param name="context">OWIN environment</param>
/// <param name="ticket">The authentication ticket</param>
public BoxReturnEndpointContext(
IOwinContext context,
AuthenticationTicket ticket)
: base(context, ticket)
{
}
}
}

View File

@@ -0,0 +1,24 @@
using System.Threading.Tasks;
namespace Owin.Security.Providers.Box
{
/// <summary>
/// Specifies callback methods which the <see cref="BoxAuthenticationMiddleware"></see> invokes to enable developer control over the authentication process. />
/// </summary>
public interface IBoxAuthenticationProvider
{
/// <summary>
/// Invoked whenever Box successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task Authenticated(BoxAuthenticatedContext context);
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task ReturnEndpoint(BoxReturnEndpointContext context);
}
}

View File

@@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Owin.Security.Providers.Box {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Owin.Security.Providers.Box.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to The &apos;{0}&apos; option must be provided..
/// </summary>
internal static string Exception_OptionMustBeProvided {
get {
return ResourceManager.GetString("Exception_OptionMustBeProvided", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler..
/// </summary>
internal static string Exception_ValidatorHandlerMismatch {
get {
return ResourceManager.GetString("Exception_ValidatorHandlerMismatch", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Exception_OptionMustBeProvided" xml:space="preserve">
<value>The '{0}' option must be provided.</value>
</data>
<data name="Exception_ValidatorHandlerMismatch" xml:space="preserve">
<value>An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.</value>
</data>
</root>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
</packages>

View File

@@ -213,7 +213,11 @@ namespace Owin.Security.Providers.LinkedIn
"&scope=" + Uri.EscapeDataString(scope) +
"&state=" + Uri.EscapeDataString(state);
Response.Redirect(authorizationEndpoint);
var redirectContext = new LinkedInApplyRedirectContext(
Context, Options,
properties, authorizationEndpoint);
Options.Provider.ApplyRedirect(redirectContext);
return Task.FromResult<object>(null);
}

View File

@@ -64,6 +64,7 @@
<Compile Include="LinkedInAuthenticationMiddleware.cs" />
<Compile Include="LinkedInAuthenticationOptions.cs" />
<Compile Include="Provider\ILinkedInAuthenticationProvider.cs" />
<Compile Include="Provider\LinkedInApplyRedirectContext.cs" />
<Compile Include="Provider\LinkedInAuthenticatedContext.cs" />
<Compile Include="Provider\LinkedInAuthenticationProvider.cs" />
<Compile Include="Provider\LinkedInReturnEndpointContext.cs" />

View File

@@ -20,5 +20,11 @@ namespace Owin.Security.Providers.LinkedIn
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task ReturnEndpoint(LinkedInReturnEndpointContext context);
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the LinkedIn middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="AuthenticationProperties"/> of the challenge </param>
void ApplyRedirect(LinkedInApplyRedirectContext context);
}
}

View File

@@ -0,0 +1,38 @@
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
namespace Owin.Security.Providers.LinkedIn
{
/// <summary>
/// Context passed when a Challenge causes a redirect to authorize endpoint in the LinkedIn middleware
/// </summary>
public class LinkedInApplyRedirectContext : BaseContext<LinkedInAuthenticationOptions>
{
/// <summary>
/// Creates a new context object.
/// </summary>
/// <param name="context">The OWIN request context</param>
/// <param name="options">The LinkedIn middleware options</param>
/// <param name="properties">The authenticaiton properties of the challenge</param>
/// <param name="redirectUri">The initial redirect URI</param>
public LinkedInApplyRedirectContext(IOwinContext context, LinkedInAuthenticationOptions options,
AuthenticationProperties properties, string redirectUri)
: base(context, options)
{
RedirectUri = redirectUri;
Properties = properties;
}
/// <summary>
/// Gets the URI used for the redirect operation.
/// </summary>
public string RedirectUri { get; private set; }
/// <summary>
/// Gets the authentication properties of the challenge
/// </summary>
public AuthenticationProperties Properties { get; private set; }
}
}

View File

@@ -15,6 +15,8 @@ namespace Owin.Security.Providers.LinkedIn
{
OnAuthenticated = context => Task.FromResult<object>(null);
OnReturnEndpoint = context => Task.FromResult<object>(null);
OnApplyRedirect = context =>
context.Response.Redirect(context.RedirectUri);
}
/// <summary>
@@ -27,6 +29,11 @@ namespace Owin.Security.Providers.LinkedIn
/// </summary>
public Func<LinkedInReturnEndpointContext, Task> OnReturnEndpoint { get; set; }
/// <summary>
/// Gets or sets the delegate that is invoked when the ApplyRedirect method is invoked.
/// </summary>
public Action<LinkedInApplyRedirectContext> OnApplyRedirect { get; set; }
/// <summary>
/// Invoked whenever LinkedIn successfully authenticates a user
/// </summary>
@@ -46,5 +53,14 @@ namespace Owin.Security.Providers.LinkedIn
{
return OnReturnEndpoint(context);
}
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the LinkedIn middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="AuthenticationProperties"/> of the challenge </param>
public virtual void ApplyRedirect(LinkedInApplyRedirectContext context)
{
OnApplyRedirect(context);
}
}
}

View File

@@ -40,6 +40,7 @@ namespace Owin.Security.Providers.Salesforce
LastName = TryGetValue(user, "last_name");
TimeZone = TryGetValue(user, "timezone");
Active = TryGetValue(user, "active");
MobilePhone = TryGetValue(user, "mobile_phone");
}
/// <summary>
@@ -121,6 +122,11 @@ namespace Owin.Security.Providers.Salesforce
/// </summary>
public string Active { get; private set; }
/// <summary>
/// Gets the user's mobile phone number
/// </summary>
public string MobilePhone { get; private set; }
/// <summary>
/// Gets the <see cref="ClaimsIdentity"/> representing the user
/// </summary>

View File

@@ -145,7 +145,7 @@ namespace Owin.Security.Providers.Salesforce
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
_logger.WriteError(ex.Message, ex);
}
return new AuthenticationTicket(null, properties);
}

View File

@@ -123,7 +123,7 @@ namespace Owin.Security.Providers.Salesforce
Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-salesforce");
AuthenticationMode = AuthenticationMode.Passive;
Scope = new List<string>();
Scope = new List<string> { "id" };
BackchannelTimeout = TimeSpan.FromSeconds(60);
Endpoints = new SalesforceAuthenticationEndpoints
{

View File

@@ -95,6 +95,12 @@ namespace Owin.Security.Providers.VKontakte
var user = await GetUser(response, accessToken);
var context = CreateAuthenticatedContext(user, accessToken, properties);
var email = response["email"]?.ToString();
if(!string.IsNullOrWhiteSpace(email))
{
// Email support. VK send it with access_token
context.Identity.AddClaim(new Claim(ClaimTypes.Email, email, XmlSchemaString, Options.AuthenticationType));
}
await Options.Provider.Authenticated(context);
@@ -226,4 +232,4 @@ namespace Owin.Security.Providers.VKontakte
return context.IsRequestCompleted;
}
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Owin.Security.Providers.WSO2
{
internal static class Constants
{
public const string DefaultAuthenticationType = "WSO2";
}
}

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8FD3A9CB-E684-42C0-A8BF-7746FDD3D43C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OWin.Security.Providers.WSO2</RootNamespace>
<AssemblyName>OWin.Security.Providers.WSO2</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Constants.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Provider\IWSO2AuthenticationProvider.cs" />
<Compile Include="Provider\WSO2ApplyRedirectContext.cs" />
<Compile Include="Provider\WSO2AuthenticatedContext.cs" />
<Compile Include="Provider\WSO2AuthenticationProvider.cs" />
<Compile Include="Provider\WSO2ReturnEndPointContext.cs" />
<Compile Include="WSO2AuthenticationExtensions.cs" />
<Compile Include="WSO2AuthenticationHandler.cs" />
<Compile Include="WSO2AuthenticationMiddleware.cs" />
<Compile Include="WSO2AuthenticationOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity>
<ItemGroup>
<VersionNumber Include="@(Targets->'%(Version)')" />
</ItemGroup>
</Target>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
PostBuildMacros;
</PostBuildEventDependsOn>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the follOwing
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Owin.Security.Providers.WSO2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Owin.Security.Providers.WSO2")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The follOwing GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8fd3a9cb-e684-42c0-a8bf-7746fdd3d43c")]
// Version information for an assembly consists of the follOwing four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,17 @@
using System.Threading.Tasks;
namespace Owin.Security.Providers.WSO2
{
public interface IWSO2AuthenticationProvider
{
Task Authenticated(WSO2AuthenticatedContext context);
Task ReturnEndpoint(WSO2ReturnEndpointContext context);
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the wso2 middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="AuthenticationProperties"/> of the challenge </param>
void ApplyRedirect(WSO2ApplyRedirectContext context);
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Owin.Security.Providers.WSO2
{
public class WSO2ApplyRedirectContext : BaseContext<WSO2AuthenticationOptions>
{
/// <summary>
/// Creates a new context object.
/// </summary>
/// <param name="context">The Owin request context</param>
/// <param name="options">The wso2 middleware options</param>
/// <param name="properties">The authenticaiton properties of the challenge</param>
/// <param name="redirectUri">The initial redirect URI</param>
public WSO2ApplyRedirectContext(IOwinContext context, WSO2AuthenticationOptions options,
AuthenticationProperties properties, string redirectUri)
: base(context, options)
{
RedirectUri = redirectUri;
Properties = properties;
}
/// <summary>
/// Gets the URI used for the redirect operation.
/// </summary>
public string RedirectUri { get; private set; }
/// <summary>
/// Gets the authentication properties of the challenge
/// </summary>
public AuthenticationProperties Properties { get; private set; }
}
}

View File

@@ -0,0 +1,48 @@
using Microsoft.Owin.Security.Provider;
using System.Security.Claims;
using Microsoft.Owin;
using Newtonsoft.Json.Linq;
using Microsoft.Owin.Security;
namespace Owin.Security.Providers.WSO2
{
public class WSO2AuthenticatedContext : BaseContext
{
public WSO2AuthenticatedContext(IOwinContext context, JObject user, string accessToken)
: base(context)
{
User = user;
AccessToken = accessToken;
Id = TryGetValue(user, "sub");
}
/// <summary>
/// Gets the WSO2 user
/// </summary>
public JObject User { get; private set; }
public string Id { get; private set;}
/// <summary>
/// Gets the access token
/// </summary>
public string AccessToken { get; private set; }
/// <summary>
/// Gets the <see cref="ClaimsIdentity"/> representing the user
/// </summary>
public ClaimsIdentity Identity { get; set; }
/// <summary>
/// Gets or sets a property bag for common authentication properties
/// </summary>
public AuthenticationProperties Properties { get; set; }
private static string TryGetValue(JObject user, string propertyName)
{
JToken value;
return user.TryGetValue(propertyName, out value) ? value.ToString() : null;
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Threading.Tasks;
namespace Owin.Security.Providers.WSO2
{
public class WSO2AuthenticationProvider : IWSO2AuthenticationProvider
{
public WSO2AuthenticationProvider()
{
OnAuthenticated = context => Task.FromResult<object>(null);
OnReturnEndpoint = context => Task.FromResult<object>(null);
OnApplyRedirect = context =>
context.Response.Redirect(context.RedirectUri);
}
/// <summary>
/// Gets or sets the function that is invoked when the Authenticated method is invoked.
/// </summary>
public Func<WSO2AuthenticatedContext, Task> OnAuthenticated { get; set; }
/// <summary>
/// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked.
/// </summary>
public Func<WSO2ReturnEndpointContext, Task> OnReturnEndpoint { get; set; }
/// <summary>
/// Gets or sets the delegate that is invoked when the ApplyRedirect method is invoked.
/// </summary>
public Action<WSO2ApplyRedirectContext> OnApplyRedirect { get; set; }
/// <summary>
/// Invoked whenever it successfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task Authenticated(WSO2AuthenticatedContext context) {
return OnAuthenticated(context);
}
/// <summary>
/// Invoked prior to the <see cref="System.Security.Claims.ClaimsIdentity"/> being saved in a local cookie and the browser being redirected to the originally requested URL.
/// </summary>
/// <param name="context"></param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
public virtual Task ReturnEndpoint(WSO2ReturnEndpointContext context) {
return OnReturnEndpoint(context);
}
public virtual void ApplyRedirect(WSO2ApplyRedirectContext context)
{
OnApplyRedirect(context);
}
}
}

View File

@@ -0,0 +1,23 @@
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Provider;
namespace Owin.Security.Providers.WSO2
{
/// <summary>
/// Provides context information to middleware providers.
/// </summary>
public class WSO2ReturnEndpointContext : ReturnEndpointContext
{
/// <summary>
///
/// </summary>
/// <param name="context">Owin environment</param>
/// <param name="ticket">The authentication ticket</param>
public WSO2ReturnEndpointContext(
IOwinContext context,
AuthenticationTicket ticket)
: base(context, ticket) {
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
namespace Owin.Security.Providers.WSO2
{
/// <summary>
/// Extension methods for using <see cref="WSO2AuthenticationMiddleware"/>
/// </summary>
public static class WSO2AuthenticationExtensions
{
/// <summary>
/// Authenticate users using WSO2 OAuth 2.0
/// </summary>
/// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
/// <param name="options">Middleware configuration options</param>
/// <returns>The updated <see cref="IAppBuilder"/></returns>
public static IAppBuilder UseWSO2Authentication(this IAppBuilder app, WSO2AuthenticationOptions options)
{
if (app == null)
throw new ArgumentNullException(nameof(app));
if (options == null)
throw new ArgumentNullException(nameof(options));
app.Use(typeof(WSO2AuthenticationMiddleware), app, options);
return app;
}
/// <summary>
/// Authenticate users using WSO2 OAuth 2.0
/// </summary>
/// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param>
/// <param name="baseUrl">The WSO2 Identity Server base url, should be like https://localhost:9443/</param>
/// <param name="clientId">The WSO2 assigned client id</param>
/// <param name="clientSecret">The WSO2 assigned client secret</param>
/// <returns>The updated <see cref="IAppBuilder"/></returns>
public static IAppBuilder UseWSO2Authentication(this IAppBuilder app, string baseUrl, string clientId, string clientSecret)
{
return app.UseWSO2Authentication(new WSO2AuthenticationOptions
{
BaseUrl = baseUrl.TrimEnd('/') + "/",
ClientId = clientId,
ClientSecret = clientSecret
});
}
}
}

View File

@@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Owin.Infrastructure;
namespace Owin.Security.Providers.WSO2
{
internal class WSO2AuthenticationHandler : AuthenticationHandler<WSO2AuthenticationOptions>
{
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string AuthorizeEndpoint = "oauth2/authorize";
private const string TokenEndpoint = "oauth2/token";
private const string TokenRevocationEndpoint = "oauth2/revoke";
private const string UserInfoEndpoint = "oauth2/userinfo";
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public WSO2AuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
_httpClient.DefaultRequestHeaders.Remove("Authorization");
string code = null;
string state = null;
var query = Request.Query;
var values = query.GetValues("code");
if (values != null && values.Count == 1)
{
code = values[0];
}
values = query.GetValues("state");
if (values != null && values.Count == 1)
{
state = values[0];
}
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
return null;
}
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
// Check for error
if (Request.Query.Get("error") != null)
return new AuthenticationTicket(null, properties);
var requestPrefix = Request.Scheme + "://" + Request.Host;
var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirectUri),
new KeyValuePair<string, string>("client_id", Options.ClientId),
new KeyValuePair<string, string>("client_secret", Options.ClientSecret)
};
// Request the token
var tokenResponse =
await _httpClient.PostAsync(Options.BaseUrl + TokenEndpoint, new FormUrlEncodedContent(body));
tokenResponse.EnsureSuccessStatusCode();
var text = await tokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
// Get the WSO2 user
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var graphResponse = await _httpClient.GetAsync(
Options.BaseUrl + UserInfoEndpoint + "?schema=openid");
graphResponse.EnsureSuccessStatusCode();
text = await graphResponse.Content.ReadAsStringAsync();
var user = JObject.Parse(text);
var context = new WSO2AuthenticatedContext(Context, user, accessToken)
{
Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType)
};
if (!string.IsNullOrEmpty(context.Id))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString, Options.AuthenticationType));
}
context.Properties = properties;
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
}
return new AuthenticationTicket(null, properties);
}
protected override Task ApplyResponseChallengeAsync()
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge == null) return Task.FromResult<object>(null);
var baseUri =
Request.Scheme +
Uri.SchemeDelimiter +
Request.Host +
Request.PathBase;
var currentUri =
baseUri +
Request.Path +
Request.QueryString;
var redirectUri =
baseUri +
Options.CallbackPath;
var properties = challenge.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
// hard code for now.
var scope = "openid email profile";
// allow scopes to be specified via the authentication properties for this request, when specified they will already be comma separated
if (properties.Dictionary.ContainsKey("scope"))
{
scope = properties.Dictionary["scope"];
}
var state = Options.StateDataFormat.Protect(properties);
var authorizationEndpoint =
Options.BaseUrl +
AuthorizeEndpoint +
"?response_type=code" +
"&client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
"&scope=" + Uri.EscapeDataString(scope) +
"&state=" + Uri.EscapeDataString(state);
var redirectContext = new WSO2ApplyRedirectContext(
Context, Options,
properties, authorizationEndpoint);
Options.Provider.ApplyRedirect(redirectContext);
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
if (!Options.CallbackPath.HasValue || Options.CallbackPath != Request.Path) return false;
// TODO: error responses
var ticket = await AuthenticateAsync();
if (ticket == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new WSO2ReturnEndpointContext(Context, ticket)
{
SignInAsAuthenticationType = Options.SignInAsAuthenticationType,
RedirectUri = ticket.Properties.RedirectUri
};
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null &&
context.Identity != null)
{
var grantIdentity = context.Identity;
if (!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, grantIdentity);
}
if (context.IsRequestCompleted || context.RedirectUri == null) return context.IsRequestCompleted;
var redirectUri = context.RedirectUri;
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied");
}
Response.Redirect(redirectUri);
context.RequestCompleted();
return context.IsRequestCompleted;
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Net.Http;
using Microsoft.Owin;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security.DataHandler;
using Microsoft.Owin.Security.DataProtection;
using Microsoft.Owin.Security.Infrastructure;
using Owin;
using Microsoft.Owin.Security;
namespace Owin.Security.Providers.WSO2
{
public class WSO2AuthenticationMiddleware : AuthenticationMiddleware<WSO2AuthenticationOptions>
{
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public WSO2AuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, WSO2AuthenticationOptions options) : base(next, options)
{
if (string.IsNullOrWhiteSpace(Options.BaseUrl))
throw new ArgumentException("Base url can not be null.");
if (string.IsNullOrWhiteSpace(Options.ClientId))
throw new ArgumentException("Client id can not be null.");
if (string.IsNullOrWhiteSpace(Options.ClientSecret))
throw new ArgumentException("Client secret can not be null.");
_logger = app.CreateLogger<WSO2AuthenticationMiddleware>();
if (Options.Provider == null)
Options.Provider = new WSO2AuthenticationProvider();
if (Options.StateDataFormat == null)
{
var dataProtector = app.CreateDataProtector(
typeof (WSO2AuthenticationMiddleware).FullName,
Options.AuthenticationType, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
_httpClient = new HttpClient(ResolveHttpMessageHandler(Options))
{
Timeout = Options.BackchannelTimeout,
MaxResponseContentBufferSize = 1024*1024*10
};
}
protected override AuthenticationHandler<WSO2AuthenticationOptions> CreateHandler()
{
return new WSO2AuthenticationHandler(_httpClient, _logger);
}
private static HttpMessageHandler ResolveHttpMessageHandler(WSO2AuthenticationOptions options)
{
var handler = options.BackchannelHttpHandler ?? new WebRequestHandler();
// If they provided a validator, apply it or fail.
if (options.BackchannelCertificateValidator == null) return handler;
// Set the cert validate callback
var webRequestHandler = handler as WebRequestHandler;
if (webRequestHandler == null)
{
throw new InvalidOperationException("An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.");
}
webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
return handler; }
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Security;
namespace Owin.Security.Providers.WSO2
{
public class WSO2AuthenticationOptions : AuthenticationOptions
{
public WSO2AuthenticationOptions() : base(Constants.DefaultAuthenticationType)
{
Caption = Constants.DefaultAuthenticationType;
CallbackPath = new PathString("/signin-wso2");
AuthenticationMode = AuthenticationMode.Passive;
BackchannelTimeout = TimeSpan.FromSeconds(60);
}
/// <summary>
/// Gets or sets the a pinned certificate validator to use to validate the endpoints used
/// in back channel communications belong to WSO2
/// </summary>
/// <value>
/// The pinned certificate validator.
/// </value>
/// <remarks>
/// If this property is null then the default certificate checks are performed,
/// validating the subject name and if the signing chain is a trusted party.
/// </remarks>
public ICertificateValidator BackchannelCertificateValidator { get; set; }
/// <summary>
/// The HttpMessageHandler used to communicate with WSO2.
/// This cannot be set at the same time as BackchannelCertificateValidator unless the value
/// can be downcast to a WebRequestHandler.
/// </summary>
public HttpMessageHandler BackchannelHttpHandler { get; set; }
/// <summary>
/// Gets or sets timeout value in milliseconds for back channel communications with WSO2.
/// </summary>
/// <value>
/// The back channel timeout in milliseconds.
/// </value>
public TimeSpan BackchannelTimeout { get; set; }
/// <summary>
/// Get or sets the text that the user can display on a sign in user interface.
/// </summary>
public string Caption
{
get { return Description.Caption; }
set { Description.Caption = value; }
}
public string ClientId { get; set; }
public string ClientSecret { get; set;}
public string BaseUrl { get; set; }
/// <summary>
/// The request path within the application's base path where the user-agent will be returned.
/// The middleware will process this request when it arrives.
/// Default value is "/signin-wso2".
/// </summary>
public PathString CallbackPath { get; set; }
public IWSO2AuthenticationProvider Provider { get; set;}
/// <summary>
/// Gets or sets the type used to secure data handled by the middleware.
/// </summary>
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
/// <summary>
/// A list of permissions to request.
/// </summary>
public IList<string> Scope { get; private set; }
/// <summary>
/// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user
/// <see cref="System.Security.Claims.ClaimsIdentity" />.
/// </summary>
public string SignInAsAuthenticationType { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
</packages>