réactive oidc, définitivement.

vnext
Paul Schneider 8 years ago
parent d5bcfd19f6
commit ebed4d2c50
7 changed files with 356 additions and 98 deletions

@ -1,17 +1,53 @@

@using Microsoft.AspNet.Http.Authentication
@model IEnumerable<AuthenticationDescription>
@using Yavsc.ViewModels.Account
@model LoginViewModel
<div class="jumbotron">
<h1>Authentication</h1>
<p class="lead text-left">Sign in using one of these external providers:</p>
<hr/>
<h2 class="lead text-left">Use a local account to log in</h2>
<form action="/login" method="post" class="form-horizontal" role="form">
@foreach (var description in Model) {
<div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
<div class="form-group">
<label for="UserName" class="col-md-2 control-label">User name</label>
<div class="col-md-10">
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label for="Password" class="col-md-2 control-label">Password</label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-lg btn-success">Login</button>
</div>
</div>
<p>
<a asp-action="Register">Register as a new user?</a>
</p>
<p>
<a asp-action="ForgotPassword">Forgot your password?</a>
</p>
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
@Html.AntiForgeryToken()
</form>
<hr/>
<h2 class="lead text-left">Sign in using one of these external providers:</h2>
@foreach (var description in Model.ExternalProviders) {
<form action="/signin" method="post">
<input type="hidden" name="Provider" value="@description.AuthenticationScheme" />
<input type="hidden" name="ReturnUrl" value="@ViewBag.ReturnUrl" />
<input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
<button class="btn btn-lg btn-success" type="submit">Connect using @description.DisplayName</button>
@Html.AntiForgeryToken()
</form>
}
</div>

@ -44,9 +44,9 @@
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">@SR["Home"]</a></li>
<li><a asp-controller="Home" asp-action="About">@SR["About"] @SiteSettings.Value.Title</a> </li>
<li><a asp-controller="Home" asp-action="Contact">@SR["Contact"]</a></li>
<li><a asp-controller="Home" asp-action="Index" class="navbar-link">@SR["Home"]</a></li>
<li><a asp-controller="Home" asp-action="About" class="navbar-link">@SR["About"] @SiteSettings.Value.Title</a> </li>
<li><a asp-controller="Home" asp-action="Contact" class="navbar-link">@SR["Contact"]</a></li>
</ul>
@await Html.PartialAsync("_LoginPartial")
</div>

@ -6,10 +6,10 @@
<language-layout>
<ul class="nav navbar-nav navbar-right">
<li>
<a asp-controller="Manage" asp-action="Index" title="Manage">@SR["Hello"] @User.GetUserName()!</a>
<a asp-controller="Manage" class="navbar-link" asp-action="Index" title="Manage">@SR["Hello"] @User.GetUserName()!</a>
</li>
<li>
<button type="submit" class="btn btn-link navbar-btn navbar-link">@SR["Logout"]</button>
<button type="submit" class="navbar-link">@SR["Logout"]</button>
</li>
</ul>
</language-layout>
@ -18,8 +18,9 @@
else
{ <language-layout>
<ul class="nav navbar-nav navbar-right">
<li><a asp-controller="Account" asp-action="Register">@SR["Register"]</a></li>
<li><a asp-controller="Account" asp-action="Login">@SR["Login"]</a></li>
<li><a class="navbar-link" asp-controller="Account" asp-action="Register">@SR["Register"]</a></li>
<li><a class="navbar-link" asp-controller="Account" asp-action="SignIn">@SR["Login"]</a></li>
</ul>
</language-layout>
}

@ -5,6 +5,7 @@ using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
@ -30,7 +31,7 @@ namespace Yavsc.Controllers
SmtpSettings _smtpSettings;
TwilioSettings _twilioSettings;
// TwilioSettings _twilioSettings;
// TwilioSettings _twilioSettings;
public AccountController(
UserManager<ApplicationUser> userManager,
@ -42,22 +43,38 @@ namespace Yavsc.Controllers
{
_userManager = userManager;
_signInManager = signInManager;
// _userManager.RegisterTokenProvider("SMS",new UserTokenProvider());
// _userManager.RegisterTokenProvider("Phone", new UserTokenProvider());
// _userManager.RegisterTokenProvider("SMS",new UserTokenProvider());
// _userManager.RegisterTokenProvider("Phone", new UserTokenProvider());
_emailSender = emailSender;
_siteSettings = siteSettings.Value;
_smtpSettings = smtpSettings.Value;
_twilioSettings = twilioSettings.Value;
_logger = loggerFactory.CreateLogger<AccountController>();
}
[HttpGet("~/signin")]
public ActionResult SignIn(string returnUrl = "/")
{
return View("SignIn", new LoginViewModel
{
ReturnUrl = returnUrl,
ExternalProviders = _signInManager.GetExternalAuthenticationSchemes()
});
/* When using an external login provider :
// Request a redirect to the external login provider.
var redirectUrl = returnUrl ?? "/";
var properties = _signInManager.ConfigureExternalAuthenticationProperties(OpenIdConnectDefaults.AuthenticationScheme, redirectUrl);
return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme, properties);
*/
}
//
// GET: /Account/Login
[HttpGet]
public IActionResult Login(string returnUrl = null)
[HttpGet("~/signout"), HttpPost("~/signout")]
public async Task<IActionResult> SignOut(string returnUrl = "/")
{
ViewData["ReturnUrl"] = returnUrl;
return View();
// Instruct the cookies middleware to delete the local cookie created when the user agent
// is redirected from the identity provider after a successful authorization flow and
// to redirect the user agent to the identity provider to sign out.
await _signInManager.SignOutAsync();
return Redirect(returnUrl);
}
public IActionResult Forbidden()
@ -65,15 +82,45 @@ namespace Yavsc.Controllers
return View();
}
// POST: /Account/Login
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
[HttpPost("~/signin")]
public async Task<IActionResult> SignIn(string provider, string returnUrl)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
// Note: the "provider" parameter corresponds to the external
// authentication provider choosen by the user agent.
if (string.IsNullOrEmpty(provider))
{
_logger.LogWarning("null provider");
ModelState.AddModelError("provider", "provider cannot be null");
return new BadRequestObjectResult(ModelState);
}
// Note: the "returnUrl" parameter corresponds to the endpoint the user agent
// will be redirected to after a successful authentication and not
// the redirect_uri of the requesting client application.
if (string.IsNullOrEmpty(returnUrl))
{
_logger.LogWarning($"null returnUrl ({provider}) ");
ModelState.AddModelError("returnUrl", "returnUrl cannot be null");
return new BadRequestObjectResult(ModelState);
}
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
// Request a redirect to the external login provider.
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}
[HttpPost("~/login")]
public async Task<IActionResult> LocalLogin(LoginViewModel model)
{
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
@ -81,11 +128,11 @@ namespace Yavsc.Controllers
{
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
return RedirectToLocal(model.ReturnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
return RedirectToAction(nameof(SendCode), new { ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
@ -98,11 +145,9 @@ namespace Yavsc.Controllers
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// GET: /Account/Register
[HttpGet]
@ -127,7 +172,7 @@ namespace Yavsc.Controllers
// Send an email with this link
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(_siteSettings, _smtpSettings, model.Email, "Confirm your account",
await _emailSender.SendEmailAsync(_siteSettings, _smtpSettings, model.Email, "Confirm your account",
"Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
// await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account with password.");
@ -171,7 +216,7 @@ namespace Yavsc.Controllers
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
return RedirectToAction(nameof(SignIn));
}
// Sign in the user with this external login provider if the user already has a login.
@ -198,20 +243,23 @@ namespace Yavsc.Controllers
var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
var name = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Name);
var avatar = info.ExternalPrincipal.FindFirstValue("urn:google:profile");
/* var phone = info.ExternalPrincipal.FindFirstValue(ClaimTypes.HomePhone);
var mobile = info.ExternalPrincipal.FindFirstValue(ClaimTypes.MobilePhone);
var postalcode = info.ExternalPrincipal.FindFirstValue(ClaimTypes.PostalCode);
var locality = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Locality);
var country = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Country);*/
/* var phone = info.ExternalPrincipal.FindFirstValue(ClaimTypes.HomePhone);
var mobile = info.ExternalPrincipal.FindFirstValue(ClaimTypes.MobilePhone);
var postalcode = info.ExternalPrincipal.FindFirstValue(ClaimTypes.PostalCode);
var locality = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Locality);
var country = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Country);*/
foreach (var claim in info.ExternalPrincipal.Claims)
_logger.LogWarning("# {0} Claim: {1} {2}",info.LoginProvider,claim.Type,claim.Value);
_logger.LogWarning("# {0} Claim: {1} {2}", info.LoginProvider, claim.Type, claim.Value);
var access_token = info.ExternalPrincipal.FindFirstValue("access_token");
var token_type = info.ExternalPrincipal.FindFirstValue("token_type");
var expires_in = info.ExternalPrincipal.FindFirstValue("expires_in");
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email,
Name = name });
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel
{
Email = email,
Name = name
});
}
}
@ -358,13 +406,13 @@ namespace Yavsc.Controllers
//
// GET: /Account/SendCode
[HttpGet,AllowAnonymous]
[HttpGet, AllowAnonymous]
public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
{
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error",new Exception("No Two factor authentication user" ));
return View("Error", new Exception("No Two factor authentication user"));
}
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
@ -376,7 +424,7 @@ namespace Yavsc.Controllers
//
// POST: /Account/SendCode
[HttpPost]
[ValidateAntiForgeryToken,AllowAnonymous]
[ValidateAntiForgeryToken, AllowAnonymous]
public async Task<IActionResult> SendCode(SendCodeViewModel model)
{
if (!ModelState.IsValid)
@ -386,26 +434,26 @@ namespace Yavsc.Controllers
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error",new Exception("user is null"));
return View("Error", new Exception("user is null"));
}
// Generate the token and send it
var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider);
if (string.IsNullOrWhiteSpace(code))
{
return View("Error",new Exception("Code is empty"));
return View("Error", new Exception("Code is empty"));
}
var message = "Your security code is: " + code;
if (model.SelectedProvider == Constants.MobileAppFactor)
{
return View("Error",new Exception("No SMS service was activated"));
return View("Error", new Exception("No SMS service was activated"));
}
else // if (model.SelectedProvider == Constants.EMailFactor || model.SelectedProvider == "Default" )
if (model.SelectedProvider == Constants.SMSFactor)
{
return View("Error",new Exception("No SMS service was activated"));
// await _smsSender.SendSmsAsync(_twilioSettings, await _userManager.GetPhoneNumberAsync(user), message);
return View("Error", new Exception("No SMS service was activated"));
// await _smsSender.SendSmsAsync(_twilioSettings, await _userManager.GetPhoneNumberAsync(user), message);
}
else // if (model.SelectedProvider == Constants.EMailFactor || model.SelectedProvider == "Default" )
{
@ -423,7 +471,7 @@ namespace Yavsc.Controllers
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error",new Exception("user is null"));
return View("Error", new Exception("user is null"));
}
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
}
@ -442,7 +490,7 @@ namespace Yavsc.Controllers
// The following code protects for brute force attacks against the two factor codes.
// If a user enters incorrect codes for a specified amount of time then the user account
// will be locked out for a specified amount of time.
_logger.LogWarning("Signin with code: {0} {1}",model.Provider, model.Code);
_logger.LogWarning("Signin with code: {0} {1}", model.Provider, model.Code);
var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
if (result.Succeeded)
{
@ -461,13 +509,13 @@ namespace Yavsc.Controllers
}
}
[HttpGet,Authorize]
[HttpGet, Authorize]
public IActionResult Delete()
{
return View();
}
[HttpPost,Authorize]
[HttpPost, Authorize]
public async Task<IActionResult> Delete(UnregisterViewModel model)
{
if (!ModelState.IsValid)
@ -477,13 +525,13 @@ namespace Yavsc.Controllers
var user = await _userManager.FindByIdAsync(User.GetUserId());
var result = await _userManager.DeleteAsync(user);
if (!result.Succeeded)
{
AddErrors(result);
return new BadRequestObjectResult(ModelState);
}
{
AddErrors(result);
return new BadRequestObjectResult(ModelState);
}
await _signInManager.SignOutAsync();
return RedirectToAction("Index","Home");
return RedirectToAction("Index", "Home");
}
#region Helpers

