Example #1
0
        /// <summary>
        /// Subscribe a user to one or more security policies.
        /// </summary>
        public async Task SubscribeAsync(User user, IUserSecurityPolicySubscription subscription)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (subscription == null)
            {
                throw new ArgumentNullException(nameof(subscription));
            }

            if (IsSubscribed(user, subscription))
            {
                Diagnostics.Information($"User '{user.Username}' is already subscribed to '{subscription.SubscriptionName}'.");
            }
            else
            {
                foreach (var policy in subscription.Policies)
                {
                    user.SecurityPolicies.Add(new UserSecurityPolicy(policy));
                }

                await subscription.OnSubscribeAsync(new UserSecurityPolicySubscriptionContext(this, user));

                await Auditing.SaveAuditRecordAsync(
                    new UserAuditRecord(user, AuditedUserAction.SubscribeToPolicies, subscription.Policies));

                await EntitiesContext.SaveChangesAsync();

                Diagnostics.Information($"User '{user.Username}' is now subscribed to '{subscription.SubscriptionName}'.");
            }
        }
Example #2
0
        /// <summary>
        /// Look up and evaluation of security policies for the specified action.
        /// </summary>
        public async Task <SecurityPolicyResult> EvaluateAsync(SecurityPolicyAction action, HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var user = httpContext.GetCurrentUser();

            foreach (var handler in UserHandlers.Where(h => h.Action == action))
            {
                var foundPolicies = user.SecurityPolicies.Where(p => p.Name.Equals(handler.Name, StringComparison.OrdinalIgnoreCase));
                if (foundPolicies.Any())
                {
                    var result = handler.Evaluate(new UserSecurityPolicyEvaluationContext(httpContext, foundPolicies));

                    await Auditing.SaveAuditRecordAsync(new UserSecurityPolicyAuditRecord(
                                                            user.Username, GetAuditAction(action), foundPolicies, result.Success, result.ErrorMessage));

                    if (!result.Success)
                    {
                        Diagnostics.Information(
                            $"Security policy '{handler.Name}' failed for user '{user.Username}' with error '{result.ErrorMessage}'.");

                        return(result);
                    }
                }
            }

            return(SecurityPolicyResult.SuccessResult);
        }
Example #3
0
        private async Task MigrateCredentials(User user, List <Credential> creds, string password)
        {
            var toRemove = creds.Where(c =>
                                       !string.Equals(
                                           c.Type,
                                           CredentialBuilder.LatestPasswordType,
                                           StringComparison.OrdinalIgnoreCase))
                           .ToList();

            // Remove any non latest credentials
            foreach (var cred in toRemove)
            {
                creds.Remove(cred);
                user.Credentials.Remove(cred);
                Entities.DeleteOnCommit(cred);
            }
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.RemoveCredential, toRemove));

            // Now add one if there are no credentials left
            if (creds.Count == 0)
            {
                var newCred = _credentialBuilder.CreatePasswordCredential(password);
                await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.AddCredential, newCred));

                user.Credentials.Add(newCred);
            }

            // Save changes, if any
            await Entities.SaveChangesAsync();
        }
Example #4
0
        public async Task CancelChangeEmailAddress(User user)
        {
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.CancelChangeEmail, user.UnconfirmedEmailAddress));

            user.CancelChangeEmailAddress();
            await UserRepository.CommitChangesAsync();
        }
Example #5
0
        public virtual async Task AddCredential(User user, Credential credential)
        {
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.AddCredential, credential));

            user.Credentials.Add(credential);
            await Entities.SaveChangesAsync();
        }
