summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--changelog.d/10108.feature1
-rw-r--r--docs/sample_config.yaml11
-rw-r--r--synapse/config/sso.py15
-rw-r--r--synapse/handlers/sso.py25
4 files changed, 51 insertions, 1 deletions
diff --git a/changelog.d/10108.feature b/changelog.d/10108.feature
new file mode 100644
index 0000000000..4930a5acf5
--- /dev/null
+++ b/changelog.d/10108.feature
@@ -0,0 +1 @@
+Implement config option `sso.update_profile_information` to sync SSO users' profile information with the identity provider each time they login. Currently only displayname is supported.
diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml
index 19505c7fd2..6fcc022b47 100644
--- a/docs/sample_config.yaml
+++ b/docs/sample_config.yaml
@@ -1975,6 +1975,17 @@ sso:
     #  - https://riot.im/develop
     #  - https://my.custom.client/
 
+    # Uncomment to keep a user's profile fields in sync with information from
+    # the identity provider. Currently only syncing the displayname is
+    # supported. Fields are checked on every SSO login, and are updated
+    # if necessary.
+    #
+    # Note that enabling this option will override user profile information,
+    # regardless of whether users have opted-out of syncing that
+    # information when first signing in. Defaults to false.
+    #
+    #update_profile_information: true
+
     # Directory in which Synapse will try to find the template files below.
     # If not set, or the files named below are not found within the template
     # directory, default templates from within the Synapse package will be used.
diff --git a/synapse/config/sso.py b/synapse/config/sso.py
index af645c930d..e4346e02aa 100644
--- a/synapse/config/sso.py
+++ b/synapse/config/sso.py
@@ -74,6 +74,10 @@ class SSOConfig(Config):
 
         self.sso_client_whitelist = sso_config.get("client_whitelist") or []
 
+        self.sso_update_profile_information = (
+            sso_config.get("update_profile_information") or False
+        )
+
         # Attempt to also whitelist the server's login fallback, since that fallback sets
         # the redirect URL to itself (so it can process the login token then return
         # gracefully to the client). This would make it pointless to ask the user for
@@ -111,6 +115,17 @@ class SSOConfig(Config):
             #  - https://riot.im/develop
             #  - https://my.custom.client/
 
+            # Uncomment to keep a user's profile fields in sync with information from
+            # the identity provider. Currently only syncing the displayname is
+            # supported. Fields are checked on every SSO login, and are updated
+            # if necessary.
+            #
+            # Note that enabling this option will override user profile information,
+            # regardless of whether users have opted-out of syncing that
+            # information when first signing in. Defaults to false.
+            #
+            #update_profile_information: true
+
             # Directory in which Synapse will try to find the template files below.
             # If not set, or the files named below are not found within the template
             # directory, default templates from within the Synapse package will be used.
diff --git a/synapse/handlers/sso.py b/synapse/handlers/sso.py
index 044ff06d84..0b297e54c4 100644
--- a/synapse/handlers/sso.py
+++ b/synapse/handlers/sso.py
@@ -41,7 +41,12 @@ from synapse.handlers.ui_auth import UIAuthSessionDataConstants
 from synapse.http import get_request_user_agent
 from synapse.http.server import respond_with_html, respond_with_redirect
 from synapse.http.site import SynapseRequest
-from synapse.types import JsonDict, UserID, contains_invalid_mxid_characters
+from synapse.types import (
+    JsonDict,
+    UserID,
+    contains_invalid_mxid_characters,
+    create_requester,
+)
 from synapse.util.async_helpers import Linearizer
 from synapse.util.stringutils import random_string
 
@@ -185,11 +190,14 @@ class SsoHandler:
         self._auth_handler = hs.get_auth_handler()
         self._error_template = hs.config.sso_error_template
         self._bad_user_template = hs.config.sso_auth_bad_user_template
+        self._profile_handler = hs.get_profile_handler()
 
         # The following template is shown after a successful user interactive
         # authentication session. It tells the user they can close the window.
         self._sso_auth_success_template = hs.config.sso_auth_success_template
 
+        self._sso_update_profile_information = hs.config.sso_update_profile_information
+
         # a lock on the mappings
         self._mapping_lock = Linearizer(name="sso_user_mapping", clock=hs.get_clock())
 
@@ -458,6 +466,21 @@ class SsoHandler:
                     request.getClientIP(),
                 )
                 new_user = True
+            elif self._sso_update_profile_information:
+                attributes = await self._call_attribute_mapper(sso_to_matrix_id_mapper)
+                if attributes.display_name:
+                    user_id_obj = UserID.from_string(user_id)
+                    profile_display_name = await self._profile_handler.get_displayname(
+                        user_id_obj
+                    )
+                    if profile_display_name != attributes.display_name:
+                        requester = create_requester(
+                            user_id,
+                            authenticated_entity=user_id,
+                        )
+                        await self._profile_handler.set_displayname(
+                            user_id_obj, requester, attributes.display_name, True
+                        )
 
         await self._auth_handler.complete_sso_login(
             user_id,