예제 #1
0
        private static void ChangePasswordInternal(User user, string newPassword)
        {
            var hashedPassword = Crypto.GenerateSaltedHash(newPassword, Constants.PBKDF2HashAlgorithmId);

            user.PasswordHashAlgorithm = Constants.PBKDF2HashAlgorithmId;
            user.HashedPassword        = hashedPassword;
        }
예제 #2
0
        public virtual User GeneratePasswordResetToken(string usernameOrEmail, int tokenExpirationMinutes)
        {
            if (String.IsNullOrEmpty(usernameOrEmail))
            {
                throw new ArgumentNullException("usernameOrEmail");
            }
            if (tokenExpirationMinutes < 1)
            {
                throw new ArgumentException(
                          "Token expiration should give the user at least a minute to change their password", "tokenExpirationMinutes");
            }

            var user = FindByEmailAddress(usernameOrEmail);

            if (user == null)
            {
                return(null);
            }

            if (!user.Confirmed)
            {
                throw new InvalidOperationException(Strings.UserIsNotYetConfirmed);
            }

            if (!String.IsNullOrEmpty(user.PasswordResetToken) && !user.PasswordResetTokenExpirationDate.IsInThePast())
            {
                return(user);
            }

            user.PasswordResetToken = Crypto.GenerateToken();
            user.PasswordResetTokenExpirationDate = DateTime.UtcNow.AddMinutes(tokenExpirationMinutes);

            UserRepository.CommitChanges();
            return(user);
        }
예제 #3
0
        public virtual User FindByUsernameOrEmailAddressAndPassword(string usernameOrEmail, string password)
        {
            // TODO: validate input

            var user = FindByUsername(usernameOrEmail)
                       ?? FindByEmailAddress(usernameOrEmail);

            if (user == null)
            {
                return(null);
            }

            if (!Crypto.ValidateSaltedHash(user.HashedPassword, password, user.PasswordHashAlgorithm))
            {
                return(null);
            }
            else if (!user.PasswordHashAlgorithm.Equals(Constants.PBKDF2HashAlgorithmId, StringComparison.OrdinalIgnoreCase))
            {
                // If the user can be authenticated and they are using an older password algorithm, migrate them to the current one.
                ChangePasswordInternal(user, password);
                UserRepository.CommitChanges();
            }

            return(user);
        }
예제 #4
0
        public async Task <Organization> AddOrganizationAsync(string username, string emailAddress, User adminUser)
        {
            if (!ContentObjectService.LoginDiscontinuationConfiguration.AreOrganizationsSupportedForUser(adminUser))
            {
                throw new EntityException(String.Format(CultureInfo.CurrentCulture,
                                                        Strings.Organizations_NotInDomainWhitelist, adminUser.Username));
            }

            var existingUserWithIdentity = EntitiesContext.Users
                                           .FirstOrDefault(u => u.Username == username || u.EmailAddress == emailAddress);

            if (existingUserWithIdentity != null)
            {
                if (existingUserWithIdentity.Username.Equals(username, StringComparison.OrdinalIgnoreCase))
                {
                    throw new EntityException(Strings.UsernameNotAvailable, username);
                }

                if (string.Equals(existingUserWithIdentity.EmailAddress, emailAddress, StringComparison.OrdinalIgnoreCase))
                {
                    throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
                }
            }

            var organization = new Organization(username)
            {
                EmailAllowed            = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken  = Crypto.GenerateToken(),
                NotifyPackagePushed     = true,
                CreatedUtc = DateTimeProvider.UtcNow,
                Members    = new List <Membership>()
            };

            var membership = new Membership {
                Organization = organization, Member = adminUser, IsAdmin = true
            };

            organization.Members.Add(membership);
            adminUser.Organizations.Add(membership);

            OrganizationRepository.InsertOnCommit(organization);

            if (string.IsNullOrEmpty(GetAzureActiveDirectoryCredentialTenant(adminUser)))
            {
                throw new EntityException(String.Format(CultureInfo.CurrentCulture,
                                                        Strings.Organizations_AdminAccountDoesNotHaveTenant, adminUser.Username));
            }

            if (!await SubscribeOrganizationToTenantPolicy(organization, adminUser, commitChanges: false))
            {
                throw new EntityException(Strings.DefaultUserSafeExceptionMessage);
            }

            await EntitiesContext.SaveChangesAsync();

            return(organization);
        }