Example #6
0
        private async Task ReplaceCredentialInternal(User user, Credential credential)
        {
            // Find the credentials we're replacing, if any
            var toRemove = user.Credentials
                           .Where(cred =>
                                  // If we're replacing a password credential, remove ALL password credentials
                                  (credential.Type.StartsWith(CredentialTypes.Password.Prefix, StringComparison.OrdinalIgnoreCase) &&
                                   cred.Type.StartsWith(CredentialTypes.Password.Prefix, StringComparison.OrdinalIgnoreCase)) ||
                                  cred.Type == credential.Type)
                           .ToList();

            foreach (var cred in toRemove)
            {
                user.Credentials.Remove(cred);
                Entities.DeleteOnCommit(cred);
            }

            if (toRemove.Any())
            {
                await Auditing.SaveAuditRecordAsync(new UserAuditRecord(
                                                        user, AuditedUserAction.RemoveCredential, toRemove));
            }

            user.Credentials.Add(credential);

            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(
                                                    user, AuditedUserAction.AddCredential, credential));
        }
Example #7
0
        public async Task <bool> ConfirmEmailAddress(User user, string token)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            if (String.IsNullOrEmpty(token))
            {
                throw new ArgumentNullException(nameof(token));
            }

            if (user.EmailConfirmationToken != token)
            {
                return(false);
            }

            var conflictingUsers = FindAllByEmailAddress(user.UnconfirmedEmailAddress);

            if (conflictingUsers.AnySafe(u => u.Key != user.Key))
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, user.UnconfirmedEmailAddress);
            }

            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.ConfirmEmail, user.UnconfirmedEmailAddress));

            user.ConfirmEmailAddress();

            await UserRepository.CommitChangesAsync();

            return(true);
        }
Example #8
0
        public async Task <User> DeleteMemberAsync(Organization organization, string memberName)
        {
            organization = organization ?? throw new ArgumentNullException(nameof(organization));

            var membership = FindMembershipByUsername(organization, memberName);

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

            var memberToRemove = membership.Member;

            // block removal of last admin
            if (membership.IsAdmin && organization.Administrators.Count() == 1)
            {
                throw new EntityException(Strings.DeleteMember_CannotRemoveLastAdmin);
            }

            organization.Members.Remove(membership);

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

            await EntitiesContext.SaveChangesAsync();

            return(memberToRemove);
        }
Example #9
0
        private async Task <SecurityPolicyResult> EvaluateInternalAsync(IEnumerable <UserSecurityPolicy> policies, HttpContextBase httpContext, SecurityPolicyAction action, bool auditSuccess)
        {
            var relevantHandlers = UserHandlers.Where(h => h.Action == action).ToList();

            foreach (var handler in relevantHandlers)
            {
                var foundPolicies = policies.Where(p => p.Name.Equals(handler.Name, StringComparison.OrdinalIgnoreCase)).ToList();

                if (foundPolicies.Any())
                {
                    var user   = httpContext.GetCurrentUser();
                    var result = handler.Evaluate(new UserSecurityPolicyEvaluationContext(httpContext, foundPolicies));

                    if (auditSuccess || !result.Success)
                    {
                        await Auditing.SaveAuditRecordAsync(new UserSecurityPolicyAuditRecord(
                                                                user.Username, GetAuditAction(action), foundPolicies, result.Success, result.ErrorMessage));
                    }

                    if (!result.Success)
                    {
                        Diagnostics.Information(
                            $"Security policy from subscription '{foundPolicies.First().Subscription}' - '{handler.Name}' failed for user '{user.Username}' with error '{result.ErrorMessage}'.");

                        return(result);
                    }
                }
            }

            return(SecurityPolicyResult.SuccessResult);
        }
Example #10
0
        public virtual async Task RemoveCredential(User user, Credential cred)
        {
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.RemoveCredential, cred));

            user.Credentials.Remove(cred);
            Entities.Credentials.Remove(cred);
            await Entities.SaveChangesAsync();
        }
Example #11
0
        public virtual async Task ChangeMultiFactorAuthentication(User user, bool enableMultiFactor)
        {
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, enableMultiFactor ? AuditedUserAction.EnabledMultiFactorAuthentication : AuditedUserAction.DisabledMultiFactorAuthentication));

            user.EnableMultiFactorAuthentication = enableMultiFactor;
            await UserRepository.CommitChangesAsync();

            TelemetryService.TrackUserChangedMultiFactorAuthentication(user, enableMultiFactor);
        }
