Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Modified by Rock Solid Knowledge Ltd. Copyright in modifications 2026, Rock Solid Knowledge Ltd.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


Expand Down Expand Up @@ -62,7 +63,12 @@ public async Task<IEnumerable<SigningCredentials>> GetAllSigningCredentialsAsync

foreach (var store in _signingCredentialStores)
{
credentials.Add(await store.GetSigningCredentialsAsync());
var credential = await store.GetSigningCredentialsAsync();

if (credential != null)
{
credentials.Add(credential);
}
}

return credentials;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (c) 2026, Rock Solid Knowledge Ltd
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;
using AwesomeAssertions;
using Microsoft.IdentityModel.Tokens;
using Open.IdentityServer.Models;
using Open.IdentityServer.Services;
using Open.IdentityServer.Stores;
using Xunit;

namespace IdentityServer.UnitTests.Services.Default;

public class TestSigningCredentialStore(SigningCredentials signingCredentials): ISigningCredentialStore {
public Task<SigningCredentials> GetSigningCredentialsAsync() => Task.FromResult(signingCredentials);
}

public class TestValidationKeysStore(IEnumerable<SecurityKeyInfo> securityKeyInfos): IValidationKeysStore {
public Task<IEnumerable<SecurityKeyInfo>> GetValidationKeysAsync() => Task.FromResult(securityKeyInfos);
}

public class DefaultKeyMaterialServiceTests
{
private IEnumerable<ISigningCredentialStore> signingCredentialStores =
[
new TestSigningCredentialStore(fakeSigningCredentials1),
new TestSigningCredentialStore(fakeSigningCredentials2),
new TestSigningCredentialStore(fakeSigningCredentials3),
];
private IEnumerable<IValidationKeysStore> validationKeysStores =
[
new TestValidationKeysStore([fakeSecurityKey1, fakeSecurityKey4, fakeSecurityKey5]),
new TestValidationKeysStore([fakeSecurityKey2, fakeSecurityKey6, fakeSecurityKey7]),
new TestValidationKeysStore([fakeSecurityKey3, fakeSecurityKey8, fakeSecurityKey9]),
];

// Test SigningCredentials
private static SigningCredentials fakeSigningCredentials1 = new(new RsaSecurityKey(RSA.Create(1024)), "RS256");
private static SigningCredentials fakeSigningCredentials2 = new(new RsaSecurityKey(RSA.Create(1024)), "PS384");
private static SigningCredentials fakeSigningCredentials3 = new(new ECDsaSecurityKey(ECDsa.Create(ECCurve.NamedCurves.nistP521)), "ES512");

// Test SigningCredentials as SecurityKeyInfo
private static SecurityKeyInfo fakeSecurityKey1 = new() { Key = fakeSigningCredentials1.Key , SigningAlgorithm = fakeSigningCredentials1.Algorithm };
private static SecurityKeyInfo fakeSecurityKey2 = new() { Key = fakeSigningCredentials2.Key , SigningAlgorithm = fakeSigningCredentials2.Algorithm };
private static SecurityKeyInfo fakeSecurityKey3 = new() { Key = fakeSigningCredentials3.Key , SigningAlgorithm = fakeSigningCredentials3.Algorithm };

// Other Test SecurityKeyInfo
private static SecurityKeyInfo fakeSecurityKey4 = new() { Key = new RsaSecurityKey(RSA.Create(1024)) , SigningAlgorithm = "RS384" };
private static SecurityKeyInfo fakeSecurityKey5 = new() { Key = new RsaSecurityKey(RSA.Create(1024)) , SigningAlgorithm = "RS512" };
private static SecurityKeyInfo fakeSecurityKey6 = new() { Key = new RsaSecurityKey(RSA.Create(1024)) , SigningAlgorithm = "PS256" };
private static SecurityKeyInfo fakeSecurityKey7 = new() { Key = new RsaSecurityKey(RSA.Create(1024)) , SigningAlgorithm = "PS512" };
private static SecurityKeyInfo fakeSecurityKey8 = new() { Key = new ECDsaSecurityKey(ECDsa.Create(ECCurve.NamedCurves.nistP256)) , SigningAlgorithm = "ES256" };
private static SecurityKeyInfo fakeSecurityKey9 = new() { Key = new ECDsaSecurityKey(ECDsa.Create(ECCurve.NamedCurves.nistP256)) , SigningAlgorithm = "ES384" };

private DefaultKeyMaterialService CreateSut() => new(validationKeysStores, signingCredentialStores);

[Fact]
public async Task GetSigningCredentialsAsync_WhenNoSigningCredentialStores_ShouldReturnNull()
{
signingCredentialStores = [];

var sut = CreateSut();

var actual = await sut.GetSigningCredentialsAsync();

actual.Should().BeNull();
}

[Fact]
public async Task GetSigningCredentialsAsync_WhenNoAllowedAlgorithmsSpecified_ShouldReturnCredentialsFromFirstStore()
{
var sut = CreateSut();

var actual = await sut.GetSigningCredentialsAsync();

actual.Should().BeEquivalentTo(fakeSigningCredentials1);
}

[Fact]
public async Task GetSigningCredentialsAsync_WhenAllowedAlgorithmsSpecified_ShouldReturnFirstCredentialsThatMatchesAllowedValues()
{
var sut = CreateSut();

var actual = await sut.GetSigningCredentialsAsync(["PS384", "ES512"]);

actual.Should().BeEquivalentTo(fakeSigningCredentials2);
}

[Fact]
public async Task GetAllSigningCredentialsAsync_WhenNoSigningCredentialStores_ShouldEmptyResultSet()
{
signingCredentialStores = [];

var sut = CreateSut();

var actual = await sut.GetAllSigningCredentialsAsync();

actual.Should().BeEmpty();
}

[Fact]
public async Task GetAllSigningCredentialsAsync_WhenSigningCredentialStoreReturnsNull_ShouldSkipThatStore()
{
signingCredentialStores = [
new TestSigningCredentialStore(fakeSigningCredentials1),
new TestSigningCredentialStore(null),
new TestSigningCredentialStore(fakeSigningCredentials3),
];

var sut = CreateSut();

var actual = await sut.GetAllSigningCredentialsAsync();

actual.Should().BeEquivalentTo([fakeSigningCredentials1, fakeSigningCredentials3]);
}

[Fact]
public async Task GetAllSigningCredentialsAsync_ShouldReturnResultsFromAllRegisteredStores()
{
var sut = CreateSut();

var actual = await sut.GetAllSigningCredentialsAsync();

actual.Should().BeEquivalentTo([
fakeSigningCredentials1, fakeSigningCredentials2, fakeSigningCredentials3,
]);
}

[Fact]
public async Task GetValidationKeysAsync_WhenNoSigningCredentialStores_ShouldEmptyResultSet()
{
validationKeysStores = [];

var sut = CreateSut();

var actual = await sut.GetValidationKeysAsync();

actual.Should().BeEmpty();
}

[Fact]
public async Task GetValidationKeysAsync_ShouldReturnResultsFromAllRegisteredStores()
{
var sut = CreateSut();

var actual = await sut.GetValidationKeysAsync();

actual.Should().BeEquivalentTo([
fakeSecurityKey1, fakeSecurityKey2, fakeSecurityKey3,
fakeSecurityKey4, fakeSecurityKey5, fakeSecurityKey6,
fakeSecurityKey7, fakeSecurityKey8, fakeSecurityKey9,
]);
}
}
Loading