private async Task <SignatureValidatorResult> AcceptAsync( Context context, PackageSigningStatus status) { await _packageSigningStateService.SetPackageSigningState( context.PackageKey, context.Message.PackageId, context.Message.PackageVersion, status); // Upload the package stream to storage if the package content has changed. Uri nupkgUri = null; if (context.Changed) { await _packageFileService.SaveAsync( context.Message.PackageId, context.Message.PackageVersion, context.Message.ValidationId, context.PackageStream); nupkgUri = await _packageFileService.GetReadAndDeleteUriAsync( context.Message.PackageId, context.Message.PackageVersion, context.Message.ValidationId); } return(new SignatureValidatorResult(ValidationStatus.Succeeded, nupkgUri)); }
public async Task SetPackageSigningState( int packageKey, string packageId, string packageVersion, PackageSigningStatus status) { if (string.IsNullOrEmpty(packageId)) { throw new ArgumentException(nameof(packageId)); } if (string.IsNullOrEmpty(packageVersion)) { throw new ArgumentException(nameof(packageVersion)); } // Update the signing state if it already exists, otherwise, create a new record. var signatureState = await _validationContext.PackageSigningStates.FirstOrDefaultAsync(s => s.PackageKey == packageKey); if (signatureState != null) { signatureState.SigningStatus = status; } else { _validationContext.PackageSigningStates.Add(new PackageSigningState { PackageId = packageId, PackageKey = packageKey, PackageNormalizedVersion = NuGetVersion.Parse(packageVersion).ToNormalizedString(), SigningStatus = status }); } }
public async Task WhenRepositorySigningIsRequired_FailsValidationOfPackageWhoseRepositorySignatureIsStripped( string resourceName, string packageId, string packageVersion, PackageSigningStatus signingStatus, bool allowSignedPackage) { // Arrange _packageStream = TestResources.GetResourceStream(resourceName); if (allowSignedPackage) { TestUtility.RequireSignedPackage(_corePackageService, packageId, packageVersion, TestResources.Leaf1Thumbprint); } else { TestUtility.RequireUnsignedPackage(_corePackageService, packageId, packageVersion); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{TestResources.RepoSignedPackageLeafId.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: true); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, signingStatus, shouldExtract: signingStatus == PackageSigningStatus.Valid); Assert.Empty(result.Issues); }
public async Task WhenStripsValidRepositorySignature_StripsAndAcceptsRepositorySignatureWhenRepositorySignatureIsNotRequired( string resourceName, string packageId, string packageVersion, PackageSigningStatus expectedSigningStatus) { // Arrange _configuration.StripValidRepositorySignatures = true; _configuration.AllowedRepositorySigningCertificates = new List <string> { TestResources.Leaf1Thumbprint, TestResources.Leaf2Thumbprint }; _packageStream = TestResources.GetResourceStream(resourceName); if (resourceName == TestResources.RepoSignedPackageLeaf1) { TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.RepoSignedPackageLeafId, TestResources.RepoSignedPackageLeaf1Version); } if (resourceName == TestResources.AuthorAndRepoSignedPackageLeaf1) { TestUtility.RequireSignedPackage(_corePackageService, TestResources.AuthorAndRepoSignedPackageLeafId, TestResources.AuthorAndRepoSignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: false); Stream uploadedStream = null; _packageFileService .Setup(x => x.SaveAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <Stream>())) .Returns(Task.CompletedTask) .Callback <string, string, Guid, Stream>((_, __, ___, s) => uploadedStream = s); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, expectedSigningStatus, _nupkgUri); Assert.Empty(result.Issues); _packageFileService.Verify( x => x.SaveAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId, It.IsAny <Stream>()), Times.Once); _packageFileService.Verify( x => x.GetReadAndDeleteUriAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId), Times.Once); Assert.IsType <FileStream>(uploadedStream); Assert.Throws <ObjectDisposedException>(() => uploadedStream.Length); }
public async Task DropsAllPackageSignaturesWhenPackageStateTransitionsToUnsigned() { // Arrange const int packageKey = 1; const string packageId = "packageId"; const string packageVersion = "1.0.0"; const PackageSigningStatus newStatus = PackageSigningStatus.Unsigned; var signature1 = new PackageSignature(); var signature2 = new PackageSignature(); var packageSigningState = new PackageSigningState { PackageId = packageId, PackageKey = packageKey, SigningStatus = PackageSigningStatus.Valid, PackageNormalizedVersion = packageVersion, PackageSignatures = new List <PackageSignature> { signature1, signature2 } }; var logger = _loggerFactory.CreateLogger <PackageSigningStateService>(); var packageSigningStatesDbSetMock = DbSetMockFactory.CreateMock(packageSigningState); var packageSignaturesDbSetMock = DbSetMockFactory.CreateMock(signature1, signature2); var validationContextMock = new Mock <IValidationEntitiesContext>(MockBehavior.Strict); validationContextMock.Setup(m => m.PackageSigningStates).Returns(packageSigningStatesDbSetMock.Object); validationContextMock.Setup(m => m.PackageSignatures).Returns(packageSignaturesDbSetMock.Object); // Act var packageSigningStateService = new PackageSigningStateService(validationContextMock.Object, logger); // Assert await packageSigningStateService.SetPackageSigningState( packageKey, packageId, packageVersion, status : newStatus); // Assert Assert.Equal(newStatus, packageSigningState.SigningStatus); packageSignaturesDbSetMock.Verify(m => m.Remove(signature1), Times.Once); packageSignaturesDbSetMock.Verify(m => m.Remove(signature2), Times.Once); validationContextMock.Verify( m => m.SaveChangesAsync(), Times.Never, "Saving the context here is incorrect as updating the validator's status also saves the context. Doing so would cause both queries not to be executed in the same transaction."); }
public async Task StripsAndAcceptsPackagesWithRepositorySignatures( string resourceName, string packageId, string packageVersion, PackageSigningStatus signingStatus, bool allowSignedPackage) { // Arrange _packageStream = TestResources.GetResourceStream(resourceName); if (allowSignedPackage) { TestUtility.RequireSignedPackage(_corePackageService, packageId, TestResources.Leaf1Thumbprint); } else { TestUtility.RequireUnsignedPackage(_corePackageService, packageId); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"), Guid.NewGuid()); Stream uploadedStream = null; _packageFileService .Setup(x => x.SaveAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <Stream>())) .Returns(Task.CompletedTask) .Callback <string, string, Guid, Stream>((_, __, ___, s) => uploadedStream = s); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, signingStatus, _nupkgUri); Assert.Empty(result.Issues); _packageFileService.Verify( x => x.SaveAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId, It.IsAny <Stream>()), Times.Once); _packageFileService.Verify( x => x.GetReadAndDeleteUriAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId), Times.Once); Assert.IsType <FileStream>(uploadedStream); Assert.Throws <ObjectDisposedException>(() => uploadedStream.Length); }
public async Task SetPackageSigningState( int packageKey, string packageId, string packageVersion, PackageSigningStatus status) { if (string.IsNullOrEmpty(packageId)) { throw new ArgumentException(nameof(packageId)); } if (string.IsNullOrEmpty(packageVersion)) { throw new ArgumentException(nameof(packageVersion)); } // Update the signing state if it already exists, otherwise, create a new record. var signatureState = await _validationContext .PackageSigningStates .Include(s => s.PackageSignatures) .FirstOrDefaultAsync(s => s.PackageKey == packageKey); if (signatureState != null) { signatureState.SigningStatus = status; // Remove all stored signatures if the package is transitioning to an unsigned state. if (status == PackageSigningStatus.Unsigned) { foreach (var signature in signatureState.PackageSignatures.ToList()) { _validationContext.PackageSignatures.Remove(signature); } } } else { _validationContext.PackageSigningStates.Add(new PackageSigningState { PackageId = packageId, PackageKey = packageKey, PackageNormalizedVersion = NuGetVersion.Parse(packageVersion).ToNormalizedString(), SigningStatus = status }); } }
private void Validate(ValidationStatus validationStatus, PackageSigningStatus packageSigningStatus) { Assert.Equal(validationStatus, _validation.State); _packageSigningStateService.Verify( x => x.SetPackageSigningState( _validation.PackageKey, _message.PackageId, _message.PackageVersion, packageSigningStatus), Times.Once); _packageSigningStateService.Verify( x => x.SetPackageSigningState( It.IsAny <int>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <PackageSigningStatus>()), Times.Once); }
private void Validate( SignatureValidatorResult result, ValidationStatus validationStatus, PackageSigningStatus packageSigningStatus, Uri nupkgUri = null, bool?shouldExtract = null) { Assert.Equal(validationStatus, result.State); Assert.Equal(nupkgUri, result.NupkgUri); _packageSigningStateService.Verify( x => x.SetPackageSigningState( _packageKey, _message.PackageId, _message.PackageVersion, packageSigningStatus), Times.Once); _packageSigningStateService.Verify( x => x.SetPackageSigningState( It.IsAny <int>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <PackageSigningStatus>()), Times.Once); if ((shouldExtract.HasValue && shouldExtract.Value) || (validationStatus == ValidationStatus.Succeeded && packageSigningStatus == PackageSigningStatus.Valid)) { _signaturePartsExtractor.Verify( x => x.ExtractAsync(_packageKey, It.Is <PrimarySignature>(y => y != null), It.IsAny <CancellationToken>()), Times.Once); _signaturePartsExtractor.Verify( x => x.ExtractAsync(It.IsAny <int>(), It.IsAny <PrimarySignature>(), It.IsAny <CancellationToken>()), Times.Once); } else { _signaturePartsExtractor.Verify( x => x.ExtractAsync(It.IsAny <int>(), It.IsAny <PrimarySignature>(), It.IsAny <CancellationToken>()), Times.Never); } _corePackageService.VerifyAll(); }
public async Task WhenStripsValidRepositorySignature_AcceptsRepositorySignatureWhenRepositorySignatureIsRequired( string resourceName, string packageId, string packageVersion, PackageSigningStatus expectedSigningStatus) { // Arrange _configuration.StripValidRepositorySignatures = true; _configuration.AllowedRepositorySigningCertificates = new List <string> { TestResources.Leaf1Thumbprint, TestResources.Leaf2Thumbprint }; _packageStream = TestResources.GetResourceStream(resourceName); if (resourceName == TestResources.RepoSignedPackageLeaf1) { TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.RepoSignedPackageLeafId, TestResources.RepoSignedPackageLeaf1Version); } if (resourceName == TestResources.AuthorAndRepoSignedPackageLeaf1) { TestUtility.RequireSignedPackage(_corePackageService, TestResources.AuthorAndRepoSignedPackageLeafId, TestResources.AuthorAndRepoSignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: true); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, expectedSigningStatus); Assert.Empty(result.Issues); }
public async Task AddsNewStateWhenSignatureStateIsNull() { // Arrange const int packageKey = 1; const string packageId = "packageId"; const string packageVersion = "1.0.0"; const PackageSigningStatus newStatus = PackageSigningStatus.Invalid; var logger = _loggerFactory.CreateLogger <PackageSigningStateService>(); var packageSigningStatesDbSetMock = DbSetMockFactory.Create <PackageSigningState>(); var validationContextMock = new Mock <IValidationEntitiesContext>(MockBehavior.Strict); validationContextMock.Setup(m => m.PackageSigningStates).Returns(packageSigningStatesDbSetMock); // Act var packageSigningStateService = new PackageSigningStateService(validationContextMock.Object, logger); // Assert await packageSigningStateService.SetPackageSigningState( packageKey, packageId, packageVersion, status : newStatus); // Assert var newState = validationContextMock.Object.PackageSigningStates.FirstOrDefault(); Assert.NotNull(newState); Assert.Equal(packageKey, newState.PackageKey); Assert.Equal(packageId, newState.PackageId); Assert.Equal(packageVersion, newState.PackageNormalizedVersion); Assert.Equal(newStatus, newState.SigningStatus); validationContextMock.Verify( m => m.SaveChangesAsync(), Times.Never, "Saving the context here is incorrect as updating the validator's status also saves the context. Doing so would cause both queries not to be executed in the same transaction."); }
public async Task SetPackageSigningState( int packageKey, string packageId, string packageVersion, PackageSigningStatus status) { if (string.IsNullOrEmpty(packageId)) { throw new ArgumentException(nameof(packageId)); } if (string.IsNullOrEmpty(packageVersion)) { throw new ArgumentException(nameof(packageVersion)); } // It is possible this package has already been validated. If so, the package's state will already exist // in the database. Updates to this state should only be requested on explicit revalidation gestures. However, // this invariant may be broken due to message duplication. var signatureState = await _validationContext.PackageSigningStates.FirstOrDefaultAsync(s => s.PackageKey == packageKey); if (signatureState != null) { signatureState.SigningStatus = status; } else { // This package does not have a persisted record for its state. Create a new one. _validationContext.PackageSigningStates.Add(new PackageSigningState { PackageId = packageId, PackageKey = packageKey, PackageNormalizedVersion = NuGetVersion.Parse(packageVersion).ToNormalizedString(), SigningStatus = status }); } }
private async Task AcceptAsync(ValidatorStatus validation, SignatureValidationMessage message, PackageSigningStatus status) { await _packageSigningStateService.SetPackageSigningState( validation.PackageKey, message.PackageId, message.PackageVersion, status); validation.State = ValidationStatus.Succeeded; }
private void VerifyPackageSigningStatus(SignatureValidatorResult result, ValidationStatus validationStatus, PackageSigningStatus packageSigningStatus) { Assert.Equal(validationStatus, result.State); var state = _validationEntitiesContext .Object .PackageSigningStates .Where(x => x.PackageKey == _packageKey) .SingleOrDefault(); Assert.Equal(state.PackageId, _message.PackageId); Assert.Equal(state.PackageNormalizedVersion, _message.PackageVersion); Assert.Equal(state.SigningStatus, packageSigningStatus); }