Example #12
0
        private async Task <AuthenticatedUser> AuthenticateInternal(Func <Credential, Credential> matchCredential, Credential credential)
        {
            if (credential.Type.StartsWith(CredentialTypes.Password.Prefix, StringComparison.OrdinalIgnoreCase))
            {
                // Password credentials cannot be used this way.
                throw new ArgumentException(Strings.PasswordCredentialsCannotBeUsedHere, nameof(credential));
            }

            using (_trace.Activity("Authenticate Credential: " + credential.Type))
            {
                var matched = matchCredential(credential);

                if (matched == null)
                {
                    _trace.Information("No user matches credential of type: " + credential.Type);

                    await Auditing.SaveAuditRecordAsync(
                        new FailedAuthenticatedOperationAuditRecord(null, AuditedAuthenticatedOperationAction.FailedLoginNoSuchUser, attemptedCredential : credential));

                    return(null);
                }

                if (matched.HasExpired)
                {
                    _trace.Verbose("Credential of type '" + matched.Type + "' for user '" + matched.User.Username + "' has expired on " + matched.Expires.Value.ToString("O", CultureInfo.InvariantCulture));

                    return(null);
                }

                if (matched.Type == CredentialTypes.ApiKey.V1 &&
                    !matched.HasBeenUsedInLastDays(_config.ExpirationInDaysForApiKeyV1))
                {
                    // API key credential was last used a long, long time ago - expire it
                    await Auditing.SaveAuditRecordAsync(
                        new UserAuditRecord(matched.User, AuditedUserAction.ExpireCredential, matched));

                    matched.Expires = _dateTimeProvider.UtcNow;
                    await Entities.SaveChangesAsync();

                    _trace.Verbose(
                        "Credential of type '" + matched.Type
                        + "' for user '" + matched.User.Username
                        + "' was last used on " + matched.LastUsed.Value.ToString("O", CultureInfo.InvariantCulture)
                        + " and has now expired.");

                    return(null);
                }

                // update last used timestamp
                matched.LastUsed = _dateTimeProvider.UtcNow;
                await Entities.SaveChangesAsync();

                _trace.Verbose("Successfully authenticated '" + matched.User.Username + "' with '" + matched.Type + "' credential");

                return(new AuthenticatedUser(matched.User, matched));
            }
        }
Example #13
0
        public virtual async Task EditCredentialScopes(User user, Credential cred, ICollection <Scope> newScopes)
        {
            foreach (var oldScope in cred.Scopes.ToArray())
            {
                Entities.Scopes.Remove(oldScope);
            }

            cred.Scopes = newScopes;

            await Entities.SaveChangesAsync();

            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.EditCredential, cred));
        }
Example #14
0
        public virtual async Task CreateSessionAsync(IOwinContext owinContext, AuthenticatedUser user)
        {
            // Create a claims identity for the session
            ClaimsIdentity identity = CreateIdentity(user.User, AuthenticationTypes.LocalUser);

            // Issue the session token and clean up the external token if present
            owinContext.Authentication.SignIn(identity);
            owinContext.Authentication.SignOut(AuthenticationTypes.External);

            // Write an audit record
            await Auditing.SaveAuditRecordAsync(
                new UserAuditRecord(user.User, AuditedUserAction.Login, user.CredentialUsed));
        }
Example #15
0
        public async Task <bool> TransformUserToOrganization(User accountToTransform, User adminUser, string token)
        {
            await SubscribeOrganizationToTenantPolicyIfTenantIdIsSupported(accountToTransform, adminUser);

            var result = await EntitiesContext.TransformUserToOrganization(accountToTransform, adminUser, token);

            if (result)
            {
                await Auditing.SaveAuditRecordAsync(new UserAuditRecord(accountToTransform, AuditedUserAction.TransformOrganization, adminUser, affectedMemberIsAdmin : true));
            }

            return(result);
        }
