public async Task EnqueueVerificationAsync(IValidationRequest request, EndCertificate certificate)
        {
            var message         = new CertificateValidationMessage(certificate.Key, request.ValidationId);
            var brokeredMessage = _serializer.Serialize(message);

            await _topicClient.SendAsync(brokeredMessage);
        }
        private bool HasOwnerWithInvalidUsername(IValidationRequest request)
        {
            var registration = _packages.FindPackageRegistrationById(request.PackageId);

            if (registration == null)
            {
                _logger.LogError("Attempted to validate package that has no package registration");

                throw new InvalidOperationException($"Registration for package id {request.PackageId} does not exist");
            }

            var owners = registration.Owners.Select(o => o.Username).ToList();

            if (owners.Any(UsernameHelper.IsInvalid))
            {
                _logger.LogWarning(
                    "Package {PackageId} {PackageVersion} has an owner with an invalid username. {Owners}",
                    request.PackageId,
                    request.PackageVersion,
                    owners);

                return(true);
            }

            return(false);
        }
Пример #3
0
        public async Task <ValidatorStatus> TryAddValidatorStatusAsync(IValidationRequest request, ValidatorStatus status, ValidationStatus desiredState)
        {
            status.State = desiredState;

            var result = await AddStatusAsync(status);

            if (result == AddStatusResult.StatusAlreadyExists)
            {
                // The add operation fails if another instance of this service has already created the status.
                // This may happen due to repeated operations kicked off by the Orchestrator. Return the result from
                // the other add operation.
                _logger.LogWarning(
                    Error.ValidatorStateServiceFailedToAddStatus,
                    "Failed to add validation status for {ValidationId} ({PackageId} {PackageVersion}) as a record already exists",
                    request.PackageId,
                    request.PackageVersion);

                return(await GetStatusAsync(request));
            }
            else if (result != AddStatusResult.Success)
            {
                throw new NotSupportedException($"Unknown {nameof(AddStatusResult)}: {result}");
            }

            return(status);
        }
Пример #4
0
        public async Task <ValidationStatus> GetStatusAsync(IValidationRequest request)
        {
            if (ShouldSkip(request))
            {
                return(ValidationStatus.Succeeded);
            }

            var audit = await _validationAuditor.ReadAuditAsync(
                request.ValidationId,
                NormalizePackageId(request.PackageId),
                NormalizePackageVersion(request.PackageVersion));

            if (audit == null)
            {
                return(ValidationStatus.NotStarted);
            }

            var validationStatusList = audit
                                       .Entries
                                       .Where(x => x.ValidatorName == ValidatorName)
                                       .Select(x => GetValidationStatus(request, x.EventId))
                                       .ToList();

            return(validationStatusList.FirstOrDefault(x => x == ValidationStatus.Failed) ??
                   validationStatusList.FirstOrDefault(x => x == ValidationStatus.Succeeded) ??
                   ValidationStatus.Incomplete);
        }
Пример #5
0
        public async Task <ValidatorStatus> TryUpdateValidationStatusAsync(IValidationRequest request, ValidatorStatus validatorStatus, ValidationStatus desiredState)
        {
            validatorStatus.State = desiredState;

            var result = await SaveStatusAsync(validatorStatus);

            if (result == SaveStatusResult.StaleStatus)
            {
                // The save operation fails if another instance of this service has already modified the status.
                // This may happen due to repeated operations kicked off by the Orchestrator. Return the result
                // from the other update.
                _logger.LogWarning(
                    Error.ValidatorStateServiceFailedToUpdateStatus,
                    "Failed to save validation status for {ValidationId} ({PackageId} {PackageVersion}) as the current status is stale",
                    request.PackageId,
                    request.PackageVersion);

                return(await GetStatusAsync(request));
            }
            else if (result != SaveStatusResult.Success)
            {
                throw new NotSupportedException($"Unknown {nameof(SaveStatusResult)}: {result}");
            }

            return(validatorStatus);
        }
        public async Task <IValidationResult> StartAsync(IValidationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var validatorStatus = await _validatorStateService.GetStatusAsync(request);

            if (validatorStatus.State != ValidationStatus.NotStarted)
            {
                _logger.LogWarning(
                    "Scan only validation with validation Id {ValidationId} ({PackageId} {PackageVersion}) has already started.",
                    request.ValidationId,
                    request.PackageId,
                    request.PackageVersion);

                return(validatorStatus.ToValidationResult());
            }

            if (ShouldSkipScan(request))
            {
                return(ValidationResult.Succeeded);
            }

            await _scanAndSignEnqueuer.EnqueueScanAsync(request.ValidationId, request.NupkgUrl);

            var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete);

            return(result.ToValidationResult());
        }
