Example #1
0
        public async Task <Group> AddChildGroups(Group group, IEnumerable <Group> childGroups)
        {
            // do not allow non-custom group to be parent
            if (!string.Equals(group.Source, GroupConstants.CustomSource, StringComparison.OrdinalIgnoreCase))
            {
                throw new BadRequestException <Group>($"{group.Name} is not a custom group. Only custom groups can serve as parent groups.");
            }

            // first make sure all the child groups are created
            var childGroupList = childGroups.ToList();

            var customGroupChildGroupWithSameName = (await _groupStore.Get(
                                                         childGroupList.Select(g => new GroupIdentifier {
                GroupName = g.GroupIdentifier.GroupName
            }), true)).ToList();

            if (customGroupChildGroupWithSameName.Any())
            {
                throw new AlreadyExistsException <Group>(
                          $"The associated user or group name should not be the same as an existing custom group: {string.Join(", ", customGroupChildGroupWithSameName.Select(g => g.Name))}");
            }

            try
            {
                await _groupStore.Get(
                    childGroupList.Select(g => g.GroupIdentifier), false);
            }
            // filter out groups that already exist so we don't attempt to create an existent group
            catch (NotFoundException <Group> ex)
            {
                var missingChildGroups = childGroupList.Where(g => ex.ExceptionDetails.Select(e => e.Identifier).Contains(g.GroupIdentifier.ToString())).ToList();

                var invalidMissingGroups =
                    missingChildGroups.Where(g => string.IsNullOrWhiteSpace(g.Name) ||
                                             string.IsNullOrWhiteSpace(g.Source) ||
                                             string.IsNullOrWhiteSpace(g.IdentityProvider) ||
                                             !IdentityConstants.ValidIdentityProviders.Contains(g.IdentityProvider, StringComparer.OrdinalIgnoreCase) ||
                                             string.Equals(g.Source, GroupConstants.CustomSource,
                                                           StringComparison.OrdinalIgnoreCase)).ToList();

                if (invalidMissingGroups.Any())
                {
                    throw new BadRequestException <Group>(
                              "The following child groups do not exist in our database and cannot be created due to 1 or more of the following reasons: " +
                              "1) missing GroupName, 2) missing GroupSource, 3) the GroupSource is incorrectly specified as Custom, or 4) The IdentityProvider field is missing or invalid: " +
                              $"{string.Join(", ", invalidMissingGroups.Select(g => g.Name))}");
                }
                await _groupStore.Add(missingChildGroups);
            }

            var childGroupIdentifierList = childGroupList.Select(g => g.GroupIdentifier).ToList();

            // do not allow custom groups to be children
            // can't find where this code is hit, since the catch above looks for g.Source equal to CustomSource
            childGroups = (await _groupStore.Get(childGroupIdentifierList, false)).ToList();
            var customGroups = childGroups.Where(g => g.Source == GroupConstants.CustomSource).ToList();

            if (customGroups.Any())
            {
                throw new BadRequestException <Group>($"Only directory groups can be child groups. The following groups are Custom groups: {string.Join(", ", customGroups)} ");
            }

            // if association already exists, return 409
            var existingAssociations = group.Children.Where(c => childGroupIdentifierList.Contains(c.GroupIdentifier, new GroupIdentifierComparer())).ToList();

            if (existingAssociations.Any())
            {
                throw new AlreadyExistsException <Group>(
                          $"The following groups are already children of group {group.Name}: {string.Join(", ", existingAssociations.Select(g => $"{g.Name} (IdP={g.IdentityProvider}, Tenant={g.TenantId})"))}");
            }

            return(await _groupStore.AddChildGroups(group, childGroups));
        }