Example #16
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);
        }
        public async Task ChangeEmailAddress(User user, string newEmailAddress)
        {
            var existingUsers = FindAllByEmailAddress(newEmailAddress);

            if (existingUsers.AnySafe(u => u.Key != user.Key))
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, newEmailAddress);
            }

            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(user, AuditedUserAction.ChangeEmail, newEmailAddress));

            user.UpdateEmailAddress(newEmailAddress, Crypto.GenerateToken);
            await UserRepository.CommitChangesAsync();
        }
Example #18
0
        public virtual async Task <AuthenticatedUser> Register(string username, string emailAddress, Credential credential)
        {
            if (_config.FeedOnlyMode)
            {
                throw new FeedOnlyModeException(FeedOnlyModeException.FeedOnlyModeError);
            }

            var existingUser = Entities.Users
                               .FirstOrDefault(u => u.Username == username || u.EmailAddress == emailAddress);

            if (existingUser != null)
            {
                if (string.Equals(existingUser.Username, username, StringComparison.OrdinalIgnoreCase))
                {
                    throw new EntityException(Strings.UsernameNotAvailable, username);
                }
                else
                {
                    throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
                }
            }

            var newUser = new User(username)
            {
                EmailAllowed            = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken  = CryptographyService.GenerateToken(),
                NotifyPackagePushed     = true,
                CreatedUtc = _dateTimeProvider.UtcNow
            };

            // Add a credential for the password
            newUser.Credentials.Add(credential);

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

            // Write an audit record
            await Auditing.SaveAuditRecordAsync(new UserAuditRecord(newUser, AuditedUserAction.Register, credential));

            Entities.Users.Add(newUser);
            await Entities.SaveChangesAsync();

            return(new AuthenticatedUser(newUser, credential));
        }
Example #19
0
        public virtual async Task GeneratePasswordResetToken(User user, int expirationInMinutes)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (expirationInMinutes < 1)
            {
                throw new ArgumentException(
                          Strings.TokenExpirationShouldGiveUser1MinuteToChangePassword, nameof(expirationInMinutes));
            }

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

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

            user.PasswordResetToken = CryptographyService.GenerateToken();
            user.PasswordResetTokenExpirationDate = _dateTimeProvider.UtcNow.AddMinutes(expirationInMinutes);

            var passwordCredential = user.Credentials.FirstOrDefault(
                credential => credential.Type.StartsWith(CredentialTypes.Password.Prefix, StringComparison.OrdinalIgnoreCase));

            UserAuditRecord auditRecord;

            if (passwordCredential == null)
            {
                auditRecord = new UserAuditRecord(user, AuditedUserAction.RequestPasswordReset);
            }
            else
            {
                auditRecord = new UserAuditRecord(user, AuditedUserAction.RequestPasswordReset, passwordCredential);
            }

            await Auditing.SaveAuditRecordAsync(auditRecord);

            await Entities.SaveChangesAsync();
        }
Example #20
0
        public async Task <bool> TransformUserToOrganization(User accountToTransform, User adminUser, string token)
        {
            if (accountToTransform.OrganizationMigrationRequest == null ||
                !accountToTransform.OrganizationMigrationRequest.AdminUser.MatchesUser(adminUser) ||
                accountToTransform.OrganizationMigrationRequest.ConfirmationToken != token)
            {
                return(false);
            }

            await SubscribeOrganizationToTenantPolicyIfTenantIdIsSupported(accountToTransform, adminUser);

            var result = await EntitiesContext.TransformUserToOrganization(accountToTransform, adminUser, token);

            if (result)
            {
                await Auditing.SaveAuditRecordAsync(new UserAuditRecord(accountToTransform, AuditedUserAction.TransformOrganization, adminUser, affectedMemberIsAdmin : true));
            }

            return(result);
        }
        /// <summary>
        /// Unsubscribe a user from one or more security policies.
        /// </summary>
        public async Task UnsubscribeAsync(User user, IUserSecurityPolicySubscription subscription, bool commitChanges = true)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }
            if (subscription == null)
            {
                throw new ArgumentNullException(nameof(subscription));
            }

            var matches = FindPolicies(user, subscription).ToList();

            if (matches.Any())
            {
                foreach (var policy in matches)
                {
                    user.SecurityPolicies.Remove(policy);

                    EntitiesContext.UserSecurityPolicies.Remove(policy);
                }

                await subscription.OnUnsubscribeAsync(new UserSecurityPolicySubscriptionContext(this, user));

                await Auditing.SaveAuditRecordAsync(
                    new UserAuditRecord(user, AuditedUserAction.UnsubscribeFromPolicies, subscription.Policies));

                if (commitChanges)
                {
                    await EntitiesContext.SaveChangesAsync();
                }

                Diagnostics.Information($"User is now unsubscribed from '{subscription.SubscriptionName}'.");
            }
            else
            {
                Diagnostics.Information($"User is already unsubscribed from '{subscription.SubscriptionName}'.");
            }
        }