예제 #5
0
        public virtual User Create(
            string username,
            string password,
            string emailAddress)
        {
            // TODO: validate input
            // TODO: consider encrypting email address with a public key, and having the background process that send messages have the private key to decrypt

            var existingUser = FindByUsername(username);

            if (existingUser != null)
            {
                throw new EntityException(Strings.UsernameNotAvailable, username);
            }

            var existingUsers = FindAllByEmailAddress(emailAddress);

            if (existingUsers.AnySafe())
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
            }

            var hashedPassword = Crypto.GenerateSaltedHash(password, Constants.PBKDF2HashAlgorithmId);

            var apiKey  = Guid.NewGuid();
            var newUser = new User(username)
            {
                ApiKey                  = apiKey,
                EmailAllowed            = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken  = Crypto.GenerateToken(),
                HashedPassword          = hashedPassword,
                PasswordHashAlgorithm   = Constants.PBKDF2HashAlgorithmId,
                CreatedUtc              = DateTime.UtcNow,
                Roles = new List <Role> {
                    RoleRepository.GetEntity(2)
                }
            };

            // Add a credential for the password and the API Key
            newUser.Credentials.Add(CredentialBuilder.CreateV1ApiKey(apiKey));
            newUser.Credentials.Add(new Credential(CredentialTypes.Password.Pbkdf2, newUser.HashedPassword));

            if (!Config.ConfirmEmailAddresses)
            {
                newUser.ConfirmEmailAddress();
            }

            newUser.Roles.Add(RoleRepository.GetEntity(2));

            UserRepository.InsertOnCommit(newUser);

            UserRepository.CommitChanges();

            return(newUser);
        }
예제 #6
0
        public async Task <Organization> AddOrganizationAsync(string username, string emailAddress, User adminUser)
        {
            var existingUserWithIdentity = EntitiesContext.Users
                                           .FirstOrDefault(u => u.Username == username || u.EmailAddress == emailAddress);

            if (existingUserWithIdentity != null)
            {
                if (existingUserWithIdentity.Username.Equals(username, StringComparison.OrdinalIgnoreCase))
                {
                    throw new EntityException(Strings.UsernameNotAvailable, username);
                }

                if (string.Equals(existingUserWithIdentity.EmailAddress, emailAddress, StringComparison.OrdinalIgnoreCase))
                {
                    throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
                }
            }

            var organization = new Organization(username)
            {
                EmailAllowed            = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken  = Crypto.GenerateToken(),
                NotifyPackagePushed     = true,
                CreatedUtc = DateTimeProvider.UtcNow,
                Members    = new List <Membership>()
            };

            if (!Config.ConfirmEmailAddresses)
            {
                organization.ConfirmEmailAddress();
            }

            var membership = new Membership {
                Organization = organization, Member = adminUser, IsAdmin = true
            };

            organization.Members.Add(membership);
            adminUser.Organizations.Add(membership);

            OrganizationRepository.InsertOnCommit(organization);

            await SubscribeOrganizationToTenantPolicyIfTenantIdIsSupported(organization, adminUser, commitChanges : false);

            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(organization, AuditedUserAction.AddOrganization, membership));

            await EntitiesContext.SaveChangesAsync();

            return(organization);
        }
예제 #7
0
        public virtual User Create(
            string username,
            string password,
            string emailAddress)
        {
            // TODO: validate input
            // TODO: consider encrypting email address with a public key, and having the background process that send messages have the private key to decrypt

            var existingUser = FindByUsername(username);

            if (existingUser != null)
            {
                throw new EntityException(Strings.UsernameNotAvailable, username);
            }

            existingUser = FindByEmailAddress(emailAddress);
            if (existingUser != null)
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
            }

            var hashedPassword = Crypto.GenerateSaltedHash(password, Constants.PBKDF2HashAlgorithmId);

            var newUser = new User(
                username,
                hashedPassword)
            {
                ApiKey                  = Guid.NewGuid(),
                EmailAllowed            = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken  = Crypto.GenerateToken(),
                PasswordHashAlgorithm   = Constants.PBKDF2HashAlgorithmId,
                CreatedUtc              = DateTime.UtcNow
            };

            if (!Config.ConfirmEmailAddresses)
            {
                newUser.ConfirmEmailAddress();
            }

            UserRepository.InsertOnCommit(newUser);
            UserRepository.CommitChanges();

            return(newUser);
        }
