вызовите IIdentityServiceBuilder.AddSigningCredential в методе Configure. - PullRequest
0 голосов
/ 20 февраля 2020

Пожалуйста, помогите мне с вызовом IIdentityServerBuilder.AddSigningCredential в методе Startup.Configure.

Я загружаю материал ключа для IdentityServer4 в методе ConfigureServices, как показано ниже:

class Startup
{
        public void ConfigureServices(IServiceCollection services)
        {
                services.AddScoped<KeyVaultAccessImpl>();

                var identityBuilder = services.AddIdentityServer();

                KeyVaultAccessImpl kva;
                kva = services.BuildServiceProvider().GetService<KeyVaultAccessImpl>();
                foreach (X509Certificate2 c in kva.LoadSignCertificates())
                    identityBuilder.AddSigningCredential(c);
        }
}

Метод AddSigningCredential вызывается в методе Startup.ConfigureServices. Реализация KeyVaultAccessImpl загружает X509Certificate2 экземпляров из внешнего хранилища для использования в identityBuilder.AddSigningCredential. KeyVaultAccessImpl содержит внешние зависимости, настроенные с помощью services.Add...

. Он работает нормально, однако вызов services.BuildServiceProvider().GetService<KeyVaultAccessImpl>() в методе ConfigureServices выдает предупреждение компилятора:

Calling ' BuildServiceProvider 'из кода приложения приводит к созданию дополнительной копии одноэлементных сервисов. Рассмотрим альтернативы, такие как сервисы внедрения зависимостей в качестве параметров для 'Configure'

Я пытался сохранить identityBuilder как свойство класса и вызвать AddSigningCredential в методе Configure, как показано ниже:

public void ConfigureServices(IServiceCollection services)
{
        services.AddScoped<KeyVaultAccessImpl>();

        identityBuilder = services.AddIdentityServer();
    }

IIdentityServerBuilder identityBuilder;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, KeyVaultAccessImpl kva)
{
        foreach (X509Certificate2 c in kva.LoadSignCertificates())
            identityBuilder.AddSigningCredential(c); // no error but key is not added
        identityBuilder.AddDeveloperSigningCredential() //is ignored either
        app.UseIdentityServer();

}

Однако проблема в том, что AddSigningCredential игнорируется, и на самом деле никакой ключ не добавляется.

При попытке получить токен возникает ошибка PolicyViolation Keyset is missing.

Возможно, потому что IdentityServer создается (и инициализируется) после ConfigureServices, но до вызова Configure метода ,

Можно ли как-нибудь вызвать identityBuilder.AddSigningCredential в методе Configure?

Ответы [ 2 ]

1 голос
/ 28 февраля 2020

Спасибо, @ mack ie

Я создал CredentialStore для реализации ISigningCredentialStore и IValidationKeysStore, как показано ниже

/// <summary>
/// implementation of signing and validation stores, 
/// loads X509Certificate from the KeyVault
/// </summary>
public class CredentialStore : ISigningCredentialStore, IValidationKeysStore
{
    private readonly KeyVaultAccessImpl kva;

    public CredentialStore(KeyVaultAccessImpl kva)
    {
        this.kva = kva;
        loadedCertificate = new Lazy<X509Certificate2>(() => LoadCertificate());
    }

    public Task<SigningCredentials> GetSigningCredentialsAsync()
    {
        return Task.Run(() => Load());
    }

    public Task<IEnumerable<SecurityKeyInfo>> GetValidationKeysAsync()
    {
        var credential = Load();

        var keyInfo = new SecurityKeyInfo
        {
            Key = credential.Key,
            SigningAlgorithm = credential.Algorithm
        };

        var res = (IEnumerable<SecurityKeyInfo>) new[] { keyInfo };

        return Task.FromResult(res);
    }

    X509Certificate2 LoadCertificate()
    {
        var cert = kva.LoadCertificate().Result;
        if (!cert.HasPrivateKey)
            throw new ArgumentException($"no private key for certificate {cert.Thumbprint} was found");
        return cert;
    }

    Lazy<X509Certificate2> loadedCertificate;

    SigningCredentials Load(string signingAlgorithm = SecurityAlgorithms.RsaSha256)
    {
        var key = new X509SecurityKey(loadedCertificate.Value);
        key.KeyId += signingAlgorithm;

        return new SigningCredentials(key, signingAlgorithm);
    }
}

Затем можно добавить синглтоны в Startup.ConfigureServices без services.BuildServiceProvider() звоните:

services.AddSingleton<ISigningCredentialStore, CredentialStore>()
    .AddSingleton<IValidationKeysStore, CredentialStore>();
1 голос
/ 20 февраля 2020

Я бы предложил реализовать ваши собственные ISigningCredentialStore и IValidationKeysStore, которые принимают KeyVaultAccessImpl в качестве зависимости. Затем они могут вызывать эту службу во время выполнения при необходимости.

Проверьте это, чтобы увидеть, как работает метод построителя AddSigningCredential() по умолчанию:

https://github.com/IdentityServer/IdentityServer4/blob/master/src/IdentityServer4/src/Configuration/DependencyInjection/BuilderExtensions/Crypto.cs

...