Repository: matrix-org/synapse

Issue:
Deactivating an account as an application service using `user_id` yields a response not containing `id_server_unbind_result`
### Description

The scenario is as follows:

- No 3PIDs or third party identity servers have been used on the synapse server involved.
- There is a configured application service.

The application service wants to deactive an account in its namespace and issues a post
request to

    /_matrix/client/v3/account/deactivate?user_id=<some user id from application service user namespace>

with request body of

    {}

Synapse answers with http status code 200 and a response body of

    {}

not containing `id_server_unbind_result` in violation of [Client Server API Spec accountdeactivate](https://spec.matrix.org/v1.8/client-server-api/#post_matrixclientv3accountdeactivate) which states as description of the response field `id_server_unbind_result`:

> Required: An indicator as to whether or not the homeserver was able to unbind the user’s 3PIDs from the identity server(s). success indicates that all identifiers have been unbound from the identity server while no-support indicates that one or more identifiers failed to unbind due to the identity server refusing the request or the homeserver being unable to determine an identity server to unbind from. This must be success if the homeserver has no identifiers to unbind for the user.
One of: [success, no-support].

So in this case, it should have answered with a response body of `{ "id_server_unbind_result": "success" }`.

### Steps to reproduce

- use clean synapse instance
- configure an application service
- create a user as an application service
- deactivate the user as an application service using the `user_id` feature explained in [Application Service API Spec 1.3.1. Identity assertion](https://spec.matrix.org/v1.8/application-service-api/#identity-assertion)
- observe a response not containing `id_server_unbind_result`.


### Homeserver

From hub.docker.com matrixdotorg/synapse:v1.92.3

### Synapse Version

{"server_version":"1.92.3","python_version":"3.11.5"}

### Installation Method

Docker (matrixdotorg/synapse)

### Database

sqlite

### Workers

I don't know

### Platform

Observed on my developer machine

NixOS 23.05 / amd64

Also observed in an deployment in nomad, I think the nodes are either rocky linux or centos 7.

### Configuration

Just an application service with a user namespace and room alias namespace.

### Relevant log output

```shell
Sorry not observed.
```


### Anything else that would be useful to know?

I assume [synapse/rest/client/account.py:307](https://github.com/matrix-org/synapse/blob/7e5d3b06fa8b6ce3676eb1178d7db0e252d48679/synapse/rest/client/account.py#L307) is the culprit.

Maybe just put `return 200, {"id_server_unbind_result": "success"}` there to satisfy the spec?


Discussion:

Resolving patch:
diff --git a/synapse/rest/client/account.py b/synapse/rest/client/account.py
--- a/synapse/rest/client/account.py
+++ b/synapse/rest/client/account.py
@@ -299,19 +299,16 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
 
         requester = await self.auth.get_user_by_req(request)
 
-        # allow ASes to deactivate their own users
-        if requester.app_service:
-            await self._deactivate_account_handler.deactivate_account(
-                requester.user.to_string(), body.erase, requester
+        # allow ASes to deactivate their own users:
+        # ASes don't need user-interactive auth
+        if not requester.app_service:
+            await self.auth_handler.validate_user_via_ui_auth(
+                requester,
+                request,
+                body.dict(exclude_unset=True),
+                "deactivate your account",
             )
-            return 200, {}
 
-        await self.auth_handler.validate_user_via_ui_auth(
-            requester,
-            request,
-            body.dict(exclude_unset=True),
-            "deactivate your account",
-        )
         result = await self._deactivate_account_handler.deactivate_account(
             requester.user.to_string(), body.erase, requester, id_server=body.id_server
         )


Test patch: