files tree made better.
This commit is contained in:
parent
ffbf032480
commit
ccc91bbf19
1630 changed files with 18209 additions and 41860 deletions
47
src/Yavsc/AuthorizationServer/GoogleExtensions.cs
Normal file
47
src/Yavsc/AuthorizationServer/GoogleExtensions.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNet.Builder;
|
||||
|
||||
namespace Yavsc.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to add Google authentication capabilities to an HTTP application pipeline.
|
||||
/// </summary>
|
||||
public static class GoogleAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the <see cref="GoogleMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Google authentication capabilities.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
|
||||
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<GoogleMiddleware>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="GoogleMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Google authentication capabilities.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
|
||||
/// <param name="options">A <see cref="YavscGoogleOptions"/> that specifies options for the middleware.</param>
|
||||
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app, YavscGoogleOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<GoogleMiddleware>(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
139
src/Yavsc/AuthorizationServer/GoogleHandler.cs
Normal file
139
src/Yavsc/AuthorizationServer/GoogleHandler.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
using Microsoft.AspNet.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Yavsc.Auth
|
||||
{
|
||||
internal class GoogleHandler : OAuthHandler<YavscGoogleOptions>
|
||||
{
|
||||
private ILogger _logger;
|
||||
public GoogleHandler(HttpClient httpClient,ILogger logger)
|
||||
: base(httpClient)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity,
|
||||
AuthenticationProperties properties, OAuthTokenResponse tokens
|
||||
)
|
||||
{
|
||||
_logger.LogInformation("Getting user info from Google ...");
|
||||
// Get the Google user
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
|
||||
|
||||
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
var identifier = GoogleHelper.GetId(payload);
|
||||
|
||||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
|
||||
var context = new GoogleOAuthCreatingTicketContext(Context, Options, Backchannel, tokens, ticket, identifier);
|
||||
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var givenName = GoogleHelper.GetGivenName(payload);
|
||||
if (!string.IsNullOrEmpty(givenName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var familyName = GoogleHelper.GetFamilyName(payload);
|
||||
if (!string.IsNullOrEmpty(familyName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, familyName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = GoogleHelper.GetName(payload);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = GoogleHelper.GetEmail(payload);
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var profile = GoogleHelper.GetProfile(payload);
|
||||
if (!string.IsNullOrEmpty(profile))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:google:profile", profile, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
|
||||
return ticket;
|
||||
}
|
||||
protected override Task<OAuthTokenResponse> ExchangeCodeAsync(string code, string ruri)
|
||||
{
|
||||
var redirectUri = $"https://{Startup.Authority}{Options.CallbackPath}";
|
||||
return base.ExchangeCodeAsync(code,redirectUri);
|
||||
}
|
||||
|
||||
// TODO: Abstract this properties override pattern into the base class?
|
||||
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
|
||||
{
|
||||
|
||||
var scope = FormatScope();
|
||||
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
queryStrings.Add("response_type", "code");
|
||||
queryStrings.Add("client_id", Options.ClientId);
|
||||
// this runtime may not known this value,
|
||||
// it should be get from config,
|
||||
// And always be using a secure sheme ... since Google won't support anymore insecure ones.
|
||||
_logger.LogInformation ($"Redirect uri was : {redirectUri}");
|
||||
|
||||
redirectUri = $"https://{Startup.Authority}{Options.CallbackPath}";
|
||||
queryStrings.Add("redirect_uri", redirectUri);
|
||||
|
||||
_logger.LogInformation ($"Using redirect uri {redirectUri}");
|
||||
|
||||
AddQueryString(queryStrings, properties, "scope", scope);
|
||||
|
||||
AddQueryString(queryStrings, properties, "access_type", Options.AccessType);
|
||||
AddQueryString(queryStrings, properties, "approval_prompt");
|
||||
AddQueryString(queryStrings, properties, "login_hint");
|
||||
|
||||
var state = Options.StateDataFormat.Protect(properties);
|
||||
queryStrings.Add("state", state);
|
||||
|
||||
var authorizationEndpoint = QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, queryStrings);
|
||||
return authorizationEndpoint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void AddQueryString(IDictionary<string, string> queryStrings, AuthenticationProperties properties,
|
||||
string name, string defaultValue = null)
|
||||
{
|
||||
string value;
|
||||
if (!properties.Items.TryGetValue(name, out value))
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the parameter from AuthenticationProperties so it won't be serialized to state parameter
|
||||
properties.Items.Remove(name);
|
||||
}
|
||||
queryStrings[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
144
src/Yavsc/AuthorizationServer/GoogleHelper.cs
Normal file
144
src/Yavsc/AuthorizationServer/GoogleHelper.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
/// <summary>
|
||||
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
|
||||
/// instance retrieved from Google after a successful authentication process.
|
||||
/// </summary>
|
||||
public static class GoogleHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Google user ID.
|
||||
/// </summary>
|
||||
public static string GetId(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's name.
|
||||
/// </summary>
|
||||
public static string GetName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("displayName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's given name.
|
||||
/// </summary>
|
||||
public static string GetGivenName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetValue(user, "name", "givenName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's family name.
|
||||
/// </summary>
|
||||
public static string GetFamilyName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetValue(user, "name", "familyName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's profile link.
|
||||
/// </summary>
|
||||
public static string GetProfile(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("url");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's email.
|
||||
/// </summary>
|
||||
public static string GetEmail(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetFirstValue(user, "emails", "value");
|
||||
}
|
||||
|
||||
// Get the given subProperty from a property.
|
||||
private static string TryGetValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var subObject = JObject.Parse(value.ToString());
|
||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#if GoogleApisAuthOAuth2
|
||||
public static ServiceAccountCredential GetGoogleApiCredentials (string[] scopes)
|
||||
{
|
||||
String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE";
|
||||
|
||||
string private_key = Startup.GoogleSettings.Account.private_key;
|
||||
|
||||
string secret = Startup.GoogleSettings.ClientSecret;
|
||||
|
||||
|
||||
var certificate = new X509Certificate2(@"key.p12", secret, X509KeyStorageFlags.Exportable);
|
||||
|
||||
return new ServiceAccountCredential(
|
||||
new ServiceAccountCredential.Initializer(serviceAccountEmail)
|
||||
{
|
||||
Scopes = scopes
|
||||
}.FromCertificate(certificate));
|
||||
}
|
||||
#endif
|
||||
// Get the given subProperty from a list property.
|
||||
private static string TryGetFirstValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var array = JArray.Parse(value.ToString());
|
||||
if (array != null && array.Count > 0)
|
||||
{
|
||||
var subObject = JObject.Parse(array.First.ToString());
|
||||
if (subObject != null)
|
||||
{
|
||||
if (subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
80
src/Yavsc/AuthorizationServer/GoogleMiddleWare.cs
Normal file
80
src/Yavsc/AuthorizationServer/GoogleMiddleWare.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.DataProtection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Microsoft.Extensions.WebEncoders;
|
||||
namespace Yavsc.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// An ASP.NET Core middleware for authenticating users using Google OAuth 2.0.
|
||||
/// </summary>
|
||||
public class GoogleMiddleware : OAuthMiddleware<YavscGoogleOptions>
|
||||
{
|
||||
private RequestDelegate _next;
|
||||
private ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="GoogleMiddleware"/>.
|
||||
/// </summary>
|
||||
/// <param name="next">The next middleware in the HTTP pipeline to invoke.</param>
|
||||
/// <param name="dataProtectionProvider"></param>
|
||||
/// <param name="loggerFactory"></param>
|
||||
/// <param name="encoder"></param>
|
||||
/// <param name="sharedOptions"></param>
|
||||
/// <param name="options">Configuration options for the middleware.</param>
|
||||
public GoogleMiddleware(
|
||||
RequestDelegate next,
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
UrlEncoder encoder,
|
||||
IOptions<SharedAuthenticationOptions> sharedOptions,
|
||||
YavscGoogleOptions options)
|
||||
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(next));
|
||||
}
|
||||
_next = next;
|
||||
|
||||
if (dataProtectionProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
_logger = loggerFactory.CreateLogger<GoogleMiddleware>();
|
||||
|
||||
if (encoder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoder));
|
||||
}
|
||||
|
||||
if (sharedOptions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sharedOptions));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override AuthenticationHandler<YavscGoogleOptions> CreateHandler()
|
||||
{
|
||||
return new GoogleHandler(Backchannel,_logger);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
27
src/Yavsc/AuthorizationServer/GoogleOAuthCreatingTicket.cs
Normal file
27
src/Yavsc/AuthorizationServer/GoogleOAuthCreatingTicket.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Yavsc.Auth {
|
||||
|
||||
|
||||
public class GoogleOAuthCreatingTicketContext : OAuthCreatingTicketContext {
|
||||
public GoogleOAuthCreatingTicketContext(HttpContext context, OAuthOptions options,
|
||||
HttpClient backchannel, OAuthTokenResponse tokens, AuthenticationTicket ticket, string googleUserId )
|
||||
: base( context, options, backchannel, tokens )
|
||||
{
|
||||
_ticket = ticket;
|
||||
_googleUserId = googleUserId;
|
||||
Principal = ticket.Principal;
|
||||
}
|
||||
AuthenticationTicket _ticket;
|
||||
string _googleUserId;
|
||||
|
||||
public AuthenticationTicket Ticket { get { return _ticket; } }
|
||||
|
||||
public string GoogleUserId { get { return _googleUserId; } }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
46
src/Yavsc/AuthorizationServer/GoogleOptions.cs
Normal file
46
src/Yavsc/AuthorizationServer/GoogleOptions.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Yavsc.Auth
|
||||
{
|
||||
public static class YavscGoogleDefaults
|
||||
{
|
||||
public const string AuthenticationScheme = "Google";
|
||||
|
||||
public static readonly string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth";
|
||||
|
||||
public static readonly string TokenEndpoint = "https://www.googleapis.com/oauth2/v3/token";
|
||||
|
||||
public static readonly string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for <see cref="GoogleMiddleware"/>.
|
||||
/// </summary>
|
||||
public class YavscGoogleOptions : OAuthOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="YavscGoogleOptions"/>.
|
||||
/// </summary>
|
||||
public YavscGoogleOptions()
|
||||
{
|
||||
AuthenticationScheme = YavscGoogleDefaults.AuthenticationScheme;
|
||||
DisplayName = AuthenticationScheme;
|
||||
CallbackPath = new PathString("/signin-google");
|
||||
AuthorizationEndpoint = YavscGoogleDefaults.AuthorizationEndpoint;
|
||||
TokenEndpoint = YavscGoogleDefaults.TokenEndpoint;
|
||||
UserInformationEndpoint = YavscGoogleDefaults.UserInformationEndpoint;
|
||||
Scope.Add("openid");
|
||||
Scope.Add("profile");
|
||||
Scope.Add("email");
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// access_type. Set to 'offline' to request a refresh token.
|
||||
/// </summary>
|
||||
public string AccessType { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
42
src/Yavsc/AuthorizationServer/MonoJwtSecurityTokenHandler.cs
Normal file
42
src/Yavsc/AuthorizationServer/MonoJwtSecurityTokenHandler.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
|
||||
|
||||
using System;
|
||||
using System.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Yavsc.Auth
|
||||
{
|
||||
|
||||
public class MonoJwtSecurityTokenHandler : JwtSecurityTokenHandler
|
||||
{
|
||||
|
||||
MonoDataProtectionProvider protectionProvider;
|
||||
public MonoJwtSecurityTokenHandler(MonoDataProtectionProvider prpro)
|
||||
{
|
||||
protectionProvider = prpro;
|
||||
}
|
||||
public override JwtSecurityToken CreateToken(
|
||||
string issuer,
|
||||
string audience, ClaimsIdentity subject,
|
||||
DateTime? notBefore, DateTime? expires, DateTime? issuedAt,
|
||||
SigningCredentials signingCredentials
|
||||
)
|
||||
{
|
||||
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Audience = audience,
|
||||
Claims = subject.Claims,
|
||||
Expires = expires,
|
||||
IssuedAt = issuedAt,
|
||||
Issuer = issuer,
|
||||
NotBefore = notBefore,
|
||||
SigningCredentials = signingCredentials
|
||||
};
|
||||
var token = base.CreateToken(tokenDescriptor);
|
||||
return token as JwtSecurityToken;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
101
src/Yavsc/AuthorizationServer/RSAKeyUtils.cs
Normal file
101
src/Yavsc/AuthorizationServer/RSAKeyUtils.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
public class RSAKeyUtils
|
||||
{
|
||||
public static RSAParameters GetRandomKey()
|
||||
{
|
||||
using (var rsa = new RSACryptoServiceProvider(2048))
|
||||
{
|
||||
try
|
||||
{
|
||||
return rsa.ExportParameters(true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
rsa.PersistKeyInCsp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static RSAParameters GenerateKeyAndSave(string file)
|
||||
{
|
||||
var p = GetRandomKey();
|
||||
RSAParametersWithPrivate t = new RSAParametersWithPrivate();
|
||||
t.SetParameters(p);
|
||||
File.WriteAllText(file, JsonConvert.SerializeObject(t));
|
||||
return p;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This expects a file in the format:
|
||||
/// {
|
||||
/// "Modulus": "z7eXmrs9z3Xm7VXwYIdziDYzXGfi3XQiozIRa58m3ApeLVDcsDeq6Iv8C5zJ2DHydDyc0x6o5dtTRIb23r5/ZRj4I/UwbgrwMk5iHA0bVsXVPBDSWsrVcPDGafr6YbUNQnNWIF8xOqgpeTwxrqGiCJMUjuKyUx01PBzpBxjpnQ++Ryz6Y7MLqKHxBkDiOw5wk9cxO8/IMspSNJJosOtRXFTR74+bj+pvNBa8IJ+5Jf/UfJEEjk+qC+pohCAryRk0ziXcPdxXEv5KGT4zf3LdtHy1YwsaGLnTb62vgbdqqCJaVyHWOoXsDTQBLjxNl9o9CzP6CrfBGK6JV8pA/xfQlw==",
|
||||
/// "Exponent": "AQAB",
|
||||
/// "P": "+VsETS2exORYlg2CxaRMzyG60dTfHSuv0CsfmO3PFv8mcYxglGa6bUV5VGtB6Pd1HdtV/iau1WR/hYXQphCP99Pu803NZvFvVi34alTFbh0LMfZ+2iQ9toGzVfO8Qdbj7go4TWoHNzCpG4UCx/9wicVIWJsNzkppSEcXYigADMM=",
|
||||
/// "Q": "1UCJ2WAHasiCdwJtV2Ep0VCK3Z4rVFLWg3q1v5OoOU1CkX5/QAcrr6bX6zOdHR1bDCPsH1n1E9cCMvwakgi9M4Ch0dYF5CxDKtlx+IGsZJL0gB6HhcEsHat+yXUtOAlS4YB82G1hZqiDw+Q0O8LGyu/gLDPB+bn0HmbkUC2kP50=",
|
||||
/// "DP": "CBqvLxr2eAu73VSfFXFblbfQ7JTwk3AiDK/6HOxNuL+eLj6TvP8BvB9v7BB4WewBAHFqgBIdyI21n09UErGjHDjlIT88F8ZtCe4AjuQmboe/H2aVhN18q/vXKkn7qmAjlE78uXdiuKZ6OIzAJGPm8nNZAJg5gKTmexTka6pFJiU=",
|
||||
/// "DQ": "ND6zhwX3yzmEfROjJh0v2ZAZ9WGiy+3fkCaoEF9kf2VmQa70DgOzuDzv+TeT7mYawEasuqGXYVzztPn+qHhrogqJmpcMqnINopnTSka6rYkzTZAtM5+35yz0yvZiNbBTFdwcuglSK4xte7iU828stNs/2JR1mXDtVeVvWhVUgCE=",
|
||||
/// "InverseQ": "Heo0BHv685rvWreFcI5MXSy3AN0Zs0YbwAYtZZd1K/OzFdYVdOnqw+Dg3wGU9yFD7h4icJFwZUBGOZ0ww/gZX/5ZgJK35/YY/DeV+qfZmywKauUzC6+DPsrDdW1uf1eAety6/huRZTduBFTwIOlPdZ+PY49j6S38DjPFNImn0cU=",
|
||||
/// "D": "IvjMI5cGzxkQqkDf2cC0aOiHOTWccqCM/GD/odkH1+A+/u4wWdLliYWYB/R731R5d6yE0t7EnP6SRGVcxx/XnxPXI2ayorRgwHeF+ScTxUZFonlKkVK5IOzI2ysQYMb01o1IoOamCTQq12iVDMvV1g+9VFlCoM+4GMjdSv6cxn6ELabuD4nWt8tCskPjECThO+WdrknbUTppb2rRgMvNKfsPuF0H7+g+WisbzVS+UVRvJe3U5O5X5j7Z82Uq6hw2NCwv2YhQZRo/XisFZI7yZe0OU2JkXyNG3NCk8CgsM9yqX8Sk5esXMZdJzjwXtEpbR7FiKZXiz9LhPSmzxz/VsQ=="
|
||||
/// }
|
||||
///
|
||||
/// Generate
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public static RSAParameters GetKeyParameters(string file)
|
||||
{
|
||||
if (!File.Exists(file)) throw new FileNotFoundException("Check configuration - cannot find auth key file: " + file);
|
||||
var keyParams = JsonConvert.DeserializeObject<RSAParametersWithPrivate>(File.ReadAllText(file));
|
||||
return keyParams.ToRSAParameters();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Util class to allow restoring RSA parameters from JSON as the normal
|
||||
/// RSA parameters class won't restore private key info.
|
||||
/// </summary>
|
||||
private class RSAParametersWithPrivate
|
||||
{
|
||||
public byte[] D { get; set; }
|
||||
public byte[] DP { get; set; }
|
||||
public byte[] DQ { get; set; }
|
||||
public byte[] Exponent { get; set; }
|
||||
public byte[] InverseQ { get; set; }
|
||||
public byte[] Modulus { get; set; }
|
||||
public byte[] P { get; set; }
|
||||
public byte[] Q { get; set; }
|
||||
|
||||
public void SetParameters(RSAParameters p)
|
||||
{
|
||||
D = p.D;
|
||||
DP = p.DP;
|
||||
DQ = p.DQ;
|
||||
Exponent = p.Exponent;
|
||||
InverseQ = p.InverseQ;
|
||||
Modulus = p.Modulus;
|
||||
P = p.P;
|
||||
Q = p.Q;
|
||||
}
|
||||
public RSAParameters ToRSAParameters()
|
||||
{
|
||||
return new RSAParameters()
|
||||
{
|
||||
D = this.D,
|
||||
DP = this.DP,
|
||||
DQ = this.DQ,
|
||||
Exponent = this.Exponent,
|
||||
InverseQ = this.InverseQ,
|
||||
Modulus = this.Modulus,
|
||||
P = this.P,
|
||||
Q = this.Q
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/Yavsc/AuthorizationServer/RequiredScopesMiddleware.cs
Normal file
57
src/Yavsc/AuthorizationServer/RequiredScopesMiddleware.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Api
|
||||
{
|
||||
public class RequiredScopesMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IEnumerable<string> _requiredScopes;
|
||||
|
||||
public RequiredScopesMiddleware(RequestDelegate next, IList<string> requiredScopes)
|
||||
{
|
||||
_next = next;
|
||||
_requiredScopes = requiredScopes;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
if (context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
if (!ScopePresent(context.User))
|
||||
{
|
||||
context.Response.OnCompleted(Send403, context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
|
||||
private bool ScopePresent(ClaimsPrincipal principal)
|
||||
{
|
||||
foreach (var scope in principal.FindAll("scope"))
|
||||
{
|
||||
if (_requiredScopes.Contains(scope.Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Task Send403(object contextObject)
|
||||
{
|
||||
var context = contextObject as HttpContext;
|
||||
context.Response.StatusCode = 403;
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Yavsc/AuthorizationServer/TokenAuthOptions.cs
Normal file
26
src/Yavsc/AuthorizationServer/TokenAuthOptions.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.IdentityModel.Tokens;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
[Obsolete("Use OAuth2AppSettings instead")]
|
||||
public class TokenAuthOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Public's identification
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Audience { get; set; }
|
||||
/// <summary>
|
||||
/// Identity authority
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Issuer { get; set; }
|
||||
/// <summary>
|
||||
/// Signin key and signature algotythm
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SigningCredentials SigningCredentials { get; set; }
|
||||
public int ExpiresIn { get; set; }
|
||||
}
|
||||
}
|
||||
43
src/Yavsc/AuthorizationServer/UserTokenProvider.cs
Normal file
43
src/Yavsc/AuthorizationServer/UserTokenProvider.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.DataProtection;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace Yavsc.Auth {
|
||||
|
||||
public class UserTokenProvider : Microsoft.AspNet.Identity.IUserTokenProvider<ApplicationUser>
|
||||
{
|
||||
private MonoDataProtector protector=null;
|
||||
public MonoDataProtector Protector {
|
||||
get { return protector; }
|
||||
}
|
||||
|
||||
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<ApplicationUser> manager, ApplicationUser user)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public Task<string> GenerateAsync(string purpose, UserManager<ApplicationUser> manager, ApplicationUser user)
|
||||
{
|
||||
if ( user==null ) throw new InvalidOperationException("no user");
|
||||
var por = new MonoDataProtector(Constants.ApplicationName,new string[] { purpose } );
|
||||
|
||||
return Task.FromResult(por.Protect(UserStamp(user)));
|
||||
}
|
||||
|
||||
public Task<bool> ValidateAsync(string purpose, string token, UserManager<ApplicationUser> manager, ApplicationUser user)
|
||||
{
|
||||
var por = new MonoDataProtector(Constants.ApplicationName,new string[] { purpose } );
|
||||
var userStamp = por.Unprotect(token);
|
||||
Console.WriteLine ("Unprotected: "+userStamp);
|
||||
string [] values = userStamp.Split(';');
|
||||
return Task.FromResult ( user.Id == values[0] && user.Email == values[1] && user.UserName == values[2]);
|
||||
}
|
||||
|
||||
public static string UserStamp(ApplicationUser user) {
|
||||
return $"{user.Id};{user.Email};{user.UserName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Yavsc/AuthorizationServer/XmlEncryptor.cs
Normal file
23
src/Yavsc/AuthorizationServer/XmlEncryptor.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.DataProtection.XmlEncryption;
|
||||
|
||||
namespace Yavsc.Auth {
|
||||
|
||||
public class MonoXmlEncryptor : IXmlEncryptor
|
||||
{
|
||||
public MonoXmlEncryptor (IServiceProvider serviceProvider)
|
||||
{
|
||||
}
|
||||
public EncryptedXmlInfo Encrypt(XElement plaintextElement)
|
||||
{
|
||||
var result = new EncryptedXmlInfo(plaintextElement,
|
||||
typeof(MonoDataProtector));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue