authentik.enterprise.providers.google_workspace.clients.users
1from django.db import transaction 2 3from authentik.core.models import User 4from authentik.enterprise.providers.google_workspace.clients.base import GoogleWorkspaceSyncClient 5from authentik.enterprise.providers.google_workspace.models import ( 6 GoogleWorkspaceProvider, 7 GoogleWorkspaceProviderMapping, 8 GoogleWorkspaceProviderUser, 9) 10from authentik.lib.sync.mapper import PropertyMappingManager 11from authentik.lib.sync.outgoing.exceptions import ( 12 ObjectExistsSyncException, 13 TransientSyncException, 14) 15from authentik.lib.sync.outgoing.models import OutgoingSyncDeleteAction 16from authentik.policies.utils import delete_none_values 17 18 19class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceProviderUser, dict]): 20 """Sync authentik users into google workspace""" 21 22 connection_type = GoogleWorkspaceProviderUser 23 connection_type_query = "user" 24 can_discover = True 25 26 def __init__(self, provider: GoogleWorkspaceProvider) -> None: 27 super().__init__(provider) 28 self.mapper = PropertyMappingManager( 29 self.provider.property_mappings.all().order_by("name").select_subclasses(), 30 GoogleWorkspaceProviderMapping, 31 ["provider", "connection"], 32 ) 33 34 def to_schema(self, obj: User, connection: GoogleWorkspaceProviderUser) -> dict: 35 """Convert authentik user""" 36 return delete_none_values(super().to_schema(obj, connection, primaryEmail=obj.email)) 37 38 def delete(self, identifier: str): 39 """Delete user""" 40 GoogleWorkspaceProviderUser.objects.filter( 41 provider=self.provider, google_id=identifier 42 ).delete() 43 if self.provider.user_delete_action == OutgoingSyncDeleteAction.DELETE: 44 return self._request(self.directory_service.users().delete(userKey=identifier)) 45 if self.provider.user_delete_action == OutgoingSyncDeleteAction.SUSPEND: 46 return self._request( 47 self.directory_service.users().update(userKey=identifier, body={"suspended": True}) 48 ) 49 50 def create(self, user: User): 51 """Create user from scratch and create a connection object""" 52 google_user = self.to_schema(user, None) 53 self.check_email_valid( 54 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 55 ) 56 with transaction.atomic(): 57 try: 58 response = self._request(self.directory_service.users().insert(body=google_user)) 59 except ObjectExistsSyncException: 60 # user already exists in google workspace, so we can connect them manually 61 return GoogleWorkspaceProviderUser.objects.create( 62 provider=self.provider, user=user, google_id=user.email, attributes={} 63 ) 64 except TransientSyncException as exc: 65 raise exc 66 else: 67 return GoogleWorkspaceProviderUser.objects.create( 68 provider=self.provider, 69 user=user, 70 google_id=response["primaryEmail"], 71 attributes=response, 72 ) 73 74 def update(self, user: User, connection: GoogleWorkspaceProviderUser): 75 """Update existing user""" 76 google_user = self.to_schema(user, connection) 77 self.check_email_valid( 78 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 79 ) 80 response = self._request( 81 self.directory_service.users().update(userKey=connection.google_id, body=google_user) 82 ) 83 connection.attributes = response 84 connection.save() 85 86 def discover(self): 87 """Iterate through all users and connect them with authentik users if possible""" 88 request = self.directory_service.users().list( 89 customer="my_customer", maxResults=500, orderBy="email" 90 ) 91 while request: 92 response = request.execute() 93 for user in response.get("users", []): 94 self._discover_single_user(user) 95 request = self.directory_service.users().list_next( 96 previous_request=request, previous_response=response 97 ) 98 99 def _discover_single_user(self, user: dict): 100 """handle discovery of a single user""" 101 email = user["primaryEmail"] 102 matching_authentik_user = self.provider.get_object_qs(User).filter(email=email).first() 103 if not matching_authentik_user: 104 return 105 GoogleWorkspaceProviderUser.objects.update_or_create( 106 provider=self.provider, 107 user=matching_authentik_user, 108 google_id=email, 109 defaults={"attributes": user}, 110 ) 111 112 def update_single_attribute(self, connection: GoogleWorkspaceProviderUser): 113 user = self.directory_service.users().get(connection.google_id) 114 connection.attributes = user
class
GoogleWorkspaceUserClient(authentik.enterprise.providers.google_workspace.clients.base.GoogleWorkspaceSyncClient[authentik.core.models.User, authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProviderUser, dict]):
20class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceProviderUser, dict]): 21 """Sync authentik users into google workspace""" 22 23 connection_type = GoogleWorkspaceProviderUser 24 connection_type_query = "user" 25 can_discover = True 26 27 def __init__(self, provider: GoogleWorkspaceProvider) -> None: 28 super().__init__(provider) 29 self.mapper = PropertyMappingManager( 30 self.provider.property_mappings.all().order_by("name").select_subclasses(), 31 GoogleWorkspaceProviderMapping, 32 ["provider", "connection"], 33 ) 34 35 def to_schema(self, obj: User, connection: GoogleWorkspaceProviderUser) -> dict: 36 """Convert authentik user""" 37 return delete_none_values(super().to_schema(obj, connection, primaryEmail=obj.email)) 38 39 def delete(self, identifier: str): 40 """Delete user""" 41 GoogleWorkspaceProviderUser.objects.filter( 42 provider=self.provider, google_id=identifier 43 ).delete() 44 if self.provider.user_delete_action == OutgoingSyncDeleteAction.DELETE: 45 return self._request(self.directory_service.users().delete(userKey=identifier)) 46 if self.provider.user_delete_action == OutgoingSyncDeleteAction.SUSPEND: 47 return self._request( 48 self.directory_service.users().update(userKey=identifier, body={"suspended": True}) 49 ) 50 51 def create(self, user: User): 52 """Create user from scratch and create a connection object""" 53 google_user = self.to_schema(user, None) 54 self.check_email_valid( 55 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 56 ) 57 with transaction.atomic(): 58 try: 59 response = self._request(self.directory_service.users().insert(body=google_user)) 60 except ObjectExistsSyncException: 61 # user already exists in google workspace, so we can connect them manually 62 return GoogleWorkspaceProviderUser.objects.create( 63 provider=self.provider, user=user, google_id=user.email, attributes={} 64 ) 65 except TransientSyncException as exc: 66 raise exc 67 else: 68 return GoogleWorkspaceProviderUser.objects.create( 69 provider=self.provider, 70 user=user, 71 google_id=response["primaryEmail"], 72 attributes=response, 73 ) 74 75 def update(self, user: User, connection: GoogleWorkspaceProviderUser): 76 """Update existing user""" 77 google_user = self.to_schema(user, connection) 78 self.check_email_valid( 79 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 80 ) 81 response = self._request( 82 self.directory_service.users().update(userKey=connection.google_id, body=google_user) 83 ) 84 connection.attributes = response 85 connection.save() 86 87 def discover(self): 88 """Iterate through all users and connect them with authentik users if possible""" 89 request = self.directory_service.users().list( 90 customer="my_customer", maxResults=500, orderBy="email" 91 ) 92 while request: 93 response = request.execute() 94 for user in response.get("users", []): 95 self._discover_single_user(user) 96 request = self.directory_service.users().list_next( 97 previous_request=request, previous_response=response 98 ) 99 100 def _discover_single_user(self, user: dict): 101 """handle discovery of a single user""" 102 email = user["primaryEmail"] 103 matching_authentik_user = self.provider.get_object_qs(User).filter(email=email).first() 104 if not matching_authentik_user: 105 return 106 GoogleWorkspaceProviderUser.objects.update_or_create( 107 provider=self.provider, 108 user=matching_authentik_user, 109 google_id=email, 110 defaults={"attributes": user}, 111 ) 112 113 def update_single_attribute(self, connection: GoogleWorkspaceProviderUser): 114 user = self.directory_service.users().get(connection.google_id) 115 connection.attributes = user
Sync authentik users into google workspace
GoogleWorkspaceUserClient( provider: authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProvider)
connection_type =
<class 'authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProviderUser'>
def
to_schema( self, obj: authentik.core.models.User, connection: authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProviderUser) -> dict:
35 def to_schema(self, obj: User, connection: GoogleWorkspaceProviderUser) -> dict: 36 """Convert authentik user""" 37 return delete_none_values(super().to_schema(obj, connection, primaryEmail=obj.email))
Convert authentik user
def
delete(self, identifier: str):
39 def delete(self, identifier: str): 40 """Delete user""" 41 GoogleWorkspaceProviderUser.objects.filter( 42 provider=self.provider, google_id=identifier 43 ).delete() 44 if self.provider.user_delete_action == OutgoingSyncDeleteAction.DELETE: 45 return self._request(self.directory_service.users().delete(userKey=identifier)) 46 if self.provider.user_delete_action == OutgoingSyncDeleteAction.SUSPEND: 47 return self._request( 48 self.directory_service.users().update(userKey=identifier, body={"suspended": True}) 49 )
Delete user
51 def create(self, user: User): 52 """Create user from scratch and create a connection object""" 53 google_user = self.to_schema(user, None) 54 self.check_email_valid( 55 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 56 ) 57 with transaction.atomic(): 58 try: 59 response = self._request(self.directory_service.users().insert(body=google_user)) 60 except ObjectExistsSyncException: 61 # user already exists in google workspace, so we can connect them manually 62 return GoogleWorkspaceProviderUser.objects.create( 63 provider=self.provider, user=user, google_id=user.email, attributes={} 64 ) 65 except TransientSyncException as exc: 66 raise exc 67 else: 68 return GoogleWorkspaceProviderUser.objects.create( 69 provider=self.provider, 70 user=user, 71 google_id=response["primaryEmail"], 72 attributes=response, 73 )
Create user from scratch and create a connection object
def
update( self, user: authentik.core.models.User, connection: authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProviderUser):
75 def update(self, user: User, connection: GoogleWorkspaceProviderUser): 76 """Update existing user""" 77 google_user = self.to_schema(user, connection) 78 self.check_email_valid( 79 google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])] 80 ) 81 response = self._request( 82 self.directory_service.users().update(userKey=connection.google_id, body=google_user) 83 ) 84 connection.attributes = response 85 connection.save()
Update existing user
def
discover(self):
87 def discover(self): 88 """Iterate through all users and connect them with authentik users if possible""" 89 request = self.directory_service.users().list( 90 customer="my_customer", maxResults=500, orderBy="email" 91 ) 92 while request: 93 response = request.execute() 94 for user in response.get("users", []): 95 self._discover_single_user(user) 96 request = self.directory_service.users().list_next( 97 previous_request=request, previous_response=response 98 )
Iterate through all users and connect them with authentik users if possible
def
update_single_attribute( self, connection: authentik.enterprise.providers.google_workspace.models.GoogleWorkspaceProviderUser):
113 def update_single_attribute(self, connection: GoogleWorkspaceProviderUser): 114 user = self.directory_service.users().get(connection.google_id) 115 connection.attributes = user
Update connection attributes on a connection object, when the connection is manually created