Example #22
0
        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)));
            }
        }
        private async Task <SecurityPolicyResult> EvaluatePackagePoliciesInternalAsync(
            SecurityPolicyAction action,
            Package package,
            User sourceAccount,
            User targetAccount,
            HttpContextBase httpContext,
            IEnumerable <UserSecurityPolicy> policies = null,
            bool auditSuccess = true)
        {
            policies = policies ?? targetAccount.SecurityPolicies;

            var relevantHandlers = PackageHandlers.Where(h => h.Action == action).ToList();

            var packagePoliciesResult = SecurityPolicyResult.SuccessResult;

            foreach (var handler in relevantHandlers)
            {
                var foundPolicies = policies.Where(p => p.Name.Equals(handler.Name, StringComparison.OrdinalIgnoreCase)).ToList();

                if (foundPolicies.Any())
                {
                    var context = new PackageSecurityPolicyEvaluationContext(
                        _userService.Value,
                        _packageOwnershipManagementService.Value,
                        _telemetryService,
                        foundPolicies,
                        package,
                        sourceAccount,
                        targetAccount,
                        httpContext);

                    var result = await handler.EvaluateAsync(context);

                    if (auditSuccess || !result.Success)
                    {
                        await Auditing.SaveAuditRecordAsync(new UserSecurityPolicyAuditRecord(
                                                                context.TargetAccount.Username, GetAuditAction(action), foundPolicies, result.Success, result.ErrorMessage));
                    }

                    if (!result.Success)
                    {
                        Diagnostics.Information(
                            $"Security policy from subscription '{foundPolicies.First().Subscription}' - '{handler.Name}' failed with error '{result.ErrorMessage}'.");

                        return(result);
                    }

                    if (result.HasWarnings)
                    {
                        if (packagePoliciesResult == SecurityPolicyResult.SuccessResult)
                        {
                            packagePoliciesResult = result;
                        }
                        else
                        {
                            packagePoliciesResult.AddWarnings(result.WarningMessages);
                        }
                    }
                }
            }

            return(packagePoliciesResult);
        }
Example #24
0
        public async Task <Membership> AddMemberAsync(Organization organization, string memberName, string confirmationToken)
        {
            organization = organization ?? throw new ArgumentNullException(nameof(organization));

            var request = FindMembershipRequestByUsername(organization, memberName);

            if (request == null || request.ConfirmationToken != confirmationToken)
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.AddMember_MissingRequest, memberName));
            }

            var member = request.NewMember;

            organization.MemberRequests.Remove(request);

            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));
            }

            var membership = FindMembershipByUsername(organization, memberName);

            if (membership == null)
            {
                // 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(string.Format(CultureInfo.CurrentCulture,
                                                            Strings.AddMember_PolicyFailure, policyResult.ErrorMessage));
                }

                membership = new Membership()
                {
                    Member  = member,
                    IsAdmin = request.IsAdmin
                };
                organization.Members.Add(membership);

                await Auditing.SaveAuditRecordAsync(new UserAuditRecord(organization, AuditedUserAction.AddOrganizationMember, membership));
            }
            else
            {
                // If the user is already a member, update the existing membership.
                // If the request grants admin but this member is not an admin, grant admin to the member.
                membership.IsAdmin = membership.IsAdmin || request.IsAdmin;

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

            await EntitiesContext.SaveChangesAsync();

            return(membership);
        }