Skip to content
Snippets Groups Projects
CertificateValidation.cs 7.42 KiB
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using Autofac;
using FitConnect;
using FitConnect.Encryption;
using FitConnect.Models;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using MockContainer;
using Newtonsoft.Json;
using NUnit.Framework;

namespace IntegrationTests;

[TestFixture]
public class CertificateValidation {
    [SetUp]
    public void Setup() {
        var container = Container.Create();
        _settings = container.Resolve<IFitConnectSettings>();

        _logger = LoggerFactory.Create(
            builder => {
                builder.AddConsole();
                builder.SetMinimumLevel(LogLevel.Debug);
            }).CreateLogger("E2E Test");


        _certificateHelper = new CertificateHelper(_logger);
    }

    private IFitConnectSettings _settings = null!;
    private ILogger _logger = null!;
    private CertificateHelper _certificateHelper = null!;

    [Test]
    [Ignore("No credentials for dev environment")]
    public void CheckCertificateInEnvironment_Dev() {
        var environment = FitConnectEnvironment.Develop;
        var sender = Client.GetSender(environment, _settings.SenderClientId,
            _settings.SenderClientSecret,
            _logger);

        var certificate = (sender as FitConnect.Sender)!
            .GetPublicKeyForDestinationAsync(_settings.DestinationId).Result;
        new CertificateHelper(_logger).ValidateCertificateJsonWebKeyAsync(
            JsonWebKey.Create(certificate),
            null,
            LogLevel.Trace).Wait();
    }

    [Test]
    public void CheckCertificateInEnvironment_Testing() {
        var environment = FitConnectEnvironment.Testing;
        var sender = Client.GetSender(environment, _settings.SenderClientId,
            _settings.SenderClientSecret,
            _logger);

        var certificate = (sender as FitConnect.Sender)!
            .GetPublicKeyForDestinationAsync(_settings.DestinationId).Result;
        new CertificateHelper(_logger).ValidateCertificateJsonWebKeyAsync(
            JsonWebKey.Create(certificate),
            null,
            LogLevel.Trace);
    }


    [Test]
    [Ignore("No credentials for staging environment")]
    public void CheckCertificateInEnvironment_Staging() {
        var environment = FitConnectEnvironment.Staging;
        var sender = Client.GetSender(environment, _settings.SenderClientId,
            _settings.SenderClientSecret,
            _logger);

        Assert.Throws<AggregateException>(() => {
            sender.SendAsync(SubmissionBuilder.WithDestination(_settings.DestinationId)
                .WithServiceType("", _settings.LeikaKey)
                .WithJsonData(@"{""data"":""value""}")
                .WithAttachments(new Attachment("Test.pdf", "Simple Test PDF"))
                .Build()).Wait();
        })!.InnerExceptions.Any(e => e.GetType() == typeof(SecurityException)).Should().BeTrue();
    }

    [Test]
    [Ignore("No credentials for production environment")]
    public void CheckCertificateInEnvironment_Production() {
        var environment = FitConnectEnvironment.Production;
        var sender = Client.GetSender(environment, _settings.SenderClientId,
            _settings.SenderClientSecret,
            _logger);

        Assert.Throws<AggregateException>(() => {
            sender.SendAsync(SubmissionBuilder.WithDestination(_settings.DestinationId)
                .WithServiceType("", _settings.LeikaKey)
                .WithJsonData(@"{""data"":""value""}")
                .WithAttachments(new Attachment("Test.pdf", "Simple Test PDF"))
                .Build()).Wait();
        })!.InnerExceptions.Any(e => e.GetType() == typeof(SecurityException)).Should().BeTrue();
    }

    [Test]
    public void CheckPublicKeyEncryption() {
        _certificateHelper
            .ValidateCertificateJsonWebKeyAsync(new JsonWebKey(_settings.PublicKeyEncryption))
            .Result
            .Should().BeFalse();
    }

    [Test]
    public void CheckPublicKeySignature() {
        _certificateHelper
            .ValidateCertificateJsonWebKeyAsync(
                new JsonWebKey(_settings.PublicKeySignatureVerification))
            .Result
            .Should().BeFalse();
    }


    [Test]
    [Ignore("Certificate from server is invalid, x5c are mixed")]
    public void TestDvdvCertificate() {
        var destinationJson = new HttpClient()
            .GetStringAsync(
                "https://dvdv-microservice-fit-connect.governikus-asp.de/dvdv-fitconnect/v1/destinations/f05bdafc-3ee7-418f-ab30-3c9fe6e1c7d6")
            .Result;

        var destination = (dynamic)JsonConvert.DeserializeObject(destinationJson)!;
        var content = JsonConvert.SerializeObject(destination.publicKeys.keys[0])!;
        var jwk = new JsonWebKey(content);
        var result = _certificateHelper.ValidateCertificateJsonWebKeyAsync(jwk).Result;
        result.Should().BeTrue();
    }
    [Test]
    [Ignore("Not implemented")]
    public void CheckPemFiles() {
        if (!Directory.Exists("./certificates") || !Directory.Exists("./certificates/roots")) {
            Assert.Inconclusive("No certificates found");
            return;
        }

        var files = Directory.GetFiles("./certificates");
        var success = 0;
        var failed = 0;
        var failedCerts = new List<string>();

        foreach (var fileName in files.Where(f => !f.EndsWith("root.pem"))) {
            _logger.LogInformation(
                "\n\n-----------------------------------------\nChecking file: {FileName}",
                fileName);


            if (fileName.EndsWith(".pem")) {
                var certificate = X509Certificate2.CreateFromPem(File.ReadAllText(fileName));
                var valid = _certificateHelper.ValidateCertificatePemAsync(certificate).Result;
                if (valid) {
                    success++;
                }
                else {
                    failed++;
                    failedCerts.Add(fileName);
                }
            }

            if (fileName.EndsWith(".json")) {
                var shouldFail = !fileName.Contains("/valid");
                var keySetImport = new JsonWebKeySet(File.ReadAllText(fileName));
                var keySet = keySetImport.Keys.Count != 0
                    ? keySetImport.Keys.ToList()
                    : new List<JsonWebKey> {
                        new(File.ReadAllText(fileName))
                    };

                foreach (var jwk in keySet) {
                    var valid = _certificateHelper.ValidateCertificateJsonWebKeyAsync(jwk,
                        Directory.GetFiles("./certificates/roots")
                            .Select(file => new X509Certificate2(file)).ToArray(),
                        shouldFail ? LogLevel.Warning : LogLevel.Critical
                    ).Result;

                    if (shouldFail)
                        valid = !valid;

                    if (valid) {
                        success++;
                    }
                    else {
                        failed++;
                        failedCerts.Add(fileName);
                    }
                }
            }
        }

        _logger.LogWarning("Failed certificates: {Certs}",
            failedCerts.Aggregate("\n", (a, b) => a + "\t - " + b + "\n"));
        _logger.LogInformation("Success: {Success}, Failed: {Failed}", success, failed);
        failed.Should().Be(0);
    }
}