Also refresh expires/Issues when renewing cookie
This commit is contained in:
parent
7a23028527
commit
5bcc1bfc26
|
|
@ -21,9 +21,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
private const string HeaderValueMinusOne = "-1";
|
private const string HeaderValueMinusOne = "-1";
|
||||||
private const string SessionIdClaim = "Microsoft.AspNet.Authentication.Cookies-SessionId";
|
private const string SessionIdClaim = "Microsoft.AspNet.Authentication.Cookies-SessionId";
|
||||||
|
|
||||||
private bool _shouldRenew;
|
private bool _shouldRefresh;
|
||||||
private DateTimeOffset? _renewIssuedUtc;
|
private DateTimeOffset? _refreshIssuedUtc;
|
||||||
private DateTimeOffset? _renewExpiresUtc;
|
private DateTimeOffset? _refreshExpiresUtc;
|
||||||
private string _sessionKey;
|
private string _sessionKey;
|
||||||
private Task<AuthenticateResult> _readCookieTask;
|
private Task<AuthenticateResult> _readCookieTask;
|
||||||
|
|
||||||
|
|
@ -37,6 +37,33 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
return _readCookieTask;
|
return _readCookieTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckForRefresh(AuthenticationTicket ticket)
|
||||||
|
{
|
||||||
|
var currentUtc = Options.SystemClock.UtcNow;
|
||||||
|
var issuedUtc = ticket.Properties.IssuedUtc;
|
||||||
|
var expiresUtc = ticket.Properties.ExpiresUtc;
|
||||||
|
var allowRefresh = ticket.Properties.AllowRefresh ?? true;
|
||||||
|
if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration && allowRefresh)
|
||||||
|
{
|
||||||
|
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
|
||||||
|
var timeRemaining = expiresUtc.Value.Subtract(currentUtc);
|
||||||
|
|
||||||
|
if (timeRemaining < timeElapsed)
|
||||||
|
{
|
||||||
|
RequestRefresh(ticket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RequestRefresh(AuthenticationTicket ticket)
|
||||||
|
{
|
||||||
|
_shouldRefresh = true;
|
||||||
|
var currentUtc = Options.SystemClock.UtcNow;
|
||||||
|
_refreshIssuedUtc = currentUtc;
|
||||||
|
var timeSpan = ticket.Properties.ExpiresUtc.Value.Subtract(ticket.Properties.IssuedUtc.Value);
|
||||||
|
_refreshExpiresUtc = currentUtc.Add(timeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<AuthenticateResult> ReadCookieTicket()
|
private async Task<AuthenticateResult> ReadCookieTicket()
|
||||||
{
|
{
|
||||||
var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName);
|
var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName);
|
||||||
|
|
@ -79,20 +106,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
return AuthenticateResult.Fail("Ticket expired");
|
return AuthenticateResult.Fail("Ticket expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowRefresh = ticket.Properties.AllowRefresh ?? true;
|
CheckForRefresh(ticket);
|
||||||
if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration && allowRefresh)
|
|
||||||
{
|
|
||||||
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
|
|
||||||
var timeRemaining = expiresUtc.Value.Subtract(currentUtc);
|
|
||||||
|
|
||||||
if (timeRemaining < timeElapsed)
|
|
||||||
{
|
|
||||||
_shouldRenew = true;
|
|
||||||
_renewIssuedUtc = currentUtc;
|
|
||||||
var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
|
|
||||||
_renewExpiresUtc = currentUtc.Add(timeSpan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally we have a valid ticket
|
// Finally we have a valid ticket
|
||||||
return AuthenticateResult.Success(ticket);
|
return AuthenticateResult.Success(ticket);
|
||||||
|
|
@ -116,7 +130,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
|
|
||||||
if (context.ShouldRenew)
|
if (context.ShouldRenew)
|
||||||
{
|
{
|
||||||
_shouldRenew = true;
|
RequestRefresh(result.Ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
|
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
|
||||||
|
|
@ -144,7 +158,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
protected override async Task FinishResponseAsync()
|
protected override async Task FinishResponseAsync()
|
||||||
{
|
{
|
||||||
// Only renew if requested, and neither sign in or sign out was called
|
// Only renew if requested, and neither sign in or sign out was called
|
||||||
if (!_shouldRenew || SignInAccepted || SignOutAccepted)
|
if (!_shouldRefresh || SignInAccepted || SignOutAccepted)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -153,13 +167,13 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
var ticket = (await HandleAuthenticateOnceAsync())?.Ticket;
|
var ticket = (await HandleAuthenticateOnceAsync())?.Ticket;
|
||||||
if (ticket != null)
|
if (ticket != null)
|
||||||
{
|
{
|
||||||
if (_renewIssuedUtc.HasValue)
|
if (_refreshIssuedUtc.HasValue)
|
||||||
{
|
{
|
||||||
ticket.Properties.IssuedUtc = _renewIssuedUtc;
|
ticket.Properties.IssuedUtc = _refreshIssuedUtc;
|
||||||
}
|
}
|
||||||
if (_renewExpiresUtc.HasValue)
|
if (_refreshExpiresUtc.HasValue)
|
||||||
{
|
{
|
||||||
ticket.Properties.ExpiresUtc = _renewExpiresUtc;
|
ticket.Properties.ExpiresUtc = _refreshExpiresUtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.SessionStore != null && _sessionKey != null)
|
if (Options.SessionStore != null && _sessionKey != null)
|
||||||
|
|
@ -175,9 +189,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
|
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
|
||||||
|
|
||||||
var cookieOptions = BuildCookieOptions();
|
var cookieOptions = BuildCookieOptions();
|
||||||
if (ticket.Properties.IsPersistent && _renewExpiresUtc.HasValue)
|
if (ticket.Properties.IsPersistent && _refreshExpiresUtc.HasValue)
|
||||||
{
|
{
|
||||||
cookieOptions.Expires = _renewExpiresUtc.Value.ToUniversalTime().DateTime;
|
cookieOptions.Expires = _refreshExpiresUtc.Value.ToUniversalTime().DateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
Options.CookieManager.AppendResponseCookie(
|
Options.CookieManager.AppendResponseCookie(
|
||||||
|
|
|
||||||
|
|
@ -580,6 +580,61 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
||||||
Assert.Null(FindClaimValue(transaction5, ClaimTypes.Name));
|
Assert.Null(FindClaimValue(transaction5, ClaimTypes.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true)]
|
||||||
|
[InlineData(false)]
|
||||||
|
public async Task ShouldRenewUpdatesIssuedExpiredUtc(bool sliding)
|
||||||
|
{
|
||||||
|
var clock = new TestClock();
|
||||||
|
DateTimeOffset? lastValidateIssuedDate = null;
|
||||||
|
DateTimeOffset? lastExpiresDate = null;
|
||||||
|
var server = CreateServer(options =>
|
||||||
|
{
|
||||||
|
options.SystemClock = clock;
|
||||||
|
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
|
||||||
|
options.SlidingExpiration = sliding;
|
||||||
|
options.Events = new CookieAuthenticationEvents
|
||||||
|
{
|
||||||
|
OnValidatePrincipal = ctx =>
|
||||||
|
{
|
||||||
|
lastValidateIssuedDate = ctx.Properties.IssuedUtc;
|
||||||
|
lastExpiresDate = ctx.Properties.ExpiresUtc;
|
||||||
|
ctx.ShouldRenew = true;
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
context.Authentication.SignInAsync("Cookies",
|
||||||
|
new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")))));
|
||||||
|
|
||||||
|
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||||
|
|
||||||
|
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||||
|
Assert.NotNull(transaction2.SetCookie);
|
||||||
|
Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name));
|
||||||
|
|
||||||
|
Assert.NotNull(lastValidateIssuedDate);
|
||||||
|
Assert.NotNull(lastExpiresDate);
|
||||||
|
|
||||||
|
var firstIssueDate = lastValidateIssuedDate;
|
||||||
|
var firstExpiresDate = lastExpiresDate;
|
||||||
|
|
||||||
|
clock.Add(TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
|
var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue);
|
||||||
|
Assert.NotNull(transaction3.SetCookie);
|
||||||
|
Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name));
|
||||||
|
|
||||||
|
clock.Add(TimeSpan.FromMinutes(2));
|
||||||
|
|
||||||
|
var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction3.CookieNameValue);
|
||||||
|
Assert.NotNull(transaction4.SetCookie);
|
||||||
|
Assert.Equal("Alice", FindClaimValue(transaction4, ClaimTypes.Name));
|
||||||
|
|
||||||
|
Assert.NotEqual(lastValidateIssuedDate, firstIssueDate);
|
||||||
|
Assert.NotEqual(firstExpiresDate, lastExpiresDate);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CookieExpirationCanBeOverridenInEvent()
|
public async Task CookieExpirationCanBeOverridenInEvent()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue