Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/sync single group #603

Merged
merged 3 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/integrations/aws/identity_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ def list_groups_with_memberships(
"""Retrieves groups with their members from the AWS Identity Center (identitystore)

Args:
group_members (bool): Include group members in the response. Default is True.
members_details (bool): Include the details of the members. Default is True.
include_empty_groups (bool): Include groups without members. Default is True.
groups_filters (list): A list of filters to apply to the groups. Default is None.
**kwargs: Additional keyword arguments for the API call. (passed to list_groups)

Returns:
Expand All @@ -309,6 +313,7 @@ def list_groups_with_memberships(
if groups_filters is not None:
for groups_filter in groups_filters:
groups = filters.filter_by_condition(groups, groups_filter)
logger.info(f"Founds {len(groups)} groups in AWS Identity Store.")
if not group_members:
return groups

Expand Down
9 changes: 7 additions & 2 deletions app/integrations/google_workspace/google_directory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Google Directory module to interact with the Google Workspace Directory API."""

from logging import getLogger
from integrations.google_workspace.google_service import (
handle_google_api_errors,
execute_google_api_call,
Expand All @@ -9,6 +10,8 @@
from integrations.utils.api import convert_string_to_camel_case
from utils import filters

logger = getLogger(__name__)


@handle_google_api_errors
def get_user(user_key, delegated_user_email=None):
Expand Down Expand Up @@ -181,8 +184,10 @@ def list_groups_with_members(
if not groups:
return []

for filter in groups_filters:
groups = filters.filter_by_condition(groups, filter)
if groups_filters is not None:
for groups_filter in groups_filters:
groups = filters.filter_by_condition(groups, groups_filter)
logger.info(f"Found {len(groups)} groups.")
if not group_members:
return groups

Expand Down
24 changes: 23 additions & 1 deletion app/modules/aws/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,37 @@ def command_handler(client, body, respond, args, logger):


def request_groups_sync(client, body, respond, args, logger):
"""Sync groups from AWS Identity Center."""
"""Sync groups from AWS Identity Center.

If additional arguments are provided, they will be used to filter the groups to sync.

Args:
client (Slack WebClient): The Slack client.
body (dict): The request body.
respond (function): The function to respond to the request.
args (list[str]): The list of arguments.
logger (Logger): The logger.
"""
requestor_email = slack_users.get_user_email_from_body(client, body)
if permissions.is_user_member_of_groups(requestor_email, AWS_ADMIN_GROUPS):
pre_processing_filters = (
[
lambda group, arg=arg: arg.lower()
in group.get("DisplayName", "").lower()
or arg.lower() in group.get("name", "").lower()
for arg in args
]
if args
else []
)
logger.info("Synchronizing AWS Identity Center Groups.")
respond("AWS Groups Memberships Synchronization Initiated.")
identity_center.synchronize(
enable_users_sync=False,
enable_user_create=False,
enable_membership_create=True,
enable_membership_delete=True,
pre_processing_filters=pre_processing_filters,
)
else:
logger.error(f"User {requestor_email} does not have permission to sync groups.")
Expand Down
10 changes: 8 additions & 2 deletions app/modules/aws/identity_center.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,26 @@ def synchronize(**kwargs):
enable_membership_create = kwargs.pop("enable_membership_create", True)
enable_membership_delete = kwargs.pop("enable_membership_delete", False)
query = kwargs.pop("query", "email:aws-*")
pre_processing_filters = kwargs.pop("pre_processing_filters", [])

users_sync_status = None
groups_sync_status = None

source_groups_filters = [lambda group: "AWS-" in group["name"]]
source_groups = groups.get_groups_from_integration(
"google_groups", query=query, post_processing_filters=source_groups_filters
"google_groups",
query=query,
pre_processing_filters=pre_processing_filters,
post_processing_filters=source_groups_filters,
)
source_users = filters.get_unique_nested_dicts(source_groups, "members")
logger.info(
f"synchronize:Found {len(source_groups)} Groups and {len(source_users)} Users from Source"
)

target_groups = groups.get_groups_from_integration("aws_identity_center")
target_groups = groups.get_groups_from_integration(
"aws_identity_center", pre_processing_filters=pre_processing_filters
)
target_users = identity_store.list_users()

logger.info(
Expand Down
37 changes: 36 additions & 1 deletion app/tests/modules/aws/test_aws_groups.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from unittest.mock import patch, MagicMock, call
from unittest.mock import patch, MagicMock, call, ANY
from modules.aws import groups


Expand Down Expand Up @@ -86,9 +86,44 @@ def test_request_groups_sync_synchronizes_groups(
)
logger.info.assert_called_once_with("Synchronizing AWS Identity Center Groups.")
mock_identity_center.synchronize.assert_called_once_with(
enable_users_sync=False,
enable_user_create=False,
enable_membership_create=True,
enable_membership_delete=True,
pre_processing_filters=[],
)
respond.assert_called_once_with("AWS Groups Memberships Synchronization Initiated.")


@patch("modules.aws.groups.slack_users")
@patch("modules.aws.groups.permissions")
@patch("modules.aws.groups.identity_center")
def test_request_groups_sync_synchronizes_groups_with_args(
mock_identity_center, mock_permissions, mock_slack_users
):
client = MagicMock()
body = MagicMock()
respond = MagicMock()
args = ["group1", "group2"]
logger = MagicMock()

mock_slack_users.get_user_email_from_body.return_value = "[email protected]"
mock_permissions.is_user_member_of_groups.return_value = True
mock_identity_center.synchronize.return_value = None

groups.request_groups_sync(client, body, respond, args, logger)

mock_slack_users.get_user_email_from_body.assert_called_once_with(client, body)
mock_permissions.is_user_member_of_groups.assert_called_once_with(
"[email protected]", groups.AWS_ADMIN_GROUPS
)
logger.info.assert_called_once_with("Synchronizing AWS Identity Center Groups.")
mock_identity_center.synchronize.assert_called_once_with(
enable_users_sync=False,
enable_user_create=False,
enable_membership_create=True,
enable_membership_delete=True,
pre_processing_filters=ANY,
)
respond.assert_called_once_with("AWS Groups Memberships Synchronization Initiated.")

Expand Down
30 changes: 22 additions & 8 deletions app/tests/modules/aws/test_sync_identity_center.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,13 @@ def test_synchronize_sync_users_and_groups_with_defaults(

assert mock_groups.get_groups_from_integration.call_count == 2
assert mock_groups.get_groups_from_integration.call_args_list == [
call("google_groups", query="email:aws-*", post_processing_filters=ANY),
call("aws_identity_center"),
call(
"google_groups",
query="email:aws-*",
pre_processing_filters=[],
post_processing_filters=ANY,
),
call("aws_identity_center", pre_processing_filters=[]),
]

assert mock_identity_store.list_users.call_count == 2
Expand Down Expand Up @@ -284,9 +289,12 @@ def test_synchronize_sync_skip_users_if_false(
assert mock_groups.get_groups_from_integration.call_count == 2

google_groups_call = call(
"google_groups", query="email:aws-*", post_processing_filters=ANY
"google_groups",
query="email:aws-*",
pre_processing_filters=[],
post_processing_filters=ANY,
)
aws_identity_center_call = call("aws_identity_center")
aws_identity_center_call = call("aws_identity_center", pre_processing_filters=[])
assert mock_groups.get_groups_from_integration.call_args_list == [
google_groups_call,
aws_identity_center_call,
Expand Down Expand Up @@ -351,9 +359,12 @@ def test_synchronize_sync_skip_groups_false_if_false(
assert mock_groups.get_groups_from_integration.call_count == 2

google_groups_call = call(
"google_groups", query="email:aws-*", post_processing_filters=ANY
"google_groups",
query="email:aws-*",
pre_processing_filters=[],
post_processing_filters=ANY,
)
aws_identity_center_call = call("aws_identity_center")
aws_identity_center_call = call("aws_identity_center", pre_processing_filters=[])
assert mock_groups.get_groups_from_integration.call_args_list == [
google_groups_call,
aws_identity_center_call,
Expand Down Expand Up @@ -419,9 +430,12 @@ def test_synchronize_sync_skip_users_and_groups_if_false(
assert mock_groups.get_groups_from_integration.call_count == 2

google_groups_call = call(
"google_groups", query="email:aws-*", post_processing_filters=ANY
"google_groups",
query="email:aws-*",
pre_processing_filters=[],
post_processing_filters=ANY,
)
aws_identity_center_call = call("aws_identity_center")
aws_identity_center_call = call("aws_identity_center", pre_processing_filters=[])
assert mock_groups.get_groups_from_integration.call_args_list == [
google_groups_call,
aws_identity_center_call,
Expand Down
Loading