예제 #8
0
        public virtual User FindByUsernameAndPassword(string username, string password)
        {
            // TODO: validate input

            var user = FindByUsername(username);

            if (user == null)
            {
                return(null);
            }

            if (!Crypto.ValidateSaltedHash(user.HashedPassword, password, user.PasswordHashAlgorithm))
            {
                return(null);
            }

            return(user);
        }
예제 #9
0
        public async Task RequestTransformToOrganizationAccount(User accountToTransform, User adminUser)
        {
            accountToTransform = accountToTransform ?? throw new ArgumentNullException(nameof(accountToTransform));
            adminUser          = adminUser ?? throw new ArgumentNullException(nameof(adminUser));

            // create new or update existing request
            if (accountToTransform.OrganizationMigrationRequest == null)
            {
                accountToTransform.OrganizationMigrationRequest = new OrganizationMigrationRequest();
            }
            ;

            accountToTransform.OrganizationMigrationRequest.NewOrganization   = accountToTransform;
            accountToTransform.OrganizationMigrationRequest.AdminUser         = adminUser;
            accountToTransform.OrganizationMigrationRequest.ConfirmationToken = Crypto.GenerateToken();
            accountToTransform.OrganizationMigrationRequest.RequestDate       = DateTime.UtcNow;

            await UserRepository.CommitChangesAsync();
        }
예제 #10
0
        public void UpdateProfile(User user, string emailAddress, bool emailAllowed)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            if (emailAddress != user.EmailAddress)
            {
                var existingUser = FindByEmailAddress(emailAddress);
                if (existingUser != null && existingUser.Key != user.Key)
                {
                    throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
                }
                user.UnconfirmedEmailAddress = emailAddress;
                user.EmailConfirmationToken  = Crypto.GenerateToken();
            }

            user.EmailAllowed = emailAllowed;
            UserRepository.CommitChanges();
        }
예제 #11
0
        public PackageOwnerRequest CreatePackageOwnerRequest(PackageRegistration package, User currentOwner, User newOwner)
        {
            var existingRequest = FindExistingPackageOwnerRequest(package, newOwner);

            if (existingRequest != null)
            {
                return(existingRequest);
            }

            var newRequest = new PackageOwnerRequest
            {
                PackageRegistrationKey = package.Key,
                RequestingOwnerKey     = currentOwner.Key,
                NewOwnerKey            = newOwner.Key,
                ConfirmationCode       = Crypto.GenerateToken(),
                RequestDate            = DateTime.UtcNow
            };

            _packageOwnerRequestRepository.InsertOnCommit(newRequest);
            _packageOwnerRequestRepository.CommitChanges();
            return(newRequest);
        }
예제 #12
0
        private User AuthenticatePassword(string password, User user)
        {
            if (user == null)
            {
                return(null);
            }

            // Check for a credential
            var creds = user.Credentials
                        .Where(c => c.Type.StartsWith(
                                   CredentialTypes.Password.Prefix,
                                   StringComparison.OrdinalIgnoreCase)).ToList();

            bool valid;

            if (creds.Count > 0)
            {
                valid = ValidatePasswordCredential(creds, password);

                if (valid &&
                    (creds.Count > 1 ||
                     !creds.Any(c => String.Equals(
                                    c.Type,
                                    CredentialTypes.Password.Pbkdf2,
                                    StringComparison.OrdinalIgnoreCase))))
                {
                    MigrateCredentials(user, creds, password);
                }
            }
            else
            {
                valid = Crypto.ValidateSaltedHash(
                    user.HashedPassword,
                    password,
                    user.PasswordHashAlgorithm);
            }

            return(valid ? user : null);
        }
