diff --git a/Directory.Build.props b/Directory.Build.props
index d0e6b43fc..f34316f4f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,6 +1,6 @@
- 3.1.2
+ 3.1.3
3.1
RockSolidKnowledge
CS1591;CS1570;CS1571;CS1572;CS1573;CS1574;CS1580;CS1581;CS1584;CS1587;CS1591;CS1658;CS1712;CS1734
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 02691d1e4..1c63a59e9 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -5,7 +5,7 @@
10.0.14
10.0.14
- 3.1.2-*
+ 3.1.3-*
diff --git a/src/EntityFramework.Storage/src/Mappers/IdentityServerServerSideSessionsExtensions.cs b/src/EntityFramework.Storage/src/Mappers/IdentityServerServerSideSessionsExtensions.cs
index fe20c9440..326aa7865 100644
--- a/src/EntityFramework.Storage/src/Mappers/IdentityServerServerSideSessionsExtensions.cs
+++ b/src/EntityFramework.Storage/src/Mappers/IdentityServerServerSideSessionsExtensions.cs
@@ -3,8 +3,10 @@
#nullable enable
+using System;
using Open.IdentityServer.EntityFramework.Entities;
using Open.IdentityServer.Models;
+using Open.IdentityServer.Stores.Serialization;
namespace Open.IdentityServer.EntityFramework.Mappers;
@@ -23,17 +25,19 @@ public static class IdentityServerServerSideSessionsExtensions
/// Mapper for to convert into an instance of
///
/// mapped instance of
- public Models.ServerSideSession ToModel() =>
- sessionEntity.ToModel();
+ public Models.ServerSideSession ToModel(IAuthenticationTicketSerializer authTicketSerializer) =>
+ sessionEntity.ToModel(authTicketSerializer);
///
/// Mapper for to convert into an instance of .
///
/// The type of model to map to.
/// mapped instance of .
- public TModel ToModel()
+ public TModel ToModel(IAuthenticationTicketSerializer authTicketSerializer)
where TModel: Models.ServerSideSession, new()
{
+ var authenticationTicket = authTicketSerializer.Deserialize(sessionEntity.Data);
+
return new TModel
{
Key = sessionEntity.Key,
@@ -44,7 +48,8 @@ public TModel ToModel()
Created = sessionEntity.Created,
Renewed = sessionEntity.Renewed,
Expires = sessionEntity.Expires,
- Data = sessionEntity.Data
+ Data = sessionEntity.Data,
+ AuthenticationTicket = authenticationTicket,
};
}
}
@@ -58,10 +63,11 @@ public TModel ToModel()
///
/// Mapper for to convert into an instance of
///
+ /// authentication ticket serializer
/// mapped instance of
- public Entities.ServerSideSession ToEntity()
+ public Entities.ServerSideSession ToEntity(IAuthenticationTicketSerializer authTicketSerializer)
{
- return new Entities.ServerSideSession
+ Entities.ServerSideSession newEntity = new()
{
Key = sessionModel.Key,
Scheme = sessionModel.Scheme,
@@ -71,15 +77,22 @@ public Entities.ServerSideSession ToEntity()
Created = sessionModel.Created,
Renewed = sessionModel.Renewed,
Expires = sessionModel.Expires,
- Data = sessionModel.Data
};
+
+ if (sessionModel.AuthenticationTicket != null)
+ {
+ newEntity.Data = authTicketSerializer.Serialize(sessionModel.AuthenticationTicket);
+ }
+
+ return newEntity;
}
-
+
///
/// Updates with instance of
///
+ /// authentication ticket serializer
/// The entity.
- public void UpdateEntity(Entities.ServerSideSession existingEntity)
+ public void UpdateEntity(IAuthenticationTicketSerializer authTicketSerializer, Entities.ServerSideSession existingEntity)
{
existingEntity.Key = sessionModel.Key;
existingEntity.Scheme = sessionModel.Scheme;
@@ -89,7 +102,11 @@ public void UpdateEntity(Entities.ServerSideSession existingEntity)
existingEntity.Created = sessionModel.Created;
existingEntity.Renewed = sessionModel.Renewed;
existingEntity.Expires = sessionModel.Expires;
- existingEntity.Data = sessionModel.Data;
+
+ if (sessionModel.AuthenticationTicket != null)
+ {
+ existingEntity.Data = authTicketSerializer.Serialize(sessionModel.AuthenticationTicket);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/EntityFramework.Storage/src/Stores/IdentityServerServerSideSessionStore.cs b/src/EntityFramework.Storage/src/Stores/IdentityServerServerSideSessionStore.cs
index 2f8198624..653ec2e2b 100644
--- a/src/EntityFramework.Storage/src/Stores/IdentityServerServerSideSessionStore.cs
+++ b/src/EntityFramework.Storage/src/Stores/IdentityServerServerSideSessionStore.cs
@@ -15,6 +15,7 @@
using Open.IdentityServer.Models;
using Open.IdentityServer.Services;
using Open.IdentityServer.Stores;
+using Open.IdentityServer.Stores.Serialization;
namespace Open.IdentityServer.EntityFramework.Stores;
@@ -23,6 +24,7 @@ namespace Open.IdentityServer.EntityFramework.Stores;
///
public class IdentityServerServerSideSessionStore(
IPersistedGrantDbContext dbContext,
+ IAuthenticationTicketSerializer authTicketSerializer,
ITelemetryService telemetry,
TimeProvider timeProvider,
ILogger logger) : IIdentityServerServerSideSessionStore
@@ -35,8 +37,12 @@ public class IdentityServerServerSideSessionStore(
///
/// Makes it possible to return an extended model.
///
- protected virtual ServerSideSession? ToModel(Entities.ServerSideSession? entities) =>
- entities?.ToModel();
+ protected virtual ServerSideSession? ToModel(Entities.ServerSideSession? entities)
+ {
+ var result = entities?.ToModel(authTicketSerializer);
+
+ return result;
+ }
///
public async Task GetSession(string key)
@@ -68,7 +74,7 @@ public async Task CreateSession(ServerSideSession session)
return;
}
- Entities.ServerSideSession sessionEntity = session.ToEntity();
+ Entities.ServerSideSession sessionEntity = session.ToEntity(authTicketSerializer);
await dbContext.ServerSideSessions.AddAsync(sessionEntity);
@@ -98,7 +104,7 @@ public async Task UpdateSession(ServerSideSession session)
return;
}
- session.UpdateEntity(existing);
+ session.UpdateEntity(authTicketSerializer, existing);
try
{
diff --git a/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/ExtendedIdentityServerServerSideSessionStore.cs b/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/ExtendedIdentityServerServerSideSessionStore.cs
index 91b5f6c96..45d8c2d13 100644
--- a/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/ExtendedIdentityServerServerSideSessionStore.cs
+++ b/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/ExtendedIdentityServerServerSideSessionStore.cs
@@ -4,19 +4,21 @@
using Open.IdentityServer.EntityFramework.Mappers;
using Open.IdentityServer.EntityFramework.Stores;
using Open.IdentityServer.Services;
+using Open.IdentityServer.Stores.Serialization;
namespace Open.IdentityServer.EntityFramework.IntegrationTests.Stores.Compatibility;
public class ExtendedIdentityServerServerSideSessionStore(
IPersistedGrantDbContext dbContext,
+ IAuthenticationTicketSerializer authTicketSerializer,
ITelemetryService telemetry,
TimeProvider timeProvider,
ILogger logger):
- IdentityServerServerSideSessionStore(dbContext, telemetry, timeProvider, logger)
+ IdentityServerServerSideSessionStore(dbContext, authTicketSerializer, telemetry, timeProvider, logger)
{
protected override Models.ServerSideSession ToModel(Entities.ServerSideSession client)
{
- var model = client.ToModel();
+ var model = client.ToModel(authTicketSerializer);
model.DataLength = model.Data.Length;
model.Lifetime = model.Expires?.Subtract(model.Renewed);
diff --git a/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/IdentityServerServerSideSessionStoreTests.cs b/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/IdentityServerServerSideSessionStoreTests.cs
index 85d3bb477..2cf0a082f 100644
--- a/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/IdentityServerServerSideSessionStoreTests.cs
+++ b/src/EntityFramework.Storage/test/IntegrationTests/Stores/Compatibility/IdentityServerServerSideSessionStoreTests.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using AwesomeAssertions;
+using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Time.Testing;
@@ -12,6 +13,8 @@
using Open.IdentityServer.EntityFramework.Stores;
using Open.IdentityServer.Models;
using Open.IdentityServer.Services;
+using Open.IdentityServer.Stores.Serialization;
+using Open.IdentityServer.Test.Utilities;
using Open.IdentityServer.Test.Utilities;
using Xunit;
@@ -19,6 +22,7 @@ namespace Open.IdentityServer.EntityFramework.IntegrationTests.Stores.Compatibil
public class IdentityServerServerSideSessionStoreTests: IntegrationTest
{
+ private readonly IAuthenticationTicketSerializer authTicketSerializer = Mock.Of();
private readonly ITelemetryService telemetry = Mock.Of();
private readonly FakeTimeProvider timeProvider = new();
private readonly MockLogger fakeLogger = new();
@@ -37,10 +41,10 @@ public IdentityServerServerSideSessionStoreTests(DatabaseProviderFixture
- new(dbContext, telemetry, timeProvider, fakeLogger);
+ new(dbContext, authTicketSerializer, telemetry, timeProvider, fakeLogger);
private ExtendedIdentityServerServerSideSessionStore CreateSutExtended(PersistedGrantDbContext dbContext) =>
- new (dbContext, telemetry, timeProvider, fakeLogger);
+ new (dbContext, authTicketSerializer, telemetry, timeProvider, fakeLogger);
[Theory]
[InlineData(null)]
@@ -83,8 +87,13 @@ public async Task GetSession_WhenExist_ShouldReturnValue(DbContextOptions x.Deserialize(seeded.Data))
+ .Returns(fakeTicket);
context.ServerSideSessions.Add(seeded);
await context.SaveChangesAsync();
@@ -103,6 +112,7 @@ public async Task GetSession_WhenExist_ShouldReturnValue(DbContextOptions x.Deserialize(seeded.Data))
+ .Returns(fakeTicket);
context.ServerSideSessions.Add(seeded);
await context.SaveChangesAsync();
@@ -144,6 +159,7 @@ public async Task GetSession_WhenExist_UsingExtendedStore_ShouldReturnValueOfTyp
resultExt.Renewed.Should().Be(seeded.Renewed);
resultExt.Expires.Should().Be(seeded.Expires);
resultExt.Data.Should().Be(seeded.Data);
+ result.AuthenticationTicket.Should().Be(fakeTicket);
resultExt.DataLength.Should().Be(seeded.Data.Length);
resultExt.Lifetime.Should().Be(seeded.Expires?.Subtract(seeded.Renewed));
@@ -199,26 +215,31 @@ public async Task CreateSession_WhenSessionDoesntExistsWithKey_ShouldStoreSessio
await using PersistedGrantDbContext context = await CreateCleanContext(options);
string key = "new-key";
- ServerSideSession session = BuildSessionModel(key, "sub-123", "sid-123", "display-123");
+ ServerSideSession newSession = BuildSessionModel(key, "sub-123", "sid-123", "display-123");
+
+ const string fakeProtectedData = "{\"version\":1,\"payload\":\"PROTECTED_DATA\"}";
+ Mock.Get(authTicketSerializer)
+ .Setup(x => x.Serialize(newSession.AuthenticationTicket))
+ .Returns(fakeProtectedData);
IdentityServerServerSideSessionStore sut = CreateSut(context);
- await sut.CreateSession(session);
+ await sut.CreateSession(newSession);
Entities.ServerSideSession stored = await context.ServerSideSessions
.AsNoTracking()
.SingleOrDefaultAsync(x => x.Key == key, cancellationToken: TestContext.Current.CancellationToken);
stored.Should().NotBeNull();
- stored!.Key.Should().Be(session.Key);
- stored.Scheme.Should().Be(session.Scheme);
- stored.SubjectId.Should().Be(session.SubjectId);
- stored.SessionId.Should().Be(session.SessionId);
- stored.DisplayName.Should().Be(session.DisplayName);
- stored.Created.Should().Be(session.Created);
- stored.Renewed.Should().Be(session.Renewed);
- stored.Expires.Should().Be(session.Expires);
- stored.Data.Should().Be(session.Data);
+ stored!.Key.Should().Be(newSession.Key);
+ stored.Scheme.Should().Be(newSession.Scheme);
+ stored.SubjectId.Should().Be(newSession.SubjectId);
+ stored.SessionId.Should().Be(newSession.SessionId);
+ stored.DisplayName.Should().Be(newSession.DisplayName);
+ stored.Created.Should().Be(newSession.Created);
+ stored.Renewed.Should().Be(newSession.Renewed);
+ stored.Expires.Should().Be(newSession.Expires);
+ stored.Data.Should().Be(fakeProtectedData);
}
[Theory]
@@ -272,10 +293,14 @@ public async Task UpdateSession_WhenSessionExistsWithKey_ShouldUpdateStoredSessi
ServerSideSession updated = BuildSessionModel(key, "new-sub", "new-sid", "new-display");
updated.Scheme = "new-scheme";
- updated.Data = "{\"version\":2}";
updated.Created = FakeNow.AddHours(-3);
updated.Renewed = FakeNow.AddMinutes(-1);
updated.Expires = FakeNow.AddHours(2);
+
+ const string fakeProtectedData = "{\"version\":1,\"payload\":\"PROTECTED_DATA\"}";
+ Mock.Get(authTicketSerializer)
+ .Setup(x => x.Serialize(updated.AuthenticationTicket))
+ .Returns(fakeProtectedData);
IdentityServerServerSideSessionStore sut = CreateSut(context);
@@ -293,7 +318,7 @@ public async Task UpdateSession_WhenSessionExistsWithKey_ShouldUpdateStoredSessi
stored.Created.Should().Be(updated.Created);
stored.Renewed.Should().Be(updated.Renewed);
stored.Expires.Should().Be(updated.Expires);
- stored.Data.Should().Be(updated.Data);
+ stored.Data.Should().Be(fakeProtectedData);
}
[Theory]
@@ -518,22 +543,44 @@ public async Task FilterSessions_WhenSubjectIdNull_ShouldReturnMatchingSessionId
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
+
+ List expectedSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
await context.SaveChangesAsync();
var actual = (await sut.FilterSessions(null,"session-0")).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == "key-0");
- actual.Should().Contain(x => x.Key == "key-4");
+ actual.Should().BeEquivalentTo(expectedSessions);
+ }
+
+ private List SetupExpectedSessions(List sessionEntities)
+ {
+ List expectedSessions = [];
+
+ foreach (var sessionEntity in sessionEntities)
+ {
+ var session = BuildSessionModel(sessionEntity.Key, sessionEntity.SubjectId, sessionEntity.SessionId, sessionEntity.DisplayName, scheme: sessionEntity.Scheme, created: sessionEntity.Created, renewed: sessionEntity.Renewed, expires: sessionEntity.Expires, data: sessionEntity.Data);
+
+ Mock.Get(authTicketSerializer)
+ .Setup(x => x.Deserialize(sessionEntity.Data))
+ .Returns(session.AuthenticationTicket);
+
+ expectedSessions.Add(session);
+ }
+
+ return expectedSessions;
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -543,13 +590,13 @@ public async Task FilterSessions_WhenSessionDontMatch_ShouldReturnEmptySet(DbCon
IdentityServerServerSideSessionStore sut = CreateSut(context);
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
@@ -563,47 +610,53 @@ public async Task FilterSessions_WhenSessionMatch_ShouldReturnMatchingSessions(D
{
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" };
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ foundSessionTwo,
]);
await context.SaveChangesAsync();
+ List expectedSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
var actual = (await sut.FilterSessions("alice", "session-1")).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == "key-1");
- actual.Should().Contain(x => x.Key == "key-6");
+ actual.Should().BeEquivalentTo(expectedSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
- public async Task FilterSessions_WhenExtendedStire_ShouldReturnMatchingExtendedSessionModels(DbContextOptions options)
+ public async Task FilterSessions_WhenExtendedStore_ShouldReturnMatchingExtendedSessionModels(DbContextOptions options)
{
await using var context = await CreateCleanContext(options);
ExtendedIdentityServerServerSideSessionStore sut = CreateSutExtended(context);
+
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" };
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ foundSessionTwo,
]);
await context.SaveChangesAsync();
+ List expectedSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
var actual = (await sut.FilterSessions("alice", "session-1")).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == "key-1");
- actual.Should().Contain(x => x.Key == "key-6");
+ actual.Should().BeEquivalentTo(expectedSessions);
foreach (var session in actual)
{
@@ -645,13 +698,13 @@ public async Task GetAndRemoveExpiredSessions_WhenExpiredSessionsExist_AndUnderB
context.ServerSideSessions.Add(expiredSession1);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([expiredSession0, expiredSession1]);
+
IdentityServerServerSideSessionStore sut = CreateSut(context);
List actual = (await sut.GetAndRemoveExpiredSessions()).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == expiredSession0.Key);
- actual.Should().Contain(x => x.Key == expiredSession1.Key);
+ actual.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -669,13 +722,13 @@ public async Task GetAndRemoveExpiredSessions_WhenExpiredSessionsExist_AndExceed
context.ServerSideSessions.Add(validSession0);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([expiredSession0, expiredSession1]);
+
IdentityServerServerSideSessionStore sut = CreateSut(context);
List actual = (await sut.GetAndRemoveExpiredSessions(2)).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == expiredSession0.Key);
- actual.Should().Contain(x => x.Key == expiredSession1.Key);
+ actual.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -693,13 +746,13 @@ public async Task GetAndRemoveExpiredSessions_WhenExtendedStore_ShouldDeleteAndR
context.ServerSideSessions.Add(validSession0);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([expiredSession0, expiredSession1]);
+
ExtendedIdentityServerServerSideSessionStore sut = CreateSutExtended(context);
List actual = (await sut.GetAndRemoveExpiredSessions(2)).ToList();
- actual.Should().HaveCount(2);
- actual.Should().Contain(x => x.Key == expiredSession0.Key);
- actual.Should().Contain(x => x.Key == expiredSession1.Key);
+ actual.Should().BeEquivalentTo(expectedExpiredSessions);
foreach (var session in actual)
{
@@ -735,12 +788,13 @@ public async Task GetAndRemoveExpiredSessions_WhenUnspecifiedTimezoneInDbEntitie
context.ServerSideSessions.Add(validSession0);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([expiredSession0]);
+
IdentityServerServerSideSessionStore sut = CreateSut(context);
List actual = (await sut.GetAndRemoveExpiredSessions(2)).ToList();
- actual.Should().HaveCount(1);
- actual.Should().Contain(x => x.Key == expiredSession0.Key);
+ actual.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -766,16 +820,20 @@ public async Task FilterSessions_WithQuery_WhenNullQuery_ShouldUseDefaultValues(
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
- await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- ]);
+ List sessionEntities = [
+ new() { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new() { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new() { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new() { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new() { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new() { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new() { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
+ ];
+
+ await context.ServerSideSessions.AddRangeAsync(sessionEntities, TestContext.Current.CancellationToken);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions(sessionEntities);
var actual = await sut.FilterSessions(null, TestContext.Current.CancellationToken);
@@ -789,14 +847,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeFalse();
- actual.Results.Should().HaveCount(7);
- actual.Results.Should().Contain(x => x.Key == "key-0");
- actual.Results.Should().Contain(x => x.Key == "key-1");
- actual.Results.Should().Contain(x => x.Key == "key-2");
- actual.Results.Should().Contain(x => x.Key == "key-3");
- actual.Results.Should().Contain(x => x.Key == "key-4");
- actual.Results.Should().Contain(x => x.Key == "key-5");
- actual.Results.Should().Contain(x => x.Key == "key-6");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -804,17 +855,22 @@ public async Task FilterSessions_WithQuery_WhenNoTokenInQuery_ShouldGetFirstPage
{
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" };
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" }
]);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
var actual = await sut.FilterSessions(new SessionQuery
{
@@ -832,9 +888,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-0");
- actual.Results.Should().Contain(x => x.Key == "key-1");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -843,17 +897,21 @@ public async Task FilterSessions_WithQuery_WhenTokenInQueryAndGetPreviousFalse_S
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ foundSessionOne,
]);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne]);
+
var sessions = context.ServerSideSessions
.OrderBy(x => x.Id).Skip(4).Take(2).ToList();
var testToken = $"{sessions.First().Id},{sessions.Last().Id}";
@@ -875,8 +933,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeTrue();
actual.HasNextResults.Should().BeFalse();
- actual.Results.Should().HaveCount(1);
- actual.Results.Should().Contain(x => x.Key == "key-6");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -885,17 +942,22 @@ public async Task FilterSessions_WithQuery_WhenTokenInQueryAndGetPreviousTrue_Sh
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ foundSessionOne,
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
var sessions = context.ServerSideSessions
.OrderBy(x => x.Id).Skip(4).Take(2).ToList();
// Ids 5,6
@@ -914,9 +976,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be("3,4");
actual.HasPrevResults.Should().BeTrue();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-2");
- actual.Results.Should().Contain(x => x.Key == "key-3");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -926,13 +986,13 @@ public async Task FilterSessions_WhenOnFinalPage_GetNextPageReturnsEmptyQueryRes
IdentityServerServerSideSessionStore sut = CreateSut(context);
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
@@ -958,13 +1018,13 @@ public async Task FilterSessions_WhenOnFirstPage_GetNextPreviousPageReturnsEmpty
IdentityServerServerSideSessionStore sut = CreateSut(context);
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
@@ -989,20 +1049,25 @@ public async Task FilterSessions_WhenUnderlyingDataChangedAndResultTokenSpansPag
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ foundSessionTwo,
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
var sessions = context.ServerSideSessions
.OrderBy(x => x.Id).Skip(3).Take(2).ToList();
// 4,5
@@ -1021,9 +1086,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be($"5,6");
actual.HasPrevResults.Should().BeTrue();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-4");
- actual.Results.Should().Contain(x => x.Key == "key-5");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1032,20 +1095,25 @@ public async Task FilterSessions_WhenUnderlyingDataChangedAndResultTokenSpansPag
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ foundSessionTwo,
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
+
var sessions = context.ServerSideSessions
.OrderBy(x => x.Id).Skip(3).Take(2).ToList();
// 4,5
@@ -1064,9 +1132,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be($"3,4");
actual.HasPrevResults.Should().BeTrue();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-2");
- actual.Results.Should().Contain(x => x.Key == "key-3");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1075,20 +1141,24 @@ public async Task FilterSessions_WhenMovingToFinalPageAndResultsAreLessThanPageS
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ foundSessionOne,
]);
await context.SaveChangesAsync();
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne]);
+
var sessions = context.ServerSideSessions
.OrderBy(x => x.Id).Skip(4).Take(2).ToList();
// 5,6
@@ -1107,8 +1177,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be($"7,7");
actual.HasPrevResults.Should().BeTrue();
actual.HasNextResults.Should().BeFalse();
- actual.Results.Should().HaveCount(1);
- actual.Results.Should().Contain(x => x.Key == "key-6");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1117,16 +1186,21 @@ public async Task FilterSessions_WithQuery_WhenSessionIdProvided_ShouldGetFilter
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
var actual = await sut.FilterSessions(new SessionQuery
{
@@ -1147,9 +1221,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeFalse();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-0");
- actual.Results.Should().Contain(x => x.Key == "key-4");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1158,16 +1230,21 @@ public async Task FilterSessions_WithQuery_WhenSubjectIdProvided_ShouldGetFilter
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" },
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" },
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
var actual = await sut.FilterSessions(new SessionQuery
{
@@ -1188,9 +1265,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-0");
- actual.Results.Should().Contain(x => x.Key == "key-2");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1199,16 +1274,21 @@ public async Task FilterSessions_WithQuery_WhenDisplayNameProvided_ShouldGetFilt
await using var context = await CreateCleanContext(options);
IdentityServerServerSideSessionStore sut = CreateSut(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-1", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-3", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
var actual = await sut.FilterSessions(new SessionQuery
{
@@ -1229,9 +1309,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.ResultsToken.Should().Be(expectedToken);
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeTrue();
- actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-1");
- actual.Results.Should().Contain(x => x.Key == "key-3");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
}
[Theory, MemberData(nameof(TestDatabaseProviders))]
@@ -1240,16 +1318,21 @@ public async Task FilterSessions_WithExtendedStore_ShouldGetFilteredResultContai
await using var context = await CreateCleanContext(options);
ExtendedIdentityServerServerSideSessionStore sut = CreateSutExtended(context);
+ Entities.ServerSideSession foundSessionOne = new () { Key = "key-1", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-1\"}" };
+ Entities.ServerSideSession foundSessionTwo = new () { Key = "key-3", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-3", Data = "{\"payload\":\"fake-payload-key-3\"}" };
+
await context.ServerSideSessions.AddRangeAsync([
- new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-1", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-3", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-3", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"delete\":true}" },
- new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"delete\":true}" },
+ new Entities.ServerSideSession { Key = "key-0", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-0\"}" },
+ foundSessionOne,
+ new Entities.ServerSideSession { Key = "key-2", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-2\"}" },
+ foundSessionTwo,
+ new Entities.ServerSideSession { Key = "key-4", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-0", Data = "{\"payload\":\"fake-payload-key-4\"}" },
+ new Entities.ServerSideSession { Key = "key-5", Scheme = "cookie", DisplayName = "Robert", SubjectId = "bob", SessionId = "session-2", Data = "{\"payload\":\"fake-payload-key-5\"}" },
+ new Entities.ServerSideSession { Key = "key-6", Scheme = "cookie", DisplayName = "Laura", SubjectId = "alice", SessionId = "session-1", Data = "{\"payload\":\"fake-payload-key-6\"}" },
]);
await context.SaveChangesAsync();
+
+ List expectedExpiredSessions = SetupExpectedSessions([foundSessionOne, foundSessionTwo]);
var actual = await sut.FilterSessions(new SessionQuery
{
@@ -1271,8 +1354,7 @@ await context.ServerSideSessions.AddRangeAsync([
actual.HasPrevResults.Should().BeFalse();
actual.HasNextResults.Should().BeTrue();
actual.Results.Should().HaveCount(2);
- actual.Results.Should().Contain(x => x.Key == "key-1");
- actual.Results.Should().Contain(x => x.Key == "key-3");
+ actual.Results.Should().BeEquivalentTo(expectedExpiredSessions);
foreach (var session in actual.Results)
{
@@ -1336,27 +1418,37 @@ private async Task CreateCleanContext(DbContextOptions<
return context;
}
- private static ServerSideSession BuildSessionModel(string key, string subjectId, string sessionId, string displayName)
+ private static ServerSideSession BuildSessionModel(string key, string subjectId, string sessionId,
+ string displayName, string? scheme = null, DateTime? created = null, DateTime? renewed = null, DateTime? expires = null,
+ string? data = null)
{
+ scheme ??= "cookie";
+ created ??= FakeNow.AddMinutes(-10);
+ renewed ??= FakeNow.AddMinutes(-5);
+ // expires ??= FakeNow.AddHours(1);
+
return new ServerSideSession
{
Key = key,
- Scheme = "cookie",
+ Scheme = scheme,
SubjectId = subjectId,
SessionId = sessionId,
DisplayName = displayName,
- Created = FakeNow.AddMinutes(-10),
- Renewed = FakeNow.AddMinutes(-5),
- Expires = FakeNow.AddHours(1),
- Data = "{\"payload\":\"value\"}"
+ Created = created.Value,
+ Renewed = renewed.Value,
+ Expires = expires,
+ Data = data!,
+ AuthenticationTicket = AuthenticationTicketGenerator.GenerateAuthenticationTicket(scheme, subjectId, sessionId, displayName, renewed, expires)
};
}
private static Entities.ServerSideSession FakeSessionSession(string subject, string sessionId, bool expired = false)
{
+ string key = Guid.NewGuid().ToString();
+
Entities.ServerSideSession session = new Entities.ServerSideSession
{
- Key = Guid.NewGuid().ToString(),
+ Key = key,
Scheme = Guid.NewGuid().ToString(),
SubjectId = subject,
SessionId = sessionId,
@@ -1364,7 +1456,7 @@ private static Entities.ServerSideSession FakeSessionSession(string subject, str
Created = FakeNow.AddDays(-3),
Renewed = FakeNow.AddDays(-3),
Expires = FakeNow.AddDays(2),
- Data = "{!}"
+ Data = $"{{\"payload\":\"fake-payload-{key}\"}}"
};
if (expired)
diff --git a/src/EntityFramework.Storage/test/UnitTests/Mappers/IdentityServerServerSideSessionsExtensionsTests.cs b/src/EntityFramework.Storage/test/UnitTests/Mappers/IdentityServerServerSideSessionsExtensionsTests.cs
index 35ba381e6..df74e91e1 100644
--- a/src/EntityFramework.Storage/test/UnitTests/Mappers/IdentityServerServerSideSessionsExtensionsTests.cs
+++ b/src/EntityFramework.Storage/test/UnitTests/Mappers/IdentityServerServerSideSessionsExtensionsTests.cs
@@ -3,14 +3,20 @@
using System;
using AwesomeAssertions;
+using Microsoft.AspNetCore.Authentication;
+using Moq;
using Open.IdentityServer.EntityFramework.Entities;
using Open.IdentityServer.EntityFramework.Mappers;
+using Open.IdentityServer.Stores.Serialization;
+using Open.IdentityServer.Test.Utilities;
using Xunit;
namespace Open.IdentityServer.EntityFramework.UnitTests.Mappers;
public class IdentityServerServerSideSessionsExtensionsTests
{
+ private readonly IAuthenticationTicketSerializer authTicketSerializer = Mock.Of();
+
[Fact]
public void EntityIdentityServerServerSideSessions_ToModel_ProducesModelWithCorrectFields()
{
@@ -25,12 +31,17 @@ public void EntityIdentityServerServerSideSessions_ToModel_ProducesModelWithCorr
Created = new DateTime(2020, 01, 01, 12, 20, 0, DateTimeKind.Utc),
Renewed = new DateTime(2020, 02, 01, 12, 20, 0, DateTimeKind.Utc),
Expires = new DateTime(2020, 03, 01, 12, 20, 0, DateTimeKind.Utc),
- Data = "FAKEPROTECTEDDATA"
+ Data = "{\"version\":1,\"payload\":\"fake-payload-FakeScheme\"}",
};
+ AuthenticationTicket authTicket = AuthenticationTicketGenerator.GenerateAuthenticationTicket(entity.Scheme, entity.SubjectId, entity.SessionId, entity.DisplayName, entity.Renewed, entity.Expires);
- Models.ServerSideSession actual = entity.ToModel();
+ Mock.Get(authTicketSerializer)
+ .Setup(x => x.Deserialize(entity.Data))
+ .Returns(authTicket);
+
+ Models.ServerSideSession actual = entity.ToModel(authTicketSerializer);
- entity.Should().BeEquivalentTo(actual);
+ actual.Should().BeEquivalentTo(entity, cnf => cnf.Excluding(x => x.Id));
}
[Fact]
@@ -46,11 +57,20 @@ public void ModelIdentityServerServerSideSessions_ToEntity_ProducesEntityWithCor
Created = new DateTime(2020, 01, 01, 12, 20, 0, DateTimeKind.Utc),
Renewed = new DateTime(2020, 02, 01, 12, 20, 0, DateTimeKind.Utc),
Expires = new DateTime(2020, 03, 01, 12, 20, 0, DateTimeKind.Utc),
- Data = "FAKEPROTECTEDDATA"
};
+ AuthenticationTicket authTicket = AuthenticationTicketGenerator.GenerateAuthenticationTicket(model.Scheme, model.SubjectId, model.SessionId, model.DisplayName, model.Renewed, model.Expires);
+ model.AuthenticationTicket = authTicket;
+
+ const string fakePayload = "{\"version\":1,\"payload\":\"fake-payload-FakeScheme\"}";
+ Mock.Get(authTicketSerializer)
+ .Setup(x => x.Serialize(model.AuthenticationTicket))
+ .Returns(fakePayload);
- ServerSideSession actual = model.ToEntity();
+ ServerSideSession actual = model.ToEntity(authTicketSerializer);
- model.Should().BeEquivalentTo(actual, cnf => cnf.Excluding(x => x.Id));
+ actual.Should().BeEquivalentTo(model, cnf => cnf
+ .Excluding(x => x.AuthenticationTicket)
+ .Excluding(x => x.Data));
+ actual.Data.Should().BeEquivalentTo(fakePayload);
}
}
\ No newline at end of file
diff --git a/src/EntityFramework.Storage/test/UnitTests/Open.IdentityServer.EntityFramework.UnitTests.csproj b/src/EntityFramework.Storage/test/UnitTests/Open.IdentityServer.EntityFramework.UnitTests.csproj
index 8d15a86af..7338e0e14 100644
--- a/src/EntityFramework.Storage/test/UnitTests/Open.IdentityServer.EntityFramework.UnitTests.csproj
+++ b/src/EntityFramework.Storage/test/UnitTests/Open.IdentityServer.EntityFramework.UnitTests.csproj
@@ -10,11 +10,13 @@
+
+
diff --git a/src/Open.IdentityServer.Test.Utilities/AuthenticationTicketGenerator.cs b/src/Open.IdentityServer.Test.Utilities/AuthenticationTicketGenerator.cs
new file mode 100644
index 000000000..9667fe0f1
--- /dev/null
+++ b/src/Open.IdentityServer.Test.Utilities/AuthenticationTicketGenerator.cs
@@ -0,0 +1,122 @@
+using System.Buffers.Text;
+using System.Security.Claims;
+using System.Text;
+using System.Text.Json;
+using Microsoft.AspNetCore.Authentication;
+
+// using Microsoft.AspNetCore.Authentication;
+
+namespace Open.IdentityServer.Test.Utilities;
+
+public static class TestsClaimTypeConstants
+{
+ public const string Subject = "sub";
+ public const string Name = "name";
+ public const string IdentityProvider = "idp";
+ public const string AuthenticationTime = "auth_time";
+ public const string AuthenticationMethod = "amr";
+ public const string Role = "role";
+ public const string Issuer = "iss";
+ public const string SessionId = "session_id";
+ public const string ClientListKey = "client_list";
+}
+
+public static class AuthenticationTicketGenerator
+{
+ public static ClaimsPrincipal CreatePrincipal(
+ string subjectId,
+ string? displayName = null,
+ string? identityProvider = null,
+ DateTime? authenticationTime = null,
+ string[]? authenticationMethods = null,
+ Claim[]? additionalClaims = null)
+ {
+ if (string.IsNullOrWhiteSpace(subjectId)) throw new ArgumentException("SubjectId is mandatory", nameof(subjectId));
+ var claims = new List { new Claim(TestsClaimTypeConstants.Subject, subjectId) };
+
+ if (!string.IsNullOrWhiteSpace(displayName))
+ {
+ claims.Add(new Claim(TestsClaimTypeConstants.Name, displayName));
+ }
+
+ if (!string.IsNullOrWhiteSpace(identityProvider))
+ {
+ claims.Add(new Claim(TestsClaimTypeConstants.IdentityProvider, identityProvider));
+ }
+
+ if (authenticationTime.HasValue)
+ {
+ claims.Add(new Claim(TestsClaimTypeConstants.AuthenticationTime, new DateTimeOffset(authenticationTime.Value).ToUnixTimeSeconds().ToString()));
+ }
+
+ if (authenticationMethods != null && authenticationMethods.Length != 0)
+ {
+ foreach (var amr in authenticationMethods)
+ {
+ claims.Add(new Claim(TestsClaimTypeConstants.AuthenticationMethod, amr));
+ }
+ }
+
+ if (additionalClaims != null)
+ {
+ claims.AddRange(additionalClaims);
+ }
+
+ var id = new ClaimsIdentity(claims, "Open.IdentityServer", TestsClaimTypeConstants.Name, TestsClaimTypeConstants.Role);
+ return new ClaimsPrincipal(id);
+ }
+
+ public static AuthenticationTicket GenerateAuthenticationTicket(
+ string authScheme,
+ string? subjectId,
+ string? sessionId,
+ string? displayName = null,
+ DateTimeOffset? issuedUtc = null,
+ DateTimeOffset? expiresUtc = null,
+ string? issuer = null,
+ string[]? clientIds = null)
+ {
+ ClaimsPrincipal principle = CreatePrincipal(subjectId ?? string.Empty, displayName: displayName);
+ AuthenticationProperties properties = new();
+
+ properties.Items[TestsClaimTypeConstants.SessionId] = sessionId;
+ properties.IssuedUtc = issuedUtc;
+ properties.ExpiresUtc = expiresUtc;
+
+ if (clientIds != null && clientIds.Any())
+ {
+ properties.Items[TestsClaimTypeConstants.ClientListKey] = GeneratePropertyList(clientIds);
+ }
+
+ if (issuer != null)
+ {
+ properties.Items[TestsClaimTypeConstants.Issuer] = issuer;
+ }
+
+ return new AuthenticationTicket(principle, properties, authScheme);
+ }
+
+ private static string GeneratePropertyList(IEnumerable list)
+ {
+ if (list != null && list.Any())
+ {
+ var value = JsonSerializer.Serialize(list);
+ var bytes = Encoding.UTF8.GetBytes(value);
+ value = Encode(bytes);
+ return value;
+ }
+
+ return null;
+ }
+
+ private static string Encode(byte[] arg)
+ {
+ var s = Convert.ToBase64String(arg); // Standard base64 encoder
+
+ s = s.Split('=')[0]; // Remove any trailing '='s
+ s = s.Replace('+', '-'); // 62nd char of encoding
+ s = s.Replace('/', '_'); // 63rd char of encoding
+
+ return s;
+ }
+}
\ No newline at end of file
diff --git a/src/Open.IdentityServer.Test.Utilities/Open.IdentityServer.Test.Utilities.csproj b/src/Open.IdentityServer.Test.Utilities/Open.IdentityServer.Test.Utilities.csproj
index d4095961e..6212256a8 100644
--- a/src/Open.IdentityServer.Test.Utilities/Open.IdentityServer.Test.Utilities.csproj
+++ b/src/Open.IdentityServer.Test.Utilities/Open.IdentityServer.Test.Utilities.csproj
@@ -7,8 +7,9 @@
-
-
+
+
+
diff --git a/src/Open.IdentityServer/src/Configuration/DependencyInjection/BuilderExtensions/Additional.cs b/src/Open.IdentityServer/src/Configuration/DependencyInjection/BuilderExtensions/Additional.cs
index 6b4e0e41f..dd6c7c1f5 100644
--- a/src/Open.IdentityServer/src/Configuration/DependencyInjection/BuilderExtensions/Additional.cs
+++ b/src/Open.IdentityServer/src/Configuration/DependencyInjection/BuilderExtensions/Additional.cs
@@ -16,8 +16,10 @@
using Open.IdentityServer.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Open.IdentityServer.DataProtection;
using Open.IdentityServer.Models;
using Open.IdentityServer.Services.Default;
+using Open.IdentityServer.Stores.Serialization;
namespace Microsoft.Extensions.DependencyInjection;
@@ -474,6 +476,7 @@ public static IIdentityServerBuilder AddUserSession(this IIdentityServerBuild
public static IIdentityServerBuilder AddServerSideSessions(this IIdentityServerBuilder builder)
{
builder.Services.AddSingleton, PostConfigureSessionStoreCookieAuthOptions>();
+ builder.Services.AddSingleton();
builder.Services.TryAddTransient();
// Token Validators
diff --git a/src/Open.IdentityServer/src/DataProtection/AuthenticationTicketSerializer.cs b/src/Open.IdentityServer/src/DataProtection/AuthenticationTicketSerializer.cs
new file mode 100644
index 000000000..ae71b71db
--- /dev/null
+++ b/src/Open.IdentityServer/src/DataProtection/AuthenticationTicketSerializer.cs
@@ -0,0 +1,69 @@
+#nullable enable
+
+using System.Text.Json;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.Extensions.Logging;
+using Open.IdentityServer.Extensions;
+using Open.IdentityServer.Stores.Serialization;
+
+namespace Open.IdentityServer.DataProtection;
+
+///
+/// Serializer class for , data is serialized/deserialized and protected/unprotected using data protection
+///
+public class AuthenticationTicketSerializer(
+ IDataProtectionProvider dataProtectionProvider,
+ ILogger logger): IAuthenticationTicketSerializer
+{
+ private readonly IDataProtector dataProtector =
+ dataProtectionProvider.CreateProtector(DataProtectionConstants.ServerSideTicketStorePurpose);
+
+ ///
+ /// to be used for storing server side sessions
+ ///
+ public static readonly JsonSerializerOptions JsonSettings = new()
+ {
+ IncludeFields = true,
+ };
+
+ ///
+ public string Serialize(AuthenticationTicket ticket)
+ {
+ string serializedTicket = JsonSerializer.Serialize(ticket.ToSerializableObj());
+
+ return JsonSerializer.Serialize(new DataProtectedSessionData
+ {
+ Payload = dataProtector.Protect(serializedTicket),
+ }, JsonSettings);
+ }
+
+ ///
+ public AuthenticationTicket? Deserialize(string data)
+ {
+ DataProtectedSessionData? dataProtectedSessionData;
+
+ try
+ {
+ dataProtectedSessionData = JsonSerializer.Deserialize(data, JsonSettings);
+ }
+ catch (JsonException exception)
+ {
+ logger.LogError(exception, "failed deserialising auth ticket data");
+ return null;
+ }
+
+ if (dataProtectedSessionData is not { Version: 1 })
+ {
+ logger.LogError("failed deserialising auth ticket data, incorrect version '{VersionOrNull}'", dataProtectedSessionData?.Version);
+ return null;
+ }
+
+ string unprotectedData = dataProtector.Unprotect(dataProtectedSessionData.Payload);
+
+ SerializedAuthenticationTicket? serializedAuthTicket =
+ JsonSerializer.Deserialize(unprotectedData);
+
+ return serializedAuthTicket?.ToAuthTicket();
+ }
+}
\ No newline at end of file
diff --git a/src/Open.IdentityServer/src/Extensions/AuthenticationTicketSerialiser.cs b/src/Open.IdentityServer/src/Extensions/AuthenticationTicketSerialiser.cs
index ed175cf10..45b1f8d6d 100644
--- a/src/Open.IdentityServer/src/Extensions/AuthenticationTicketSerialiser.cs
+++ b/src/Open.IdentityServer/src/Extensions/AuthenticationTicketSerialiser.cs
@@ -26,12 +26,19 @@ public SerializedAuthenticationTicket ToSerializableObj()
extension(SerializedAuthenticationTicket serializationAuthTicket)
{
- public AuthenticationTicket ToAuthTicket(ServerSideSession? session)
+ public AuthenticationTicket ToAuthTicket()
{
var authTicket = new AuthenticationTicket(
serializationAuthTicket.User.ToClaimsPrincipal(),
new AuthenticationProperties(serializationAuthTicket.Items),
serializationAuthTicket.Scheme);
+
+ return authTicket;
+ }
+
+ public AuthenticationTicket ToAuthTicket(ServerSideSession session)
+ {
+ var authTicket = serializationAuthTicket.ToAuthTicket();
if (session != null)
{
diff --git a/src/Open.IdentityServer/src/Extensions/HttpContextExtensions.cs b/src/Open.IdentityServer/src/Extensions/HttpContextExtensions.cs
index 8315bb3ce..22a8a6334 100644
--- a/src/Open.IdentityServer/src/Extensions/HttpContextExtensions.cs
+++ b/src/Open.IdentityServer/src/Extensions/HttpContextExtensions.cs
@@ -99,12 +99,11 @@ internal static void SetSignOutCalled(this HttpContext context)
internal static void SetSessionExpired(
this HttpContext context,
- ServerSideSession session,
- AuthenticationTicket ticket)
+ ServerSideSession session)
{
if (context == null) throw new ArgumentNullException(nameof(context));
context.Items[Constants.EnvironmentKeys.ExpiredSession] = session;
- context.Items[Constants.EnvironmentKeys.ExpiredTicket] = ticket;
+ context.Items[Constants.EnvironmentKeys.ExpiredTicket] = session.AuthenticationTicket;
}
internal static (ServerSideSession Session, AuthenticationTicket Ticket) GetSessionExpired(this HttpContext context)
diff --git a/src/Open.IdentityServer/src/Models/AuthenticationTicketFilterResult.cs b/src/Open.IdentityServer/src/Models/AuthenticationTicketFilterResult.cs
index fcad63492..02b6b8bf4 100644
--- a/src/Open.IdentityServer/src/Models/AuthenticationTicketFilterResult.cs
+++ b/src/Open.IdentityServer/src/Models/AuthenticationTicketFilterResult.cs
@@ -19,9 +19,9 @@ public class AuthenticationTicketFilterResult
/// Session model returned from filtering
///
public ServerSideSession Session { get; set; } = null!;
-
+
///
/// AuthenticationTicket deserialized from the data property on the session entity
///
- public AuthenticationTicket? AuthTicket { get; set; }
+ public AuthenticationTicket? AuthTicket => Session.AuthenticationTicket;
}
\ No newline at end of file
diff --git a/src/Open.IdentityServer/src/Services/Default/DefaultSessionManagementService.cs b/src/Open.IdentityServer/src/Services/Default/DefaultSessionManagementService.cs
index c47c2f1b4..e1cb4a56f 100644
--- a/src/Open.IdentityServer/src/Services/Default/DefaultSessionManagementService.cs
+++ b/src/Open.IdentityServer/src/Services/Default/DefaultSessionManagementService.cs
@@ -49,7 +49,7 @@ public async Task RemoveSessionsAsync(RemoveSessionsContext context, Cancellatio
var sessions = await serverSessionTicketStore.FilterServerAuthenticationTickets(context.SubjectId, context.SessionId);
foreach (var session in sessions)
{
- List? sessionClientList = session.AuthTicket?.Properties.GetClientList().ToList();
+ List? sessionClientList = session.Session.AuthenticationTicket?.Properties.GetClientList().ToList();
string[] clientIds = [];
if (!sessionClientList.IsNullOrEmpty() && !context.ClientIds.IsNullOrEmpty())
diff --git a/src/Open.IdentityServer/src/Services/Default/DefaultUserSessionEventsService.cs b/src/Open.IdentityServer/src/Services/Default/DefaultUserSessionEventsService.cs
index d5fe669e5..a7a5bd2bb 100644
--- a/src/Open.IdentityServer/src/Services/Default/DefaultUserSessionEventsService.cs
+++ b/src/Open.IdentityServer/src/Services/Default/DefaultUserSessionEventsService.cs
@@ -122,14 +122,14 @@ public async Task ValidateSession(ValidateUserSessionEventContext sessionE
TimeSpan? diff = session.Session.Expires - session.Session.Renewed;
session.Session.Renewed = timeProvider.GetUtcNow().UtcDateTime;
session.Session.Expires = session.Session.Renewed + diff;
+ session.Session.AuthenticationTicket?.Properties.IssuedUtc = session.Session.Renewed;
+ session.Session.AuthenticationTicket?.Properties.ExpiresUtc = session.Session.Expires;
if (idsOptions.Authentication.CookieSlidingExpiration &&
- session.AuthTicket?.Properties is { IsPersistent: true, AllowRefresh: true or null })
+ session.Session.AuthenticationTicket?.Properties is { IsPersistent: true, AllowRefresh: true or null })
{
- session.AuthTicket.Properties.IssuedUtc = session.Session.Renewed;
- session.AuthTicket.Properties.ExpiresUtc = session.Session.Expires;
- session.AuthTicket.Properties.SetString(IdentityServerConstants.ForceCookieRefresh, string.Empty);
- await serverSessionTicketStore.RenewAsync(session.Session.Key, session.AuthTicket);
+ session.Session.AuthenticationTicket.Properties.SetString(IdentityServerConstants.ForceCookieRefresh, string.Empty);
+ await serverSessionTicketStore.RenewAsync(session.Session.Key, session.Session.AuthenticationTicket);
}
else
{
diff --git a/src/Open.IdentityServer/src/Services/Default/SessionCleanupService.cs b/src/Open.IdentityServer/src/Services/Default/SessionCleanupService.cs
index ad655cbaa..f3925e0d6 100644
--- a/src/Open.IdentityServer/src/Services/Default/SessionCleanupService.cs
+++ b/src/Open.IdentityServer/src/Services/Default/SessionCleanupService.cs
@@ -70,7 +70,7 @@ await userSessionEventsService.HandleUserSessionExpiry(new EndUserSessionEventCo
{
SubjectId = expiredSession.Session.SubjectId,
SessionId = expiredSession.Session.SessionId,
- ClientIds = expiredSession.AuthTicket?.Properties.GetClientList().ToArray() ?? [],
+ ClientIds = expiredSession.Session.AuthenticationTicket?.Properties.GetClientList().ToArray() ?? [],
});
}
} while (found >= options.ServerSideSessions.RemoveExpiredSessionsBatchSize);
diff --git a/src/Open.IdentityServer/src/Stores/Default/ServerSessionTicketStore.cs b/src/Open.IdentityServer/src/Stores/Default/ServerSessionTicketStore.cs
index 560dc810e..86f52f3ae 100644
--- a/src/Open.IdentityServer/src/Stores/Default/ServerSessionTicketStore.cs
+++ b/src/Open.IdentityServer/src/Stores/Default/ServerSessionTicketStore.cs
@@ -7,21 +7,17 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
-using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
-using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Open.IdentityServer.Configuration;
-using Open.IdentityServer.DataProtection;
using Open.IdentityServer.Extensions;
using Open.IdentityServer.Models;
using Open.IdentityServer.Services;
using Open.IdentityServer.Stores.Default;
-using Open.IdentityServer.Stores.Serialization;
namespace Open.IdentityServer.Stores;
@@ -30,7 +26,6 @@ namespace Open.IdentityServer.Stores;
/// implementation in Open.IdentityServer
///
///
-/// data protection provider
/// persisted grant store
/// handle generation service
/// time provider
@@ -40,7 +35,6 @@ namespace Open.IdentityServer.Stores;
/// the logger
public class ServerSessionTicketStore(
IIdentityServerServerSideSessionStore serverServerSideSessionStore,
- IDataProtectionProvider dataProtectionProvider,
IPersistedGrantStore persistedGrantStore,
IHandleGenerationService handleGenerationService,
TimeProvider timeProvider,
@@ -49,17 +43,6 @@ public class ServerSessionTicketStore(
ITelemetryService telemetry,
ILogger logger): IServerSessionTicketStore
{
- private readonly IDataProtector dataProtector =
- dataProtectionProvider.CreateProtector(DataProtectionConstants.ServerSideTicketStorePurpose);
-
- ///
- /// to be used for storing server side sessions
- ///
- public static readonly JsonSerializerOptions JsonSettings = new()
- {
- IncludeFields = true,
- };
-
///
public async Task StoreAsync(AuthenticationTicket ticket)
{
@@ -115,7 +98,7 @@ await persistedGrantStore.RemoveAllAsync(new PersistedGrantFilter
existingSession.DisplayName = ticket.Principal.FindFirstValue(JwtClaimTypes.Name);
existingSession.Renewed = ticket.Properties.IssuedUtc?.UtcDateTime ?? timeProvider.GetUtcNow().UtcDateTime;
existingSession.Expires = ticket.Properties.ExpiresUtc?.UtcDateTime;
- existingSession.Data = ToProtectedDataString(ticket);
+ existingSession.AuthenticationTicket = ticket;
await serverServerSideSessionStore.UpdateSession(existingSession);
}
@@ -138,17 +121,16 @@ await persistedGrantStore.RemoveAllAsync(new PersistedGrantFilter
return null;
}
- var authTicket = DeserializeAuthTicket(existingSession);
- if(authTicket == null)
+ if(existingSession.AuthenticationTicket == null)
{
logger.FailedToRetrieveTicketFromStore(key);
}
else
{
- logger.TicketFoundInStore(key, authTicket.Properties.ExpiresUtc);
+ logger.TicketFoundInStore(key, existingSession.AuthenticationTicket.Properties.ExpiresUtc);
}
- return authTicket;
+ return existingSession.AuthenticationTicket;
}
///
@@ -165,7 +147,7 @@ public async Task RemoveAsync(string key)
var session = await serverServerSideSessionStore.GetSession(key);
if(session != null)
{
- httpContextAccessor.HttpContext.SetSessionExpired(session, DeserializeAuthTicket(session));
+ httpContextAccessor.HttpContext.SetSessionExpired(session);
}
await serverServerSideSessionStore.DeleteSession(key);
@@ -176,13 +158,8 @@ public async Task> FilterServerAut
{
using ITrace? trace = telemetry.Trace(TelemetryConstants.TraceCategories.Stores, this);
- IEnumerable sessions = await serverServerSideSessionStore.FilterSessions(subjectId, sessionId);
-
- return sessions.Select(x => new AuthenticationTicketFilterResult
- {
- Session = x,
- AuthTicket = DeserializeAuthTicket(x),
- }).Where(x => x.AuthTicket != null);
+ return (await serverServerSideSessionStore.FilterSessions(subjectId, sessionId))
+ .Select(x => new AuthenticationTicketFilterResult { Session = x });
}
///
@@ -190,13 +167,8 @@ public async Task> FilterServerAut
{
using ITrace? trace = telemetry.Trace(TelemetryConstants.TraceCategories.Stores, this);
- QueryResult sessions = await serverServerSideSessionStore.FilterSessions(query, ct);
-
- return sessions.MapTo(x => new AuthenticationTicketFilterResult
- {
- Session = x,
- AuthTicket = DeserializeAuthTicket(x),
- });
+ return (await serverServerSideSessionStore.FilterSessions(query, ct))
+ .MapTo(x => new AuthenticationTicketFilterResult { Session = x });
}
///
@@ -204,13 +176,8 @@ public async Task> GetAndRemoveExp
{
using ITrace? trace = telemetry.Trace(TelemetryConstants.TraceCategories.Stores, this);
- var sessionRemoved = await serverServerSideSessionStore.GetAndRemoveExpiredSessions(batchSize);
-
- return sessionRemoved.Select(x => new AuthenticationTicketFilterResult
- {
- Session = x,
- AuthTicket = DeserializeAuthTicket(x),
- });
+ return (await serverServerSideSessionStore.GetAndRemoveExpiredSessions(batchSize))
+ .Select(x => new AuthenticationTicketFilterResult { Session = x });
}
private async Task StoreNewSession(string key, AuthenticationTicket ticket)
@@ -238,49 +205,27 @@ private async Task StoreNewSession(string key, Authentication
Created = ticket.Properties.IssuedUtc?.UtcDateTime ?? timeProvider.GetUtcNow().UtcDateTime,
Renewed = ticket.Properties.IssuedUtc?.UtcDateTime ?? timeProvider.GetUtcNow().UtcDateTime,
Expires = ticket.Properties.ExpiresUtc?.UtcDateTime,
- Data = ToProtectedDataString(ticket),
+ AuthenticationTicket = ticket,
};
await serverServerSideSessionStore.CreateSession(serverSideSession);
return serverSideSession;
}
-
- private string ToProtectedDataString(AuthenticationTicket ticket)
- {
- string serializedTicket = JsonSerializer.Serialize(ticket.ToSerializableObj());
-
- return JsonSerializer.Serialize(new DataProtectedSessionData
- {
- Payload = dataProtector.Protect(serializedTicket),
- }, JsonSettings);
- }
- private AuthenticationTicket? DeserializeAuthTicket(ServerSideSession existingSession)
- {
- DataProtectedSessionData? dataProtectedSessionData;
-
- try
- {
- dataProtectedSessionData = JsonSerializer.Deserialize(existingSession.Data, JsonSettings);
- }
- catch (JsonException exception)
- {
- logger.LogError(exception, "failed deserialising auth ticket data '{SessionKey}'", existingSession.Key);
- return null;
- }
-
- if (dataProtectedSessionData is not { Version: 1 })
- {
- logger.LogError("failed retrieving '{SessionKey}', deserialisation failed, incorrect version '{VersionOrNull}'", existingSession.Key, dataProtectedSessionData?.Version);
- return null;
- }
-
- string unprotectedData = dataProtector.Unprotect(dataProtectedSessionData.Payload);
-
- SerializedAuthenticationTicket? serializedAuthTicket =
- JsonSerializer.Deserialize(unprotectedData);
-
- return serializedAuthTicket?.ToAuthTicket(existingSession);
- }
+ // private AuthenticationTicket? DeserializeAuthTicket(ServerSideSession existingSession)
+ // {
+ // AuthenticationTicket? authenticationTicket = authenticationTicketSerializer.Deserialize(existingSession.Data);
+ //
+ // if (authenticationTicket != null)
+ // {
+ // authenticationTicket.Properties.IssuedUtc = new DateTimeOffset(existingSession.Renewed, TimeSpan.Zero);
+ // if (existingSession.Expires.HasValue)
+ // {
+ // authenticationTicket.Properties.ExpiresUtc = new DateTimeOffset(existingSession.Expires.Value, TimeSpan.Zero);
+ // }
+ // }
+ //
+ // return authenticationTicket;
+ // }
}
\ No newline at end of file
diff --git a/src/Open.IdentityServer/src/Stores/IServerSessionTicketStore.cs b/src/Open.IdentityServer/src/Stores/IServerSessionTicketStore.cs
index ff9562820..410b98b75 100644
--- a/src/Open.IdentityServer/src/Stores/IServerSessionTicketStore.cs
+++ b/src/Open.IdentityServer/src/Stores/IServerSessionTicketStore.cs
@@ -6,7 +6,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Open.IdentityServer.Models;
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Configuration/DependencyInjection/BuilderExtensions/AdditionalTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Configuration/DependencyInjection/BuilderExtensions/AdditionalTests.cs
index d51579fd4..0f3a4164a 100644
--- a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Configuration/DependencyInjection/BuilderExtensions/AdditionalTests.cs
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Configuration/DependencyInjection/BuilderExtensions/AdditionalTests.cs
@@ -11,10 +11,11 @@
using Microsoft.Extensions.Options;
using Open.IdentityServer.Configuration;
using Open.IdentityServer.Configuration.DependencyInjection;
+using Open.IdentityServer.DataProtection;
using Open.IdentityServer.Models;
using Open.IdentityServer.Services;
-using Open.IdentityServer.Services.Default;
using Open.IdentityServer.Stores;
+using Open.IdentityServer.Stores.Serialization;
using Open.IdentityServer.Validation;
using Xunit;
@@ -43,6 +44,11 @@ public void AddServerSideSessions_WhenNoStoreConfigured_ShouldConfigureServerSid
d.ImplementationType == typeof(PostConfigureSessionStoreCookieAuthOptions) &&
d.Lifetime == ServiceLifetime.Singleton);
+ serviceCollection.Should().ContainSingle(d =>
+ d.ServiceType == typeof(IAuthenticationTicketSerializer) &&
+ d.ImplementationType == typeof(AuthenticationTicketSerializer) &&
+ d.Lifetime == ServiceLifetime.Singleton);
+
serviceCollection.Should().ContainSingle(d =>
d.ServiceType == typeof(IServerSessionTicketStore) &&
d.ImplementationType == typeof(ServerSessionTicketStore) &&
@@ -127,6 +133,11 @@ public void AddServerSideSessions_WhenStoreConfigured_ShouldConfigureServerSideS
d.ImplementationType == typeof(PostConfigureSessionStoreCookieAuthOptions) &&
d.Lifetime == ServiceLifetime.Singleton);
+ serviceCollection.Should().ContainSingle(d =>
+ d.ServiceType == typeof(IAuthenticationTicketSerializer) &&
+ d.ImplementationType == typeof(AuthenticationTicketSerializer) &&
+ d.Lifetime == ServiceLifetime.Singleton);
+
serviceCollection.Should().ContainSingle(d =>
d.ServiceType == typeof(IServerSessionTicketStore) &&
d.ImplementationType == typeof(ServerSessionTicketStore) &&
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/DataProtection/AuthenticationTicketSerializerTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/DataProtection/AuthenticationTicketSerializerTests.cs
new file mode 100644
index 000000000..c52fe14b4
--- /dev/null
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/DataProtection/AuthenticationTicketSerializerTests.cs
@@ -0,0 +1,118 @@
+#nullable enable
+
+using System;
+using System.Text.Json;
+using System.Threading.Tasks;
+using AwesomeAssertions;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.DataProtection;
+using Moq;
+using Open.IdentityServer.DataProtection;
+using Open.IdentityServer.Extensions;
+using Open.IdentityServer.Stores.Serialization;
+using Open.IdentityServer.Test.Utilities;
+using Open.IdentityServer.UnitTests.Utilities.Generators;
+using Xunit;
+
+namespace Open.IdentityServer.UnitTests.DataProtection;
+
+public class AuthenticationTicketSerializerTests
+{
+ private readonly IDataProtectionProvider dataProtectionProvider = Mock.Of();
+ private readonly MockDataProtector dataProtector = new();
+ private readonly MockLogger logger = new();
+
+ public AuthenticationTicketSerializerTests()
+ {
+ Mock.Get(dataProtectionProvider)
+ .Setup(x => x.CreateProtector(DataProtectionConstants.ServerSideTicketStorePurpose))
+ .Returns(dataProtector);
+ }
+
+ private AuthenticationTicketSerializer CreateSut() => new(dataProtectionProvider, logger);
+
+ [Fact]
+ public async Task Serialize_When_Should()
+ {
+ const string authScheme = "FakeAuthScheme";
+ string subjectId = Guid.NewGuid().ToString();
+ string sessionId = Guid.NewGuid().ToString();
+ const string displayName = "Fake User";
+ DateTime issuedUtc = new(2026, 02, 19, 12, 0, 0, DateTimeKind.Utc);
+ DateTime expiresUtc = new(2026, 02, 19, 12, 0, 0, DateTimeKind.Utc);
+ string fakeIssuer = "https://fake.issuer.com";
+
+ AuthenticationTicket authenticationTicket =
+ ServerSessionTestGenerators.GenerateAuthenticationTicket(authScheme, subjectId, sessionId, displayName, issuedUtc, expiresUtc, issuer: fakeIssuer);
+
+ AuthenticationTicketSerializer sut = CreateSut();
+
+ var actualData = sut.Serialize(authenticationTicket);
+
+ var jsonElement = JsonElement.Parse(actualData);
+
+ jsonElement.GetProperty("Version").GetInt32().Should().Be(1);
+ var actualPayload = jsonElement.GetProperty("Payload").GetString();
+ actualPayload.Should().NotBeNull();
+
+ var expectedAuthTicket = authenticationTicket.Clone();
+ expectedAuthTicket.Properties.Items[JwtClaimTypes.Issuer] = fakeIssuer;
+
+ string expectedJson = JsonSerializer.Serialize(expectedAuthTicket.ToSerializableObj(),
+ AuthenticationTicketSerializer.JsonSettings);
+ dataProtector.ValidateProtectedData(actualPayload, expectedJson);
+ }
+
+ [Fact]
+ public async Task Deserialize_When_Should()
+ {
+ const string authScheme = "FakeAuthScheme";
+ string subjectId = Guid.NewGuid().ToString();
+ string sessionId = Guid.NewGuid().ToString();
+ const string displayName = "Fake User";
+ DateTime issuedUtc = new(2026, 02, 19, 12, 0, 0, DateTimeKind.Utc);
+ DateTime expiresUtc = new(2026, 02, 19, 12, 0, 0, DateTimeKind.Utc);
+ string fakeIssuer = "https://fake.issuer.com";
+
+ SerializedAuthenticationTicket authenticationTicket = ServerSessionTestGenerators.GenerateSerializedAuthenticationTicket(authScheme, subjectId, sessionId, displayName, issuedUtc, expiresUtc, issuer: fakeIssuer);
+
+ AuthenticationTicketSerializer sut = CreateSut();
+
+ string fakeProtectedData = GenerateFakeProtectedData(authenticationTicket);
+ AuthenticationTicket? actual = sut.Deserialize(fakeProtectedData);
+
+ actual.Should().BeOfType();
+ actual.AuthenticationScheme.Should().Be(authScheme);
+ actual.Principal.Identity.Should().NotBeNull();
+ actual.Principal.Identity?.AuthenticationType.Should()
+ .BeEquivalentTo(authenticationTicket.User.AuthenticationType);
+ actual.Principal.Identity?.Name.Should().BeEquivalentTo(displayName);
+ actual.Principal.Identities.Should().Contain(x =>
+ x.NameClaimType == JwtClaimTypes.Name &&
+ x.RoleClaimType == JwtClaimTypes.Role);
+ actual.Properties.Items.Should().BeEquivalentTo(authenticationTicket.Items);
+ }
+
+ [Theory]
+ [InlineData("{invalid.json}")]
+ [InlineData("{\"Version\": 2, Payload: \"SOMEDATA\"}")]
+ public async Task Deserialize_WhenSessionDataDeserialisationFails_ShouldReturnNull(string data)
+ {
+ AuthenticationTicketSerializer sut = CreateSut();
+
+ AuthenticationTicket? actual = sut.Deserialize(data);
+
+ actual.Should().BeNull();
+ }
+
+ private string GenerateFakeProtectedData(SerializedAuthenticationTicket serializedAuthenticationTicket)
+ {
+ DataProtectedSessionData sessionData = new DataProtectedSessionData
+ {
+ Payload = dataProtector.GenerateFakeProtectedData(JsonSerializer.Serialize(serializedAuthenticationTicket,
+ AuthenticationTicketSerializer.JsonSettings))
+ };
+
+ return JsonSerializer.Serialize(sessionData, AuthenticationTicketSerializer.JsonSettings);
+ }
+}
\ No newline at end of file
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Extensions/Mapping/AuthenticationTicketFilterResultMappingExtensionsTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Extensions/Mapping/AuthenticationTicketFilterResultMappingExtensionsTests.cs
index b1e0818ad..22f5b685d 100644
--- a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Extensions/Mapping/AuthenticationTicketFilterResultMappingExtensionsTests.cs
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Extensions/Mapping/AuthenticationTicketFilterResultMappingExtensionsTests.cs
@@ -22,7 +22,7 @@ public void ToUserSession_ShouldMapAuthTicketResultToUserSession()
actualSession.Created.Should().Be(sut.Session.Created);
actualSession.Renewed.Should().Be(sut.Session.Renewed);
actualSession.Expires.Should().Be(sut.Session.Expires);
- actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.AuthTicket);
+ actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.Session.AuthenticationTicket);
actualSession.Issuer.Should().BeNullOrWhiteSpace();
actualSession.ClientIds.Should().BeNullOrEmpty();
}
@@ -42,8 +42,8 @@ public void ToUserSession_WhenClientIdsSet_ShouldExtractClientIdsInResult()
actualSession.Renewed.Should().Be(sut.Session.Renewed);
actualSession.Expires.Should().Be(sut.Session.Expires);
actualSession.Issuer.Should().BeNullOrWhiteSpace();
- actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.AuthTicket);
- actualSession.ClientIds.Should().BeEquivalentTo(sut.AuthTicket!.Properties.GetClientList());
+ actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.Session.AuthenticationTicket);
+ actualSession.ClientIds.Should().BeEquivalentTo(sut.Session.AuthenticationTicket!.Properties.GetClientList());
}
[Fact]
@@ -63,7 +63,7 @@ public void ToUserSession_WhenIssuerSet_ShouldExtractIssuerInResult()
actualSession.Renewed.Should().Be(sut.Session.Renewed);
actualSession.Expires.Should().Be(sut.Session.Expires);
actualSession.Issuer.Should().Be(fakeIssuer);
- actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.AuthTicket);
- actualSession.ClientIds.Should().BeEquivalentTo(sut.AuthTicket!.Properties.GetClientList());
+ actualSession.AuthenticationTicket.Should().BeEquivalentTo(sut.Session.AuthenticationTicket);
+ actualSession.ClientIds.Should().BeEquivalentTo(sut.Session.AuthenticationTicket!.Properties.GetClientList());
}
}
\ No newline at end of file
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Hosting/IdentityServerMiddlewareTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Hosting/IdentityServerMiddlewareTests.cs
index 2a05faaed..5d2c0486c 100644
--- a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Hosting/IdentityServerMiddlewareTests.cs
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Hosting/IdentityServerMiddlewareTests.cs
@@ -282,9 +282,9 @@ public async Task Invoke_WhenSessionExpired_ShouldCallHandleUserSessionExpiry_On
var ticketProperties = new AuthenticationProperties();
ticketProperties.AddClientId("client-1");
ticketProperties.AddClientId("client-2");
- var expiredTicket = new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity()), ticketProperties, "cookie");
+ expiredSession.AuthenticationTicket = new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity()), ticketProperties, "cookie");
- _context.SetSessionExpired(expiredSession, expiredTicket);
+ _context.SetSessionExpired(expiredSession);
EndUserSessionEventContext actualContext = null;
Mock.Get(userSessionEventsService)
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultSessionManagementServiceTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultSessionManagementServiceTests.cs
index e1c7f88fa..0123abded 100644
--- a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultSessionManagementServiceTests.cs
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultSessionManagementServiceTests.cs
@@ -106,8 +106,8 @@ public async Task QuerySessionsAsync_WhenResultsReturned_ShouldMapToUserSessionC
actualSession.Created.Should().Be(expected.Session.Created);
actualSession.Renewed.Should().Be(expected.Session.Renewed);
actualSession.Expires.Should().Be(expected.Session.Expires);
- actualSession.AuthenticationTicket.Should().BeEquivalentTo(expected.AuthTicket);
- actualSession.ClientIds.Should().BeEquivalentTo(expected.AuthTicket!.Properties.GetClientList());
+ actualSession.AuthenticationTicket.Should().BeEquivalentTo(expected.Session.AuthenticationTicket);
+ actualSession.ClientIds.Should().BeEquivalentTo(expected.Session.AuthenticationTicket!.Properties.GetClientList());
}
Mock.Get(serverSessionTicketStore)
@@ -149,8 +149,8 @@ public async Task RemoveSessionsAsync_WhenFilterSpecified_ShouldRemoveAllSession
.Verify(x => x.SendLogoutNotificationsAsync(It.Is(ctx =>
ctx.SessionId == fakeSession.Session.SessionId &&
ctx.SubjectId == fakeSession.Session.SubjectId &&
- fakeSession.AuthTicket != null &&
- ctx.ClientIds == fakeSession.AuthTicket.Properties.GetClientList())));
+ fakeSession.Session.AuthenticationTicket != null &&
+ ctx.ClientIds == fakeSession.Session.AuthenticationTicket.Properties.GetClientList())));
}
Mock.Get(persistedGrantStore)
@@ -230,8 +230,8 @@ public async Task RemoveSessionsAsync_WhenRemoveSessionsSetToFalse_ShouldNotRemo
.Verify(x => x.SendLogoutNotificationsAsync(It.Is(ctx =>
ctx.SessionId == fakeSession.Session.SessionId &&
ctx.SubjectId == fakeSession.Session.SubjectId &&
- fakeSession.AuthTicket != null &&
- ctx.ClientIds.ToHashSet().SetEquals(fakeSession.AuthTicket.Properties.GetClientList()))));
+ fakeSession.Session.AuthenticationTicket != null &&
+ ctx.ClientIds.ToHashSet().SetEquals(fakeSession.Session.AuthenticationTicket.Properties.GetClientList()))));
}
Mock.Get(persistedGrantStore)
@@ -311,8 +311,8 @@ public async Task RemoveSessionsAsync_WhenRevokeTokensFalse_ShouldNotRevokeToken
.Verify(x => x.SendLogoutNotificationsAsync(It.Is(ctx =>
ctx.SessionId == fakeSession.Session.SessionId &&
ctx.SubjectId == fakeSession.Session.SubjectId &&
- fakeSession.AuthTicket != null &&
- ctx.ClientIds.ToHashSet().SetEquals(fakeSession.AuthTicket.Properties.GetClientList()))));
+ fakeSession.Session.AuthenticationTicket != null &&
+ ctx.ClientIds.ToHashSet().SetEquals(fakeSession.Session.AuthenticationTicket.Properties.GetClientList()))));
}
Mock.Get(persistedGrantStore)
@@ -355,8 +355,8 @@ public async Task RemoveSessionsAsync_WhenRevokeConsentsFalse_ShouldNotRevokeCon
.Verify(x => x.SendLogoutNotificationsAsync(It.Is(ctx =>
ctx.SessionId == fakeSession.Session.SessionId &&
ctx.SubjectId == fakeSession.Session.SubjectId &&
- fakeSession.AuthTicket != null &&
- ctx.ClientIds.ToHashSet().SetEquals(fakeSession.AuthTicket.Properties.GetClientList()))));
+ fakeSession.Session.AuthenticationTicket != null &&
+ ctx.ClientIds.ToHashSet().SetEquals(fakeSession.Session.AuthenticationTicket.Properties.GetClientList()))));
}
Mock.Get(persistedGrantStore)
@@ -399,8 +399,8 @@ public async Task RemoveSessionsAsync_WhenRevokeTokensAndConsentsFalse_ShouldNot
.Verify(x => x.SendLogoutNotificationsAsync(It.Is(ctx =>
ctx.SessionId == fakeSession.Session.SessionId &&
ctx.SubjectId == fakeSession.Session.SubjectId &&
- fakeSession.AuthTicket != null &&
- ctx.ClientIds.ToHashSet().SetEquals(fakeSession.AuthTicket.Properties.GetClientList()))));
+ fakeSession.Session.AuthenticationTicket != null &&
+ ctx.ClientIds.ToHashSet().SetEquals(fakeSession.Session.AuthenticationTicket.Properties.GetClientList()))));
}
Mock.Get(persistedGrantStore)
diff --git a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultUserSessionEventsServiceTests.cs b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultUserSessionEventsServiceTests.cs
index 89b404040..cd114afc2 100644
--- a/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultUserSessionEventsServiceTests.cs
+++ b/src/Open.IdentityServer/test/Open.IdentityServer.UnitTests/Services/Default/DefaultUserSessionEventsServiceTests.cs
@@ -538,16 +538,14 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
DateTime issued = fakeNow.AddDays(-10);
DateTime expires = fakeNow.AddDays(19);
- ServerSideSession fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
+ AuthenticationTicketFilterResult fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
created: issued, renewed: issued, expires: expires);
- AuthenticationTicket fakeAuthTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
+ fakeSession.Session.AuthenticationTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
isPersistent: isPersistent, allowRefresh: allowRefresh, issuedUtc: issued, expiresUtc: expires);
Mock.Get(serverSessionTicketStore)
.Setup(x => x.FilterServerAuthenticationTickets(fakeSubjectId, fakeSessionId))
- .ReturnsAsync([
- new AuthenticationTicketFilterResult { Session = fakeSession, AuthTicket = fakeAuthTicket },
- ]);
+ .ReturnsAsync([fakeSession]);
ServerSideSession? updatedSession = null;
Mock.Get(identityServerServerSideSessionStore)
@@ -558,8 +556,8 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
bool actual = await sut.ValidateSession(testCtx);
actual.Should().BeTrue();
-
- updatedSession.Should().BeEquivalentTo(fakeSession, opt => opt
+
+ updatedSession.Should().BeEquivalentTo(fakeSession.Session, opt => opt
.Excluding(y => y.Renewed)
.Excluding(y => y.Expires));
@@ -595,16 +593,14 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
DateTime issued = fakeNow.AddDays(-10);
DateTime expires = fakeNow.AddDays(19);
- ServerSideSession fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
+ AuthenticationTicketFilterResult fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
created: issued, renewed: issued, expires: expires);
- AuthenticationTicket fakeAuthTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
+ fakeSession.Session.AuthenticationTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
isPersistent: isPersistent, allowRefresh: allowRefresh, issuedUtc: issued, expiresUtc: expires);
Mock.Get(serverSessionTicketStore)
.Setup(x => x.FilterServerAuthenticationTickets(fakeSubjectId, fakeSessionId))
- .ReturnsAsync([
- new AuthenticationTicketFilterResult { Session = fakeSession, AuthTicket = fakeAuthTicket },
- ]);
+ .ReturnsAsync([fakeSession]);
ServerSideSession? updatedSession = null;
Mock.Get(identityServerServerSideSessionStore)
@@ -616,7 +612,7 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
actual.Should().BeTrue();
- updatedSession.Should().BeEquivalentTo(fakeSession, opt => opt
+ updatedSession.Should().BeEquivalentTo(fakeSession.Session, opt => opt
.Excluding(y => y.Renewed)
.Excluding(y => y.Expires));
@@ -652,16 +648,14 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
DateTime issued = fakeNow.AddDays(-10);
DateTime expires = fakeNow.AddDays(19);
- ServerSideSession fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
+ AuthenticationTicketFilterResult fakeSession = FakeSession(fakKey, fakeScheme, fakeSessionId, fakeSubjectId, fakeDisplayName,
created: issued, renewed: issued, expires: expires);
- AuthenticationTicket fakeAuthTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
+ fakeSession.Session.AuthenticationTicket = GenerateAuthenticationTicket(fakeScheme, fakeSubjectId, fakeSessionId, fakeDisplayName,
isPersistent: isPersistent, allowRefresh: allowRefresh, issuedUtc: issued, expiresUtc: expires);
Mock.Get(serverSessionTicketStore)
.Setup(x => x.FilterServerAuthenticationTickets(fakeSubjectId, fakeSessionId))
- .ReturnsAsync([
- new AuthenticationTicketFilterResult { Session = fakeSession, AuthTicket = fakeAuthTicket },
- ]);
+ .ReturnsAsync([fakeSession]);
AuthenticationTicket? updatedTicket = null;
Mock.Get(serverSessionTicketStore)
@@ -673,7 +667,7 @@ private async Task ValidateRefreshTokenAsync_CoordinationEnabledWithValidSession
actual.Should().BeTrue();
- updatedTicket.Should().BeEquivalentTo(fakeAuthTicket);
+ updatedTicket.Should().BeEquivalentTo(fakeSession.Session.AuthenticationTicket);
updatedTicket.Properties.IssuedUtc.Should().Be(fakeNow);
updatedTicket.Properties.ExpiresUtc.Should().Be(fakeNow.AddDays(29));
updatedTicket.Properties.GetString(IdentityServerConstants.ForceCookieRefresh).Should().BeEmpty();
@@ -706,18 +700,18 @@ public async Task PublicMethods_WhenCalled_ShouldTelemetryTrace()
foreach ((Func actMethod, string traceMethodName) method in
methods)
{
- ITrace trace = Mock.Of();
+ ITrace traceMock = Mock.Of();
Mock.Get(telemetry).Setup(t => t.Trace(It.IsAny(), It.IsAny