Browse Source

Introduce OpenIddictToken.Start/End to expose the token validation validity period as first class properties

pull/443/head
vyfster 9 years ago
committed by Kévin Chalet
parent
commit
524fe6f055
  1. 17
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  2. 14
      src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs
  3. 17
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  4. 12
      src/OpenIddict.Models/OpenIddictToken.cs
  5. 83
      src/OpenIddict/OpenIddictProvider.Serialization.cs
  6. 8
      test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs
  7. 149
      test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs

17
src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs

@ -61,11 +61,16 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="type">The token type.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
public virtual Task<TToken> CreateAsync([NotNull] string type, [NotNull] string subject, CancellationToken cancellationToken)
public virtual Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject,
[CanBeNull] DateTimeOffset? start,
[CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(type))
{
@ -77,7 +82,7 @@ namespace OpenIddict.Core
throw new ArgumentException("The subject cannot be null or empty.");
}
return Store.CreateAsync(type, subject, cancellationToken);
return Store.CreateAsync(type, subject, start, end, cancellationToken);
}
/// <summary>
@ -87,13 +92,15 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the token.</param>
/// <param name="hash">The hash of the crypto-secure random identifier associated with the token.</param>
/// <param name="ciphertext">The ciphertext associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
public virtual Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject, [NotNull] string hash,
[NotNull] string ciphertext, CancellationToken cancellationToken)
[NotNull] string type, [NotNull] string subject, [NotNull] string hash, [NotNull] string ciphertext,
[CanBeNull] DateTimeOffset? start, [CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(type))
{
@ -110,7 +117,7 @@ namespace OpenIddict.Core
throw new ArgumentException("The ciphertext cannot be null or empty.", nameof(ciphertext));
}
return Store.CreateAsync(type, subject, hash, ciphertext, cancellationToken);
return Store.CreateAsync(type, subject, hash, ciphertext, start, end, cancellationToken);
}
/// <summary>

14
src/OpenIddict.Core/Stores/IOpenIddictTokenStore.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using System;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -31,11 +32,16 @@ namespace OpenIddict.Core
/// </summary>
/// <param name="type">The token type.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
Task<TToken> CreateAsync([NotNull] string type, [NotNull] string subject, CancellationToken cancellationToken);
Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject,
[CanBeNull] DateTimeOffset? start,
[CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken);
/// <summary>
/// Creates a new reference token, which is associated with a particular subject.
@ -44,13 +50,15 @@ namespace OpenIddict.Core
/// <param name="subject">The subject associated with the token.</param>
/// <param name="hash">The hash of the crypto-secure random identifier associated with the token.</param>
/// <param name="ciphertext">The ciphertext associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject, [NotNull] string hash,
[NotNull] string ciphertext, CancellationToken cancellationToken);
[NotNull] string type, [NotNull] string subject, [NotNull] string hash, [NotNull] string ciphertext,
[CanBeNull] DateTimeOffset? start, [CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken);
/// <summary>
/// Removes a token.

