diff --git a/README.md b/README.md index 07bd67d..9c560c4 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,9 @@ For the grafana integration the following 3 must exist and have valid values, th - GONB_GRAFANA_MAIN_ORG - allow management of Grafana `Main Org.`, default `False` - GONB_GRAFANA_TEAM_FOLDER - create team folder, default `True` - GONB_SSO_PROVIDER - specify if the provider is based on a IAM used for Grafana authentication, default `True`. +- GONB_GRAFANA_DELETE_EXTERNAL_AUTH_USERS - if set to `True` gonb will delete users that are not in the + source system, but have been created just by Grafana through the auth process. Default is `False`. + This options should typical only be used if all users are provisioned by gonb. > If `GONB_SSO_PROVIDER` is True there is some updating operations that are not done by gonb, e.g. update a > user's name or email. diff --git a/gonb/grafana.py b/gonb/grafana.py index 6a52630..53d2710 100644 --- a/gonb/grafana.py +++ b/gonb/grafana.py @@ -43,6 +43,7 @@ GONB_SSO_PROVIDER = 'GONB_SSO_PROVIDER' GONB_GRAFANA_MAIN_ORG = 'GONB_GRAFANA_MAIN_ORG' GONB_GRAFANA_TEAM_FOLDER = 'GONB_GRAFANA_TEAM_FOLDER' +GONB_GRAFANA_DELETE_EXTERNAL_AUTH_USERS = 'GONB_GRAFANA_DELETE_EXTERNAL_AUTH_USERS' MAIN_ORG = 'Main Org.' ADMIN = 'Admin' @@ -575,12 +576,15 @@ def provision(self, iam_organisations: Dict[str, Organization]) \ # for organisation_name in set(source_users_idx.keys()).union(set(self.customer_users_idx.keys())): # Only manage users that is part of we got from the source users_managed = {} + # This enables that external auth users can be deleted - only use this if all users are provisioned from IAM + # and not automaticaly added in grafana + delete_external_auth_users = strtobool(os.getenv(GONB_GRAFANA_DELETE_EXTERNAL_AUTH_USERS, 'FALSE')) for organisation_name in set(iam_organisations.keys()): users_managed[organisation_name] = {} users_managed[organisation_name][UPDATED] = \ self._update_users(organisation_name, diff_users.update(organisation_name), iam_organisations) users_managed[organisation_name][REMOVED] = \ - self._remove_users(organisation_name, diff_users.delete(organisation_name)) + self._remove_users(organisation_name, diff_users.delete(organisation_name, delete_external_auth_users)) users_managed[organisation_name][ADDED] = \ self._add_users(organisation_name, diff_users.add(organisation_name), iam_organisations) diff --git a/gonb/organization.py b/gonb/organization.py index e0f62b9..bba05d5 100644 --- a/gonb/organization.py +++ b/gonb/organization.py @@ -52,16 +52,17 @@ def add(self, organisation_name: str) -> Set[str]: add_users.remove(self.exclude_user) return add_users - def delete(self, organisation_name: str) -> Set[str]: + def delete(self, organisation_name: str, delete_external_sso_users: bool = False) -> Set[str]: self._init(organisation_name=organisation_name) del_users = self.grafana_users_idx[organisation_name] - self.iam_users_idx[organisation_name] if self.exclude_user in del_users: del_users.remove(self.exclude_user) # Exclude users from grafana that have external auth - for user_name in del_users: - if self._grafana_orgs[organisation_name].users[user_name].external_auth: + for user_name in del_users.copy(): + if self._grafana_orgs[organisation_name].users[user_name].external_auth and not delete_external_sso_users: log.info("exclude delete of user due to external SSO", extra={'organization': organisation_name, 'user': user_name}) self._grafana_orgs[organisation_name].users.pop(user_name) + del_users.remove(user_name) return del_users def update(self, organisation_name: str) -> Set[str]: diff --git a/tests/test_diff.py b/tests/test_diff.py index 466129c..329c4a0 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -79,6 +79,55 @@ def test_diff(self): self.assertEqual(len(diff.add('foo_org')), 0) self.assertEqual(len(diff.delete('foo_org')), 1) + def test_diff_external_auth(self): + orgs_grafana: Dict[str, Organization] = {} + org = Organization(organisation_name='foo_org', org_id=100) + orgs_grafana[org.organisation_name] = org + + orgs_iam: Dict[str, Organization] = {} + org = Organization(organisation_name='foo_org', org_id=None) + orgs_iam[org.organisation_name] = org + + user = User(login_name="andy@foo.com") + user.name = "Andy Borg" + user.email = user.login + user.role = 'Viewer' + orgs_iam['foo_org'].users[user.login] = user + + user = User(login_name="andy@foo.com") + user.name = "Andy Borg" + user.email = user.login + user.role = 'Viewer' + user.user_id = 200 + orgs_grafana['foo_org'].users[user.login] = user + + user = User(login_name="bull@foo.com") + user.name = "Bull Borg" + user.email = user.login + user.role = 'Viewer' + user.user_id = 201 + user.external_auth = True + orgs_grafana['foo_org'].users[user.login] = user + + # "Same" user in both orgs + diff = DiffUsers(iam_orgs=orgs_iam, grafana_orgs=orgs_grafana, exclude_user="foobar_admin") + self.assertEqual(len(diff.update('foo_org')), 0) + self.assertEqual(len(diff.add('foo_org')), 0) + # External auth user is not deleted + self.assertEqual(len(diff.delete('foo_org')), 0) + + # Need to add it again since it was pop'ed in the previous delete + user = User(login_name="bull@foo.com") + user.name = "Bull Borg" + user.email = user.login + user.role = 'Viewer' + user.user_id = 201 + user.external_auth = True + orgs_grafana['foo_org'].users[user.login] = user + diff = DiffUsers(iam_orgs=orgs_iam, grafana_orgs=orgs_grafana, exclude_user="foobar_admin") + # External auth user is deleted + self.assertEqual(len(diff.delete('foo_org', True)), 1) + if __name__ == '__main__': unittest.main()