From 5cf1410e47e3a9b0312788820f3b579333901840 Mon Sep 17 00:00:00 2001 From: Rick Zakharov Date: Fri, 22 Apr 2016 20:26:37 -0400 Subject: [PATCH 1/2] Added Owin.Security.Providers.Orcid project --- OwinOAuthProviders.sln | 6 ++ .../Owin.Security.Providers.Orcid.csproj | 70 +++++++++++++++++++ .../Owin.Security.Providers.Orcid.nuspec | 29 ++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++++++ .../packages.config | 7 ++ 5 files changed, 148 insertions(+) create mode 100644 src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj create mode 100644 src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.nuspec create mode 100644 src/Owin.Security.Providers.Orcid/Properties/AssemblyInfo.cs create mode 100644 src/Owin.Security.Providers.Orcid/packages.config diff --git a/OwinOAuthProviders.sln b/OwinOAuthProviders.sln index 3cf5f2b..47c9d23 100644 --- a/OwinOAuthProviders.sln +++ b/OwinOAuthProviders.sln @@ -92,6 +92,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.Yam EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.OpenIDBase", "src\Owin.Security.Providers.OpenIDBase\Owin.Security.Providers.OpenIDBase.csproj", "{4FD7B873-1994-4990-AA40-C37060121494}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Providers.Orcid", "src\Owin.Security.Providers.Orcid\Owin.Security.Providers.Orcid.csproj", "{89CB4342-E23D-4E7C-89E5-C369599A5860}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -278,6 +280,10 @@ Global {4FD7B873-1994-4990-AA40-C37060121494}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FD7B873-1994-4990-AA40-C37060121494}.Release|Any CPU.ActiveCfg = Release|Any CPU {4FD7B873-1994-4990-AA40-C37060121494}.Release|Any CPU.Build.0 = Release|Any CPU + {89CB4342-E23D-4E7C-89E5-C369599A5860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89CB4342-E23D-4E7C-89E5-C369599A5860}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89CB4342-E23D-4E7C-89E5-C369599A5860}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89CB4342-E23D-4E7C-89E5-C369599A5860}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj new file mode 100644 index 0000000..3220c98 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {89CB4342-E23D-4E7C-89E5-C369599A5860} + Library + Properties + Owin.Security.Providers.Orcid + Owin.Security.Providers.Orcid + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll + True + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + ..\..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.nuspec b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.nuspec new file mode 100644 index 0000000..e9d9eb5 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.nuspec @@ -0,0 +1,29 @@ + + + + Owin.Security.Providers.Orcid + 1.0.0 + Rick Zakharov + RickZee + http://opensource.org/licenses/MIT + https://github.com/RickZee/OwinOAuthProviders + false + + Adds ORCID OAuth provider for OWIN to use with ASP.NET + + + Providers have now been split into their own packages from Owin.Security.Providers + + + + Copyright 2016 + owin katana oauth LinkedIn + + + + + + + + + diff --git a/src/Owin.Security.Providers.Orcid/Properties/AssemblyInfo.cs b/src/Owin.Security.Providers.Orcid/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8ade133 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Properties/AssemblyInfo.cs @@ -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.Orcid")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Owin.Security.Providers.Orcid")] +[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("89cb4342-e23d-4e7c-89e5-c369599a5860")] + +// 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")] diff --git a/src/Owin.Security.Providers.Orcid/packages.config b/src/Owin.Security.Providers.Orcid/packages.config new file mode 100644 index 0000000..a35e97b --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From 993825574972dca475851c610ff02578fe80fe07 Mon Sep 17 00:00:00 2001 From: Rick Zakharov Date: Mon, 25 Apr 2016 08:08:15 -0400 Subject: [PATCH 2/2] Added ORCID authentication provider --- .../App_Start/Startup.Auth.cs | 410 +++++++++--------- README.md | 1 + .../Constants.cs | 7 + .../Message/OrcidMessage.cs | 293 +++++++++++++ .../Message/OrcidMessageExtensions.cs | 35 ++ .../OrcidAuthenticationEndpoints.cs | 33 ++ .../OrcidAuthenticationExtensions.cs | 29 ++ .../OrcidAuthenticationHandler.cs | 275 ++++++++++++ .../OrcidAuthenticationMiddleware.cs | 82 ++++ .../OrcidAuthenticationOptions.cs | 120 +++++ .../Owin.Security.Providers.Orcid.csproj | 17 + .../Provider/IOrcidAuthenticationProvider.cs | 24 + .../Provider/OrcidAuthenticatedContext.cs | 84 ++++ .../Provider/OrcidAuthenticationProvider.cs | 50 +++ .../Provider/OrcidReturnEndpointContext.cs | 26 ++ 15 files changed, 1282 insertions(+), 204 deletions(-) create mode 100644 src/Owin.Security.Providers.Orcid/Constants.cs create mode 100644 src/Owin.Security.Providers.Orcid/Message/OrcidMessage.cs create mode 100644 src/Owin.Security.Providers.Orcid/Message/OrcidMessageExtensions.cs create mode 100644 src/Owin.Security.Providers.Orcid/OrcidAuthenticationEndpoints.cs create mode 100644 src/Owin.Security.Providers.Orcid/OrcidAuthenticationExtensions.cs create mode 100644 src/Owin.Security.Providers.Orcid/OrcidAuthenticationHandler.cs create mode 100644 src/Owin.Security.Providers.Orcid/OrcidAuthenticationMiddleware.cs create mode 100644 src/Owin.Security.Providers.Orcid/OrcidAuthenticationOptions.cs create mode 100644 src/Owin.Security.Providers.Orcid/Provider/IOrcidAuthenticationProvider.cs create mode 100644 src/Owin.Security.Providers.Orcid/Provider/OrcidAuthenticatedContext.cs create mode 100644 src/Owin.Security.Providers.Orcid/Provider/OrcidAuthenticationProvider.cs create mode 100644 src/Owin.Security.Providers.Orcid/Provider/OrcidReturnEndpointContext.cs diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs index 75ddad9..a6f3847 100755 --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -18,263 +18,265 @@ 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() - // { + ////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 - // /* + // 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.UseBattleNetAuthentication(new BattleNetAuthenticationOptions + //{ + // ClientId = "", + // ClientSecret = "" + //}); + //app.UseBattleNetAuthentication( + // clientId: "", + // clientSecret: ""); - //app.UseAsanaAuthentication("", ""); + //app.UseAsanaAuthentication("", ""); - //app.UseEveOnlineAuthentication("", ""); + //app.UseEveOnlineAuthentication("", ""); - //app.UseSoundCloudAuthentication("", ""); + //app.UseSoundCloudAuthentication("", ""); - //app.UseFoursquareAuthentication( - // clientId: "", - // clientSecret: ""); + //app.UseFoursquareAuthentication( + // clientId: "", + // clientSecret: ""); - //app.UsePayPalAuthentication( - // clientId: "", - // clientSecret: "", - // isSandbox: false); + //app.UsePayPalAuthentication( + // clientId: "", + // clientSecret: "", + // isSandbox: false); - //app.UseWargamingAccountAuthentication("", WargamingAuthenticationOptions.Region.NorthAmerica); + //app.UseWargamingAccountAuthentication("", WargamingAuthenticationOptions.Region.NorthAmerica); - //app.UseFlickrAuthentication("", ""); - //app.UseVisualStudioAuthentication( - // appId: "", - // appSecret: ""); + //app.UseFlickrAuthentication("", ""); + //app.UseVisualStudioAuthentication( + // appId: "", + // appSecret: ""); - //app.UseSpotifyAuthentication( - // clientId: "", - // clientSecret: ""); + //app.UseSpotifyAuthentication( + // clientId: "", + // clientSecret: ""); - //var options = new SlackAuthenticationOptions - //{ - // ClientId = "", - // ClientSecret = "", - // TeamId = "" // optional - //}; - //options.Scope.Add("identify"); - //app.UseSlackAuthentication(options); + //var options = new SlackAuthenticationOptions + //{ + // ClientId = "", + // ClientSecret = "", + // TeamId = "" // optional + //}; + //options.Scope.Add("identify"); + //app.UseSlackAuthentication(options); - //app.UseGitterAuthentication( - // clientId: "", - // clientSecret: "" - //); + //app.UseGitterAuthentication( + // clientId: "", + // clientSecret: "" + //); - //app.UseImgurAuthentication( - // new ImgurAuthenticationOptions - // { - // ClientId = "", - // ClientSecret = "" - // }); + //app.UseImgurAuthentication( + // new ImgurAuthenticationOptions + // { + // ClientId = "", + // ClientSecret = "" + // }); - //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)); }) - // } - //}; + //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.UseBacklogAuthentication(options); + //app.UseBacklogAuthentication(options); - //var cosignOptions = new CosignAuthenticationOptions - //{ - // AuthenticationType = "Cosign", - // SignInAsAuthenticationType = signInAsType, - // CosignServer = "weblogin.umich.edu", - // CosignServicePort = 6663, - // IdentityServerHostInstance = "core1", - // ClientServer = "cosignservername" - //}; - //app.UseCosignAuthentication(cosignOptions); + //var cosignOptions = new CosignAuthenticationOptions + //{ + // AuthenticationType = "Cosign", + // SignInAsAuthenticationType = signInAsType, + // CosignServer = "weblogin.umich.edu", + // CosignServicePort = 6663, + // IdentityServerHostInstance = "core1", + // ClientServer = "cosignservername" + //}; + //app.UseCosignAuthentication(cosignOptions); - //app.UseVimeoAuthentication("", ""); - - //app.UseFitbitAuthentication(new FitbitAuthenticationOptions - //{ - // ClientId = "", - // ClientSecret = "" - //}); + //app.UseVimeoAuthentication("", ""); - //app.UseOnshapeAuthentication( - // appKey: "", - // appSecret: ""); - // - // - //app.UseOnshapeAuthentication(new OnshapeAuthenticationOptions() - //{ - // AppKey = "", - // AppSecret = "", - // CallbackPath = new PathString("/oauthRedirect"), - // Hostname = "partner.dev.onshape.com" - //}); + //app.UseFitbitAuthentication(new FitbitAuthenticationOptions + //{ + // ClientId = "", + // ClientSecret = "" + //}); - //app.UseVKontakteAuthentication("", ""); + //app.UseOnshapeAuthentication( + // appKey: "", + // appSecret: ""); + // + // + //app.UseOnshapeAuthentication(new OnshapeAuthenticationOptions() + //{ + // AppKey = "", + // AppSecret = "", + // CallbackPath = new PathString("/oauthRedirect"), + // Hostname = "partner.dev.onshape.com" + //}); - //app.UseXingAuthentication("", ""); + //app.UseVKontakteAuthentication("", ""); - //app.UseDoYouBuzzAuthentication("", ""); - } - } + //app.UseXingAuthentication("", ""); + + //app.UseDoYouBuzzAuthentication("", ""); + + //app.UseOrcidAuthentication("", ""); + } + } } diff --git a/README.md b/README.md index 378079c..693c698 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Provides a set of extra authentication providers for OWIN ([Project Katana](http - Instagram - LinkedIn - Onshape + - ORCID - PayPal - Reddit - Salesforce diff --git a/src/Owin.Security.Providers.Orcid/Constants.cs b/src/Owin.Security.Providers.Orcid/Constants.cs new file mode 100644 index 0000000..acb1dd2 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Constants.cs @@ -0,0 +1,7 @@ +namespace Owin.Security.Providers.Orcid +{ + internal static class Constants + { + public const string DefaultAuthenticationType = "Orcid"; + } +} \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/Message/OrcidMessage.cs b/src/Owin.Security.Providers.Orcid/Message/OrcidMessage.cs new file mode 100644 index 0000000..f60bf79 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Message/OrcidMessage.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace Owin.Security.Providers.Orcid.Message +{ + public class OrcidIdentifier + { + + [JsonProperty("value")] + public object Value { get; set; } + + [JsonProperty("uri")] + public string Uri { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("host")] + public string Host { get; set; } + } + + public class OrcidPreferences + { + + [JsonProperty("locale")] + public string Locale { get; set; } + } + + public class SubmissionDate + { + + [JsonProperty("value")] + public long Value { get; set; } + } + + public class LastModifiedDate + { + + [JsonProperty("value")] + public long Value { get; set; } + } + + public class Claimed + { + + [JsonProperty("value")] + public bool Value { get; set; } + } + + public class VerifiedEmail + { + + [JsonProperty("value")] + public bool Value { get; set; } + } + + public class VerifiedPrimaryEmail + { + + [JsonProperty("value")] + public bool Value { get; set; } + } + + public class OrcidHistory + { + + [JsonProperty("creation-method")] + public string CreationMethod { get; set; } + + [JsonProperty("completion-date")] + public object CompletionDate { get; set; } + + [JsonProperty("submission-date")] + public SubmissionDate SubmissionDate { get; set; } + + [JsonProperty("last-modified-date")] + public LastModifiedDate LastModifiedDate { get; set; } + + [JsonProperty("claimed")] + public Claimed Claimed { get; set; } + + [JsonProperty("source")] + public object Source { get; set; } + + [JsonProperty("deactivation-date")] + public object DeactivationDate { get; set; } + + [JsonProperty("verified-email")] + public VerifiedEmail VerifiedEmail { get; set; } + + [JsonProperty("verified-primary-email")] + public VerifiedPrimaryEmail VerifiedPrimaryEmail { get; set; } + + [JsonProperty("visibility")] + public object Visibility { get; set; } + } + + public class GivenNames + { + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("visibility")] + public object Visibility { get; set; } + } + + public class FamilyName + { + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("visibility")] + public object Visibility { get; set; } + } + + public class OtherNames + { + + [JsonProperty("other-name")] + public object[] OtherName { get; set; } + + [JsonProperty("visibility")] + public string Visibility { get; set; } + } + + public class PersonalDetails + { + + [JsonProperty("given-names")] + public GivenNames GivenNames { get; set; } + + [JsonProperty("family-name")] + public FamilyName FamilyName { get; set; } + + [JsonProperty("credit-name")] + public object CreditName { get; set; } + + [JsonProperty("other-names")] + public OtherNames OtherNames { get; set; } + } + + public class Biography + { + + [JsonProperty("value")] + public object Value { get; set; } + + [JsonProperty("visibility")] + public string Visibility { get; set; } + } + + public class ResearcherUrls + { + + [JsonProperty("researcher-url")] + public object[] ResearcherUrl { get; set; } + + [JsonProperty("visibility")] + public string Visibility { get; set; } + } + + public class Email + { + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("primary")] + public bool Primary { get; set; } + + [JsonProperty("current")] + public bool Current { get; set; } + + [JsonProperty("verified")] + public bool Verified { get; set; } + + [JsonProperty("visibility")] + public string Visibility { get; set; } + + [JsonProperty("source")] + public string Source { get; set; } + + [JsonProperty("source-client-id")] + public object SourceClientId { get; set; } + } + + public class ContactDetails + { + + [JsonProperty("email")] + public Email[] Email { get; set; } + + [JsonProperty("address")] + public object Address { get; set; } + } + + public class ExternalIdentifiers + { + + [JsonProperty("external-identifier")] + public object[] ExternalIdentifier { get; set; } + + [JsonProperty("visibility")] + public string Visibility { get; set; } + } + + public class OrcidBio + { + + [JsonProperty("personal-details")] + public PersonalDetails PersonalDetails { get; set; } + + [JsonProperty("biography")] + public Biography Biography { get; set; } + + [JsonProperty("researcher-urls")] + public ResearcherUrls ResearcherUrls { get; set; } + + [JsonProperty("contact-details")] + public ContactDetails ContactDetails { get; set; } + + [JsonProperty("keywords")] + public object Keywords { get; set; } + + [JsonProperty("external-identifiers")] + public ExternalIdentifiers ExternalIdentifiers { get; set; } + + [JsonProperty("delegation")] + public object Delegation { get; set; } + + [JsonProperty("scope")] + public object Scope { get; set; } + } + + public class OrcidProfile + { + + [JsonProperty("orcid")] + public object Orcid { get; set; } + + [JsonProperty("orcid-id")] + public object OrcidId { get; set; } + + [JsonProperty("orcid-identifier")] + public OrcidIdentifier OrcidIdentifier { get; set; } + + [JsonProperty("orcid-deprecated")] + public object OrcidDeprecated { get; set; } + + [JsonProperty("orcid-preferences")] + public OrcidPreferences OrcidPreferences { get; set; } + + [JsonProperty("orcid-history")] + public OrcidHistory OrcidHistory { get; set; } + + [JsonProperty("orcid-bio")] + public OrcidBio OrcidBio { get; set; } + + [JsonProperty("orcid-activities")] + public object OrcidActivities { get; set; } + + [JsonProperty("orcid-internal")] + public object OrcidInternal { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("group-type")] + public object GroupType { get; set; } + + [JsonProperty("client-type")] + public object ClientType { get; set; } + } + + public class OrcidProfileMessage + { + + [JsonProperty("message-version")] + public string MessageVersion { get; set; } + + [JsonProperty("orcid-profile")] + public OrcidProfile OrcidProfile { get; set; } + + [JsonProperty("error-desc")] + public object ErrorDesc { get; set; } + } +} diff --git a/src/Owin.Security.Providers.Orcid/Message/OrcidMessageExtensions.cs b/src/Owin.Security.Providers.Orcid/Message/OrcidMessageExtensions.cs new file mode 100644 index 0000000..b0e280c --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/Message/OrcidMessageExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Owin; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Owin.Security.Providers.Orcid.Message +{ + public static class OrcidMessageExtensions + { + public static OrcidAuthenticatedContext ToAuthenticationContext(this string json, IOwinContext context, string orcid, string accessToken) + { + var profile = JsonConvert.DeserializeObject(json); + + var user = JObject.Parse(json); + + var authenticatedContext = new OrcidAuthenticatedContext(context, user, accessToken); + + var email = profile.OrcidProfile.OrcidBio.ContactDetails.Email.LastOrDefault(); + if (email != null) + authenticatedContext.Email = email.Value; + + authenticatedContext.Id = orcid; + authenticatedContext.UserName = orcid; + + authenticatedContext.FirstName = profile.OrcidProfile.OrcidBio.PersonalDetails.GivenNames.Value; + authenticatedContext.LastName = profile.OrcidProfile.OrcidBio.PersonalDetails.FamilyName.Value; + + return authenticatedContext; + } + } +} diff --git a/src/Owin.Security.Providers.Orcid/OrcidAuthenticationEndpoints.cs b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationEndpoints.cs new file mode 100644 index 0000000..bf878b9 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationEndpoints.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; + +namespace Owin.Security.Providers.Orcid +{ + public class OrcidAuthenticationEndpoints + { + public static class Default + { + public const string AuthorizationEndPoint = @"https://orcid.org/oauth/authorize"; + public const string TokenEndpoint = @"https://pub.orcid.org/oauth/token"; + public const string ApiEndpoint = @"http://pub.orcid.org/v1.2"; + } + + /// + /// Endpoint which is used to redirect users to request Orcid access + /// + public string AuthorizationEndpoint { get; set; } + + /// + /// Endpoint which is used to exchange code for access token + /// + public string TokenEndpoint { get; set; } + + /// + /// Endpoint which is used to exchange code for access token + /// + public string ApiEndpoint { get; set; } + } +} \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/OrcidAuthenticationExtensions.cs b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationExtensions.cs new file mode 100644 index 0000000..c0ecfed --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationExtensions.cs @@ -0,0 +1,29 @@ +using System; + +namespace Owin.Security.Providers.Orcid +{ + public static class OrcidAuthenticationExtensions + { + public static IAppBuilder UseOrcidAuthentication(this IAppBuilder app, + OrcidAuthenticationOptions options) + { + if (app == null) + throw new ArgumentNullException(nameof(app)); + if (options == null) + throw new ArgumentNullException(nameof(options)); + + app.Use(typeof(OrcidAuthenticationMiddleware), app, options); + + return app; + } + + public static IAppBuilder UseOrcidAuthentication(this IAppBuilder app, string clientId, string clientSecret) + { + return app.UseOrcidAuthentication(new OrcidAuthenticationOptions + { + ClientId = clientId, + ClientSecret = clientSecret + }); + } + } +} \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/OrcidAuthenticationHandler.cs b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationHandler.cs new file mode 100644 index 0000000..a01e5e3 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationHandler.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Threading.Tasks; +using System.Web; +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 Owin.Security.Providers.Orcid.Message; + +namespace Owin.Security.Providers.Orcid +{ + public class OrcidAuthenticationHandler : AuthenticationHandler + { + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + + private readonly ILogger _logger; + private readonly HttpClient _httpClient; + + public OrcidAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + this._httpClient = httpClient; + this._logger = logger; + } + + protected override async Task AuthenticateCoreAsync() + { + AuthenticationProperties properties = new AuthenticationProperties(); + + try + { + string code = null; + string state = null; + + IReadableStringCollection query = Request.Query; + IList 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]; + } + + if (state != null) + { + properties = Options.StateDataFormat.Unprotect(state); + if (properties == null) + { + return null; + } + + // OAuth2 10.12 CSRF + if (!ValidateCorrelationId(properties, _logger)) + { + return new AuthenticationTicket(null, properties); + } + } + + string requestPrefix = Request.Scheme + "://" + Request.Host; + string redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath; + + // Build up the body for the token request + var body = new List> + { + new KeyValuePair("client_id", Options.ClientId), + new KeyValuePair("client_secret", Options.ClientSecret), + new KeyValuePair("scope", "/read-public"), + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("code", code), + new KeyValuePair("redirect_uri", redirectUri), + }; + + // Request the token + var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.Endpoints.TokenEndpoint); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + requestMessage.Content = new FormUrlEncodedContent(body); + + HttpResponseMessage tokenResponse = await _httpClient.SendAsync(requestMessage); + tokenResponse.EnsureSuccessStatusCode(); + string text = await tokenResponse.Content.ReadAsStringAsync(); + + // Deserializes the token response + dynamic response = JsonConvert.DeserializeObject(text); + string accessToken = (string)response.access_token; + string refreshToken = (string)response.refresh_token; + string orcid = (string)response.orcid; + + string profileEndpoint = + string.Format("{0}/{1}/{2}", + Options.Endpoints.ApiEndpoint, + orcid, + "orcid-profile/"); + + // Get Orcid profile + HttpRequestMessage userRequest = new HttpRequestMessage(HttpMethod.Get, profileEndpoint); + + //Requesting public info for now - no authirization needed + //userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + + userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + HttpResponseMessage userResponse = await _httpClient.SendAsync(userRequest, Request.CallCancelled); + userResponse.EnsureSuccessStatusCode(); + text = await userResponse.Content.ReadAsStringAsync(); + + // Get the Orcid user using the user info endpoint, which is part of the token - response.id + var context = text.ToAuthenticationContext(Context, orcid, accessToken); + + context.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.UserName)) + { + context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName, XmlSchemaString, Options.AuthenticationType)); + } + + if (!string.IsNullOrEmpty(context.Email)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, Options.AuthenticationType)); + } + + if (!string.IsNullOrEmpty(context.FirstName)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.GivenName, context.FirstName, XmlSchemaString, Options.AuthenticationType)); + } + + if (!string.IsNullOrEmpty(context.LastName)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.Surname, context.LastName, 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(null); + } + + AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode); + + if (challenge != null) + { + string baseUri = + Request.Scheme + + Uri.SchemeDelimiter + + Request.Host + + Request.PathBase; + + string currentUri = + baseUri + + Request.Path + + Request.QueryString; + + string redirectUri = + baseUri + + Options.CallbackPath; + + AuthenticationProperties properties = challenge.Properties; + if (string.IsNullOrEmpty(properties.RedirectUri)) + { + properties.RedirectUri = currentUri; + } + + // OAuth2 10.12 CSRF + GenerateCorrelationId(properties); + + string state = Options.StateDataFormat.Protect(properties); + + string authorizationEndpoint = string.Format( + "{0}?client_id={1}&response_type={2}&scope={3}&redirect_uri={4}&state={5}", + Options.Endpoints.AuthorizationEndpoint, + Options.ClientId, + "code", + @"/authenticate", + HttpUtility.UrlEncode(redirectUri), + state + ); + + //RZ: Need this? + if (Options.Prompt != null) + { + authorizationEndpoint += string.Format("&prompt={0}", Options.Prompt); + } + + Response.Redirect(authorizationEndpoint); + } + + return Task.FromResult(null); + } + + public override async Task InvokeAsync() + { + return await InvokeReplyPathAsync(); + } + + private async Task InvokeReplyPathAsync() + { + if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path) + { + // TODO: error responses + + AuthenticationTicket ticket = await AuthenticateAsync(); + if (ticket == null) + { + _logger.WriteWarning("Invalid return state, unable to redirect."); + Response.StatusCode = 500; + return true; + } + + var context = new OrcidReturnEndpointContext(Context, ticket) + { + SignInAsAuthenticationType = Options.SignInAsAuthenticationType, + RedirectUri = ticket.Properties.RedirectUri + }; + + await Options.Provider.ReturnEndpoint(context); + + if (context.SignInAsAuthenticationType != null && + context.Identity != null) + { + ClaimsIdentity 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) + { + string 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; + } + return false; + } + } +} diff --git a/src/Owin.Security.Providers.Orcid/OrcidAuthenticationMiddleware.cs b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationMiddleware.cs new file mode 100644 index 0000000..ceff614 --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationMiddleware.cs @@ -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.Orcid +{ + public class OrcidAuthenticationMiddleware : AuthenticationMiddleware + { + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public OrcidAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, + OrcidAuthenticationOptions options) + : base(next, options) + { + if (string.IsNullOrWhiteSpace(Options.ClientId)) + throw new ArgumentException("ClientId"); + if (string.IsNullOrWhiteSpace(Options.ClientSecret)) + throw new ArgumentException("ClientSecret"); + + _logger = app.CreateLogger(); + + if (Options.Provider == null) + Options.Provider = new OrcidAuthenticationProvider(); + + if (Options.StateDataFormat == null) + { + IDataProtector dataProtector = app.CreateDataProtector( + typeof(OrcidAuthenticationMiddleware).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, + }; + } + + /// + /// Provides the object for processing + /// authentication-related requests. + /// + /// + /// An configured with the + /// supplied to the constructor. + /// + protected override AuthenticationHandler CreateHandler() + { + return new OrcidAuthenticationHandler(_httpClient, _logger); + } + + private HttpMessageHandler ResolveHttpMessageHandler(OrcidAuthenticationOptions options) + { + HttpMessageHandler handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + + // If they provided a validator, apply it or fail. + if (options.BackchannelCertificateValidator != null) + { + // Set the cert validate callback + var webRequestHandler = handler as WebRequestHandler; + if (webRequestHandler == null) + { + throw new InvalidOperationException("ValidatorHandlerMismatch"); + } + webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; + } + + return handler; + } + } +} \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/OrcidAuthenticationOptions.cs b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationOptions.cs new file mode 100644 index 0000000..5c10cbb --- /dev/null +++ b/src/Owin.Security.Providers.Orcid/OrcidAuthenticationOptions.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; + +namespace Owin.Security.Providers.Orcid +{ + public class OrcidAuthenticationOptions : AuthenticationOptions + { + /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used + /// in back channel communications belong to Orcid. + /// + /// + /// The pinned certificate validator. + /// + /// + /// 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. + /// + public ICertificateValidator BackchannelCertificateValidator { get; set; } + + /// + /// The HttpMessageHandler used to communicate with Orcid. + /// This cannot be set at the same time as BackchannelCertificateValidator unless the value + /// can be downcast to a WebRequestHandler. + /// + public HttpMessageHandler BackchannelHttpHandler { get; set; } + + /// + /// Gets or sets timeout value in milliseconds for back channel communications with Orcid. + /// + /// + /// The back channel timeout in milliseconds. + /// + public TimeSpan BackchannelTimeout { get; set; } + + /// + /// 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-Orcid". + /// + public PathString CallbackPath { get; set; } + + /// + /// Get or sets the text that the user can display on a sign in user interface. + /// + public string Caption + { + get { return Description.Caption; } + set { Description.Caption = value; } + } + + /// + /// Gets or sets the Orcid supplied Client ID + /// + public string ClientId { get; set; } + + /// + /// Gets or sets the Orcid supplied Client Secret + /// + public string ClientSecret { get; set; } + + /// + /// Gets the sets of OAuth endpoints used to authenticate against Orcid. Overriding these endpoints allows you to use Orcid Enterprise for + /// authentication. + /// + public OrcidAuthenticationEndpoints Endpoints { get; set; } + + /// + /// Gets or sets the used in the authentication events + /// + public IOrcidAuthenticationProvider Provider { get; set; } + + /// + /// A list of permissions to request. + /// + public IList Scope { get; private set; } + + /// + /// Specifies how the authorization server prompts the user for reauthentication and reapproval. This parameter is optional. + /// The only values Orcid supports are: + /// login—The authorization server must prompt the user for reauthentication, forcing the user to log in again. + /// consent—The authorization server must prompt the user for reapproval before returning information to the client. + /// It is valid to pass both values, separated by a space, to require the user to both log in and reauthorize. + /// + public string Prompt { get; set; } + + /// + /// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user + /// . + /// + public string SignInAsAuthenticationType { get; set; } + + /// + /// Gets or sets the type used to secure data handled by the middleware. + /// + public ISecureDataFormat StateDataFormat { get; set; } + + /// + /// Initializes a new + /// + public OrcidAuthenticationOptions() + : base("Orcid") + { + Caption = Constants.DefaultAuthenticationType; + CallbackPath = new PathString("/signin-orcid"); + AuthenticationMode = AuthenticationMode.Passive; + Scope = new List(); + BackchannelTimeout = TimeSpan.FromSeconds(60); + Endpoints = new OrcidAuthenticationEndpoints + { + AuthorizationEndpoint = OrcidAuthenticationEndpoints.Default.AuthorizationEndPoint, + TokenEndpoint = OrcidAuthenticationEndpoints.Default.TokenEndpoint, + ApiEndpoint = OrcidAuthenticationEndpoints.Default.ApiEndpoint + }; + } + } +} \ No newline at end of file diff --git a/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj index 3220c98..fac17cc 100644 --- a/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj +++ b/src/Owin.Security.Providers.Orcid/Owin.Security.Providers.Orcid.csproj @@ -49,6 +49,7 @@ + @@ -57,7 +58,23 @@ + + + + + + + + + + + + + + + +