@ -0,0 +1,128 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Yavsc.Models;
namespace Yavsc.Providers {
public sealed class AuthorizationProvider : OpenIdConnectServerProvider {
private ILogger _logger;
public AuthorizationProvider(ILoggerFactory loggerFactory) {
_logger = loggerFactory.CreateLogger<AuthorizationProvider>();
}
public override Task MatchEndpoint(MatchEndpointContext context) {
// Note: by default, OpenIdConnectServerHandler only handles authorization requests made to the authorization endpoint.
// This context handler uses a more relaxed policy that allows extracting authorization requests received at
// /connect/authorize/accept and /connect/authorize/deny (see AuthorizationController.cs for more information).
if (context.Options.AuthorizationEndpointPath.HasValue &&
context.Request.Path.StartsWithSegments(context.Options.AuthorizationEndpointPath)) {
context.MatchesAuthorizationEndpoint();
}
return Task.FromResult<object>(null);
}
public override async Task ValidateAuthorizationRequest(ValidateAuthorizationRequestContext context) {
// Note: the OpenID Connect server middleware supports the authorization code, implicit and hybrid flows
// but this authorization provider only accepts response_type=code authorization/authentication requests.
// You may consider relaxing it to support the implicit or hybrid flows. In this case, consider adding
// checks rejecting implicit/hybrid authorization requests when the client is a confidential application.
if (!context.Request.IsAuthorizationCodeFlow()) {
context.Rejected(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
description: "Only the authorization code flow is supported by this authorization server");
return;
}
var database = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
_logger.LogInformation($"Searching fo app id {context.ClientId}");
// Retrieve the application details corresponding to the requested client_id.
var application = await (from entity in database.Applications
where entity.ApplicationID == context.ClientId
select entity).SingleOrDefaultAsync(context.HttpContext.RequestAborted);
if (application == null) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Application not found in the database: ensure that your client_id is correct");
return;
}
if (!string.IsNullOrEmpty(context.Request.RedirectUri) &&
!string.Equals(context.Request.RedirectUri, application.RedirectUri, StringComparison.Ordinal)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Invalid redirect_uri");
return;
}
context.Validated();
}
public override async Task ValidateTokenRequest(ValidateTokenRequestContext context) {
// Note: the OpenID Connect server middleware supports authorization code, refresh token, client credentials
// and resource owner password credentials grant types but this authorization provider uses a safer policy
// rejecting the last two ones. You may consider relaxing it to support the ROPC or client credentials grant types.
if (!context.Request.IsAuthorizationCodeGrantType() && !context.Request.IsRefreshTokenGrantType()) {
context.Rejected(
error: OpenIdConnectConstants.Errors.UnsupportedGrantType,
description: "Only authorization code and refresh token grant types " +
"are accepted by this authorization server");
return;
}
// Note: client authentication is not mandatory for non-confidential client applications like mobile apps
// (except when using the client credentials grant type) but this authorization server uses a safer policy
// that makes client authentication mandatory and returns an error if client_id or client_secret is missing.
// You may consider relaxing it to support the resource owner password credentials grant type
// with JavaScript or desktop applications, where client credentials cannot be safely stored.
// In this case, call context.Skip() to inform the server middleware the client is not trusted.
if (string.IsNullOrEmpty(context.Request.ClientId) || string.IsNullOrEmpty(context.Request.ClientSecret)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "Missing credentials: ensure that your credentials were correctly " +
"flowed in the request body or in the authorization header");
return;
}
var database = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
// Retrieve the application details corresponding to the requested client_id.
var application = await (from entity in database.Applications
where entity.ApplicationID == context.ClientId
select entity).SingleOrDefaultAsync(context.HttpContext.RequestAborted);
if (application == null) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Application not found in the database: ensure that your client_id is correct");
return;
}
if (!string.Equals(context.Request.ClientSecret, application.Secret, StringComparison.Ordinal)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Invalid credentials: ensure that you specified a correct client_secret");
return;
}
context.Validated();
}
}
}

