Member 13444435 Ответов: 3

Удаленный сертификат недействителен в соответствии с процедурой проверки


Здравствуйте вместе,

Я безуспешно висел целыми днями над этой проблемой, и ни один ответ на разные посты на разных сайтах не помог мне так решить ее.

Я работаю над системой Windows 10 и внедряю ее с помощью VisualStudio 2017.
С помощью AspNetCore я реализовал следующие проекты:

1.) паутина.AuthServer: IdentityServer4 для аутентификации.
2.) Web.ApiServer: Первый SignalR-сервер.
3.) Web.ApiSwitch: Второй SignalR-сервер.
Он имеет HostedService с 2 SignalR-клиентами в качестве
"мост" между двумя SignalR-серверами.>


Web.ApiSwitch запускает свой HostedService, который подключается к себе и Web.ApiServer, включая аутентификацию в Интернете.AuthServer. Это хорошо работало до тех пор, пока они работали с некоторым URL-адресом "localhost:PORT".

Теперь я попробовал запустить все проекты с помощью "MyIP:PORT". сеть.AuthServer использует HTTPS вместе с самозаверяющим сертификатом (генерируемым с помощью OpenSSL).
Сам сертификат был создан с помощью следующих командных строк:

Генерация закрытого ключа:
openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout IdentityServer4Auth.key -out IdentityServer4Auth.crt -subj "/CN=example.com" -days 3650


Генерация сертификата:
openssl pkcs12 -export -out IdentityServer4Auth.pfx -inkey IdentityServer4Auth.key -in IdentityServer4Auth.crt -certfile IdentityServer4Auth.crt


Файл был добавлен в mmc:
1.) Файл -> Добавить или удалить Оснастки -> сертификаты -> Добавить -> учетная запись компьютера -> ОК
2.) импортируйте сертификат (.cer) в личные Доверенные корневые центры сертификации)
3.) Импортировать файл с экспортируемым закрытым ключом поддержки, личный -&ГТ; сертификаты.

Код веба.AuthServer:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseKestrel(options =>
        {
            options.Listen(IPAddress.Any, 5000, listenOptions =>
            {
                listenOptions.UseHttps();
            });
        })
        .UseStartup<Startup>()
        .ConfigureLogging(builder =>
        {
            builder.ClearProviders();
            builder.AddSerilog();
        })
        .Build();


public void ConfigureServices(IServiceCollection services)
 {
     // Gets connection strings from "appsettings.json".
     string csApplicationContext = Configuration.GetConnectionString("ApplicationContext");
     string csConfigurationStore = Configuration.GetConnectionString("ConfigurationStore");
     var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

     var settings = JsonFileManager<ServerSettings>.Load(AppDomain.CurrentDomain.BaseDirectory + "Config\\svConf.json");

     // Add cross origin resource sharing.
     services.AddCors(options =>
     {
         options.AddPolicy("default", policy =>
         {
             policy.WithOrigins(settings.CorsOrigins)
                   .AllowAnyHeader()
                   .AllowAnyMethod()
                   .AllowCredentials();
         });
     });

     // Add bearer token authentication.
     services.AddAuthentication()
         .AddJwtBearer(jwt =>
         {
             jwt.Authority = settings.JWTBearerSettings.Authority;
             jwt.Audience = settings.JWTBearerSettings.Audience;
             jwt.RequireHttpsMetadata = settings.JWTBearerSettings.RequireHttpsMetadata;
             jwt.Validate();
         });

     services.AddPolicyServerClient(Configuration.GetSection("Policy"))
         .AddAuthorizationPermissionPolicies();

     // DB und User registieren für DI
     services.AddDbContext<ApplicationDbContext>(builder =>
         builder.UseSqlite(csApplicationContext, sqlOptions =>
             sqlOptions.MigrationsAssembly(migrationsAssembly)));

     services.AddIdentity<ApplicationUser, IdentityRole>()
         .AddEntityFrameworkStores<ApplicationDbContext>();

     services.AddTransient<IClientStore, ClientService>();

     // Add IS4 as authentication server.
     var is4Builder = services.AddIdentityServer(options =>
         {
             options.Events.RaiseErrorEvents = true;
             options.Events.RaiseFailureEvents = true;
             options.Events.RaiseSuccessEvents = true;
             options.Events.RaiseInformationEvents = true;
         })
         // Add config data (clients, resources, CORS).
         .AddConfigurationStore(options =>
             options.ConfigureDbContext = builder =>
                 builder.UseSqlite(csConfigurationStore, sqlOptions =>
                     sqlOptions.MigrationsAssembly(migrationsAssembly)))
         .AddClientStore<ClientService>()
         .AddAspNetIdentity<ApplicationUser>();

     SigninCredentialExtension.AddSigninCredentialFromConfig(is4Builder, Configuration.GetSection("SigninKeyCredentials"), Logger);

     services.AddMvc(options =>
     {
         // this sets up a default authorization policy for the application
         // in this case, authenticated users are required (besides controllers/actions that have [AllowAnonymous]
         var policy = new AuthorizationPolicyBuilder()
                         .RequireAuthenticatedUser()
                         .Build();
         options.Filters.Add(new AuthorizeFilter(policy));

         options.SslPort = 5000;
         options.Filters.Add(new RequireHttpsAttribute());
     });
 }


