diff --git a/config.yaml b/config.yaml index 32cbf1a9..137e8f89 100644 --- a/config.yaml +++ b/config.yaml @@ -8,6 +8,13 @@ options: description: | Configures whether to enable Mjolnir - moderation tool for Matrix. Reference: https://github.com/matrix-org/mjolnir + enable_password_config: + type: boolean + default: true + description: | + Defaults to true. If Synapse uses a single sign-on provider for + authentication, this option can be used to disable the regular login + flow. public_baseurl: type: string description: | diff --git a/src-docs/charm_state.py.md b/src-docs/charm_state.py.md index 22e059cd..d500af70 100644 --- a/src-docs/charm_state.py.md +++ b/src-docs/charm_state.py.md @@ -17,7 +17,7 @@ Exception raised when a charm configuration is found to be invalid. Attrs: msg (str): Explanation of the error. - + ### function `__init__` @@ -67,7 +67,7 @@ Get charm proxy information from juju charm environment. --- - + ### classmethod `from_charm` @@ -128,6 +128,7 @@ Represent Synapse builtin configuration values. - `report_stats`: report_stats config. - `public_baseurl`: public_baseurl config. - `enable_mjolnir`: enable_mjolnir config. + - `enable_password_config`: enable_password_config config. - `smtp_enable_tls`: enable tls while connecting to SMTP server. - `smtp_host`: SMTP host. - `smtp_notif_from`: defines the "From" address to use when sending emails. @@ -140,7 +141,7 @@ Represent Synapse builtin configuration values. --- - + ### classmethod `set_default_smtp_notif_from` @@ -167,7 +168,7 @@ Set server_name as default value to smtp_notif_from. --- - + ### classmethod `to_yes_or_no` diff --git a/src-docs/pebble.py.md b/src-docs/pebble.py.md index 2e685c33..36b3f0b5 100644 --- a/src-docs/pebble.py.md +++ b/src-docs/pebble.py.md @@ -57,7 +57,7 @@ Change the configuration. --- - + ### function `enable_saml` @@ -117,7 +117,7 @@ Replan Synapse NGINX service. --- - + ### function `reset_instance` diff --git a/src/charm_state.py b/src/charm_state.py index 4ca62745..bb09670c 100644 --- a/src/charm_state.py +++ b/src/charm_state.py @@ -26,6 +26,7 @@ KNOWN_CHARM_CONFIG = ( "enable_mjolnir", + "enable_password_config", "public_baseurl", "report_stats", "server_name", @@ -76,6 +77,7 @@ class SynapseConfig(BaseModel): # pylint: disable=too-few-public-methods report_stats: report_stats config. public_baseurl: public_baseurl config. enable_mjolnir: enable_mjolnir config. + enable_password_config: enable_password_config config. smtp_enable_tls: enable tls while connecting to SMTP server. smtp_host: SMTP host. smtp_notif_from: defines the "From" address to use when sending emails. @@ -88,6 +90,7 @@ class SynapseConfig(BaseModel): # pylint: disable=too-few-public-methods report_stats: str | None = Field(None) public_baseurl: str | None = Field(None) enable_mjolnir: bool = False + enable_password_config: bool = True smtp_enable_tls: bool = True smtp_host: str | None = Field(None) smtp_notif_from: str | None = Field(None) diff --git a/src/pebble.py b/src/pebble.py index 661f2dcc..f671242b 100644 --- a/src/pebble.py +++ b/src/pebble.py @@ -91,6 +91,8 @@ def change_config(self, container: ops.model.Container) -> None: synapse.enable_saml(container=container, charm_state=self._charm_state) if self._charm_state.synapse_config.smtp_host: synapse.enable_smtp(container=container, charm_state=self._charm_state) + if not self._charm_state.synapse_config.enable_password_config: + synapse.disable_password_config(container=container) self.restart_synapse(container) except (synapse.WorkloadError, ops.pebble.PathError) as exc: raise PebbleServiceError(str(exc)) from exc diff --git a/src/synapse/__init__.py b/src/synapse/__init__.py index 061c9639..88edff45 100644 --- a/src/synapse/__init__.py +++ b/src/synapse/__init__.py @@ -53,6 +53,7 @@ check_nginx_ready, check_ready, create_mjolnir_config, + disable_password_config, enable_metrics, enable_saml, enable_serve_server_wellknown, diff --git a/src/synapse/workload.py b/src/synapse/workload.py index 66f0f805..1706bb2c 100644 --- a/src/synapse/workload.py +++ b/src/synapse/workload.py @@ -289,6 +289,24 @@ def enable_metrics(container: ops.Container) -> None: raise EnableMetricsError(str(exc)) from exc +def disable_password_config(container: ops.Container) -> None: + """Change the Synapse configuration to disable password config. + + Args: + container: Container of the charm. + + Raises: + WorkloadError: something went wrong disabling password config. + """ + try: + config = container.pull(SYNAPSE_CONFIG_PATH).read() + current_yaml = yaml.safe_load(config) + current_yaml["password_config"] = {"enabled": False} + container.push(SYNAPSE_CONFIG_PATH, yaml.safe_dump(current_yaml)) + except ops.pebble.PathError as exc: + raise WorkloadError(str(exc)) from exc + + def enable_serve_server_wellknown(container: ops.Container) -> None: """Change the Synapse configuration to enable server wellknown file. diff --git a/tests/unit/test_synapse_workload.py b/tests/unit/test_synapse_workload.py index f9ba5290..7e5c6c3d 100644 --- a/tests/unit/test_synapse_workload.py +++ b/tests/unit/test_synapse_workload.py @@ -377,6 +377,51 @@ def test_enable_serve_server_wellknown_error(monkeypatch: pytest.MonkeyPatch): synapse.enable_serve_server_wellknown(container_mock) +def test_disable_password_config_success(monkeypatch: pytest.MonkeyPatch): + """ + arrange: set mock container with file. + act: call disable_password_config. + assert: new configuration file is pushed and password_config is disabled. + """ + config_content = """ + password_config: + enabled: true + """ + text_io_mock = io.StringIO(config_content) + pull_mock = Mock(return_value=text_io_mock) + push_mock = MagicMock() + container_mock = MagicMock() + monkeypatch.setattr(container_mock, "pull", pull_mock) + monkeypatch.setattr(container_mock, "push", push_mock) + + synapse.disable_password_config(container_mock) + + assert pull_mock.call_args[0][0] == synapse.SYNAPSE_CONFIG_PATH + assert push_mock.call_args[0][0] == synapse.SYNAPSE_CONFIG_PATH + expected_config_content = { + "password_config": { + "enabled": False, + }, + } + assert push_mock.call_args[0][1] == yaml.safe_dump(expected_config_content) + + +def test_disable_password_config_error(monkeypatch: pytest.MonkeyPatch): + """ + arrange: set mock container with file. + act: call disable_password_config. + assert: raise WorkloadError. + """ + error_message = "Error pulling file" + path_error = ops.pebble.PathError(kind="fake", message=error_message) + pull_mock = MagicMock(side_effect=path_error) + container_mock = MagicMock() + monkeypatch.setattr(container_mock, "pull", pull_mock) + + with pytest.raises(synapse.WorkloadError, match=error_message): + synapse.disable_password_config(container_mock) + + def test_get_registration_shared_secret_success(monkeypatch: pytest.MonkeyPatch): """ arrange: set mock container with file.