Пример #7
0
        public async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request)
        {
            var status = await GetStatusAsync(request.ValidationId);

            if (status == null)
            {
                return(new ValidatorStatus
                {
                    ValidationId = request.ValidationId,
                    PackageKey = request.PackageKey,
                    ValidatorName = _validatorName,
                    State = ValidationStatus.NotStarted,
                    ValidatorIssues = new List <ValidatorIssue>(),
                });
            }
            else if (status.PackageKey != request.PackageKey)
            {
                throw new ArgumentException(
                          $"Validation expected package key {status.PackageKey}, actual {request.PackageKey}",
                          nameof(request));
            }
            else if (status.ValidatorName != _validatorName)
            {
                throw new ArgumentException(
                          $"Validation expected validator {status.ValidatorName}, actual {_validatorName}",
                          nameof(request));
            }

            return(status);
        }
Пример #8
0
        public async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request)
        {
            var status = await _validationContext
                         .ValidatorStatuses
                         .Where(s => s.ValidationId == request.ValidationId)
                         .FirstOrDefaultAsync();

            if (status == null)
            {
                return(new ValidatorStatus
                {
                    ValidationId = request.ValidationId,
                    PackageKey = request.PackageKey,
                    ValidatorName = _validatorName,
                    State = ValidationStatus.NotStarted,
                });
            }
            else if (status.PackageKey != request.PackageKey)
            {
                throw new ArgumentException(
                          $"Validation expected package key {status.PackageKey}, actual {request.PackageKey}",
                          nameof(request));
            }
            else if (status.ValidatorName != _validatorName)
            {
                throw new ArgumentException(
                          $"Validation expected validator {status.ValidatorName}, actual {_validatorName}",
                          nameof(request));
            }

            return(status);
        }
Пример #9
0
        /// <summary>
        /// Kicks off the package verification process for the given request. Verification will begin when the
        /// <see cref="ValidationEntitiesContext"/> has a <see cref="ValidatorStatus"/> that matches the
        /// <see cref="IValidationRequest"/>'s validationId. Once verification completes, the <see cref="ValidatorStatus"/>'s
        /// State will be updated to "Succeeded" or "Failed".
        /// </summary>
        /// <param name="request">The request that details the package to be verified.</param>
        /// <returns>A task that will complete when the verification process has been queued.</returns>
        public Task EnqueueVerificationAsync(IValidationRequest request)
        {
            var brokeredMessage = _signatureValidationSerializer.Serialize(
                new SignatureValidationMessage(request.PackageId, request.PackageVersion, new Uri(request.NupkgUrl), request.ValidationId));

            return(_topicClient.SendAsync(brokeredMessage));
        }