Example #2
0
        public async Task <GroupMigrationResult> MigrateDuplicateGroups()
        {
            var groups = (await _groupStore.GetAll()).ToList();

            var groupKeys = groups
                            .GroupBy(g => g.GroupIdentifier, new GroupIdentifierComparer())
                            .Where(g => g.Count() > 1)
                            .Select(g => g.Key)
                            .ToList();

            var groupMigrationResult = new GroupMigrationResult();

            foreach (var key in groupKeys)
            {
                var duplicateGroups = groups.Where(g => new GroupIdentifierComparer().Equals(g.GroupIdentifier, key)).ToList();
                var originalGroup   = duplicateGroups.First();
                duplicateGroups.RemoveAt(0);

                var groupMigrationRecord = new GroupMigrationRecord
                {
                    DuplicateCount = duplicateGroups.Count
                };

                var deletedDuplicateGroups = new List <Group>();
                foreach (var duplicateGroup in duplicateGroups)
                {
                    try
                    {
                        await _groupStore.Delete(duplicateGroup);

                        deletedDuplicateGroups.Add(duplicateGroup);
                    }
                    catch (Exception e)
                    {
                        var msg = $"Exception thrown while deleting DUPLICATE group {duplicateGroup}";
                        _logger.Error(e, msg);
                        groupMigrationRecord.Errors.Add($"{msg} ({e.Message})");
                    }
                }

                // only migrate the groups that were successfully deleted
                foreach (var duplicateGroup in deletedDuplicateGroups)
                {
                    // migrate roles
                    foreach (var role in duplicateGroup.Roles)
                    {
                        var roleExists = originalGroup.Roles.Any(r => r.Equals(role));
                        if (!roleExists)
                        {
                            _logger.Information($"Migrating Role {role} from {duplicateGroup} to group {originalGroup}");
                            try
                            {
                                await _groupStore.AddRolesToGroup(originalGroup, new List <Role> {
                                    role
                                });
                            }
                            catch (Exception e)
                            {
                                var msg = $"Error migrating Role {role} to Group {originalGroup}";
                                _logger.Error(e, msg);
                                groupMigrationRecord.Errors.Add($"{msg} ({e.Message})");
                            }
                        }
                    }

                    // migrate users (applies custom groups only)
                    foreach (var user in duplicateGroup.Users)
                    {
                        var userExists = originalGroup.Users.Any(u => new UserComparer().Equals(u, user));
                        if (!userExists)
                        {
                            _logger.Information($"Migrating User {user} from {duplicateGroup} to group {originalGroup}");
                            try
                            {
                                await _groupStore.AddUsersToGroup(originalGroup, new List <User> {
                                    user
                                });
                            }
                            catch (Exception e)
                            {
                                var msg = $"Error migrating User {user} to Group {originalGroup}";
                                _logger.Error(e, msg);
                                groupMigrationRecord.Errors.Add($"{msg} ({e.Message})");
                            }
                        }
                    }

                    // migrate directory groups to new parents (this will not execute if the duplicate group is a custom group)
                    foreach (var parent in duplicateGroup.Parents)
                    {
                        var parentExists = originalGroup.Parents.Any(p => p.Id == parent.Id);
                        if (!parentExists)
                        {
                            _logger.Information($"Migrating Group {originalGroup} to Parent Group {parent}");
                            try
                            {
                                await _groupStore.AddChildGroups(parent, new List <Group> {
                                    originalGroup
                                });
                            }
                            catch (Exception e)
                            {
                                var msg = $"Error migrating Directory Child Group {originalGroup} to Parent Group {parent}";
                                _logger.Error(e, msg);
                                groupMigrationRecord.Errors.Add($"{msg} ({e.Message})");
                            }
                        }
                    }

                    // migrate custom parent groups to new child groups (this will not execute if the duplicate group is a directory group)
                    foreach (var child in duplicateGroup.Children)
                    {
                        var childExists = originalGroup.Children.Any(c => c.Id == child.Id);
                        if (!childExists)
                        {
                            _logger.Information($"Error migrating Custom Parent Group {originalGroup} to Child Group {child}");
                            try
                            {
                                await _groupStore.AddChildGroups(originalGroup, new List <Group> {
                                    child
                                });
                            }
                            catch (Exception e)
                            {
                                var msg = $"Error migrating Custom Parent Group {originalGroup} to Child Group {child}";
                                _logger.Error(e, msg);
                                groupMigrationRecord.Errors.Add($"{msg} ({e.Message})");
                            }
                        }
                    }
                }

                groupMigrationRecord.MigratedGroup = originalGroup;
                groupMigrationResult.GroupMigrationRecords.Add(groupMigrationRecord);
            }

            return(groupMigrationResult);
        }