Skip to content
This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
/ NuGet.Jobs Public archive

[Repository Signing] Add option to suppress repository signature extraction #495

Merged
merged 4 commits into from
Jul 26, 2018
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
Expand Up @@ -20,5 +20,11 @@ public class ProcessSignatureConfiguration
/// repository signature is removed.
/// </summary>
public string V3ServiceIndexUrl { get; set; }

/// <summary>
/// Whether repository signatures should be persisted to the database. Disable this if repository signing
/// is in test mode and repository signed packages are not published.
/// </summary>
public bool CommitRepositorySignatures { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf6ce6768ef858a3a667be1af8aa524d386c7f59a34542713f5dfb0d79acf3dd"
],
"V3ServiceIndexUrl": "https://apidev.nugettest.org/v3/index.json"
"V3ServiceIndexUrl": "https://apidev.nugettest.org/v3/index.json",
"CommitRepositorySignatures": false
},

"PackageDownloadTimeout": "00:10:00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf6ce6768ef858a3a667be1af8aa524d386c7f59a34542713f5dfb0d79acf3dd"
],
"V3ServiceIndexUrl": "https://apiint.nugettest.org/v3/index.json"
"V3ServiceIndexUrl": "https://apiint.nugettest.org/v3/index.json",
"CommitRepositorySignatures": false
},

"PackageDownloadTimeout": "00:10:00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"AllowedRepositorySigningCertificates": [
"cf7ac17ad047ecd5fdc36822031b12d4ef078b6f2b4c5e6ba41f8ff2cf4bad67"
],
"V3ServiceIndexUrl": "https://api.nuget.org/v3/index.json"
"V3ServiceIndexUrl": "https://api.nuget.org/v3/index.json",
"CommitRepositorySignatures": false
},

"PackageDownloadTimeout": "00:10:00",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NuGet.Jobs.Validation.PackageSigning.Storage;
using NuGet.Packaging.Signing;
using NuGet.Services.Validation;
Expand All @@ -18,15 +19,18 @@ public class SignaturePartsExtractor : ISignaturePartsExtractor
{
private readonly ICertificateStore _certificateStore;
private readonly IValidationEntitiesContext _entitiesContext;
private readonly IOptionsSnapshot<ProcessSignatureConfiguration> _configuration;
private readonly ILogger<SignaturePartsExtractor> _logger;

public SignaturePartsExtractor(
ICertificateStore certificateStore,
IValidationEntitiesContext entitiesContext,
IOptionsSnapshot<ProcessSignatureConfiguration> configuration,
ILogger<SignaturePartsExtractor> logger)
{
_certificateStore = certificateStore ?? throw new ArgumentNullException(nameof(certificateStore));
_entitiesContext = entitiesContext ?? throw new ArgumentNullException(nameof(entitiesContext));
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Expand Down Expand Up @@ -227,6 +231,12 @@ private async Task InitializePackageSignatureAndTrustedTimestampAsync(
return;
}

if (type == PackageSignatureType.Repository && !_configuration.Value.CommitRepositorySignatures)
{
_logger.LogInformation("Skipping initialization of repository signature due to configuration!");
return;
}

// Initialize the package signature record.
var packageSignature = await InitializePackageSignatureAsync(
packageKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NuGet.Jobs.Validation.PackageSigning;
using NuGet.Jobs.Validation.PackageSigning.ProcessSignature;
using NuGet.Jobs.Validation.PackageSigning.Storage;
using NuGet.Packaging.Signing;
Expand Down Expand Up @@ -62,7 +64,7 @@ public class SignaturePartsExtractorFacts
"CN=NUGET_DO_NOT_TRUST.root.test.test, OU=Test Organizational Unit Name, O=Test Organization Name, L=Redmond, S=WA, C=US",
TestResources.RootThumbprint),
},
TimestampEndCertificate = new SubjectAndThumbprint(
TimestampEndCertificate = new SubjectAndThumbprint(
"CN=Symantec SHA256 TimeStamping Signer - G2, OU=Symantec Trust Network, O=Symantec Corporation, C=US",
TestResources.Leaf1TimestampThumbprint),
TimestampParentCertificates = new[]
Expand Down Expand Up @@ -116,6 +118,8 @@ public class ExtractAsync
private readonly Mock<ICertificateStore> _certificateStore;
private readonly List<X509Certificate2> _savedCertificates;
private readonly Mock<IValidationEntitiesContext> _entitiesContext;
private readonly Mock<IOptionsSnapshot<ProcessSignatureConfiguration>> _configAccessor;
private readonly ProcessSignatureConfiguration _config;
private readonly Mock<ILogger<SignaturePartsExtractor>> _logger;
private readonly SignaturePartsExtractor _target;

Expand Down Expand Up @@ -152,11 +156,20 @@ public ExtractAsync()
.Setup(x => x.TrustedTimestamps)
.Returns(DbSetMockFactory.Create<TrustedTimestamp>());

_configAccessor = new Mock<IOptionsSnapshot<ProcessSignatureConfiguration>>();
_config = new ProcessSignatureConfiguration
{
CommitRepositorySignatures = true
};

_configAccessor.Setup(a => a.Value).Returns(_config);

_logger = new Mock<ILogger<SignaturePartsExtractor>>();

_target = new SignaturePartsExtractor(
_certificateStore.Object,
_entitiesContext.Object,
_configAccessor.Object,
_logger.Object);
}

Expand Down Expand Up @@ -616,6 +629,51 @@ public async Task IgnoreExtraCertificates()
signature.SignedCms.Certificates.Count + signature.Timestamps.Sum(x => x.SignedCms.Certificates.Count));
}

