diff --git a/azure_dbr_scim_sync/cli.py b/azure_dbr_scim_sync/cli.py index 3f6084e..41a23ee 100644 --- a/azure_dbr_scim_sync/cli.py +++ b/azure_dbr_scim_sync/cli.py @@ -58,9 +58,21 @@ is_flag=True, show_default=True, help="synchronizes all groups defined in `groups-json-file` instead of using graph api change feed") +@click.option( + '--include-non-security-groups', + default=False, + is_flag=True, + show_default=True, + help="include non-security Entra groups in the sync") +@click.option( + '--include-mail-enabled-groups', + default=False, + is_flag=True, + show_default=True, + help="include mail-enabled Entra groups in the sync") def sync_cli(groups_json_file, verbose, debug, dry_run_security_principals, dry_run_members, worker_threads, save_graph_response_json, query_graph_only, group_search_depth, full_sync, - graph_change_feed_grace_time): + graph_change_feed_grace_time, include_non_security_groups, include_mail_enabled_groups): install_logger() logger = logging.getLogger('sync') @@ -71,7 +83,10 @@ def sync_cli(groups_json_file, verbose, debug, dry_run_security_principals, dry_ if verbose: logger.setLevel(logging.DEBUG) - graph_client = GraphAPIClient() + graph_client = GraphAPIClient( + include_mail_enabled_groups=include_mail_enabled_groups, + include_non_security_groups=include_non_security_groups + ) account_client = get_account_client() if groups_json_file: diff --git a/azure_dbr_scim_sync/graph.py b/azure_dbr_scim_sync/graph.py index 024c1c0..c2d44e6 100644 --- a/azure_dbr_scim_sync/graph.py +++ b/azure_dbr_scim_sync/graph.py @@ -74,9 +74,14 @@ def save_to_json_file(self, file_name: str): class GraphAPIClient: - def __init__(self, tenant_id: str = None, spn_id: str = None, spn_key: str = None): + def __init__(self, + include_mail_enabled_groups: bool = False, + include_non_security_groups: bool = False): self._tenant_id = None + self._include_mail_enabled_groups = include_mail_enabled_groups + self._include_non_security_groups = include_non_security_groups + retry_strategy = Retry( total=6, backoff_factor=1, @@ -123,10 +128,13 @@ def get_group_by_name(self, name: str) -> dict: if data and len(data) == 1: group_info = data[0] # https://learn.microsoft.com/en-us/graph/api/resources/groups-overview?view=graph-rest-1.0&tabs=http#group-types-in-microsoft-entra-id-and-microsoft-graph - if group_info.get('mailEnabled') == False and group_info.get('securityEnabled') == True: + if ( + (group_info.get('securityEnabled') or self._include_non_security_groups) and + ((not group_info.get('mailEnabled')) or self._include_mail_enabled_groups) + ): return group_info - logger.warning(f"Skipping non security group '{name}': {data}") + logger.warning(f"Skipping group '{name}': {data}") return None @@ -240,12 +248,15 @@ def _register_group(d): id = d['id'] if id not in sync_data.groups: try: - if d.get('mailEnabled') == False and d.get('securityEnabled') == True: + if ( + (d.get('securityEnabled') or self._include_non_security_groups) and + ((not d.get('mailEnabled')) or self._include_mail_enabled_groups) + ): obj = GraphGroup.model_validate(d) sync_data.groups[id] = obj logger.debug(f"Downloaded GraphGroup: {obj}") else: - logger.info(f"Skipping non security group '{d['displayName']}': {d}") + logger.info(f"Skipping group '{d['displayName']}': {d}") return None except Exception as e: logger.error(f"Invalid GraphGroup: {d}", exc_info=e)