public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseExceptionHandler("/Home/Error");

    // Use specific cross origin resource sharing configuration.
    app.UseCors("default");

    app.UseDefaultFiles();

    app.UsePolicyServerClaims();

    app.UseStaticFiles();

    app.UseHttpsRedirection();

    app.UseIdentityServer();

    // Adding test data to database.
    await InitializeDbTestData.GenerateTestData(app);

    app.UseMvcWithDefaultRoute();
}


public static class SigninCredentialExtension
{
    private const string KeyType = "KeyType";
    private const string KeyTypeKeyFile = "KeyFile";
    private const string KeyTypeKeyStore = "KeyStore";
    private const string KeyTypeTemporary = "Temporary";
    private const string KeyFilePath = "KeyFilePath";
    private const string KeyFilePassword = "KeyFilePassword";
    private const string KeyStoreIssuer = "KeyStoreIssuer";

    public static IIdentityServerBuilder AddSigninCredentialFromConfig(
        this IIdentityServerBuilder builder, IConfigurationSection options, ILogger logger)
    {
        string keyType = options.GetValue<string>(KeyType);
        logger.LogDebug($"SigninCredentialExtension keyType is {keyType}");

        switch (keyType)
        {
            case KeyTypeTemporary:
                logger.LogDebug($"SigninCredentialExtension adding Developer Signing Credential");
                builder.AddDeveloperSigningCredential();
                break;

            case KeyTypeKeyFile:
                AddCertificateFromFile(builder, options, logger);
                break;

            case KeyTypeKeyStore:
                AddCertificateFromStore(builder, options, logger);
                break;
        }

        return builder;
    }

    public static X509Certificate2 GetCertificateByThumbprint(string thumbprint)
    {
        using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
        {
            certStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
            if (certCollection.Count > 0) return certCollection[0];
        }
        return null;
    }

    private static void AddCertificateFromStore(IIdentityServerBuilder builder,
        IConfigurationSection options, ILogger logger)
    {
        var keyIssuer = options.GetValue<string>(KeyStoreIssuer);
        logger.LogDebug($"SigninCredentialExtension adding key from store by {keyIssuer}");

        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);

        var certificates = store.Certificates.Find(X509FindType.FindByIssuerName, keyIssuer, true);

        if (certificates.Count > 0)
        {
            builder.AddSigningCredential(certificates[0]);
            builder.AddValidationKey(certificates[0]);
        }
        else
            logger.LogError("A matching key couldn't be found in the store");
    }

    private static void AddCertificateFromFile(IIdentityServerBuilder builder,
        IConfigurationSection options, ILogger logger)
    {
        var keyFilePath = options.GetValue<string>(KeyFilePath);
        var keyFilePassword = options.GetValue<string>(KeyFilePassword);

        if (File.Exists(keyFilePath))
        {
            logger.LogDebug($"SigninCredentialExtension adding key from file {keyFilePath}");
            builder.AddSigningCredential(new X509Certificate2(keyFilePath, keyFilePassword));
        }
        else
        {
            logger.LogError($"SigninCredentialExtension cannot find key file {keyFilePath}");
        }
    }
}


Код Web.ApiServer:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseKestrel(options =>
        {
            options.Listen(IPAddress.Any, 5004, listenOptions =>
            {
                listenOptions.UseHttps();
            });
        })
        .UseStartup<Startup>()
        .ConfigureLogging(builder =>
        {
            builder.ClearProviders();
            builder.AddSerilog();
        })
        .Build();


public void ConfigureServices(IServiceCollection services)
{
    // Add cross origin resource sharing.
    services.AddCors(options =>
    {
        options.AddPolicy("default", policy =>
        {
            policy.WithOrigins(_settings.CorsOrigins)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
        });
    });

    // Add bearer token authentication and our IS4 as authentication server.
    services.AddAuthentication(_settings.ISAuthenticationSettings.DefaultScheme)
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = _settings.ISAuthenticationSettings.Authority;
        options.RequireHttpsMetadata = _settings.ISAuthenticationSettings.RequireHttpsMetadata;
        options.ApiName = _settings.ISAuthenticationSettings.ApiName;

        // Handling the token from query string in due to the reason
        // that signalR clients are handling them over it.
        options.TokenRetriever = new Func<HttpRequest, string>(req =>
        {
            var fromHeader = TokenRetrieval.FromAuthorizationHeader();
            var fromQuery = TokenRetrieval.FromQueryString();
            return fromHeader(req) ?? fromQuery(req);
        });

        options.Validate();
    });

    // Add singalR as event bus.
    services.AddSignalR(options => options.EnableDetailedErrors = true);

    services.AddMvcCore(options =>
            {
                options.SslPort = 5003;
                options.Filters.Add(new RequireHttpsAttribute());
            })
            .AddAuthorization()
            .AddJsonFormatters();

    // Register ConnectionHost as hosted service with its wrapper class.
    services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, ConnectionHost>();
}


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();

    app.UseHttpsRedirection();

    // Has to be called before UseSignalR and UseMvc!
    app.UseAuthentication();

    // Use specific cross origin resource sharing configuration.
    app.UseCors("default");

    app.UseSignalR(routes => routes.MapHub<EventHub>("/live"));

    app.UseMvc();
}