Пример #10
0
        public ScanAndSignEnqueuerFactsBase()
        {
            _topicClientMock           = new Mock <ITopicClient>();
            _serializerMock            = new Mock <IBrokeredMessageSerializer <ScanAndSignMessage> >();
            _logger                    = Mock.Of <ILogger <ScanAndSignEnqueuer> >();
            _configurationAccessorMock = new Mock <IOptionsSnapshot <ScanAndSignEnqueuerConfiguration> >();

            _configuration = new ScanAndSignEnqueuerConfiguration();
            _configurationAccessorMock
            .SetupGet(ca => ca.Value)
            .Returns(_configuration);

            _target = new ScanAndSignEnqueuer(
                _topicClientMock.Object,
                _serializerMock.Object,
                _configurationAccessorMock.Object,
                _logger);

            _validationRequest = new ValidationRequest(Guid.NewGuid(), 42, "somepackage", "someversion", "https://example.com/testpackage.nupkg");
            _owners            = new List <string> {
                "Billy", "Bob"
            };

            _serializedMessage = new BrokeredMessageWrapper("somedata");

            _serializerMock
            .Setup(s => s.Serialize(It.IsAny <ScanAndSignMessage>()))
            .Callback <ScanAndSignMessage>(m => _capturedMessage = m)
            .Returns(_serializedMessage);

            _topicClientMock
            .Setup(tc => tc.SendAsync(It.IsAny <IBrokeredMessage>()))
            .Callback <IBrokeredMessage>(m => _capturedBrokeredMessage = m)
            .Returns(Task.CompletedTask);
        }
Пример #11
0
        /// <summary>
        /// The pattern used for the StartAsync:
        /// 1. Check if a validation was already started
        /// 2. Only if a validation was not started queue the message to be processed.
        /// 3. After the message is queued, update the ValidatorStatus for the <paramref name="request"/>.
        /// </summary>
        /// <param name="request">The request to be send to the validator job queue.</param>
        /// <returns>The validation status.</returns>
        public async Task <IValidationResult> StartAsync(IValidationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var validatorStatus = await _validatorStateService.GetStatusAsync(request);

            // See issue https://github.com/NuGet/NuGetGallery/issues/6249
            validatorStatus.ValidatingType = ValidatingType.SymbolPackage;

            if (validatorStatus.State != ValidationStatus.NotStarted)
            {
                _logger.LogWarning(
                    "Symbol validation for {PackageId} {PackageNormalizedVersion} has already started.",
                    request.PackageId,
                    request.PackageVersion);

                return(validatorStatus.ToValidationResult());
            }

            // Due to race conditions or failure of method TryAddValidatorStatusAsync the same message can be enqueued multiple times
            // Log this information to postmortem evaluate this behavior
            _telemetryService.TrackSymbolsMessageEnqueued(ValidatorName.SymbolsValidator, request.ValidationId);
            await _symbolMessageEnqueuer.EnqueueSymbolsValidationMessageAsync(request);

            var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete);

            return(result.ToValidationResult());
        }
        public async Task CleanUpAsync(IValidationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var validatorStatus = await _validatorStateService.GetStatusAsync(request);

            if (validatorStatus.NupkgUrl == null)
            {
                return;
            }

            if (!_configuration.RepositorySigningEnabled)
            {
                _logger.LogWarning(
                    "Skipping cleanup of .nupkg for validation ID {ValidationId} ({PackageId} {PackageVersion})",
                    request.ValidationId,
                    request.PackageId,
                    request.PackageVersion);

                return;
            }

            _logger.LogInformation(
                "Cleaning up the .nupkg URL for validation ID {ValidationId} ({PackageId} {PackageVersion}).",
                request.ValidationId,
                request.PackageId,
                request.PackageVersion);

            var blob = _blobProvider.GetBlobFromUrl(validatorStatus.NupkgUrl);
            await blob.DeleteIfExistsAsync();
        }
        private async Task <bool> ShouldRepositorySignAsync(IValidationRequest request, List <string> owners)
        {
            var hasRepositorySignature = await _validationContext
                                         .PackageSignatures
                                         .Where(s => s.PackageKey == request.PackageKey)
                                         .Where(s => s.Type == PackageSignatureType.Repository)
                                         .AnyAsync();

            if (hasRepositorySignature)
            {
                _logger.LogInformation(
                    "Package {PackageId} {PackageVersion} already has a repository signature. Scanning instead of signing package",
                    request.PackageId,
                    request.PackageVersion);

                return(false);
            }

            // TODO: Remove this check.
            // See: https://github.com/NuGet/Engineering/issues/1582
            if (owners.Any(UsernameHelper.IsInvalid))
            {
                _logger.LogWarning(
                    "Package {PackageId} {PackageVersion} has an owner with an invalid username. Scanning instead of signing. {Owners}",
                    request.PackageId,
                    request.PackageVersion,
                    owners);

                return(false);
            }

            return(true);
        }