@ -35,8 +35,10 @@ using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.Extensions.WebEncoders;
using Microsoft.Net.Http.Headers;
using Yavsc.Auth;
using Yavsc.Extensions;
using Yavsc.Formatters;
using Yavsc.Models;
using Yavsc.Providers;
using Yavsc.Services;
@ -66,8 +68,6 @@ namespace Yavsc
"~/bower_components/dropzone/dist/min/basic.min.css",
"~/bower_components/dropzone/dist/min/dropzone.min.css"
));
}
}
@ -155,7 +155,8 @@ namespace Yavsc
RSAKeyUtils.GetKeyParameters(keyParamsFileInfo.Name) :
RSAKeyUtils.GenerateKeyAndSave(keyParamsFileInfo.Name);
key = new RsaSecurityKey(keyParams);
services.Configure<SharedAuthenticationOptions>(options => {
services.Configure<SharedAuthenticationOptions>(options =>
{
options.SignInScheme = "ServerCookie";
});
services.Configure<TokenAuthOptions>(
@ -187,8 +188,10 @@ namespace Yavsc
configure.PersistKeysToFileSystem(
new DirectoryInfo(Configuration["DataProtection:Keys:Dir"]));
});
services.AddAuthentication();
services.AddAuthentication(options => {
options.SignInScheme = "ServerCookie"; }
);
// Add framework services.
services.AddEntityFramework()
.AddNpgsql()
@ -227,12 +230,13 @@ namespace Yavsc
// Add the system clock service
services.AddSingleton<ISystemClock, SystemClock>();
services.AddAuthorization(options =>
{
options.AddPolicy("AdministratorOnly", policy => policy.RequireRole(Constants.AdminGroupName));
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
options.AddPolicy("API", policy => {
options.AddPolicy("API", policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireClaim(OpenIdConnectConstants.Claims.Scope, "api-resource-controller");
});
@ -319,7 +323,7 @@ namespace Yavsc
{
// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
app.UseExceptionHandler("/Home/Error");
app.UseExceptionHandler("/Home/Error");
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
@ -334,18 +338,12 @@ namespace Yavsc
if (ex.InnerException is InvalidOperationException)
// nothing to do ?
{
// TODO Send an email to the Admin
}
// TODO Send an email to the Admin
}
else throw ex;
}
}
// Create a new branch where the registered middleware will be executed only for API calls.
/* MapWhenExtensions.MapWhen(app,(Func<Microsoft.AspNet.Http.HttpContext, bool>)(context =>
context.Request.Path.StartsWithSegments((PathString)new PathString((string)"/api"))),
(Action<IApplicationBuilder>)( branch => { }));
*/
var googleOptions = new GoogleOptions
{
@ -376,19 +374,6 @@ namespace Yavsc
googleOptions.Scope.Add("https://www.googleapis.com/auth/calendar");
var udirinfo = new DirectoryInfo(Configuration["Site:UserFiles:RootDir"]);
if (!udirinfo.Exists)
throw new Exception($"Configuration value for Site:UserFiles:RootDir : {udirinfo.FullName}");
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(
udirinfo.FullName),
RequestPath = new PathString(Constants.UserFilesRequestPath),
EnableDirectoryBrowsing = true
});
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseStaticFiles().UseWebSockets();
@ -397,28 +382,83 @@ namespace Yavsc
app.UseIdentity();
// Create a new branch where the registered middleware will be executed only for non API calls.
app.UseCookieAuthentication(options => {
app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
{
branch.UseJwtBearerAuthentication(options =>
{
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.RequireHttpsMetadata = false;
options.Audience = siteSettings.Value.Audience;
options.Authority = siteSettings.Value.Authority;
});
});
// Create a new branch where the registered middleware will be executed only for API calls.
app.UseWhen(context => !context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
{
// Create a new branch where the registered middleware will be executed only for non API calls.
branch.UseCookieAuthentication(options =>
{
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.AuthenticationScheme = "ServerCookie";
options.CookieName = CookieAuthenticationDefaults.CookiePrefix + "ServerCookie";
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = new PathString("/Account/Login");
options.LoginPath = new PathString("/signin");
options.LogoutPath = new PathString("/signout");
});
app.UseMiddleware<GoogleMiddleware>(googleOptions);
branch.UseMiddleware<GoogleMiddleware>(googleOptions);
// Facebook
app.UseFacebookAuthentication(options =>
{
options.AppId = Configuration["Authentication:Facebook:AppId"];
options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
options.Scope.Add("email");
options.UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email,first_name,last_name";
});
branch.UseFacebookAuthentication(options =>
{
options.AppId = Configuration["Authentication:Facebook:AppId"];
options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
options.Scope.Add("email");
options.UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email,first_name,last_name";
});
});
app.UseOpenIdConnectServer(options =>
{
options.Provider = new AuthorizationProvider(loggerFactory);
// Register the certificate used to sign the JWT tokens.
/* options.SigningCredentials.AddCertificate(
assembly: typeof(Startup).GetTypeInfo().Assembly,
resource: "Mvc.Server.Certificate.pfx",
password: "Owin.Security.OpenIdConnect.Server"); */
// options.SigningCredentials.AddKey(key);
// Note: see AuthorizationController.cs for more
// information concerning ApplicationCanDisplayErrors.
options.ApplicationCanDisplayErrors = true;
options.AllowInsecureHttp = true;
options.AutomaticChallenge = true;
options.AuthorizationEndpointPath = new PathString("/connect/authorize");
options.TokenEndpointPath = new PathString("/connect/authorize/accept");
options.UseSlidingExpiration = true;
options.AllowInsecureHttp = true;
options.AuthenticationScheme = "oidc"; // was = OpenIdConnectDefaults.AuthenticationScheme;
options.LogoutEndpointPath = new PathString("/connect/logout");
/* options.ValidationEndpointPath = new PathString("/connect/introspect"); */
});
var udirinfo = new DirectoryInfo(Configuration["Site:UserFiles:RootDir"]);
if (!udirinfo.Exists)
throw new Exception($"Configuration value for Site:UserFiles:RootDir : {udirinfo.FullName}");
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(
udirinfo.FullName),
RequestPath = new PathString(Constants.UserFilesRequestPath),
EnableDirectoryBrowsing = true
});
/* Generic OAuth (here GitHub): options.Notifications = new OAuthAuthenticationNotifications

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Http.Authentication;
namespace Yavsc.ViewModels.Account
{
@ -14,5 +16,8 @@ namespace Yavsc.ViewModels.Account
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
public string ReturnUrl { get; set; }
public IEnumerable<AuthenticationDescription> ExternalProviders { get; set; }
}
}

Loading…