Skip to content

Commit 5e9e01b

Browse files
committed
Merge branch 'feature/sign-exclusion' into v2
2 parents 1ddd84a + 93636cf commit 5e9e01b

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

user_sync/config/sign_sync.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ def config_schema() -> Schema:
5656
}
5757
})
5858

59+
def connector_schema() -> Schema:
60+
from schema import And, Optional, Or, Regex
61+
return Schema({
62+
'host': str,
63+
Or('integration_key', 'secure_integration_key'): str,
64+
'admin_email': str,
65+
Optional('create_users'): Optional(bool),
66+
Optional('deactivate_users'): Optional(bool),
67+
Optional('exclusions'): {
68+
Optional('groups'): list,
69+
Optional('users'): list,
70+
}
71+
})
5972

6073
class SignConfigLoader(ConfigLoader):
6174
"""
@@ -96,7 +109,7 @@ def __init__(self, args: dict):
96109
filename, encoding = self._config_file_info()
97110
self.config_loader = ConfigFileLoader(encoding, self.ROOT_CONFIG_PATH_KEYS, self.SUB_CONFIG_PATH_KEYS)
98111
self.raw_config = self._load_raw_config(filename, encoding)
99-
self._validate(self.raw_config)
112+
self._validate(config_schema, self.raw_config)
100113
self.main_config = self.load_main_config(filename, self.raw_config)
101114
self.invocation_options = self.load_invocation_options()
102115
self.directory_groups = self.load_directory_groups()
@@ -143,10 +156,10 @@ def _load_raw_config(self, filename, encoding) -> dict:
143156
return self.config_loader.load_root_config(filename)
144157

145158
@staticmethod
146-
def _validate(raw_config: dict):
159+
def _validate(schm, raw_config: dict):
147160
from schema import SchemaError
148161
try:
149-
config_schema().validate(raw_config)
162+
schm().validate(raw_config)
150163
except SchemaError as e:
151164
raise ConfigValidationError(e.code) from e
152165

@@ -211,11 +224,14 @@ def get_target_options(self) -> dict[str, dict]:
211224
if self.DEFAULT_ORG_NAME not in target_configs:
212225
raise AssertionException(f"'sign_orgs' config must specify a connector with '{self.DEFAULT_ORG_NAME}' key")
213226
primary_options = self.config_loader.load_sub_config(target_configs[self.DEFAULT_ORG_NAME])
227+
self._validate(connector_schema, primary_options)
214228
all_options = {}
215229
for target_id, config_file in target_configs.items():
216230
if target_id == self.DEFAULT_ORG_NAME:
217231
continue
218-
all_options[target_id] = self.config_loader.load_sub_config(config_file)
232+
cfg = self.config_loader.load_sub_config(config_file)
233+
self._validate(connector_schema, cfg)
234+
all_options[target_id] = cfg
219235
all_options[self.DEFAULT_ORG_NAME] = primary_options
220236
return all_options
221237

user_sync/connector/connector_sign.py

+15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from ..error import AssertionException
2828
from sign_client.client import SignClient
2929
from pathlib import Path
30+
import re
3031

3132

3233
class SignConnector(object):
@@ -45,6 +46,20 @@ def __init__(self, caller_options, org_name, test_mode, connection, cache_config
4546
sign_builder.require_string_value('admin_email')
4647
self.create_users = sign_builder.require_value('create_users', bool)
4748
self.deactivate_users = sign_builder.require_value('deactivate_users', bool)
49+
50+
exclusion_config = caller_config.get_dict_config('exclusions', True)
51+
exclusion_builder = OptionsBuilder(exclusion_config)
52+
exclusion_builder.set_value('groups', list, [])
53+
exclusion_builder.set_value('users', list, [])
54+
55+
self.exclusion_options = exclusion_builder.get_options()
56+
57+
if 'users' in self.exclusion_options:
58+
compiled_rules = []
59+
for rule in self.exclusion_options['users']:
60+
compiled_rules.append(re.compile(rule))
61+
self.exclusion_options['users'] = compiled_rules
62+
4863
store_path = Path(cache_config['path'])
4964

5065
options = sign_builder.get_options()

user_sync/engine/sign.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from sign_client.error import AssertionException as ClientException
88

99
from sign_client.model import DetailedUserInfo, GroupInfo, UserGroupsInfo, UserGroupInfo, DetailedGroupInfo, UserStateInfo
10+
import re
1011

1112

1213
class SignSyncEngine:
@@ -130,6 +131,18 @@ def log_action_summary(self):
130131
for description, count in self.action_summary.items():
131132
self.logger.info(' {}: {}'.format(description.rjust(pad, ' '), count))
132133

134+
def sign_user_excluded(self, user, user_groups, connector):
135+
if 'users' in connector.exclusion_options:
136+
for rule in connector.exclusion_options['users']:
137+
if rule.match(user.email.lower()):
138+
return True
139+
if 'groups' in connector.exclusion_options:
140+
user_group_names = set([ug.name.lower() for ug in user_groups])
141+
for group in connector.exclusion_options['groups']:
142+
if group.lower() in user_group_names:
143+
return True
144+
return False
145+
133146
def update_sign_users(self, directory_users, sign_connector: SignConnector, org_name):
134147
"""
135148
Updates user details or inserts new user
@@ -139,9 +152,12 @@ def update_sign_users(self, directory_users, sign_connector: SignConnector, org_
139152
:return:
140153
"""
141154
# Fetch the list of active Sign users
142-
sign_users = {user.email: user for user in sign_connector.get_users().values() if user.status != 'INACTIVE'}
143-
inactive_sign_users = {user.email: user for user in sign_connector.get_users().values() if user.status == 'INACTIVE'}
144155
sign_user_groups = sign_connector.get_user_groups()
156+
all_users = sign_connector.get_users().values()
157+
filtered_users = {user.email: user for user in all_users if not self.sign_user_excluded(user, sign_user_groups[user.id], sign_connector)}
158+
sign_users = {user.email: user for user in filtered_users.values() if user.status != 'INACTIVE'}
159+
inactive_sign_users = {user.email: user for user in filtered_users.values() if user.status == 'INACTIVE'}
160+
self.excluded_users = {user.email: user for user in all_users if self.sign_user_excluded(user, sign_user_groups[user.id], sign_connector)}
145161
self.sign_user_primary_groups[org_name] = {id: [g for g in groups if g.isPrimaryGroup][0] for id, groups in sign_user_groups.items()}
146162
users_update_list = []
147163
user_groups_update_list = []
@@ -161,6 +177,9 @@ def update_sign_users(self, directory_users, sign_connector: SignConnector, org_
161177
assignment_group = self.default_groups[org_name].groupName
162178
user_roles = self.retrieve_admin_role(directory_user)
163179
if sign_user is None:
180+
if directory_user['email'] in self.excluded_users:
181+
self.logger.debug("(%s) Found excluded user %s directory user list, skipping", org_name, directory_user['email'])
182+
continue
164183
if sign_connector.create_users:
165184
inactive_user = inactive_sign_users.get(directory_user_key)
166185
# if Standalone user is inactive, we need to reactivate instead of trying to create new account

0 commit comments

Comments
 (0)