Пример #14
0
        private async Task <ValidatorStatus> StartInternalAsync(IValidationRequest request)
        {
            // Check that this is the first validation for this specific request.
            var validatorStatus = await _validatorStateService.GetStatusAsync(request);

            if (validatorStatus.State != ValidationStatus.NotStarted)
            {
                _logger.LogWarning(
                    "Package Signing validation with validationId {ValidationId} ({PackageId} {PackageVersion}) has already started.",
                    request.ValidationId,
                    request.PackageId,
                    request.PackageVersion);

                return(validatorStatus);
            }

            // Kick off the verification process. Note that the jobs will not verify the package until the
            // state of this validator has been persisted to the database.
            var stopwatch = Stopwatch.StartNew();

            await _signatureVerificationEnqueuer.EnqueueVerificationAsync(request);

            var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete);

            _telemetryService.TrackDurationToStartPackageSigningValidator(stopwatch.Elapsed);

            return(result);
        }
        public async Task UsesProperNupkgUrl(bool existsInPublicContainer, bool existsInValidationContainer, string expectedUrlSubstring)
        {
            UseDefaultValidatorProvider();
            var validator = AddValidation("validation1", TimeSpan.FromDays(1));

            PackageFileServiceMock
            .Setup(pfs => pfs.DoesPackageFileExistAsync(Package))
            .ReturnsAsync(existsInPublicContainer);
            PackageFileServiceMock
            .Setup(pfs => pfs.DoesValidationPackageFileExistAsync(Package))
            .ReturnsAsync(existsInValidationContainer);
            IValidationRequest validationRequest = null;

            validator
            .Setup(v => v.GetStatusAsync(It.IsAny <IValidationRequest>()))
            .ReturnsAsync(ValidationStatus.NotStarted)
            .Callback <IValidationRequest>(vr => validationRequest = vr);

            var processor = CreateProcessor();
            await processor.ProcessValidationsAsync(ValidationSet, Package);

            validator
            .Verify(v => v.GetStatusAsync(It.IsAny <IValidationRequest>()), Times.AtLeastOnce());
            Assert.NotNull(validationRequest);
            Assert.Contains(expectedUrlSubstring, validationRequest.NupkgUrl);
            Assert.Equal(Package.PackageRegistration.Id, validationRequest.PackageId);
            Assert.Equal(Package.NormalizedVersion, validationRequest.PackageVersion);
        }
Пример #16
0
 /// <summary>
 /// Find the state of a package's signing.
 /// </summary>
 /// <param name="request">The validation request containing the package whose signing state should be fetched.</param>
 /// <returns>The package's signing state.</returns>
 private Task <PackageSigningState> FindPackageSigningStateAsync(IValidationRequest request)
 {
     return(_validationContext
            .PackageSigningStates
            .Where(p => p.PackageKey == request.PackageKey)
            .FirstAsync());
 }
        private async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request)
        {
            // Look up this validator's state in the database.
            var status = await _validatorStateService.GetStatusAsync(request);

            if (status.State != ValidationStatus.Incomplete)
            {
                return(status);
            }

            // Wait until ALL certificate validations kicked off by this validation request have finished.
            if (!await AllCertificateValidationsAreFinishedAsync(request))
            {
                // We know this status is incomplete.
                return(status);
            }

            // All of the requested certificate validations have finished. At this point, the signature
            // may have a status of "Unknown" if the package is at ingestion and its signature has passed
            // all validations, "Invalid" if one or more of the signature's certificates has failed validations,
            // or "InGracePeriod" or "Valid" if this is a revalidation request.
            var signature = await FindAuthorSignatureAsync(request);

            if (signature == null)
            {
                _logger.LogError(
                    "Could not find author signature for {PackageKey} {PackageId} {PackageVersion} {ValidationId}",
                    request.PackageKey,
                    request.PackageId,
                    request.PackageVersion,
                    request.ValidationId);

                throw new InvalidOperationException($"Package with key {request.PackageKey} does not have an author signature");
            }

            if (signature.Status == PackageSignatureStatus.Invalid)
            {
                _logger.LogWarning(
                    "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalidated signature: {SignatureKey}",
                    request.ValidationId,
                    request.PackageId,
                    request.PackageVersion,
                    signature.Key);

                return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed));
            }
            else
            {
                _logger.LogInformation(
                    "Successful validation {ValidationId} ({PackageId} {PackageVersion})",
                    request.ValidationId,
                    request.PackageId,
                    request.PackageVersion);

                PromoteSignature(request, signature);

                return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Succeeded));
            }
        }
