diff --git a/samples/CookieSample/Startup.cs b/samples/CookieSample/Startup.cs
index 6547450e51..04694b7cfd 100644
--- a/samples/CookieSample/Startup.cs
+++ b/samples/CookieSample/Startup.cs
@@ -28,7 +28,7 @@ namespace CookieSample
if (string.IsNullOrEmpty(context.User.Identity.Name))
{
var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }));
- context.Authentication.SignIn(CookieAuthenticationDefaults.AuthenticationScheme, user);
+ await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello First timer");
return;
diff --git a/samples/CookieSessionSample/Startup.cs b/samples/CookieSessionSample/Startup.cs
index f0b1b5219b..5858c2c39f 100644
--- a/samples/CookieSessionSample/Startup.cs
+++ b/samples/CookieSessionSample/Startup.cs
@@ -36,7 +36,7 @@ namespace CookieSessionSample
{
claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe"));
}
- context.Authentication.SignIn(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(claims)));
+ await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(claims)));
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello First timer");
return;
diff --git a/samples/OpenIdConnectSample/Startup.cs b/samples/OpenIdConnectSample/Startup.cs
index 2077d802bb..b07d87da50 100644
--- a/samples/OpenIdConnectSample/Startup.cs
+++ b/samples/OpenIdConnectSample/Startup.cs
@@ -40,7 +40,7 @@ namespace OpenIdConnectSample
{
if (string.IsNullOrEmpty(context.User.Identity.Name))
{
- context.Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
+ await context.Authentication.ChallengeAsync(OpenIdConnectAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello First timer");
diff --git a/samples/SocialSample/Startup.cs b/samples/SocialSample/Startup.cs
index eb6c74563b..62d9c83803 100644
--- a/samples/SocialSample/Startup.cs
+++ b/samples/SocialSample/Startup.cs
@@ -187,7 +187,7 @@ namespace CookieSample
{
// By default the client will be redirect back to the URL that issued the challenge (/login?authtype=foo),
// send them to the home page instead (/).
- context.Authentication.Challenge(authType, new AuthenticationProperties() { RedirectUri = "/" });
+ await context.Authentication.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" });
return;
}
@@ -207,7 +207,7 @@ namespace CookieSample
{
signoutApp.Run(async context =>
{
- context.Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationScheme);
+ await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("
");
await context.Response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "
");
@@ -222,7 +222,7 @@ namespace CookieSample
if (string.IsNullOrEmpty(context.User.Identity.Name))
{
// The cookie middleware will intercept this 401 and redirect to /login
- context.Authentication.Challenge();
+ await context.Authentication.ChallengeAsync();
return;
}
await next();
diff --git a/src/Microsoft.AspNet.Authentication.Cookies/CookieAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.Cookies/CookieAuthenticationHandler.cs
index b790291ea9..66fe679bd1 100644
--- a/src/Microsoft.AspNet.Authentication.Cookies/CookieAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.Cookies/CookieAuthenticationHandler.cs
@@ -8,6 +8,8 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
+using Microsoft.AspNet.Http.Features.Authentication;
+using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Authentication.Cookies
@@ -26,12 +28,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
private DateTimeOffset _renewExpiresUtc;
private string _sessionKey;
- protected override AuthenticationTicket AuthenticateCore()
- {
- return AuthenticateCoreAsync().GetAwaiter().GetResult();
- }
-
- protected override async Task AuthenticateCoreAsync()
+ public override async Task AuthenticateAsync()
{
AuthenticationTicket ticket = null;
try
@@ -99,7 +96,6 @@ namespace Microsoft.AspNet.Authentication.Cookies
await Options.Notifications.ValidatePrincipal(context);
- AuthenticateCalled = true;
return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme);
}
catch (Exception exception)
@@ -115,19 +111,72 @@ namespace Microsoft.AspNet.Authentication.Cookies
}
}
- protected override void ApplyResponseGrant()
+ private CookieOptions BuildCookieOptions()
{
- ApplyResponseGrantAsync().GetAwaiter().GetResult();
+ var cookieOptions = new CookieOptions
+ {
+ Domain = Options.CookieDomain,
+ HttpOnly = Options.CookieHttpOnly,
+ Path = Options.CookiePath ?? (RequestPathBase.HasValue ? RequestPathBase.ToString() : "/"),
+ };
+ if (Options.CookieSecure == CookieSecureOption.SameAsRequest)
+ {
+ cookieOptions.Secure = Request.IsHttps;
+ }
+ else
+ {
+ cookieOptions.Secure = Options.CookieSecure == CookieSecureOption.Always;
+ }
+ return cookieOptions;
}
- protected override async Task ApplyResponseGrantAsync()
+ private async Task ApplyCookie(AuthenticationTicket model)
{
- var signin = SignInContext;
- var shouldSignin = signin != null;
- var signout = SignOutContext;
- var shouldSignout = signout != null;
+ var cookieOptions = BuildCookieOptions();
- if (!(shouldSignin || shouldSignout || _shouldRenew))
+ model.Properties.IssuedUtc = _renewIssuedUtc;
+ model.Properties.ExpiresUtc = _renewExpiresUtc;
+
+ if (Options.SessionStore != null && _sessionKey != null)
+ {
+ await Options.SessionStore.RenewAsync(_sessionKey, model);
+ var principal = new ClaimsPrincipal(
+ new ClaimsIdentity(
+ new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
+ Options.AuthenticationScheme));
+ model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
+ }
+
+ var cookieValue = Options.TicketDataFormat.Protect(model);
+
+ if (model.Properties.IsPersistent)
+ {
+ cookieOptions.Expires = _renewExpiresUtc.ToUniversalTime().DateTime;
+ }
+
+ Options.CookieManager.AppendResponseCookie(
+ Context,
+ Options.CookieName,
+ cookieValue,
+ cookieOptions);
+
+ Response.Headers.Set(
+ HeaderNameCacheControl,
+ HeaderValueNoCache);
+
+ Response.Headers.Set(
+ HeaderNamePragma,
+ HeaderValueNoCache);
+
+ Response.Headers.Set(
+ HeaderNameExpires,
+ HeaderValueMinusOne);
+ }
+
+ protected override async Task FinishResponseAsync()
+ {
+ // Only renew if requested, and neither sign in or sign out was called
+ if (!_shouldRenew || SignInAccepted || SignOutAccepted)
{
return;
}
@@ -135,133 +184,89 @@ namespace Microsoft.AspNet.Authentication.Cookies
var model = await AuthenticateAsync();
try
{
- var cookieOptions = new CookieOptions
+ await ApplyCookie(model);
+ }
+ catch (Exception exception)
+ {
+ var exceptionContext = new CookieExceptionContext(Context, Options,
+ CookieExceptionContext.ExceptionLocation.ApplyResponseGrant, exception, model);
+ Options.Notifications.Exception(exceptionContext);
+ if (exceptionContext.Rethrow)
{
- Domain = Options.CookieDomain,
- HttpOnly = Options.CookieHttpOnly,
- Path = Options.CookiePath ?? (RequestPathBase.HasValue ? RequestPathBase.ToString() : "/"),
- };
- if (Options.CookieSecure == CookieSecureOption.SameAsRequest)
+ throw;
+ }
+ }
+ }
+
+ protected override async Task HandleSignInAsync(SignInContext signin)
+ {
+ var model = await AuthenticateAsync();
+ try
+ {
+ var cookieOptions = BuildCookieOptions();
+
+ var signInContext = new CookieResponseSignInContext(
+ Context,
+ Options,
+ Options.AuthenticationScheme,
+ signin.Principal,
+ new AuthenticationProperties(signin.Properties),
+ cookieOptions);
+
+ DateTimeOffset issuedUtc;
+ if (signInContext.Properties.IssuedUtc.HasValue)
{
- cookieOptions.Secure = Request.IsHttps;
+ issuedUtc = signInContext.Properties.IssuedUtc.Value;
}
else
{
- cookieOptions.Secure = Options.CookieSecure == CookieSecureOption.Always;
+ issuedUtc = Options.SystemClock.UtcNow;
+ signInContext.Properties.IssuedUtc = issuedUtc;
}
- if (shouldSignin)
+ if (!signInContext.Properties.ExpiresUtc.HasValue)
{
- var signInContext = new CookieResponseSignInContext(
- Context,
- Options,
- Options.AuthenticationScheme,
- signin.Principal,
- new AuthenticationProperties(signin.Properties),
- cookieOptions);
-
- DateTimeOffset issuedUtc;
- if (signInContext.Properties.IssuedUtc.HasValue)
- {
- issuedUtc = signInContext.Properties.IssuedUtc.Value;
- }
- else
- {
- issuedUtc = Options.SystemClock.UtcNow;
- signInContext.Properties.IssuedUtc = issuedUtc;
- }
-
- if (!signInContext.Properties.ExpiresUtc.HasValue)
- {
- signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
- }
-
- Options.Notifications.ResponseSignIn(signInContext);
-
- if (signInContext.Properties.IsPersistent)
- {
- var expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
- signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime;
- }
-
- model = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.AuthenticationScheme);
- if (Options.SessionStore != null)
- {
- if (_sessionKey != null)
- {
- await Options.SessionStore.RemoveAsync(_sessionKey);
- }
- _sessionKey = await Options.SessionStore.StoreAsync(model);
- var principal = new ClaimsPrincipal(
- new ClaimsIdentity(
- new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
- Options.ClaimsIssuer));
- model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
- }
- var cookieValue = Options.TicketDataFormat.Protect(model);
-
- Options.CookieManager.AppendResponseCookie(
- Context,
- Options.CookieName,
- cookieValue,
- signInContext.CookieOptions);
-
- var signedInContext = new CookieResponseSignedInContext(
- Context,
- Options,
- Options.AuthenticationScheme,
- signInContext.Principal,
- signInContext.Properties);
-
- Options.Notifications.ResponseSignedIn(signedInContext);
+ signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
}
- else if (shouldSignout)
+
+ Options.Notifications.ResponseSignIn(signInContext);
+
+ if (signInContext.Properties.IsPersistent)
{
- if (Options.SessionStore != null && _sessionKey != null)
+ var expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
+ signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime;
+ }
+
+ model = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.AuthenticationScheme);
+ if (Options.SessionStore != null)
+ {
+ if (_sessionKey != null)
{
await Options.SessionStore.RemoveAsync(_sessionKey);
}
-
- var context = new CookieResponseSignOutContext(
- Context,
- Options,
- cookieOptions);
-
- Options.Notifications.ResponseSignOut(context);
-
- Options.CookieManager.DeleteCookie(
- Context,
- Options.CookieName,
- context.CookieOptions);
+ _sessionKey = await Options.SessionStore.StoreAsync(model);
+ var principal = new ClaimsPrincipal(
+ new ClaimsIdentity(
+ new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
+ Options.ClaimsIssuer));
+ model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
}
- else if (_shouldRenew)
- {
- model.Properties.IssuedUtc = _renewIssuedUtc;
- model.Properties.ExpiresUtc = _renewExpiresUtc;
+ var cookieValue = Options.TicketDataFormat.Protect(model);
- if (Options.SessionStore != null && _sessionKey != null)
- {
- await Options.SessionStore.RenewAsync(_sessionKey, model);
- var principal = new ClaimsPrincipal(
- new ClaimsIdentity(
- new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
- Options.AuthenticationScheme));
- model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
- }
+ Options.CookieManager.AppendResponseCookie(
+ Context,
+ Options.CookieName,
+ cookieValue,
+ signInContext.CookieOptions);
- var cookieValue = Options.TicketDataFormat.Protect(model);
+ var signedInContext = new CookieResponseSignedInContext(
+ Context,
+ Options,
+ Options.AuthenticationScheme,
+ signInContext.Principal,
+ signInContext.Properties);
- if (model.Properties.IsPersistent)
- {
- cookieOptions.Expires = _renewExpiresUtc.ToUniversalTime().DateTime;
- }
-
- Options.CookieManager.AppendResponseCookie(
- Context,
- Options.CookieName,
- cookieValue,
- cookieOptions);
- }
+ Options.Notifications.ResponseSignedIn(signedInContext);
Response.Headers.Set(
HeaderNameCacheControl,
@@ -275,10 +280,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
HeaderNameExpires,
HeaderValueMinusOne);
- var shouldLoginRedirect = shouldSignin && Options.LoginPath.HasValue && Request.Path == Options.LoginPath;
- var shouldLogoutRedirect = shouldSignout && Options.LogoutPath.HasValue && Request.Path == Options.LogoutPath;
+ var shouldLoginRedirect = Options.LoginPath.HasValue && Request.Path == Options.LoginPath;
- if ((shouldLoginRedirect || shouldLogoutRedirect) && Response.StatusCode == 200)
+ if ((shouldLoginRedirect) && Response.StatusCode == 200)
{
var query = Request.Query;
var redirectUri = query.Get(Options.ReturnUrlParameter);
@@ -302,6 +306,69 @@ namespace Microsoft.AspNet.Authentication.Cookies
}
}
+ protected override async Task HandleSignOutAsync(SignOutContext signOutContext)
+ {
+ var model = await AuthenticateAsync();
+ try
+ {
+ var cookieOptions = BuildCookieOptions();
+
+ if (Options.SessionStore != null && _sessionKey != null)
+ {
+ await Options.SessionStore.RemoveAsync(_sessionKey);
+ }
+
+ var context = new CookieResponseSignOutContext(
+ Context,
+ Options,
+ cookieOptions);
+
+ Options.Notifications.ResponseSignOut(context);
+
+ Options.CookieManager.DeleteCookie(
+ Context,
+ Options.CookieName,
+ context.CookieOptions);
+
+ Response.Headers.Set(
+ HeaderNameCacheControl,
+ HeaderValueNoCache);
+
+ Response.Headers.Set(
+ HeaderNamePragma,
+ HeaderValueNoCache);
+
+ Response.Headers.Set(
+ HeaderNameExpires,
+ HeaderValueMinusOne);
+
+ var shouldLogoutRedirect = Options.LogoutPath.HasValue && Request.Path == Options.LogoutPath;
+
+ if (shouldLogoutRedirect && Response.StatusCode == 200)
+ {
+ var query = Request.Query;
+ var redirectUri = query.Get(Options.ReturnUrlParameter);
+ if (!string.IsNullOrWhiteSpace(redirectUri)
+ && IsHostRelative(redirectUri))
+ {
+ var redirectContext = new CookieApplyRedirectContext(Context, Options, redirectUri);
+ Options.Notifications.ApplyRedirect(redirectContext);
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ var exceptionContext = new CookieExceptionContext(Context, Options,
+ CookieExceptionContext.ExceptionLocation.ApplyResponseGrant, exception, model);
+ Options.Notifications.Exception(exceptionContext);
+ if (exceptionContext.Rethrow)
+ {
+ throw;
+ }
+ }
+
+ }
+
private static bool IsHostRelative(string path)
{
if (string.IsNullOrEmpty(path))
@@ -315,60 +382,49 @@ namespace Microsoft.AspNet.Authentication.Cookies
return path[0] == '/' && path[1] != '/' && path[1] != '\\';
}
- protected override void ApplyResponseChallenge()
+ protected override Task HandleForbiddenAsync(ChallengeContext context)
{
- if (ShouldConvertChallengeToForbidden())
+ // HandleForbidden by redirecting to AccessDeniedPath if set
+ if (Options.AccessDeniedPath.HasValue)
{
- // Handle 403 by redirecting to AccessDeniedPath if set
- if (Options.AccessDeniedPath.HasValue)
+ try
{
- try
- {
- var accessDeniedUri =
- Request.Scheme +
- "://" +
- Request.Host +
- Request.PathBase +
- Options.AccessDeniedPath;
+ var accessDeniedUri =
+ Request.Scheme +
+ "://" +
+ Request.Host +
+ Request.PathBase +
+ Options.AccessDeniedPath;
- var redirectContext = new CookieApplyRedirectContext(Context, Options, accessDeniedUri);
- Options.Notifications.ApplyRedirect(redirectContext);
- }
- catch (Exception exception)
+ var redirectContext = new CookieApplyRedirectContext(Context, Options, accessDeniedUri);
+ Options.Notifications.ApplyRedirect(redirectContext);
+ }
+ catch (Exception exception)
+ {
+ var exceptionContext = new CookieExceptionContext(Context, Options,
+ CookieExceptionContext.ExceptionLocation.ApplyResponseChallenge, exception, ticket: null);
+ Options.Notifications.Exception(exceptionContext);
+ if (exceptionContext.Rethrow)
{
- var exceptionContext = new CookieExceptionContext(Context, Options,
- CookieExceptionContext.ExceptionLocation.ApplyResponseChallenge, exception, ticket: null);
- Options.Notifications.Exception(exceptionContext);
- if (exceptionContext.Rethrow)
- {
- throw;
- }
+ throw;
}
}
- else
- {
- Response.StatusCode = 403;
- }
- return;
+ return Task.FromResult(true);
}
-
- if (Response.StatusCode != 401 || !Options.LoginPath.HasValue )
+ else
{
- return;
+ return base.HandleForbiddenAsync(context);
}
+ }
- // Automatic middleware should redirect on 401 even if there wasn't an explicit challenge.
- if (ChallengeContext == null && !Options.AutomaticAuthentication)
+ protected override Task HandleUnauthorizedAsync([NotNull] ChallengeContext context)
+ {
+ if (!Options.LoginPath.HasValue)
{
- return;
- }
-
- var redirectUri = string.Empty;
- if (ChallengeContext != null)
- {
- redirectUri = new AuthenticationProperties(ChallengeContext.Properties).RedirectUri;
+ return base.HandleUnauthorizedAsync(context);
}
+ var redirectUri = new AuthenticationProperties(context.Properties).RedirectUri;
try
{
if (string.IsNullOrWhiteSpace(redirectUri))
@@ -400,6 +456,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
throw;
}
}
+ return Task.FromResult(true);
}
}
}
diff --git a/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationHandler.cs
index d9c2183443..c5a8b0fc7f 100644
--- a/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.OAuth/OAuthAuthenticationHandler.cs
@@ -6,10 +6,11 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
-using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Http.Extensions;
+using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.AspNet.WebUtilities;
+using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
using Newtonsoft.Json.Linq;
@@ -37,7 +38,7 @@ namespace Microsoft.AspNet.Authentication.OAuth
public async Task InvokeReturnPathAsync()
{
- AuthenticationTicket ticket = await AuthenticateAsync();
+ var ticket = await AuthenticateAsync();
if (ticket == null)
{
Logger.LogWarning("Invalid return state, unable to redirect.");
@@ -56,7 +57,7 @@ namespace Microsoft.AspNet.Authentication.OAuth
if (context.SignInScheme != null && context.Principal != null)
{
- Context.Authentication.SignIn(context.SignInScheme, context.Principal, context.Properties);
+ await Context.Authentication.SignInAsync(context.SignInScheme, context.Principal, context.Properties);
}
if (!context.IsRequestCompleted && context.RedirectUri != null)
@@ -73,17 +74,12 @@ namespace Microsoft.AspNet.Authentication.OAuth
return context.IsRequestCompleted;
}
- protected override AuthenticationTicket AuthenticateCore()
- {
- return AuthenticateCoreAsync().GetAwaiter().GetResult();
- }
-
- protected override async Task AuthenticateCoreAsync()
+ public override async Task AuthenticateAsync()
{
AuthenticationProperties properties = null;
try
{
- IReadableStringCollection query = Request.Query;
+ var query = Request.Query;
// TODO: Is this a standard error returned by servers?
var value = query.Get("error");
@@ -94,8 +90,8 @@ namespace Microsoft.AspNet.Authentication.OAuth
return null;
}
- string code = query.Get("code");
- string state = query.Get("state");
+ var code = query.Get("code");
+ var state = query.Get("state");
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
@@ -115,8 +111,8 @@ namespace Microsoft.AspNet.Authentication.OAuth
return new AuthenticationTicket(properties, Options.AuthenticationScheme);
}
- string requestPrefix = Request.Scheme + "://" + Request.Host;
- string redirectUri = requestPrefix + RequestPathBase + Options.CallbackPath;
+ var requestPrefix = Request.Scheme + "://" + Request.Host;
+ var redirectUri = requestPrefix + RequestPathBase + Options.CallbackPath;
var tokens = await ExchangeCodeAsync(code, redirectUri);
@@ -151,11 +147,11 @@ namespace Microsoft.AspNet.Authentication.OAuth
var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = requestContent;
- HttpResponseMessage response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
+ var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
response.EnsureSuccessStatusCode();
- string oauthTokenResponse = await response.Content.ReadAsStringAsync();
+ var oauthTokenResponse = await response.Content.ReadAsStringAsync();
- JObject oauth2Token = JObject.Parse(oauthTokenResponse);
+ var oauth2Token = JObject.Parse(oauthTokenResponse);
return new TokenResponse(oauth2Token);
}
@@ -169,40 +165,13 @@ namespace Microsoft.AspNet.Authentication.OAuth
return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme);
}
- protected override void ApplyResponseChallenge()
+ protected override Task HandleUnauthorizedAsync([NotNull] ChallengeContext context)
{
- if (ShouldConvertChallengeToForbidden())
- {
- Response.StatusCode = 403;
- return;
- }
+ var baseUri = Request.Scheme + "://" + Request.Host + Request.PathBase;
+ var currentUri = baseUri + Request.Path + Request.QueryString;
+ var redirectUri = baseUri + Options.CallbackPath;
- if (Response.StatusCode != 401)
- {
- return;
- }
-
- // When Automatic should redirect on 401 even if there wasn't an explicit challenge.
- if (ChallengeContext == null && !Options.AutomaticAuthentication)
- {
- return;
- }
-
- string baseUri = Request.Scheme + "://" + Request.Host + Request.PathBase;
-
- string currentUri = baseUri + Request.Path + Request.QueryString;
-
- string redirectUri = baseUri + Options.CallbackPath;
-
- AuthenticationProperties properties;
- if (ChallengeContext == null)
- {
- properties = new AuthenticationProperties();
- }
- else
- {
- properties = new AuthenticationProperties(ChallengeContext.Properties);
- }
+ var properties = new AuthenticationProperties(context.Properties);
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
@@ -211,19 +180,35 @@ namespace Microsoft.AspNet.Authentication.OAuth
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
- string authorizationEndpoint = BuildChallengeUrl(properties, redirectUri);
+ var authorizationEndpoint = BuildChallengeUrl(properties, redirectUri);
var redirectContext = new OAuthApplyRedirectContext(
Context, Options,
properties, authorizationEndpoint);
Options.Notifications.ApplyRedirect(redirectContext);
+ return Task.FromResult(true);
+ }
+
+ protected override Task HandleSignOutAsync(SignOutContext context)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected override Task HandleSignInAsync(SignInContext context)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected override Task HandleForbiddenAsync(ChallengeContext context)
+ {
+ throw new NotSupportedException();
}
protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
- string scope = FormatScope();
+ var scope = FormatScope();
- string state = Options.StateDataFormat.Protect(properties);
+ var state = Options.StateDataFormat.Protect(properties);
var queryBuilder = new QueryBuilder()
{
@@ -241,10 +226,5 @@ namespace Microsoft.AspNet.Authentication.OAuth
// OAuth2 3.3 space separated
return string.Join(" ", Options.Scope);
}
-
- protected override void ApplyResponseGrant()
- {
- // N/A - No SignIn or SignOut support.
- }
}
}
diff --git a/src/Microsoft.AspNet.Authentication.OAuthBearer/OAuthBearerAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.OAuthBearer/OAuthBearerAuthenticationHandler.cs
index b088519509..6357a35af9 100644
--- a/src/Microsoft.AspNet.Authentication.OAuthBearer/OAuthBearerAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.OAuthBearer/OAuthBearerAuthenticationHandler.cs
@@ -2,14 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Linq;
-using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Authentication.Notifications;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
+using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.Framework.Logging;
using Microsoft.IdentityModel.Protocols;
@@ -19,16 +18,11 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
{
private OpenIdConnectConfiguration _configuration;
- protected override AuthenticationTicket AuthenticateCore()
- {
- return AuthenticateCoreAsync().GetAwaiter().GetResult();
- }
-
///
/// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using set in the options.
///
///
- protected override async Task AuthenticateCoreAsync()
+ public override async Task AuthenticateAsync()
{
string token = null;
try
@@ -179,30 +173,21 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
}
}
- protected override void ApplyResponseChallenge()
+ protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{
- ApplyResponseChallengeAsync().GetAwaiter().GetResult();
- }
-
- protected override async Task ApplyResponseChallengeAsync()
- {
- if (ShouldConvertChallengeToForbidden())
- {
- Response.StatusCode = 403;
- return;
- }
-
- if ((Response.StatusCode != 401) || (ChallengeContext == null && !Options.AutomaticAuthentication))
- {
- return;
- }
-
+ Response.StatusCode = 401;
await Options.Notifications.ApplyChallenge(new AuthenticationChallengeNotification(Context, Options));
+ return false;
}
- protected override void ApplyResponseGrant()
+ protected override Task HandleSignOutAsync(SignOutContext context)
{
- // N/A
+ throw new NotSupportedException();
+ }
+
+ protected override Task HandleSignInAsync(SignInContext context)
+ {
+ throw new NotSupportedException();
}
}
}
diff --git a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs
index 7e97628e14..b542c2ef81 100644
--- a/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs
@@ -11,6 +11,8 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Authentication.Notifications;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
+using Microsoft.AspNet.Http.Features.Authentication;
+using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
using Microsoft.IdentityModel.Protocols;
@@ -38,18 +40,12 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
}
}
- protected override void ApplyResponseGrant()
- {
- ApplyResponseGrantAsync().GetAwaiter().GetResult();
- }
-
///
/// Handles Signout
///
///
- protected override async Task ApplyResponseGrantAsync()
+ protected override async Task HandleSignOutAsync(SignOutContext signout)
{
- var signout = SignOutContext;
if (signout != null)
{
if (_configuration == null && Options.ConfigurationManager != null)
@@ -96,52 +92,19 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
}
}
- protected override void ApplyResponseChallenge()
- {
- ApplyResponseChallengeAsync().GetAwaiter().GetResult();
- }
-
///
/// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity.
///
///
/// Uses log id's OIDCH-0026 - OIDCH-0050, next num: 37
- protected override async Task ApplyResponseChallengeAsync()
+ protected override async Task HandleUnauthorizedAsync([NotNull] ChallengeContext context)
{
Logger.LogDebug(Resources.OIDCH_0026_ApplyResponseChallengeAsync, this.GetType());
- if (ShouldConvertChallengeToForbidden())
- {
- Logger.LogDebug(Resources.OIDCH_0027_401_ConvertedTo_403);
- Response.StatusCode = 403;
- return;
- }
-
- if (Response.StatusCode != 401)
- {
- Logger.LogDebug(Resources.OIDCH_0028_StatusCodeNot401, Response.StatusCode);
- return;
- }
-
- // When Automatic should redirect on 401 even if there wasn't an explicit challenge.
- if (ChallengeContext == null && !Options.AutomaticAuthentication)
- {
- Logger.LogDebug(Resources.OIDCH_0029_ChallengeContextEqualsNull);
- return;
- }
-
// order for local RedirectUri
// 1. challenge.Properties.RedirectUri
// 2. CurrentUri if Options.DefaultToCurrentUriOnRedirect is true)
- AuthenticationProperties properties;
- if (ChallengeContext == null)
- {
- properties = new AuthenticationProperties();
- }
- else
- {
- properties = new AuthenticationProperties(ChallengeContext.Properties);
- }
+ AuthenticationProperties properties = new AuthenticationProperties(context.Properties);
if (!string.IsNullOrWhiteSpace(properties.RedirectUri))
{
@@ -209,12 +172,12 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
if (redirectToIdentityProviderNotification.HandledResponse)
{
Logger.LogInformation(Resources.OIDCH_0034_RedirectToIdentityProviderNotificationHandledResponse);
- return;
+ return true; // REVIEW: Make sure this should stop all other handlers
}
else if (redirectToIdentityProviderNotification.Skipped)
{
Logger.LogInformation(Resources.OIDCH_0035_RedirectToIdentityProviderNotificationSkipped);
- return;
+ return false; // REVIEW: Make sure this should not stop all other handlers
}
var redirectUri = redirectToIdentityProviderNotification.ProtocolMessage.CreateAuthenticationRequestUrl();
@@ -224,11 +187,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
}
Response.Redirect(redirectUri);
- }
-
- protected override AuthenticationTicket AuthenticateCore()
- {
- return AuthenticateCoreAsync().GetAwaiter().GetResult();
+ return true;
}
///
@@ -236,7 +195,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
///
/// An if successful.
/// Uses log id's OIDCH-0000 - OIDCH-0025
- protected override async Task AuthenticateCoreAsync()
+ public override async Task AuthenticateAsync()
{
Logger.LogDebug(Resources.OIDCH_0000_AuthenticateCoreAsync, this.GetType());
@@ -632,7 +591,7 @@ namespace Microsoft.AspNet.Authentication.OpenIdConnect
{
if (ticket.Principal != null)
{
- Request.HttpContext.Authentication.SignIn(Options.SignInScheme, ticket.Principal, ticket.Properties);
+ await Request.HttpContext.Authentication.SignInAsync(Options.SignInScheme, ticket.Principal, ticket.Properties);
}
// Redirect back to the original secured resource, if any.
diff --git a/src/Microsoft.AspNet.Authentication.Twitter/TwitterAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.Twitter/TwitterAuthenticationHandler.cs
index eecc1a0434..659b8b6aad 100644
--- a/src/Microsoft.AspNet.Authentication.Twitter/TwitterAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication.Twitter/TwitterAuthenticationHandler.cs
@@ -12,8 +12,10 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Authentication.Twitter.Messages;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
+using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.WebUtilities;
+using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Authentication.Twitter
@@ -42,12 +44,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
return false;
}
- protected override AuthenticationTicket AuthenticateCore()
- {
- return AuthenticateCoreAsync().GetAwaiter().GetResult();
- }
-
- protected override async Task AuthenticateCoreAsync()
+ public override async Task AuthenticateAsync()
{
AuthenticationProperties properties = null;
try
@@ -121,49 +118,18 @@ namespace Microsoft.AspNet.Authentication.Twitter
return new AuthenticationTicket(properties, Options.AuthenticationScheme);
}
}
- protected override void ApplyResponseChallenge()
+ protected override async Task HandleUnauthorizedAsync([NotNull] ChallengeContext context)
{
- ApplyResponseChallengeAsync().GetAwaiter().GetResult();
- }
-
- protected override async Task ApplyResponseChallengeAsync()
- {
- if (ShouldConvertChallengeToForbidden())
- {
- Response.StatusCode = 403;
- return;
- }
-
- if (Response.StatusCode != 401)
- {
- return;
- }
-
- // When Automatic should redirect on 401 even if there wasn't an explicit challenge.
- if (ChallengeContext == null && !Options.AutomaticAuthentication)
- {
- return;
- }
-
var requestPrefix = Request.Scheme + "://" + Request.Host;
var callBackUrl = requestPrefix + RequestPathBase + Options.CallbackPath;
- AuthenticationProperties properties;
- if (ChallengeContext == null)
- {
- properties = new AuthenticationProperties();
- }
- else
- {
- properties = new AuthenticationProperties(ChallengeContext.Properties);
- }
+ var properties = new AuthenticationProperties(context.Properties);
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = requestPrefix + Request.PathBase + Request.Path + Request.QueryString;
}
var requestToken = await ObtainRequestTokenAsync(Options.ConsumerKey, Options.ConsumerSecret, callBackUrl, properties);
-
if (requestToken.CallbackConfirmed)
{
var twitterAuthenticationEndpoint = AuthenticationEndpoint + requestToken.Token;
@@ -180,11 +146,13 @@ namespace Microsoft.AspNet.Authentication.Twitter
Context, Options,
properties, twitterAuthenticationEndpoint);
Options.Notifications.ApplyRedirect(redirectContext);
+ return true;
}
else
{
Logger.LogError("requestToken CallbackConfirmed!=true");
}
+ return false; // REVIEW: Make sure this should not stop other handlers
}
public async Task InvokeReturnPathAsync()
@@ -208,7 +176,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
if (context.SignInScheme != null && context.Principal != null)
{
- Context.Authentication.SignIn(context.SignInScheme, context.Principal, context.Properties);
+ await Context.Authentication.SignInAsync(context.SignInScheme, context.Principal, context.Properties);
}
if (!context.IsRequestCompleted && context.RedirectUri != null)
@@ -225,6 +193,21 @@ namespace Microsoft.AspNet.Authentication.Twitter
return context.IsRequestCompleted;
}
+ protected override Task HandleSignOutAsync(SignOutContext context)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected override Task HandleSignInAsync(SignInContext context)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected override Task HandleForbiddenAsync(ChallengeContext context)
+ {
+ throw new NotSupportedException();
+ }
+
private async Task ObtainRequestTokenAsync(string consumerKey, string consumerSecret, string callBackUri, AuthenticationProperties properties)
{
Logger.LogVerbose("ObtainRequestToken");
@@ -380,10 +363,5 @@ namespace Microsoft.AspNet.Authentication.Twitter
return Convert.ToBase64String(hash);
}
}
-
- protected override void ApplyResponseGrant()
- {
- // N/A - No SignIn or SignOut support.
- }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Authentication/AuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication/AuthenticationHandler.cs
index fd6950ff5b..d9933f5f74 100644
--- a/src/Microsoft.AspNet.Authentication/AuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication/AuthenticationHandler.cs
@@ -3,7 +3,6 @@
using System;
using System.Security.Cryptography;
-using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Authentication.DataHandler.Encoder;
using Microsoft.AspNet.Http;
@@ -22,19 +21,12 @@ namespace Microsoft.AspNet.Authentication
{
private static readonly RandomNumberGenerator CryptoRandom = RandomNumberGenerator.Create();
- private Task _authenticate;
- private bool _authenticateInitialized;
- private object _authenticateSyncLock;
-
- private Task _applyResponse;
- private bool _applyResponseInitialized;
- private object _applyResponseSyncLock;
-
+ private bool _finishCalled;
private AuthenticationOptions _baseOptions;
- protected ChallengeContext ChallengeContext { get; set; }
- protected SignInContext SignInContext { get; set; }
- protected SignOutContext SignOutContext { get; set; }
+ protected bool SignInAccepted { get; set; }
+ protected bool SignOutAccepted { get; set; }
+ protected bool ChallengeCalled { get; set; }
protected HttpContext Context { get; private set; }
@@ -59,13 +51,8 @@ namespace Microsoft.AspNet.Authentication
get { return _baseOptions; }
}
- // REVIEW: Overriding Authenticate and not calling base requires manually calling this for 401-403 to work
- protected bool AuthenticateCalled { get; set; }
-
public IAuthenticationHandler PriorHandler { get; set; }
- public bool Faulted { get; set; }
-
protected async Task BaseInitializeAsync([NotNull] AuthenticationOptions options, [NotNull] HttpContext context, [NotNull] ILogger logger, [NotNull] IUrlEncoder encoder)
{
_baseOptions = options;
@@ -76,9 +63,7 @@ namespace Microsoft.AspNet.Authentication
RegisterAuthenticationHandler();
- Response.OnResponseStarting(OnSendingHeaderCallback, this);
-
- await InitializeCoreAsync();
+ Response.OnStarting(OnStartingCallback, this);
if (BaseOptions.AutomaticAuthentication)
{
@@ -90,50 +75,49 @@ namespace Microsoft.AspNet.Authentication
}
}
- private static void OnSendingHeaderCallback(object state)
+ private static async Task OnStartingCallback(object state)
{
- AuthenticationHandler handler = (AuthenticationHandler)state;
- handler.ApplyResponse();
+ var handler = (AuthenticationHandler)state;
+ await handler.FinishResponseOnce();
}
- protected virtual Task InitializeCoreAsync()
+ private async Task FinishResponseOnce()
+ {
+ if (!_finishCalled)
+ {
+ _finishCalled = true;
+ await FinishResponseAsync();
+ await HandleAutomaticChallengeIfNeeded();
+ }
+ }
+
+ ///
+ /// Hook that is called when the response about to be sent
+ ///
+ ///
+ protected virtual Task FinishResponseAsync()
{
return Task.FromResult(0);
}
+ private async Task HandleAutomaticChallengeIfNeeded()
+ {
+ if (!ChallengeCalled && BaseOptions.AutomaticAuthentication && Response.StatusCode == 401)
+ {
+ await HandleUnauthorizedAsync(new ChallengeContext(BaseOptions.AuthenticationScheme));
+ }
+ }
+
///
- /// Called once per request after Initialize and Invoke.
+ /// Called once after Invoke by AuthenticationMiddleware.
///
/// async completion
internal async Task TeardownAsync()
{
- try
- {
- await ApplyResponseAsync();
- }
- catch (Exception)
- {
- try
- {
- await TeardownCoreAsync();
- }
- catch (Exception)
- {
- // Don't mask the original exception
- }
- UnregisterAuthenticationHandler();
- throw;
- }
-
- await TeardownCoreAsync();
+ await FinishResponseOnce();
UnregisterAuthenticationHandler();
}
- protected virtual Task TeardownCoreAsync()
- {
- return Task.FromResult(0);
- }
-
///
/// Called once by common code after initialization. If an authentication middleware responds directly to
/// specifically known paths it must override this virtual, compare the request path to it's known paths,
@@ -147,7 +131,7 @@ namespace Microsoft.AspNet.Authentication
return Task.FromResult(false);
}
- public virtual void GetDescriptions(DescribeSchemesContext describeContext)
+ public void GetDescriptions(DescribeSchemesContext describeContext)
{
describeContext.Accept(BaseOptions.Description.Items);
@@ -157,36 +141,13 @@ namespace Microsoft.AspNet.Authentication
}
}
- public virtual void Authenticate(AuthenticateContext context)
- {
- if (ShouldHandleScheme(context.AuthenticationScheme))
- {
- var ticket = Authenticate();
- if (ticket?.Principal != null)
- {
- AuthenticateCalled = true;
- context.Authenticated(ticket.Principal, ticket.Properties.Items, BaseOptions.Description.Items);
- }
- else
- {
- context.NotAuthenticated();
- }
- }
-
- if (PriorHandler != null)
- {
- PriorHandler.Authenticate(context);
- }
- }
-
- public virtual async Task AuthenticateAsync(AuthenticateContext context)
+ public async Task AuthenticateAsync(AuthenticateContext context)
{
if (ShouldHandleScheme(context.AuthenticationScheme))
{
var ticket = await AuthenticateAsync();
if (ticket?.Principal != null)
{
- AuthenticateCalled = true;
context.Authenticated(ticket.Principal, ticket.Properties.Items, BaseOptions.Description.Items);
}
else
@@ -201,193 +162,66 @@ namespace Microsoft.AspNet.Authentication
}
}
- public AuthenticationTicket Authenticate()
- {
- return LazyInitializer.EnsureInitialized(
- ref _authenticate,
- ref _authenticateInitialized,
- ref _authenticateSyncLock,
- () =>
- {
- return Task.FromResult(AuthenticateCore());
- }).GetAwaiter().GetResult();
- }
-
- protected abstract AuthenticationTicket AuthenticateCore();
-
///
- /// Causes the authentication logic in AuthenticateCore to be performed for the current request
- /// at most once and returns the results. Calling Authenticate more than once will always return
- /// the original value.
- ///
- /// This method should always be called instead of calling AuthenticateCore directly.
+ /// Calling Authenticate more than once should always return the original value.
///
/// The ticket data provided by the authentication logic
- public Task AuthenticateAsync()
- {
- return LazyInitializer.EnsureInitialized(
- ref _authenticate,
- ref _authenticateInitialized,
- ref _authenticateSyncLock,
- AuthenticateCoreAsync);
- }
+ public abstract Task AuthenticateAsync();
- ///
- /// The core authentication logic which must be provided by the handler. Will be invoked at most
- /// once per request. Do not call directly, call the wrapping Authenticate method instead.
- ///
- /// The ticket data provided by the authentication logic
- protected virtual Task AuthenticateCoreAsync()
- {
- return Task.FromResult(AuthenticateCore());
- }
-
- private void ApplyResponse()
- {
- // If ApplyResponse already failed in the OnSendingHeaderCallback or TeardownAsync code path then a
- // failed task is cached. If called again the same error will be re-thrown. This breaks error handling
- // scenarios like the ability to display the error page or re-execute the request.
- try
- {
- if (!Faulted)
- {
- LazyInitializer.EnsureInitialized(
- ref _applyResponse,
- ref _applyResponseInitialized,
- ref _applyResponseSyncLock,
- () =>
- {
- ApplyResponseCore();
- return Task.FromResult(0);
- }).GetAwaiter().GetResult(); // Block if the async version is in progress.
- }
- }
- catch (Exception)
- {
- Faulted = true;
- throw;
- }
- }
-
- protected virtual void ApplyResponseCore()
- {
- ApplyResponseGrant();
- ApplyResponseChallenge();
- }
-
- ///
- /// Causes the ApplyResponseCore to be invoked at most once per request. This method will be
- /// invoked either earlier, when the response headers are sent as a result of a response write or flush,
- /// or later, as the last step when the original async call to the middleware is returning.
- ///
- ///
- private async Task ApplyResponseAsync()
- {
- // If ApplyResponse already failed in the OnSendingHeaderCallback or TeardownAsync code path then a
- // failed task is cached. If called again the same error will be re-thrown. This breaks error handling
- // scenarios like the ability to display the error page or re-execute the request.
- try
- {
- if (!Faulted)
- {
- await LazyInitializer.EnsureInitialized(
- ref _applyResponse,
- ref _applyResponseInitialized,
- ref _applyResponseSyncLock,
- ApplyResponseCoreAsync);
- }
- }
- catch (Exception)
- {
- Faulted = true;
- throw;
- }
- }
-
- ///
- /// Core method that may be overridden by handler. The default behavior is to call two common response
- /// activities, one that deals with sign-in/sign-out concerns, and a second to deal with 401 challenges.
- ///
- ///
- protected virtual async Task ApplyResponseCoreAsync()
- {
- await ApplyResponseGrantAsync();
- await ApplyResponseChallengeAsync();
- }
-
- protected abstract void ApplyResponseGrant();
-
- ///
- /// Override this method to dela with sign-in/sign-out concerns, if an authentication scheme in question
- /// deals with grant/revoke as part of it's request flow. (like setting/deleting cookies)
- ///
- ///
- protected virtual Task ApplyResponseGrantAsync()
- {
- ApplyResponseGrant();
- return Task.FromResult(0);
- }
-
- public virtual void SignIn(SignInContext context)
- {
- if (ShouldHandleScheme(context.AuthenticationScheme))
- {
- SignInContext = context;
- SignOutContext = null;
- context.Accept();
- }
-
- if (PriorHandler != null)
- {
- PriorHandler.SignIn(context);
- }
- }
-
- public virtual void SignOut(SignOutContext context)
- {
- if (ShouldHandleScheme(context.AuthenticationScheme))
- {
- SignInContext = null;
- SignOutContext = context;
- context.Accept();
- }
-
- if (PriorHandler != null)
- {
- PriorHandler.SignOut(context);
- }
- }
-
- public virtual void Challenge(ChallengeContext context)
- {
- if (ShouldHandleScheme(context.AuthenticationScheme))
- {
- ChallengeContext = context;
- context.Accept();
- }
-
- if (PriorHandler != null)
- {
- PriorHandler.Challenge(context);
- }
- }
-
- protected abstract void ApplyResponseChallenge();
-
- public virtual bool ShouldHandleScheme(string authenticationScheme)
+ public bool ShouldHandleScheme(string authenticationScheme)
{
return string.Equals(BaseOptions.AuthenticationScheme, authenticationScheme, StringComparison.Ordinal) ||
(BaseOptions.AutomaticAuthentication && string.IsNullOrWhiteSpace(authenticationScheme));
}
- public virtual bool ShouldConvertChallengeToForbidden()
+ public async Task SignInAsync(SignInContext context)
{
- // Return 403 iff 401 and this handler's authenticate was called
- // and the challenge is for the authentication type
- return Response.StatusCode == 401 &&
- AuthenticateCalled &&
- ChallengeContext != null &&
- ShouldHandleScheme(ChallengeContext.AuthenticationScheme);
+ if (ShouldHandleScheme(context.AuthenticationScheme))
+ {
+ SignInAccepted = true;
+ await HandleSignInAsync(context);
+ context.Accept();
+ }
+
+ if (PriorHandler != null)
+ {
+ await PriorHandler.SignInAsync(context);
+ }
+ }
+
+ protected virtual Task HandleSignInAsync(SignInContext context)
+ {
+ return Task.FromResult(0);
+ }
+
+ public async Task SignOutAsync(SignOutContext context)
+ {
+ if (ShouldHandleScheme(context.AuthenticationScheme))
+ {
+ SignOutAccepted = true;
+ await HandleSignOutAsync(context);
+ context.Accept();
+ }
+
+ if (PriorHandler != null)
+ {
+ await PriorHandler.SignOutAsync(context);
+ }
+ }
+
+ protected virtual Task HandleSignOutAsync(SignOutContext context)
+ {
+ return Task.FromResult(0);
+ }
+
+ ///
+ ///
+ ///
+ /// True if no other handlers should be called
+ protected virtual Task HandleForbiddenAsync(ChallengeContext context)
+ {
+ Response.StatusCode = 403;
+ return Task.FromResult(true);
}
///
@@ -395,11 +229,48 @@ namespace Microsoft.AspNet.Authentication
/// deals an authentication interaction as part of it's request flow. (like adding a response header, or
/// changing the 401 result to 302 of a login page or external sign-in location.)
///
- ///
- protected virtual Task ApplyResponseChallengeAsync()
+ ///
+ /// True if no other handlers should be called
+ protected virtual Task HandleUnauthorizedAsync(ChallengeContext context)
{
- ApplyResponseChallenge();
- return Task.FromResult(0);
+ Response.StatusCode = 401;
+ return Task.FromResult(false);
+ }
+
+ public async Task ChallengeAsync(ChallengeContext context)
+ {
+ bool handled = false;
+ ChallengeCalled = true;
+ if (ShouldHandleScheme(context.AuthenticationScheme))
+ {
+ switch (context.Behavior)
+ {
+ case ChallengeBehavior.Automatic:
+ // If there is a principal already, invoke the forbidden code path
+ var ticket = await AuthenticateAsync();
+ if (ticket?.Principal != null)
+ {
+ handled = await HandleForbiddenAsync(context);
+ }
+ else
+ {
+ handled = await HandleUnauthorizedAsync(context);
+ }
+ break;
+ case ChallengeBehavior.Unauthorized:
+ handled = await HandleUnauthorizedAsync(context);
+ break;
+ case ChallengeBehavior.Forbidden:
+ handled = await HandleForbiddenAsync(context);
+ break;
+ }
+ context.Accept();
+ }
+
+ if (!handled && PriorHandler != null)
+ {
+ await PriorHandler.ChallengeAsync(context);
+ }
}
protected void GenerateCorrelationId([NotNull] AuthenticationProperties properties)
diff --git a/src/Microsoft.AspNet.Authentication/AuthenticationMiddleware.cs b/src/Microsoft.AspNet.Authentication/AuthenticationMiddleware.cs
index 188f903c49..b8b57d7472 100644
--- a/src/Microsoft.AspNet.Authentication/AuthenticationMiddleware.cs
+++ b/src/Microsoft.AspNet.Authentication/AuthenticationMiddleware.cs
@@ -67,7 +67,6 @@ namespace Microsoft.AspNet.Authentication
{
try
{
- handler.Faulted = true;
await handler.TeardownAsync();
}
catch (Exception)
diff --git a/src/Microsoft.AspNet.Authentication/AuthenticationServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Authentication/AuthenticationServiceCollectionExtensions.cs
index 0b6cfdb9f5..fb62323545 100644
--- a/src/Microsoft.AspNet.Authentication/AuthenticationServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNet.Authentication/AuthenticationServiceCollectionExtensions.cs
@@ -3,6 +3,7 @@
using System;
using System.Security.Claims;
+using System.Threading.Tasks;
using Microsoft.AspNet.Authentication;
using Microsoft.Framework.Internal;
@@ -24,7 +25,12 @@ namespace Microsoft.Framework.DependencyInjection
public static IServiceCollection ConfigureClaimsTransformation([NotNull] this IServiceCollection services, [NotNull] Func transform)
{
- return services.Configure(o => o.Transformation = transform);
+ return services.Configure(o => o.Transformer = new ClaimsTransformer { TransformSyncDelegate = transform });
+ }
+
+ public static IServiceCollection ConfigureClaimsTransformation([NotNull] this IServiceCollection services, [NotNull] Func> asyncTransform)
+ {
+ return services.Configure(o => o.Transformer = new ClaimsTransformer { TransformAsyncDelegate = asyncTransform });
}
}
diff --git a/src/Microsoft.AspNet.Authentication/ClaimsTransformationAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication/ClaimsTransformationAuthenticationHandler.cs
index 4d896e152a..ebc04cb696 100644
--- a/src/Microsoft.AspNet.Authentication/ClaimsTransformationAuthenticationHandler.cs
+++ b/src/Microsoft.AspNet.Authentication/ClaimsTransformationAuthenticationHandler.cs
@@ -1,8 +1,6 @@
// 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 System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features.Authentication;
@@ -13,56 +11,37 @@ namespace Microsoft.AspNet.Authentication
///
public class ClaimsTransformationAuthenticationHandler : IAuthenticationHandler
{
- private readonly Func _transform;
+ private readonly IClaimsTransformer _transform;
- public ClaimsTransformationAuthenticationHandler(Func transform)
+ public ClaimsTransformationAuthenticationHandler(IClaimsTransformer transform)
{
_transform = transform;
}
public IAuthenticationHandler PriorHandler { get; set; }
- private void ApplyTransform(AuthenticateContext context)
- {
- if (_transform != null)
- {
- // REVIEW: this cast seems really bad (missing interface way to get the result back out?)
- var authContext = context as AuthenticateContext;
- if (authContext?.Principal != null)
- {
- context.Authenticated(
- _transform.Invoke(authContext.Principal),
- authContext.Properties,
- authContext.Description);
- }
- }
-
- }
-
- public void Authenticate(AuthenticateContext context)
- {
- if (PriorHandler != null)
- {
- PriorHandler.Authenticate(context);
- ApplyTransform(context);
- }
- }
-
public async Task AuthenticateAsync(AuthenticateContext context)
{
if (PriorHandler != null)
{
await PriorHandler.AuthenticateAsync(context);
- ApplyTransform(context);
+ if (_transform != null && context?.Principal != null)
+ {
+ context.Authenticated(
+ await _transform.TransformAsync(context.Principal),
+ context.Properties,
+ context.Description);
+ }
}
}
- public void Challenge(ChallengeContext context)
+ public Task ChallengeAsync(ChallengeContext context)
{
if (PriorHandler != null)
{
- PriorHandler.Challenge(context);
+ return PriorHandler.ChallengeAsync(context);
}
+ return Task.FromResult(0);
}
public void GetDescriptions(DescribeSchemesContext context)
@@ -73,20 +52,22 @@ namespace Microsoft.AspNet.Authentication
}
}
- public void SignIn(SignInContext context)
+ public Task SignInAsync(SignInContext context)
{
if (PriorHandler != null)
{
- PriorHandler.SignIn(context);
+ return PriorHandler.SignInAsync(context);
}
+ return Task.FromResult(0);
}
- public void SignOut(SignOutContext context)
+ public Task SignOutAsync(SignOutContext context)
{
if (PriorHandler != null)
{
- PriorHandler.SignOut(context);
+ return PriorHandler.SignOutAsync(context);
}
+ return Task.FromResult(0);
}
public void RegisterAuthenticationHandler(IHttpAuthenticationFeature auth)
diff --git a/src/Microsoft.AspNet.Authentication/ClaimsTransformationMiddleware.cs b/src/Microsoft.AspNet.Authentication/ClaimsTransformationMiddleware.cs
index 0f785161c4..eb616d9fb9 100644
--- a/src/Microsoft.AspNet.Authentication/ClaimsTransformationMiddleware.cs
+++ b/src/Microsoft.AspNet.Authentication/ClaimsTransformationMiddleware.cs
@@ -34,12 +34,12 @@ namespace Microsoft.AspNet.Authentication
public async Task Invoke(HttpContext context)
{
- var handler = new ClaimsTransformationAuthenticationHandler(Options.Transformation);
+ var handler = new ClaimsTransformationAuthenticationHandler(Options.Transformer);
handler.RegisterAuthenticationHandler(context.GetAuthentication());
try {
- if (Options.Transformation != null)
+ if (Options.Transformer != null)
{
- context.User = Options.Transformation.Invoke(context.User);
+ context.User = await Options.Transformer.TransformAsync(context.User);
}
await _next(context);
}
diff --git a/src/Microsoft.AspNet.Authentication/ClaimsTransformationOptions.cs b/src/Microsoft.AspNet.Authentication/ClaimsTransformationOptions.cs
index 1eb76c82ac..acc1a5e499 100644
--- a/src/Microsoft.AspNet.Authentication/ClaimsTransformationOptions.cs
+++ b/src/Microsoft.AspNet.Authentication/ClaimsTransformationOptions.cs
@@ -3,11 +3,42 @@
using System;
using System.Security.Claims;
+using System.Threading.Tasks;
namespace Microsoft.AspNet.Authentication
{
public class ClaimsTransformationOptions
{
- public Func Transformation { get; set; }
+ public IClaimsTransformer Transformer { get; set; }
+ }
+
+ public interface IClaimsTransformer
+ {
+ Task TransformAsync(ClaimsPrincipal principal);
+ ClaimsPrincipal Transform(ClaimsPrincipal principal);
+ }
+
+ public class ClaimsTransformer : IClaimsTransformer
+ {
+ public Func> TransformAsyncDelegate { get; set; }
+ public Func TransformSyncDelegate { get; set; }
+
+ public virtual ClaimsPrincipal Transform(ClaimsPrincipal principal)
+ {
+ if (TransformSyncDelegate != null)
+ {
+ return TransformSyncDelegate(principal);
+ }
+ return principal;
+ }
+
+ public virtual Task TransformAsync(ClaimsPrincipal principal)
+ {
+ if (TransformAsyncDelegate != null)
+ {
+ return TransformAsyncDelegate(principal);
+ }
+ return Task.FromResult(Transform(principal));
+ }
}
}
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizationContext.cs b/src/Microsoft.AspNet.Authorization/AuthorizationContext.cs
index b117f8851d..54f6b6bbc4 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizationContext.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizationContext.cs
@@ -9,7 +9,7 @@ using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Authorization
{
///
- /// Contains authorization information used by .
+ /// Contains authorization information used by .
///
public class AuthorizationContext
{
@@ -28,9 +28,9 @@ namespace Microsoft.AspNet.Authorization
_pendingRequirements = new HashSet(requirements);
}
- public IEnumerable Requirements { get; private set; }
- public ClaimsPrincipal User { get; private set; }
- public object Resource { get; private set; }
+ public IEnumerable Requirements { get; }
+ public ClaimsPrincipal User { get; }
+ public object Resource { get; }
public IEnumerable PendingRequirements { get { return _pendingRequirements; } }
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizationHandler.cs b/src/Microsoft.AspNet.Authorization/AuthorizationHandler.cs
index b682e43ffd..f5418841ab 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizationHandler.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizationHandler.cs
@@ -17,14 +17,21 @@ namespace Microsoft.AspNet.Authorization
}
}
- public virtual Task HandleAsync(AuthorizationContext context)
+ public virtual async Task HandleAsync(AuthorizationContext context)
{
- Handle(context);
- return Task.FromResult(0);
+ foreach (var req in context.Requirements.OfType())
+ {
+ await HandleAsync(context, req);
+ }
}
- // REVIEW: do we need an async hook too?
- public abstract void Handle(AuthorizationContext context, TRequirement requirement);
+ protected abstract void Handle(AuthorizationContext context, TRequirement requirement);
+
+ protected virtual Task HandleAsync(AuthorizationContext context, TRequirement requirement)
+ {
+ Handle(context, requirement);
+ return Task.FromResult(0);
+ }
}
public abstract class AuthorizationHandler : IAuthorizationHandler
@@ -34,17 +41,13 @@ namespace Microsoft.AspNet.Authorization
public virtual async Task HandleAsync(AuthorizationContext context)
{
var resource = context.Resource as TResource;
- // REVIEW: should we allow null resources?
- if (resource != null)
+ foreach (var req in context.Requirements.OfType())
{
- foreach (var req in context.Requirements.OfType())
- {
- await HandleAsync(context, req, resource);
- }
+ await HandleAsync(context, req, resource);
}
}
- public virtual Task HandleAsync(AuthorizationContext context, TRequirement requirement, TResource resource)
+ protected virtual Task HandleAsync(AuthorizationContext context, TRequirement requirement, TResource resource)
{
Handle(context, requirement, resource);
return Task.FromResult(0);
@@ -63,6 +66,6 @@ namespace Microsoft.AspNet.Authorization
}
}
- public abstract void Handle(AuthorizationContext context, TRequirement requirement, TResource resource);
+ protected abstract void Handle(AuthorizationContext context, TRequirement requirement, TResource resource);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizationOptions.cs b/src/Microsoft.AspNet.Authorization/AuthorizationOptions.cs
index 17d879329b..14da299d91 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizationOptions.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizationOptions.cs
@@ -9,8 +9,7 @@ namespace Microsoft.AspNet.Authorization
{
public class AuthorizationOptions
{
- // TODO: make this case insensitive
- private IDictionary PolicyMap { get; } = new Dictionary();
+ private IDictionary PolicyMap { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
public void AddPolicy([NotNull] string name, [NotNull] AuthorizationPolicy policy)
{
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizationPolicy.cs b/src/Microsoft.AspNet.Authorization/AuthorizationPolicy.cs
index 3799264508..6f2ecc79e9 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizationPolicy.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizationPolicy.cs
@@ -20,15 +20,14 @@ namespace Microsoft.AspNet.Authorization
ActiveAuthenticationSchemes = new List(activeAuthenticationSchemes).AsReadOnly();
}
- public IReadOnlyList Requirements { get; private set; }
- public IReadOnlyList ActiveAuthenticationSchemes { get; private set; }
+ public IReadOnlyList Requirements { get; }
+ public IReadOnlyList ActiveAuthenticationSchemes { get; }
public static AuthorizationPolicy Combine([NotNull] params AuthorizationPolicy[] policies)
{
return Combine((IEnumerable)policies);
}
- // TODO: Add unit tests
public static AuthorizationPolicy Combine([NotNull] IEnumerable policies)
{
var builder = new AuthorizationPolicyBuilder();
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizationPolicyBuilder.cs b/src/Microsoft.AspNet.Authorization/AuthorizationPolicyBuilder.cs
index f41fe73692..7cc20d06b3 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizationPolicyBuilder.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizationPolicyBuilder.cs
@@ -1,9 +1,9 @@
// 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 System.Collections.Generic;
using System.Linq;
-using System.Security.Claims;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Authorization
@@ -88,6 +88,12 @@ namespace Microsoft.AspNet.Authorization
return this;
}
+ public AuthorizationPolicyBuilder RequireDelegate([NotNull] Action handler)
+ {
+ Requirements.Add(new DelegateRequirement(handler));
+ return this;
+ }
+
public AuthorizationPolicy Build()
{
return new AuthorizationPolicy(Requirements, ActiveAuthenticationSchemes.Distinct());
diff --git a/src/Microsoft.AspNet.Authorization/AuthorizeAttribute.cs b/src/Microsoft.AspNet.Authorization/AuthorizeAttribute.cs
index 42d757d8e6..cffc17dbd5 100644
--- a/src/Microsoft.AspNet.Authorization/AuthorizeAttribute.cs
+++ b/src/Microsoft.AspNet.Authorization/AuthorizeAttribute.cs
@@ -6,7 +6,7 @@ using System;
namespace Microsoft.AspNet.Authorization
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public class AuthorizeAttribute : Attribute
+ public class AuthorizeAttribute : Attribute, IAuthorizeData
{
public AuthorizeAttribute() { }
diff --git a/src/Microsoft.AspNet.Authorization/ClaimsAuthorizationRequirement.cs b/src/Microsoft.AspNet.Authorization/ClaimsAuthorizationRequirement.cs
index c5af9449b1..fa061d28c8 100644
--- a/src/Microsoft.AspNet.Authorization/ClaimsAuthorizationRequirement.cs
+++ b/src/Microsoft.AspNet.Authorization/ClaimsAuthorizationRequirement.cs
@@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Authorization
public string ClaimType { get; }
public IEnumerable AllowedValues { get; }
- public override void Handle(AuthorizationContext context, ClaimsAuthorizationRequirement requirement)
+ protected override void Handle(AuthorizationContext context, ClaimsAuthorizationRequirement requirement)
{
if (context.User != null)
{
diff --git a/src/Microsoft.AspNet.Authorization/DefaultAuthorizationService.cs b/src/Microsoft.AspNet.Authorization/DefaultAuthorizationService.cs
index e66721a5c1..bb3d888298 100644
--- a/src/Microsoft.AspNet.Authorization/DefaultAuthorizationService.cs
+++ b/src/Microsoft.AspNet.Authorization/DefaultAuthorizationService.cs
@@ -35,6 +35,7 @@ namespace Microsoft.AspNet.Authorization
foreach (var handler in _handlers)
{
handler.Handle(authContext);
+ //REVIEW: Do we want to consider short circuiting on failure
}
return authContext.HasSucceeded;
}
diff --git a/src/Microsoft.AspNet.Authorization/DelegateRequirement.cs b/src/Microsoft.AspNet.Authorization/DelegateRequirement.cs
new file mode 100644
index 0000000000..11e30c3e6b
--- /dev/null
+++ b/src/Microsoft.AspNet.Authorization/DelegateRequirement.cs
@@ -0,0 +1,22 @@
+// 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;
+
+namespace Microsoft.AspNet.Authorization
+{
+ public class DelegateRequirement : AuthorizationHandler, IAuthorizationRequirement
+ {
+ public Action Handler { get; }
+
+ public DelegateRequirement(Action handleMe)
+ {
+ Handler = handleMe;
+ }
+
+ protected override void Handle(AuthorizationContext context, DelegateRequirement requirement)
+ {
+ Handler.Invoke(context, requirement);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Authorization/DenyAnonymousAuthorizationRequirement.cs b/src/Microsoft.AspNet.Authorization/DenyAnonymousAuthorizationRequirement.cs
index 92f48c1fe4..8dcc9b1eee 100644
--- a/src/Microsoft.AspNet.Authorization/DenyAnonymousAuthorizationRequirement.cs
+++ b/src/Microsoft.AspNet.Authorization/DenyAnonymousAuthorizationRequirement.cs
@@ -7,7 +7,7 @@ namespace Microsoft.AspNet.Authorization
{
public class DenyAnonymousAuthorizationRequirement : AuthorizationHandler, IAuthorizationRequirement
{
- public override void Handle(AuthorizationContext context, DenyAnonymousAuthorizationRequirement requirement)
+ protected override void Handle(AuthorizationContext context, DenyAnonymousAuthorizationRequirement requirement)
{
var user = context.User;
var userIsAnonymous =
diff --git a/src/Microsoft.AspNet.Authorization/IAuthorizeData.cs b/src/Microsoft.AspNet.Authorization/IAuthorizeData.cs
new file mode 100644
index 0000000000..2571fb28e7
--- /dev/null
+++ b/src/Microsoft.AspNet.Authorization/IAuthorizeData.cs
@@ -0,0 +1,14 @@
+// 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.
+
+namespace Microsoft.AspNet.Authorization
+{
+ public interface IAuthorizeData
+ {
+ string Policy { get; set; }
+
+ string Roles { get; set; }
+
+ string ActiveAuthenticationSchemes { get; set; }
+ }
+}
diff --git a/src/Microsoft.AspNet.Authorization/NameAuthorizationRequirement.cs b/src/Microsoft.AspNet.Authorization/NameAuthorizationRequirement.cs
index 7d64f1b71c..5798a0efd0 100644
--- a/src/Microsoft.AspNet.Authorization/NameAuthorizationRequirement.cs
+++ b/src/Microsoft.AspNet.Authorization/NameAuthorizationRequirement.cs
@@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Authorization
public string RequiredName { get; }
- public override void Handle(AuthorizationContext context, NameAuthorizationRequirement requirement)
+ protected override void Handle(AuthorizationContext context, NameAuthorizationRequirement requirement)
{
if (context.User != null)
{
diff --git a/src/Microsoft.AspNet.Authorization/RolesAuthorizationRequirement.cs b/src/Microsoft.AspNet.Authorization/RolesAuthorizationRequirement.cs
index f3336237ea..8521c43c12 100644
--- a/src/Microsoft.AspNet.Authorization/RolesAuthorizationRequirement.cs
+++ b/src/Microsoft.AspNet.Authorization/RolesAuthorizationRequirement.cs
@@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Authorization
public IEnumerable AllowedRoles { get; }
- public override void Handle(AuthorizationContext context, RolesAuthorizationRequirement requirement)
+ protected override void Handle(AuthorizationContext context, RolesAuthorizationRequirement requirement)
{
if (context.User != null)
{
diff --git a/test/Microsoft.AspNet.Authentication.Test/AuthenticationHandlerFacts.cs b/test/Microsoft.AspNet.Authentication.Test/AuthenticationHandlerFacts.cs
index c531c17caa..e12d4e533c 100644
--- a/test/Microsoft.AspNet.Authentication.Test/AuthenticationHandlerFacts.cs
+++ b/test/Microsoft.AspNet.Authentication.Test/AuthenticationHandlerFacts.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.AspNet.Http.Internal;
using Microsoft.Framework.Logging;
using Xunit;
@@ -59,17 +61,7 @@ namespace Microsoft.AspNet.Authentication
Options.AuthenticationScheme = scheme;
}
- protected override void ApplyResponseChallenge()
- {
- throw new NotImplementedException();
- }
-
- protected override void ApplyResponseGrant()
- {
- throw new NotImplementedException();
- }
-
- protected override AuthenticationTicket AuthenticateCore()
+ public override Task AuthenticateAsync()
{
throw new NotImplementedException();
}
@@ -94,17 +86,7 @@ namespace Microsoft.AspNet.Authentication
Options.AutomaticAuthentication = auto;
}
- protected override void ApplyResponseChallenge()
- {
- throw new NotImplementedException();
- }
-
- protected override void ApplyResponseGrant()
- {
- throw new NotImplementedException();
- }
-
- protected override AuthenticationTicket AuthenticateCore()
+ public override Task AuthenticateAsync()
{
throw new NotImplementedException();
}
diff --git a/test/Microsoft.AspNet.Authentication.Test/Cookies/CookieMiddlewareTests.cs b/test/Microsoft.AspNet.Authentication.Test/Cookies/CookieMiddlewareTests.cs
index a2628f0224..9b8686c92d 100644
--- a/test/Microsoft.AspNet.Authentication.Test/Cookies/CookieMiddlewareTests.cs
+++ b/test/Microsoft.AspNet.Authentication.Test/Cookies/CookieMiddlewareTests.cs
@@ -15,6 +15,7 @@ using System.Xml.Linq;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
+using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.AspNet.TestHost;
using Microsoft.Framework.DependencyInjection;
using Shouldly;
@@ -50,7 +51,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
transaction.Response.StatusCode.ShouldBe(auto ? HttpStatusCode.Redirect : HttpStatusCode.Unauthorized);
if (auto)
{
- Uri location = transaction.Response.Headers.Location;
+ var location = transaction.Response.Headers.Location;
location.LocalPath.ShouldBe("/login");
location.Query.ShouldBe("?ReturnUrl=%2Fprotected");
}
@@ -69,34 +70,32 @@ namespace Microsoft.AspNet.Authentication.Cookies
var transaction = await SendAsync(server, "http://example.com/protected/CustomRedirect");
- transaction.Response.StatusCode.ShouldBe(auto ? HttpStatusCode.Redirect : HttpStatusCode.Unauthorized);
+ // REVIEW: Now when Cookies are not in auto, noone handles the challenge so the Status stays OK, is that reasonable??
+ transaction.Response.StatusCode.ShouldBe(auto ? HttpStatusCode.Redirect : HttpStatusCode.OK);
if (auto)
{
- Uri location = transaction.Response.Headers.Location;
+ var location = transaction.Response.Headers.Location;
location.ToString().ShouldBe("http://example.com/login?ReturnUrl=%2FCustomRedirect");
}
}
private Task SignInAsAlice(HttpContext context)
{
- context.Authentication.SignIn("Cookies",
+ return context.Authentication.SignInAsync("Cookies",
new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))),
new AuthenticationProperties());
- return Task.FromResult