[Fact]
public async Task IfRepositorySignatureExtractionIsDisabled_IgnoresRepositorySignatureOnRepositorySignedPackage()
{
// Arrange
var signature = await TestResources.LoadPrimarySignatureAsync(TestResources.RepoSignedPackageLeaf1);

_entitiesContext
.Setup(x => x.PackageSignatures)
.Returns(DbSetMockFactory.Create<PackageSignature>());

_config.CommitRepositorySignatures = false;

// Act
await _target.ExtractAsync(_packageKey, signature, _token);

// Assert
Assert.Equal(0, _entitiesContext.Object.PackageSignatures.Count());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe assert blobs are persisted, so we have expected behavior covered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


// The repository signature's certificate is still stored on blob storage.
VerifyStoredCertificates(Leaf1Certificates);
}

[Fact]
public async Task IfRepositorySignatureExtractionIsDisabled_IgnoresRepositorySignatureOnRepositoryCounterSignedPackage()
{
// Arrange
var signature = await TestResources.LoadPrimarySignatureAsync(TestResources.AuthorAndRepoSignedPackageLeaf1);

_entitiesContext
.Setup(x => x.PackageSignatures)
.Returns(DbSetMockFactory.Create<PackageSignature>());

_config.CommitRepositorySignatures = false;

// Act
await _target.ExtractAsync(_packageKey, signature, _token);

// Assert
Assert.Equal(1, _entitiesContext.Object.PackageSignatures.Count());
Assert.Equal(PackageSignatureType.Author, _entitiesContext.Object.PackageSignatures.First().Type);

// The repository signature's certificate is still stored on blob storage.
VerifyStoredCertificates(AuthorAndRepoSignedCertificates);
}

private void AssignIds()
{
var endCertificates = _entitiesContext.Object.EndCertificates.AsQueryable().ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,21 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt

_certificateStore = new Mock<ICertificateStore>();

// These dependencies are concrete.
_configuration = new ProcessSignatureConfiguration
{
AllowedRepositorySigningCertificates = new List<string> { "fake-thumbprint" },
V3ServiceIndexUrl = TestResources.V3ServiceIndexUrl,
CommitRepositorySignatures = true,
};
_optionsSnapshot = new Mock<IOptionsSnapshot<ProcessSignatureConfiguration>>();
_optionsSnapshot.Setup(x => x.Value).Returns(() => _configuration);
_formatValidator = new SignatureFormatValidator(_optionsSnapshot.Object);

_signaturePartsExtractor = new SignaturePartsExtractor(
_certificateStore.Object,
_validationEntitiesContext.Object,
_optionsSnapshot.Object,
loggerFactory.CreateLogger<SignaturePartsExtractor>());

_packageFileService = new Mock<IProcessorPackageFileService>();
Expand All @@ -144,16 +156,6 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt

_corePackageService = new Mock<ICorePackageService>();

// These dependencies are concrete.
_configuration = new ProcessSignatureConfiguration
{
AllowedRepositorySigningCertificates = new List<string> { "fake-thumbprint" },
V3ServiceIndexUrl = TestResources.V3ServiceIndexUrl,
};
_optionsSnapshot = new Mock<IOptionsSnapshot<ProcessSignatureConfiguration>>();
_optionsSnapshot.Setup(x => x.Value).Returns(() => _configuration);
_formatValidator = new SignatureFormatValidator(_optionsSnapshot.Object);

_telemetryClient = new Mock<ITelemetryClient>();
_telemetryService = new TelemetryService(_telemetryClient.Object);

Expand Down