예제 #13
0
        private Package CreatePackageFromNuGetPackage(PackageRegistration packageRegistration, INupkg nugetPackage, User user)
        {
            var package = packageRegistration.Packages.SingleOrDefault(pv => pv.Version == nugetPackage.Metadata.Version.ToString());

            if (package != null)
            {
                throw new EntityException(
                          "A package with identifier '{0}' and version '{1}' already exists.", packageRegistration.Id, package.Version);
            }

            var now = DateTime.UtcNow;
            var packageFileStream = nugetPackage.GetStream();

            package = new Package
            {
                // Version must always be the exact string from the nuspec, which ToString will return to us.
                // However, we do also store a normalized copy for looking up later.
                Version           = nugetPackage.Metadata.Version.ToString(),
                NormalizedVersion = nugetPackage.Metadata.Version.ToNormalizedString(),

                Description               = nugetPackage.Metadata.Description,
                ReleaseNotes              = nugetPackage.Metadata.ReleaseNotes,
                HashAlgorithm             = Constants.Sha512HashAlgorithmId,
                Hash                      = Crypto.GenerateHash(packageFileStream.ReadAllBytes()),
                PackageFileSize           = packageFileStream.Length,
                Created                   = now,
                Language                  = nugetPackage.Metadata.Language,
                LastUpdated               = now,
                Published                 = now,
                Copyright                 = nugetPackage.Metadata.Copyright,
                FlattenedAuthors          = nugetPackage.Metadata.Authors.Flatten(),
                IsPrerelease              = !nugetPackage.Metadata.IsReleaseVersion(),
                Listed                    = true,
                PackageRegistration       = packageRegistration,
                RequiresLicenseAcceptance = nugetPackage.Metadata.RequireLicenseAcceptance,
                Summary                   = nugetPackage.Metadata.Summary,
                Tags                      = PackageHelper.ParseTags(nugetPackage.Metadata.Tags),
                Title                     = nugetPackage.Metadata.Title,
                User                      = user,
            };

            package.IconUrl          = nugetPackage.Metadata.IconUrl.ToEncodedUrlStringOrNull();
            package.LicenseUrl       = nugetPackage.Metadata.LicenseUrl.ToEncodedUrlStringOrNull();
            package.ProjectUrl       = nugetPackage.Metadata.ProjectUrl.ToEncodedUrlStringOrNull();
            package.MinClientVersion = nugetPackage.Metadata.MinClientVersion.ToStringOrNull();

#pragma warning disable 618 // TODO: remove Package.Authors completely once prodution services definitely no longer need it
            foreach (var author in nugetPackage.Metadata.Authors)
            {
                package.Authors.Add(new PackageAuthor {
                    Name = author
                });
            }
#pragma warning restore 618

            var supportedFrameworks = GetSupportedFrameworks(nugetPackage).Select(fn => fn.ToShortNameOrNull()).ToArray();
            if (!supportedFrameworks.AnySafe(sf => sf == null))
            {
                foreach (var supportedFramework in supportedFrameworks)
                {
                    package.SupportedFrameworks.Add(new PackageFramework {
                        TargetFramework = supportedFramework
                    });
                }
            }

            foreach (var dependencySet in nugetPackage.Metadata.DependencySets)
            {
                if (dependencySet.Dependencies.Count == 0)
                {
                    package.Dependencies.Add(
                        new PackageDependency
                    {
                        Id              = null,
                        VersionSpec     = null,
                        TargetFramework = dependencySet.TargetFramework.ToShortNameOrNull()
                    });
                }
                else
                {
                    foreach (var dependency in dependencySet.Dependencies.Select(d => new { d.Id, d.VersionSpec, dependencySet.TargetFramework }))
                    {
                        package.Dependencies.Add(
                            new PackageDependency
                        {
                            Id              = dependency.Id,
                            VersionSpec     = dependency.VersionSpec == null ? null : dependency.VersionSpec.ToString(),
                            TargetFramework = dependency.TargetFramework.ToShortNameOrNull()
                        });
                    }
                }
            }

            package.FlattenedDependencies = package.Dependencies.Flatten();

            return(package);
        }
예제 #14
0
        public async Task <MembershipRequest> AddMembershipRequestAsync(Organization organization, string memberName, bool isAdmin)
        {
            organization = organization ?? throw new ArgumentNullException(nameof(organization));

            var membership = FindMembershipByUsername(organization, memberName);

            if (membership != null)
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.AddMember_AlreadyAMember, memberName));
            }

            var request = FindMembershipRequestByUsername(organization, memberName);

            if (request != null)
            {
                // If there is already an existing request, return it.
                // If the existing request grants collaborator but we are trying to create a request that grants admin, update the request to grant admin.
                request.IsAdmin = isAdmin || request.IsAdmin;
                await EntitiesContext.SaveChangesAsync();

                return(request);
            }

            if (Regex.IsMatch(memberName, GalleryConstants.EmailValidationRegex, RegexOptions.None, GalleryConstants.EmailValidationRegexTimeout))
            {
                throw new EntityException(Strings.AddMember_NameIsEmail);
            }

            var member = FindByUsername(memberName);

            if (member == null)
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.AddMember_UserNotFound, memberName));
            }

            if (!member.Confirmed)
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.AddMember_UserNotConfirmed, memberName));
            }

            if (member is Organization)
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.AddMember_UserIsOrganization, memberName));
            }

            // Ensure that the new member meets the AAD tenant policy for this organization.
            var policyResult = await SecurityPolicyService.EvaluateOrganizationPoliciesAsync(
                SecurityPolicyAction.JoinOrganization, organization, member);

            if (policyResult != SecurityPolicyResult.SuccessResult)
            {
                throw new EntityException(policyResult.ErrorMessage);
            }

            request = new MembershipRequest()
            {
                Organization      = organization,
                NewMember         = member,
                IsAdmin           = isAdmin,
                ConfirmationToken = Crypto.GenerateToken(),
                RequestDate       = DateTime.UtcNow,
            };
            organization.MemberRequests.Add(request);

            await EntitiesContext.SaveChangesAsync();

            return(request);
        }