Запрос токена для клиентов SignalR:

public static async Task<TokenResponse> RequestTokenAsync(string authority, string clientID, string scope)
{
    var client = new HttpClient();
    var disco = await client.GetDiscoveryDocumentAsync(authority);
    if (disco.IsError) throw new Exception(disco.Error);

    var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        Address = disco.TokenEndpoint,

        ClientId = clientID,
        ClientSecret = "SomeTestSecret",
        Scope = scope
    });

    if (response.IsError)
    {
        throw new Exception(response.Error);
    }

    return response;
}


TokenRetriever ConfigureServices от Web.ApiServer предназначен только для проверки подлинности запущенных клиентов SignalR по той причине, что они передают токены через строку запроса. Он делает свою работу.

Теперь проблема:

Клиенты HostedService Web.ApiServer пытаются получить токен аутентификации (jwt bearer) из Web.AuthServer но каждый раз когда я получаю
следующее исключение:

System.Security.Authentication.AuthenticationException: 'The remote certificate is invalid according to the validation procedure.'


Если я открываю браузер и введите адрес веб-страницы.AuthServer "MyIP:5000" все работает нормально, после того как я принимаю самозаверяющий сертификат.
Но клиенты HostedService Web.ApiServer не могут этого сделать.
Как мне избавиться от этого исключения и получить какой-то действительный сертификат? Может быть, я что-то упустил при реализации клиента? Надеюсь, кто - то сможет мне помочь-я застрял на этом уже более 4 дней.

Что я уже пробовал:

- Создание различных сертификатов с помощью EasyRSA, OpenSSL, инструментов из Windows Kits 10.

- Изменения кода сервера.. чтобы многое здесь записать.

3 Ответов

Рейтинг:
2

Member 13444435

Привет, Ричард, это устраняет только некоторые исключения, но я все равно получаю исключение, что удаленный сертификат недействителен.

Если я заведу паутину.AuthServer и после этого только Web.ApiServer все в порядке. Но Web.ApiServer пытается получить SignalR-соединение с Web.ApiSwitch, и если это было запущено, то исключение возникает после возврата маркера ответа, который имеет код успеха 200.

APISwitchConnection = new HubConnectionBuilder()
    .WithUrl(apiSwitchUrl, options =>
    {
        options.AccessTokenProvider = async () =>
        {
            logger.LogInformation(string.Format("Hosted hub connection service requesting access token for {0}..", EventHub.PlantName));
            var response = await TokenService.RequestTokenAsync(_settings.ISAuthenticationSettings.Authority,
                                                                EventHub.PlantName,
                                                                                                    _settings.ISAuthenticationSettings.ApiName);
            return response.AccessToken;
        };
    })
    .Build();



public static async Task<TokenResponse> RequestTokenAsync(string authority, string clientID, string scope)
{
    using (var httpClientHandler = new HttpClientHandler())
    {
        httpClientHandler.ServerCertificateCustomValidationCallback += (message, cert, chain, erros) => true;

        using (var client = new HttpClient(httpClientHandler))
        {
            var disco = await client.GetDiscoveryDocumentAsync(authority);
            if (disco.IsError) throw new Exception(disco.Error);

            var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId = clientID,
                ClientSecret = clientID + "-SecretValue",
                Scope = scope
            });

            if (response.IsError)
            {
                throw new Exception(response.Error);
            }

            return response;
        }
    }
}


Рейтинг:
2

rajesh2245977

Привет,

У вас есть какое-нибудь решение для этого ? Я также сталкиваюсь с аналогичной проблемой в linux с помощью docker.

С уважением,
Раджеш


CHill60

Если у вас есть вопрос или комментарий к сообщению, то используйте кнопку "есть вопрос или комментарий?" ссылка рядом с ним. Участник получит уведомление о вашем сообщении.
Я предлагаю вам удалить этот пост, так как это не решение проблемы

Рейтинг:
1

Richard Deeming

Если вы хотите использовать самозаверяющий сертификат, то вам нужно будет обойти проверку сертификата. Есть несколько предложений в этой области: этот поток StackOverflow[^]. Например:

using (var httpClientHandler = new HttpClientHandler())
{
    // NB: You should make this more robust by actually checking the certificate:
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
    
    using (var client = new HttpClient(httpClientHandler))
    {
        // Make your request...
    }
}

HttpClientHandler.Свойство ServerCertificateCustomValidationcallback (System.Net.Http) | Microsoft Docs[^]