public virtual async Task <AuthenticatedUser> Authenticate(string userNameOrEmail, string password) { using (_trace.Activity("Authenticate:" + userNameOrEmail)) { var user = FindByUserNameOrEmail(userNameOrEmail); // Check if the user exists if (user == null) { _trace.Information("No such user: "******"Password validation failed: " + userNameOrEmail); return(null); } var passwordCredentials = user .Credentials .Where(c => c.Type.StartsWith(CredentialTypes.Password.Prefix, StringComparison.OrdinalIgnoreCase)) .ToList(); if (passwordCredentials.Count > 1 || !passwordCredentials.Any(c => String.Equals(c.Type, CredentialTypes.Password.Pbkdf2, StringComparison.OrdinalIgnoreCase))) { await MigrateCredentials(user, passwordCredentials, password); } // Return the result _trace.Verbose("Successfully authenticated '" + user.Username + "' with '" + matched.Type + "' credential"); return(new AuthenticatedUser(user, matched)); } }
/// <summary> /// On subscribe, set API keys with push capability to expire in <see cref="PushKeysExpirationInDays" /> days. /// </summary> /// <param name="context"></param> public async Task OnSubscribeAsync(UserSecurityPolicySubscriptionContext context) { var pushKeys = context.User.Credentials.Where(c => CredentialTypes.IsApiKey(c.Type) && ( c.Scopes.Count == 0 || c.Scopes.Any(s => s.AllowedAction.Equals(NuGetScopes.PackagePush, StringComparison.OrdinalIgnoreCase) || s.AllowedAction.Equals(NuGetScopes.PackagePushVersion, StringComparison.OrdinalIgnoreCase) )) ); var expires = DateTime.UtcNow.AddDays(PushKeysExpirationInDays); var expireTasks = new List <Task>(); foreach (var key in pushKeys) { if (!key.Expires.HasValue || key.Expires > expires) { expireTasks.Add(_auditing.SaveAuditRecordAsync( new UserAuditRecord(context.User, AuditedUserAction.ExpireCredential, key))); key.Expires = expires; } } await Task.WhenAll(expireTasks); _diagnostics.Information($"Expiring {pushKeys.Count()} keys with push capability for user '{context.User.Username}'."); }
public async Task <string> GetSecretAsync(string secretName) { if (!_cache.ContainsKey(secretName)) { _trace.Information("Cache miss for setting " + secretName); var secretValue = await _internalReader.GetSecretAsync(secretName); _cache[secretName] = secretValue; } return(_cache[secretName]); }
public async Task UpdateIsLatestAsync(PackageRegistration packageRegistration) { // Must suspend the retry execution strategy in order to use transactions. using (EntitiesConfiguration.SuspendRetriableExecutionStrategy()) { if (await TryUpdateIsLatestAsync(_entitiesContext, packageRegistration)) { return; } // Retry the update in case a concurrency conflict was detected on the first attempt. int retryCount = 1; do { await Task.Delay(_randomGenerator.Value.Next(0, 1000)); _trace.Information(String.Format("Retrying {0} for package '{1}' ({2}/{3})", nameof(UpdateIsLatestAsync), packageRegistration.Id, retryCount, UpdateIsLatestMaxRetries)); // Since EF contexts are short-lived and do not really support refresh, we will use a // different context than the request on retry to avoid putting the request context in // a bad state. More than likely the retry will detect that the concurrent update has // already made the right updates and no changes will be necessary. using (var detachedRetryContext = CreateNewEntitiesContext()) { var detachedPackageRegistration = detachedRetryContext.PackageRegistrations.SingleOrDefault( pr => pr.Id == packageRegistration.Id); if (await TryUpdateIsLatestAsync(detachedRetryContext, detachedPackageRegistration)) { return; } } retryCount++; }while (retryCount <= UpdateIsLatestMaxRetries); } }
public virtual async Task <PasswordAuthenticationResult> Authenticate(string userNameOrEmail, string password) { using (_trace.Activity("Authenticate")) { var user = FindByUserNameOrEmail(userNameOrEmail); // Check if the user exists if (user == null) { _trace.Information("No such user."); await Auditing.SaveAuditRecordAsync( new FailedAuthenticatedOperationAuditRecord( userNameOrEmail, AuditedAuthenticatedOperationAction.FailedLoginNoSuchUser)); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.BadCredentials)); } if (user is Organization) { _trace.Information("Cannot authenticate organization account."); await Auditing.SaveAuditRecordAsync( new FailedAuthenticatedOperationAuditRecord( userNameOrEmail, AuditedAuthenticatedOperationAction.FailedLoginUserIsOrganization)); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.BadCredentials)); } int remainingMinutes; if (IsAccountLocked(user, out remainingMinutes)) { _trace.Information($"Login failed. User account is locked for the next {remainingMinutes} minutes."); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.AccountLocked, authenticatedUser: null, lockTimeRemainingMinutes: remainingMinutes)); } // Validate the password Credential matched; if (!ValidatePasswordCredential(user.Credentials, password, out matched)) { _trace.Information("Password validation failed."); await UpdateFailedLoginAttempt(user); await Auditing.SaveAuditRecordAsync( new FailedAuthenticatedOperationAuditRecord( userNameOrEmail, AuditedAuthenticatedOperationAction.FailedLoginInvalidPassword)); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.BadCredentials)); } var passwordCredentials = user .Credentials .Where(c => c.IsPassword()) .ToList(); if (passwordCredentials.Count > 1 || !passwordCredentials.Any(c => string.Equals(c.Type, CredentialBuilder.LatestPasswordType, StringComparison.OrdinalIgnoreCase))) { await MigrateCredentials(user, passwordCredentials, password); } // Reset failed login count upon successful login await UpdateSuccessfulLoginAttempt(user); // Return the result _trace.Verbose("User successfully authenticated with '" + matched.Type + "' credential"); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.Success, new AuthenticatedUser(user, matched))); } }
private async Task <PackageValidationResult> CheckLicenseMetadataAsync(PackageArchiveReader nuGetPackage, List <IValidationMessage> warnings, User user) { var nuspecReader = GetNuspecReader(nuGetPackage); var licenseElement = nuspecReader.LicenseElement; if (licenseElement != null) { if (licenseElement.Value.Length > MaxAllowedLicenseNodeValueLength) { return(PackageValidationResult.Invalid(Strings.UploadPackage_LicenseNodeValueTooLong)); } if (HasChildElements(licenseElement)) { return(PackageValidationResult.Invalid(string.Format(Strings.UploadPackage_NodeContainsChildren, LicenseNodeName))); } var typeText = GetLicenseType(licenseElement); if (!AllowedLicenseTypes.Contains(typeText, StringComparer.OrdinalIgnoreCase)) { return(PackageValidationResult.Invalid(string.Format(Strings.UploadPackage_UnsupportedLicenseType, typeText))); } var versionText = GetLicenseVersion(licenseElement); if (versionText != null && AllowedLicenseVersion != versionText) { return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_UnsupportedLicenseVersion, versionText))); } } var licenseUrl = nuspecReader.GetLicenseUrl(); var licenseMetadata = nuspecReader.GetLicenseMetadata(); var licenseDeprecationUrl = GetExpectedLicenseUrl(licenseMetadata); if (licenseMetadata == null) { if (string.IsNullOrWhiteSpace(licenseUrl)) { if (!_config.AllowLicenselessPackages) { return(PackageValidationResult.Invalid(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_MissingLicenseInformation))); } else { warnings.Add(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_LicenseShouldBeSpecified)); } } if (licenseDeprecationUrl == licenseUrl) { return(PackageValidationResult.Invalid(Strings.UploadPackage_DeprecationUrlUsage)); } if (!string.IsNullOrWhiteSpace(licenseUrl)) { if (_config.BlockLegacyLicenseUrl) { return(PackageValidationResult.Invalid(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_LegacyLicenseUrlNotAllowed))); } else { warnings.Add(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_DeprecatingLicenseUrl)); } } // we will return here, so the code below would not need to check for licenseMetadata to be non-null over and over. return(null); } if (licenseMetadata.WarningsAndErrors != null && licenseMetadata.WarningsAndErrors.Any()) { _telemetryService.TrackInvalidLicenseMetadata(licenseMetadata.License); return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_InvalidLicenseMetadata, string.Join(" ", licenseMetadata.WarningsAndErrors)))); } if (licenseDeprecationUrl != licenseUrl) { if (IsMalformedDeprecationUrl(licenseUrl)) { return(PackageValidationResult.Invalid(new InvalidUrlEncodingForLicenseUrlValidationMessage())); } if (licenseMetadata.Type == LicenseType.File) { return(PackageValidationResult.Invalid( new InvalidLicenseUrlValidationMessage( string.Format(Strings.UploadPackage_DeprecationUrlRequiredForLicenseFiles, licenseDeprecationUrl)))); } else if (licenseMetadata.Type == LicenseType.Expression) { return(PackageValidationResult.Invalid( new InvalidLicenseUrlValidationMessage( string.Format(Strings.UploadPackage_DeprecationUrlRequiredForLicenseExpressions, licenseDeprecationUrl)))); } } if (licenseMetadata.Type == LicenseType.File) { // fix the path separator. Client enforces forward slashes in all file paths when packing var licenseFilename = FileNameHelper.GetZipEntryPath(licenseMetadata.License); if (licenseFilename != licenseMetadata.License) { var packageIdentity = nuspecReader.GetIdentity(); _trace.Information($"Transformed license file name from `{licenseMetadata.License}` to `{licenseFilename}` for package {packageIdentity.Id} {packageIdentity.Version}"); } // check if specified file is present in the package if (!FileExists(nuGetPackage, licenseFilename)) { return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_FileDoesNotExist, Strings.UploadPackage_LicenseFileType, licenseFilename))); } // check if specified file has allowed extension var licenseFileExtension = Path.GetExtension(licenseFilename); if (!AllowedLicenseFileExtensions.Contains(licenseFileExtension, StringComparer.OrdinalIgnoreCase)) { return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_InvalidLicenseFileExtension, licenseFileExtension, string.Join(", ", AllowedLicenseFileExtensions.Where(x => x != string.Empty).Select(extension => $"'{extension}'"))))); } var licenseFileEntry = nuGetPackage.GetEntry(licenseFilename); if (licenseFileEntry.Length > MaxAllowedLicenseLengthForUploading) { return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_FileTooLong, Strings.UploadPackage_LicenseFileType, MaxAllowedLicenseLengthForUploading.ToUserFriendlyBytesLabel()))); } if (!await IsStreamLengthMatchesReportedAsync(nuGetPackage, licenseFilename, licenseFileEntry.Length)) { return(PackageValidationResult.Invalid(Strings.UploadPackage_CorruptNupkg)); } // zip streams do not support seeking, so we'll have to reopen them using (var licenseFileStream = nuGetPackage.GetStream(licenseFilename)) { // check if specified file is a text file if (!await TextHelper.LooksLikeUtf8TextStreamAsync(licenseFileStream)) { return(PackageValidationResult.Invalid(Strings.UploadPackage_LicenseMustBePlainText)); } } } if (licenseMetadata.Type == LicenseType.Expression) { if (licenseMetadata.LicenseExpression == null) { throw new InvalidOperationException($"Unexpected value of {nameof(licenseMetadata.LicenseExpression)} property"); } var licenseList = GetLicenseList(licenseMetadata.LicenseExpression); var unapprovedLicenses = licenseList.Where(license => !license.IsOsiApproved && !license.IsFsfLibre).ToList(); if (unapprovedLicenses.Any()) { _telemetryService.TrackNonFsfOsiLicenseUse(licenseMetadata.License); return(PackageValidationResult.Invalid( string.Format( Strings.UploadPackage_NonFsfOrOsiLicense, string.Join(", ", unapprovedLicenses.Select(l => l.LicenseID))))); } } return(null); }
public virtual async Task <PasswordAuthenticationResult> Authenticate(string userNameOrEmail, string password) { using (_trace.Activity("Authenticate:" + userNameOrEmail)) { var user = FindByUserNameOrEmail(userNameOrEmail); // Check if the user exists if (user == null) { var ldapUser = this.Ldap.ValidateUsernameAndPassword(userNameOrEmail, password); if (ldapUser != null) { _trace.Information($"Creating user from LDAP credentials: {userNameOrEmail}"); var ldapCredential = _credentialBuilder.CreateExternalCredential(AuthenticationTypes.LdapUser, ldapUser.Username, ldapUser.Identity); var authUser = await this.Register(ldapUser.Username, ldapUser.Email, ldapCredential); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.Success, authUser)); } _trace.Information("No such user: "******"Login failed. User account {userNameOrEmail} is locked for the next {remainingMinutes} minutes."); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.AccountLocked, authenticatedUser: null, lockTimeRemainingMinutes: remainingMinutes)); } // Validate the password Credential matched; if (!ValidatePasswordCredential(user.Credentials, password, out matched)) { var isValid = this.Ldap.ValidateCredentials(user.Credentials, password, out matched); if (isValid) { _trace.Verbose($"Successfully authenticated '{user.Username}' with '{matched.Type}' credential"); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.Success, new AuthenticatedUser(user, matched))); } _trace.Information($"Password validation failed: {userNameOrEmail}"); await UpdateFailedLoginAttempt(user); await Auditing.SaveAuditRecordAsync( new FailedAuthenticatedOperationAuditRecord( userNameOrEmail, AuditedAuthenticatedOperationAction.FailedLoginInvalidPassword)); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.BadCredentials)); } var passwordCredentials = user .Credentials .Where(c => CredentialTypes.IsPassword(c.Type)) .ToList(); if (passwordCredentials.Count > 1 || !passwordCredentials.Any(c => string.Equals(c.Type, CredentialBuilder.LatestPasswordType, StringComparison.OrdinalIgnoreCase))) { await MigrateCredentials(user, passwordCredentials, password); } // Reset failed login count upon successful login await UpdateSuccessfulLoginAttempt(user); // Return the result _trace.Verbose("Successfully authenticated '" + user.Username + "' with '" + matched.Type + "' credential"); return(new PasswordAuthenticationResult(PasswordAuthenticationResult.AuthenticationResult.Success, new AuthenticatedUser(user, matched))); } }