예제 #15
0
        private Package CreatePackageFromNuGetPackage(PackageRegistration packageRegistration, INupkg nugetPackage)
        {
            var package = packageRegistration.Packages.SingleOrDefault(pv => pv.Version == nugetPackage.Metadata.Version.ToString());

            if (package != null)
            {
                throw new EntityException(
                          "A package with identifier '{0}' and version '{1}' already exists.", packageRegistration.Id, package.Version);
            }

            var now = DateTime.UtcNow;
            var packageFileStream = nugetPackage.GetStream();

            package = new Package
            {
                Version      = nugetPackage.Metadata.Version.ToString(),
                Description  = nugetPackage.Metadata.Description,
                ReleaseNotes = nugetPackage.Metadata.ReleaseNotes,
                RequiresLicenseAcceptance = nugetPackage.Metadata.RequireLicenseAcceptance,
                HashAlgorithm             = Constants.Sha512HashAlgorithmId,
                Hash                = Crypto.GenerateHash(packageFileStream.ReadAllBytes()),
                PackageFileSize     = packageFileStream.Length,
                Created             = now,
                Language            = nugetPackage.Metadata.Language,
                LastUpdated         = now,
                Published           = now,
                Copyright           = nugetPackage.Metadata.Copyright,
                IsPrerelease        = !nugetPackage.Metadata.IsReleaseVersion(),
                Listed              = true,
                PackageRegistration = packageRegistration,
                Summary             = nugetPackage.Metadata.Summary,
                Tags                = nugetPackage.Metadata.Tags,
                Title               = nugetPackage.Metadata.Title,
            };

            package.IconUrl          = nugetPackage.Metadata.IconUrl.ToStringOrNull();
            package.LicenseUrl       = nugetPackage.Metadata.LicenseUrl.ToStringOrNull();
            package.ProjectUrl       = nugetPackage.Metadata.ProjectUrl.ToStringOrNull();
            package.MinClientVersion = nugetPackage.Metadata.MinClientVersion.ToStringOrNull();

            foreach (var author in nugetPackage.Metadata.Authors)
            {
                package.Authors.Add(new PackageAuthor {
                    Name = author
                });
            }

            var supportedFrameworks = GetSupportedFrameworks(nugetPackage).Select(fn => fn.ToShortNameOrNull()).ToArray();

            if (!supportedFrameworks.AnySafe(sf => sf == null))
            {
                foreach (var supportedFramework in supportedFrameworks)
                {
                    package.SupportedFrameworks.Add(new PackageFramework {
                        TargetFramework = supportedFramework
                    });
                }
            }

            foreach (var dependencySet in nugetPackage.Metadata.DependencySets)
            {
                if (dependencySet.Dependencies.Count == 0)
                {
                    package.Dependencies.Add(
                        new PackageDependency
                    {
                        Id              = null,
                        VersionSpec     = null,
                        TargetFramework = dependencySet.TargetFramework.ToShortNameOrNull()
                    });
                }
                else
                {
                    foreach (var dependency in dependencySet.Dependencies.Select(d => new { d.Id, d.VersionSpec, dependencySet.TargetFramework }))
                    {
                        package.Dependencies.Add(
                            new PackageDependency
                        {
                            Id              = dependency.Id,
                            VersionSpec     = dependency.VersionSpec == null ? null : dependency.VersionSpec.ToString(),
                            TargetFramework = dependency.TargetFramework.ToShortNameOrNull()
                        });
                    }
                }
            }

            package.FlattenedAuthors      = package.Authors.Flatten();
            package.FlattenedDependencies = package.Dependencies.Flatten();

            return(package);
        }