Пример #18
0
 /// <summary>
 /// Check whether all certificate validations for the given validation request are finished.
 /// </summary>
 /// <param name="request">The validation request that started the certificate validations.</param>
 /// <returns>Whether the certificate validations are ALL finished.</returns>
 private Task <bool> AllCertificateValidationsAreFinishedAsync(IValidationRequest request)
 {
     // Incomplete CertificateValidation have a Status of NULL.
     return(_validationContext
            .CertificateValidations
            .Where(v => v.ValidationId == request.ValidationId)
            .AllAsync(v => v.Status.HasValue));
 }
        private IValidationResult Validate(IValidationRequest request, IValidationResult result)
        {
            /// The package signature validator runs after the <see cref="PackageSignatureProcessor" />.
            /// All signature validation issues should be caught and handled by the processor.
            if (result.Status == ValidationStatus.Failed || result.NupkgUrl != null)
            {
                if (!_config.RepositorySigningEnabled)
                {
                    _logger.LogInformation(
                        "Ignoring invalid validation result in package signature validator as repository signing is disabled. " +
                        "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
                        result.Status,
                        result.NupkgUrl,
                        result.Issues.Select(i => i.IssueCode));

                    return(ValidationResult.Succeeded);
                }

                // TODO: Remove this.
                // See: https://github.com/NuGet/Engineering/issues/1592
                if (HasOwnerWithInvalidUsername(request))
                {
                    _logger.LogWarning(
                        "Ignoring invalid validation result in package signature validator as the package has an owner with an invalid username. " +
                        "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
                        result.Status,
                        result.NupkgUrl,
                        result.Issues.Select(i => i.IssueCode));

                    return(ValidationResult.Succeeded);
                }

                _logger.LogCritical(
                    "Unexpected validation result in package signature validator. This may be caused by an invalid repository " +
                    "signature. Throwing an exception to force this validation to dead-letter. " +
                    "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}",
                    result.Status,
                    result.NupkgUrl,
                    result.Issues.Select(i => i.IssueCode));

                throw new InvalidOperationException("Package signature validator has an unexpected validation result");
            }

            /// Suppress all validation issues. The <see cref="PackageSignatureProcessor"/> should
            /// have already reported any issues related to the author signature. Customers should
            /// not be notified of validation issues due to the repository signature.
            if (result.Issues.Count != 0)
            {
                _logger.LogWarning(
                    "Ignoring {ValidationIssueCount} validation issues from result. Issues: {Issues}",
                    result.Issues.Count,
                    result.Issues.Select(i => i.IssueCode));

                return(new ValidationResult(result.Status));
            }

            return(result);
        }
Пример #20
0
 /// <summary>
 /// Find all of the signatures and their certificates for the given validation request's package.
 /// </summary>
 /// <param name="request">The validation request containing the package whose signatures should be fetched.</param>
 /// <returns>The package's signatures with their certificates.</returns>
 private Task <List <PackageSignature> > FindSignaturesAsync(IValidationRequest request)
 {
     return(_validationContext
            .PackageSignatures
            .Where(s => s.PackageKey == request.PackageKey)
            .Include(s => s.TrustedTimestamps)
            .Include(s => s.EndCertificate)
            .ToListAsync());
 }