17
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -114,11 +114,16 @@ namespace OpenIddict.EntityFrameworkCore
/// </summary>
/// <param name="type">The token type.</param>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
public virtual Task<TToken> CreateAsync([NotNull] string type, [NotNull] string subject, CancellationToken cancellationToken)
public virtual Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject,
[CanBeNull] DateTimeOffset? start,
[CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(type))
{
@ -132,6 +137,8 @@ namespace OpenIddict.EntityFrameworkCore
var token = new TToken
{
End = end,
Start = start,
Subject = subject,
Type = type
};
@ -146,13 +153,15 @@ namespace OpenIddict.EntityFrameworkCore
/// <param name="subject">The subject associated with the token.</param>
/// <param name="hash">The hash of the crypto-secure random identifier associated with the token.</param>
/// <param name="ciphertext">The ciphertext associated with the token.</param>
/// <param name="start">The date on which the token will start to be considered valid.</param>
/// <param name="end">The date on which the token will no longer be considered valid.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result returns the token.
/// </returns>
public virtual Task<TToken> CreateAsync(
[NotNull] string type, [NotNull] string subject, [NotNull] string hash,
[NotNull] string ciphertext, CancellationToken cancellationToken)
[NotNull] string type, [NotNull] string subject, [NotNull] string hash, [NotNull] string ciphertext,
[CanBeNull] DateTimeOffset? start, [CanBeNull] DateTimeOffset? end, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(type))
{
@ -167,7 +176,9 @@ namespace OpenIddict.EntityFrameworkCore
var token = new TToken
{
Ciphertext = ciphertext,
End = end,
Hash = hash,
Start = start,
Subject = subject,
Type = type
};

12
src/OpenIddict.Models/OpenIddictToken.cs

@ -50,6 +50,12 @@ namespace OpenIddict.Models
/// </summary>
public virtual string Ciphertext { get; set; }
/// <summary>
/// Gets or sets the date on which the token
/// will no longer be considered valid.
/// </summary>
public virtual DateTimeOffset? End { get; set; }
/// <summary>
/// Gets or sets the hashed identifier associated
/// with the current token, if applicable.
@ -63,6 +69,12 @@ namespace OpenIddict.Models
/// </summary>
public virtual TKey Id { get; set; }
/// <summary>
/// Gets or sets the date on which the token
/// will start to be considered valid.
/// </summary>
public virtual DateTimeOffset? Start { get; set; }
/// <summary>
/// Gets or sets the status of the current token.
/// </summary>

83
src/OpenIddict/OpenIddictProvider.Serialization.cs

@ -14,6 +14,7 @@ using AspNet.Security.OpenIdConnect.Primitives;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
@ -31,8 +32,9 @@ namespace OpenIddict
return;
}
var ticket = await ReceiveTokenAsync(context.AccessToken, options, context.Request,
context.DataFormat, context.HttpContext.RequestAborted);
var ticket = await ReceiveTokenAsync(
context.AccessToken, options, context.HttpContext,
context.Request, context.DataFormat);
// If a valid ticket was returned by ReceiveTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -54,8 +56,9 @@ namespace OpenIddict
return;
}
var ticket = await ReceiveTokenAsync(context.AuthorizationCode, options, context.Request,
context.DataFormat, context.HttpContext.RequestAborted);
var ticket = await ReceiveTokenAsync(
context.AuthorizationCode, options, context.HttpContext,
context.Request, context.DataFormat);
// If a valid ticket was returned by ReceiveTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -77,8 +80,9 @@ namespace OpenIddict
return;
}
var ticket = await ReceiveTokenAsync(context.RefreshToken, options, context.Request,
context.DataFormat, context.HttpContext.RequestAborted);
var ticket = await ReceiveTokenAsync(
context.RefreshToken, options, context.HttpContext,
context.Request, context.DataFormat);
// If a valid ticket was returned by ReceiveTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -94,9 +98,10 @@ namespace OpenIddict
public override async Task SerializeAccessToken([NotNull] SerializeAccessTokenContext context)
{
var token = await CreateTokenAsync(OpenIdConnectConstants.TokenUsages.AccessToken,
(OpenIddictOptions) context.Options, context.Request, context.DataFormat,
context.Ticket, context.HttpContext.RequestAborted);
var token = await CreateTokenAsync(
OpenIdConnectConstants.TokenUsages.AccessToken,
context.Ticket, (OpenIddictOptions) context.Options,
context.HttpContext, context.Request, context.DataFormat);
// If a reference token was returned by CreateTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -112,9 +117,10 @@ namespace OpenIddict
public override async Task SerializeAuthorizationCode([NotNull] SerializeAuthorizationCodeContext context)
{
var token = await CreateTokenAsync(OpenIdConnectConstants.TokenUsages.AuthorizationCode,
(OpenIddictOptions) context.Options, context.Request, context.DataFormat,
context.Ticket, context.HttpContext.RequestAborted);
var token = await CreateTokenAsync(
OpenIdConnectConstants.TokenUsages.AuthorizationCode,
context.Ticket, (OpenIddictOptions) context.Options,
context.HttpContext, context.Request, context.DataFormat);
// If a reference token was returned by CreateTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -130,9 +136,10 @@ namespace OpenIddict
public override async Task SerializeRefreshToken([NotNull] SerializeRefreshTokenContext context)
{
var token = await CreateTokenAsync(OpenIdConnectConstants.TokenUsages.RefreshToken,
(OpenIddictOptions) context.Options, context.Request, context.DataFormat,
context.Ticket, context.HttpContext.RequestAborted);
var token = await CreateTokenAsync(
OpenIdConnectConstants.TokenUsages.RefreshToken,
context.Ticket, (OpenIddictOptions) context.Options,
context.HttpContext, context.Request, context.DataFormat);
// If a reference token was returned by CreateTokenAsync(),
// force the OpenID Connect server middleware to use it.
@ -147,10 +154,10 @@ namespace OpenIddict
}
private async Task<string> CreateTokenAsync(
[NotNull] string type, [NotNull] OpenIddictOptions options,
[NotNull] string type, [NotNull] AuthenticationTicket ticket,
[NotNull] OpenIddictOptions options, [NotNull] HttpContext context,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format,
[NotNull] AuthenticationTicket ticket, CancellationToken cancellationToken)
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
Debug.Assert(!(options.DisableTokenRevocation && options.UseReferenceTokens),
"Token revocation cannot be disabled when using reference tokens.");
@ -202,14 +209,18 @@ namespace OpenIddict
hash = Convert.ToBase64String(algorithm.ComputeHash(bytes));
}
token = await Tokens.CreateAsync(type, subject, hash, ciphertext, cancellationToken);
token = await Tokens.CreateAsync(type, subject, hash, ciphertext,
ticket.Properties.IssuedUtc,
ticket.Properties.ExpiresUtc, context.RequestAborted);
}
// Otherwise, only create a token metadata entry for authorization codes and refresh tokens.
else if (string.Equals(type, OpenIdConnectConstants.TokenUsages.AuthorizationCode, StringComparison.OrdinalIgnoreCase) ||
string.Equals(type, OpenIdConnectConstants.TokenUsages.RefreshToken, StringComparison.OrdinalIgnoreCase))
{
token = await Tokens.CreateAsync(type, subject, cancellationToken);
token = await Tokens.CreateAsync(type, subject,
ticket.Properties.IssuedUtc,
ticket.Properties.ExpiresUtc, context.RequestAborted);
}
else
@ -224,7 +235,7 @@ namespace OpenIddict
}
// Throw an exception if the token identifier can't be resolved.
var identifier = await Tokens.GetIdAsync(token, cancellationToken);
var identifier = await Tokens.GetIdAsync(token, context.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty.");
@ -238,22 +249,22 @@ namespace OpenIddict
// If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(request.ClientId))
{
var application = await Applications.FindByClientIdAsync(request.ClientId, cancellationToken);
var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
var key = await Applications.GetIdAsync(application, cancellationToken);
var key = await Applications.GetIdAsync(application, context.RequestAborted);
await Tokens.SetClientAsync(token, key, cancellationToken);
await Tokens.SetClientAsync(token, key, context.RequestAborted);
}
// If an authorization identifier was specified, bind it to the token.
if (ticket.HasProperty(OpenIddictConstants.Properties.AuthorizationId))
{
await Tokens.SetAuthorizationAsync(token,
ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId), cancellationToken);
ticket.GetProperty(OpenIddictConstants.Properties.AuthorizationId), context.RequestAborted);
}
// Otherwise, create an ad-hoc authorization if the token is an authorization code.
@ -261,21 +272,21 @@ namespace OpenIddict
{
Debug.Assert(!string.IsNullOrEmpty(request.ClientId), "The client identifier shouldn't be null.");
var application = await Applications.FindByClientIdAsync(request.ClientId, cancellationToken);
var application = await Applications.FindByClientIdAsync(request.ClientId, context.RequestAborted);
if (application == null)
{
throw new InvalidOperationException("The client application cannot be retrieved from the database.");
}
var authorization = await Authorizations.CreateAsync(subject,
await Applications.GetIdAsync(application, cancellationToken), request.GetScopes(), cancellationToken);
await Applications.GetIdAsync(application, context.RequestAborted), request.GetScopes(), context.RequestAborted);
if (authorization != null)
{
var key = await Authorizations.GetIdAsync(authorization, cancellationToken);
var key = await Authorizations.GetIdAsync(authorization, context.RequestAborted);
ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId, key);
await Tokens.SetAuthorizationAsync(token, key, cancellationToken);
await Tokens.SetAuthorizationAsync(token, key, context.RequestAborted);
}
}
@ -291,8 +302,8 @@ namespace OpenIddict
private async Task<AuthenticationTicket> ReceiveTokenAsync(
[NotNull] string value, [NotNull] OpenIddictOptions options,
[NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format, CancellationToken cancellationToken)
[NotNull] HttpContext context, [NotNull] OpenIdConnectRequest request,
[NotNull] ISecureDataFormat<AuthenticationTicket> format)
{
if (!options.UseReferenceTokens)
{
@ -319,7 +330,7 @@ namespace OpenIddict
// Retrieve the token entry from the database. If it
// cannot be found, assume the token is not valid.
var token = await Tokens.FindByHashAsync(hash, cancellationToken);
var token = await Tokens.FindByHashAsync(hash, context.RequestAborted);
if (token == null)
{
Logger.LogInformation("The reference token corresponding to the '{Hash}' hashed " +
@ -328,7 +339,7 @@ namespace OpenIddict
return null;
}
var identifier = await Tokens.GetIdAsync(token, cancellationToken);
var identifier = await Tokens.GetIdAsync(token, context.RequestAborted);
if (string.IsNullOrEmpty(identifier))
{
Logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
@ -339,7 +350,7 @@ namespace OpenIddict
// Extract the encrypted payload from the token. If it's null or empty,
// assume the token is not a reference token and consider it as invalid.
var ciphertext = await Tokens.GetCiphertextAsync(token, cancellationToken);
var ciphertext = await Tokens.GetCiphertextAsync(token, context.RequestAborted);
if (string.IsNullOrEmpty(ciphertext))
{
Logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be retrieved. " +
@ -353,7 +364,7 @@ namespace OpenIddict
{
Logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be decrypted. " +
"This may indicate that the token entry is corrupted or tampered.",
await Tokens.GetIdAsync(token, cancellationToken));
await Tokens.GetIdAsync(token, context.RequestAborted));
return null;
}
@ -367,7 +378,7 @@ namespace OpenIddict
if (!ticket.HasProperty(OpenIddictConstants.Properties.AuthorizationId))
{
ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId,
await Tokens.GetAuthorizationIdAsync(token, cancellationToken));
await Tokens.GetAuthorizationIdAsync(token, context.RequestAborted));
}
Logger.LogTrace("The reference token '{Identifier}' was successfully retrieved " +

8
test/OpenIddict.Tests/OpenIddictProviderTests.Authentication.cs

@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -559,7 +560,10 @@ namespace OpenIddict.Tests
{
var token = new OpenIddictToken();
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))

149
test/OpenIddict.Tests/OpenIddictProviderTests.Serialization.cs

@ -1,9 +1,11 @@
using System.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Client;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
@ -43,20 +45,28 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.AccessToken);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique", It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()), Times.Never());
}
[Fact]
public async Task SerializeAccessToken_ReferenceAccessTokenIsCorrectlyPersisted()
{
// Arrange
var token = new OpenIddictToken();
var token = new OpenIddictToken
{
End = new DateTimeOffset(2017, 01, 01, 00, 00, 00, TimeSpan.Zero),
Start = new DateTimeOffset(2017, 01, 02, 00, 00, 00, TimeSpan.Zero),
};
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()))
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -68,6 +78,12 @@ namespace OpenIddict.Tests
builder.Services.AddSingleton(manager);
builder.UseReferenceTokens();
builder.Configure(options =>
{
options.SystemClock = Mock.Of<ISystemClock>(mock => mock.UtcNow == token.Start.Value);
options.AccessTokenLifetime = token.End.Value - token.Start.Value;
});
});
var client = new OpenIdConnectClient(server.CreateClient());
@ -86,7 +102,8 @@ namespace OpenIddict.Tests
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()), Times.Once());
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -100,7 +117,9 @@ namespace OpenIddict.Tests
{
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()))
It.IsNotNull<string>(), It.IsNotNull<string>(),
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -159,7 +178,9 @@ namespace OpenIddict.Tests
{
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AccessToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()))
It.IsNotNull<string>(), It.IsNotNull<string>(),
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -245,18 +266,27 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.Code);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()), Times.Never());
}
[Fact]
public async Task SerializeAuthorizationCode_AuthorizationCodeIsCorrectlyPersisted()
{
// Arrange
var token = new OpenIddictToken();
var token = new OpenIddictToken
{
End = new DateTimeOffset(2017, 01, 02, 00, 00, 00, TimeSpan.Zero),
Start = new DateTimeOffset(2017, 01, 01, 00, 00, 00, TimeSpan.Zero),
};
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
token.Start, token.End, It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -283,6 +313,12 @@ namespace OpenIddict.Tests
}));
builder.Services.AddSingleton(manager);
builder.Configure(options =>
{
options.SystemClock = Mock.Of<ISystemClock>(mock => mock.UtcNow == token.Start.Value);
options.AuthorizationCodeLifetime = token.End.Value - token.Start.Value;
});
});
var client = new OpenIdConnectClient(server.CreateClient());
@ -298,7 +334,9 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.Code);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
token.Start, token.End, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -306,13 +344,18 @@ namespace OpenIddict.Tests
public async Task SerializeAuthorizationCode_ReferenceAuthorizationCodeIsCorrectlyPersisted()
{
// Arrange
var token = new OpenIddictToken();
var token = new OpenIddictToken
{
End = new DateTimeOffset(2017, 01, 02, 00, 00, 00, TimeSpan.Zero),
Start = new DateTimeOffset(2017, 01, 01, 00, 00, 00, TimeSpan.Zero),
};
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()))
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -341,6 +384,12 @@ namespace OpenIddict.Tests
builder.Services.AddSingleton(manager);
builder.UseReferenceTokens();
builder.Configure(options =>
{
options.SystemClock = Mock.Of<ISystemClock>(mock => mock.UtcNow == token.Start.Value);
options.AuthorizationCodeLifetime = token.End.Value - token.Start.Value;
});
});
var client = new OpenIdConnectClient(server.CreateClient());
@ -356,8 +405,10 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.Code);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode,
"Bob le Magnifique", It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -369,7 +420,10 @@ namespace OpenIddict.Tests
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -428,7 +482,10 @@ namespace OpenIddict.Tests
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -525,7 +582,10 @@ namespace OpenIddict.Tests
builder.Services.AddSingleton(CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.AuthorizationCode, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -581,18 +641,27 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique", It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()), Times.Never());
}
[Fact]
public async Task SerializeRefreshToken_RefreshTokenIsCorrectlyPersisted()
{
// Arrange
var token = new OpenIddictToken();
var token = new OpenIddictToken
{
End = new DateTimeOffset(2017, 01, 02, 00, 00, 00, TimeSpan.Zero),
Start = new DateTimeOffset(2017, 01, 01, 00, 00, 00, TimeSpan.Zero)
};
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
token.Start, token.End, It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -602,6 +671,12 @@ namespace OpenIddict.Tests
var server = CreateAuthorizationServer(builder =>
{
builder.Services.AddSingleton(manager);
builder.Configure(options =>
{
options.SystemClock = Mock.Of<ISystemClock>(mock => mock.UtcNow == token.Start.Value);
options.RefreshTokenLifetime = token.End.Value - token.Start.Value;
});
});
var client = new OpenIdConnectClient(server.CreateClient());
@ -618,7 +693,9 @@ namespace OpenIddict.Tests
// Assert
Assert.NotNull(response.RefreshToken);
Mock.Get(manager).Verify(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique", It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
token.Start, token.End, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -626,13 +703,18 @@ namespace OpenIddict.Tests
public async Task SerializeRefreshToken_ReferenceRefreshTokenIsCorrectlyPersisted()
{
// Arrange
var token = new OpenIddictToken();
var token = new OpenIddictToken
{
End = new DateTimeOffset(2017, 01, 02, 00, 00, 00, TimeSpan.Zero),
Start = new DateTimeOffset(2017, 01, 01, 00, 00, 00, TimeSpan.Zero),
};
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()))
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -644,6 +726,12 @@ namespace OpenIddict.Tests
builder.Services.AddSingleton(manager);
builder.UseReferenceTokens();
builder.Configure(options =>
{
options.SystemClock = Mock.Of<ISystemClock>(mock => mock.UtcNow == token.Start.Value);
options.RefreshTokenLifetime = token.End.Value - token.Start.Value;
});
});
var client = new OpenIdConnectClient(server.CreateClient());
@ -662,7 +750,8 @@ namespace OpenIddict.Tests
Mock.Get(manager).Verify(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
It.IsNotNull<string>(), It.IsNotNull<string>(), It.IsAny<CancellationToken>()), Times.Once());
It.IsNotNull<string>(), It.IsNotNull<string>(),
token.Start, token.End, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()), Times.Once());
}
@ -674,7 +763,10 @@ namespace OpenIddict.Tests
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))
@ -729,7 +821,10 @@ namespace OpenIddict.Tests
var manager = CreateTokenManager(instance =>
{
instance.Setup(mock => mock.CreateAsync(OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique", It.IsAny<CancellationToken>()))
instance.Setup(mock => mock.CreateAsync(
OpenIdConnectConstants.TokenTypeHints.RefreshToken, "Bob le Magnifique",
It.IsAny<DateTimeOffset?>(), It.IsAny<DateTimeOffset?>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
instance.Setup(mock => mock.GetIdAsync(token, It.IsAny<CancellationToken>()))

Loading…
Cancel
Save