Пример #21
0
 public ValidationHandler(
     IValidationRequest request,
     ValidationTypes validationType,
     IHandler handler)
 {
     this.request        = request;
     this.next           = handler;
     this.validationType = validationType;
 }
Пример #22
0
 /// <summary>
 /// Find all of the signatures and their certificates for the given validation request's package.
 /// </summary>
 /// <param name="request">The validation request containing the package whose signatures should be fetched.</param>
 /// <returns>The package's signatures with their certificates.</returns>
 private Task <PackageSignature> FindSignatureAsync(IValidationRequest request)
 {
     return(_validationContext
            .PackageSignatures
            .Include(s => s.EndCertificate)
            .Include(s => s.TrustedTimestamps.Select(t => t.EndCertificate))
            .Where(s => s.Type == PackageSignatureType.Author)
            .SingleAsync(s => s.PackageKey == request.PackageKey));
 }
Пример #23
0
 public SecurityValidationHandler(
     IValidationRequest request,
     IValidation validation,
     IHandler handler)
 {
     this.request    = request;
     this.next       = handler;
     this.validation = validation;
 }
Пример #24
0
        public async Task <ValidationStatus> GetStatusAsync(IValidationRequest request)
        {
            // Look up this validator's state in the database.
            var status = await _validatorStateService.GetStatusAsync(request);

            if (status.State != ValidationStatus.Incomplete)
            {
                return(status.State);
            }

            // Wait until ALL certificate validations kicked off by this validation request have finished.
            if (!await AllCertificateValidationsAreFinishedAsync(request))
            {
                return(ValidationStatus.Incomplete);
            }

            // All of the requested certificate validations have finished. Fail the validation if any
            // signatures have been invalidated.
            var signatures = await FindSignaturesAsync(request);

            foreach (var signature in signatures)
            {
                // Signatures at this point MUST have a state of either "Unknown" or "Invalid" at this point as the
                // PackageSigningValidator will set all signatures to an "Unknown" status, and the ValidateCertificate
                // job may set signatures to the "Invalid" state.
                if (signature.Status == PackageSignatureStatus.Invalid)
                {
                    _logger.LogWarning(
                        "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalidated signature: {SignatureKey}",
                        request.ValidationId,
                        request.PackageId,
                        request.PackageVersion,
                        signature.Key);

                    return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed));
                }

                if (signature.Status != PackageSignatureStatus.Unknown)
                {
                    _logger.LogError(
                        Error.PackageCertificateValidationInvalidSignatureState,
                        "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalid signature status: {SignatureStatus}",
                        request.ValidationId,
                        request.PackageId,
                        request.PackageVersion,
                        signature.Status);

                    return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed));
                }
            }

            // All signatures are valid. Promote signatures out of the "Unknown" state to either "Valid" or "InGracePeriod".
            PromoteSignatures(signatures);

            return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Succeeded));
        }
Пример #25
0
        /// <summary>
        /// Mark a package's signing state and its revoked signatures as invalid. This method does NOT
        /// persist entity changes to the database.
        /// </summary>
        /// <param name="request">The request to validate a package.</param>
        /// <param name="package">The package's overall signing state that should be invalidated.</param>
        /// <param name="signature">The package's signatures that should be invalidated.</param>
        /// <returns>A task that completes when the entities have been updated.</returns>
        private void InvalidatePackageSignature(IValidationRequest request, PackageSigningState package, PackageSignature signature)
        {
            _logger.LogWarning(
                "Invalidating package {PackageId} {PackageVersion} due to revoked signatures.",
                request.PackageId,
                request.PackageVersion);

            package.SigningStatus = PackageSigningStatus.Invalid;
            signature.Status      = PackageSignatureStatus.Invalid;
        }
        public async Task <IValidationResult> GetResultAsync(IValidationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var result = await GetProcessorStatusAsync(request);

            return(result.ToValidationResult());
        }
Пример #27
0
 /// <summary>
 /// Creates a <see cref="SymbolsServerRequest"/> from a <see cref="IValidationRequest"/>
 /// </summary>
 /// <param name="validationRequest">The <see cref="IValidationRequest"/>.</param>
 /// <param name="status">The <see cref="SymbolsPackageIngestRequestStatus"/>.</param>
 /// <returns></returns>
 public static SymbolsServerRequest CreateFromValidationRequest(IValidationRequest validationRequest, SymbolsPackageIngestRequestStatus status, string requestName)
 {
     return(new SymbolsServerRequest()
     {
         Created = DateTime.UtcNow,
         LastUpdated = DateTime.UtcNow,
         RequestName = requestName,
         RequestStatusKey = status,
         SymbolsKey = validationRequest.PackageKey
     });
 }
Пример #28
0
        public async Task <IValidationResult> GetResultAsync(IValidationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var validatorStatus = await _validatorStateService.GetStatusAsync(request);

            return(validatorStatus.ToValidationResult());
        }
        public async Task EnqueueVerificationAsync(IValidationRequest request, EndCertificate certificate)
        {
            var message         = new CertificateValidationMessage(certificate.Key, request.ValidationId);
            var brokeredMessage = _serializer.Serialize(message);

            var visibleAt = DateTimeOffset.UtcNow + (_configuration.Value.MessageDelay ?? TimeSpan.Zero);

            brokeredMessage.ScheduledEnqueueTimeUtc = visibleAt;

            await _topicClient.SendAsync(brokeredMessage);
        }
Пример #30
0
        /// <summary>
        /// Decide whether the valid signature should be considered "Valid" or "InGracePeriod".
        /// </summary>
        /// <param name="request">The validation request for the package whose signature should be inspected.</param>
        /// <param name="signature">The valid signature whose status should be decided.</param>
        /// <returns>True if the signature should be "Valid", false if it should be "InGracePeriod".</returns>
        private bool IsValidSignatureOutOfGracePeriod(IValidationRequest request, PackageSignature signature)
        {
            bool IsCertificateStatusPastTime(EndCertificate certificate, DateTime time)
            {
                return(certificate.StatusUpdateTime.HasValue && certificate.StatusUpdateTime > time);
            }

            var signingTime = signature.TrustedTimestamps.Max(t => t.Value);

            // Ensure the timestamps' certificate statuses are fresher than the signature.
            foreach (var timestamp in signature.TrustedTimestamps)
            {
                // A valid signature should NEVER have a timestamp whose end certificate is revoked.
                // Note that it is possible for a valid signature to have an invalid certificate as
                // certain certificate statuses, like "NotTimeNested", do not affect signatures.
                if (timestamp.EndCertificate.Status == EndCertificateStatus.Revoked)
                {
                    _logger.LogError(
                        Error.PackageCertificateValidationInvalidSignatureState,
                        "Valid signature cannot have a timestamp whose end certificate is revoked ({ValidationId}, {PackageId} {PackageVersion})",
                        request.ValidationId,
                        request.PackageId,
                        request.PackageVersion,
                        signature.Status);

                    throw new InvalidOperationException(
                              $"ValidationId {request.ValidationId} has valid signature with a timestamp whose end certificate is revoked");
                }

                if (!IsCertificateStatusPastTime(timestamp.EndCertificate, signingTime))
                {
                    return(false);
                }
            }

            // A signature can be valid even if its certificate is revoked as long as the certificate
            // revocation date begins after the signature was created. The validation pipeline does
            // not revalidate revoked certificates, thus, a valid package signature with a revoked
            // certificate is considered out of the grace period regardless of the certificate's
            // status update time.
            if (signature.EndCertificate.Status != EndCertificateStatus.Revoked)
            {
                // Ensure the signature's certificate status is fresher than the signature.
                if (!IsCertificateStatusPastTime(signature.EndCertificate, signingTime))
                {
                    return(false);
                }
            }

            return(true);
        }