lint
This commit is contained in:
@@ -47,11 +47,11 @@ options in order to give the module access to [MAS' Admin
|
||||
API](https://element-hq.github.io/matrix-authentication-service/topics/admin-api.html).
|
||||
|
||||
- `mas` - optional configuration for Matrix Authentication Service (MAS). When set, the module creates users via MAS' admin API.
|
||||
- `admin_api_base_url` - Base URL for MAS' admin API (e.g. `https://mas.example.org`). Trailing slashes will be automatically stripped.
|
||||
- `oauth_base_url` - Base URL for MAS' OAuth endpoints (defaults to `admin_api_base_url` if not set). Trailing slashes will be automatically stripped.
|
||||
- `client_id` - client ID for the automated tool. Must be a valid [ULID](https://github.com/ulid/spec). Generate one [here](https://ulidtools.com/).
|
||||
- `client_secret` - client secret for the automated tool. Ideally long and cryptographically secure. Keep it a secret!
|
||||
- `client_secret_filepath` - path to a plaintext file containing the client secret. If set, this is used instead of `client_secret`.
|
||||
- `admin_api_base_url` - Base URL for MAS' admin API (e.g. `https://mas.example.org`). Trailing slashes will be automatically stripped.
|
||||
- `oauth_base_url` - Base URL for MAS' OAuth endpoints (defaults to `admin_api_base_url` if not set). Trailing slashes will be automatically stripped.
|
||||
- `client_id` - client ID for the automated tool. Must be a valid [ULID](https://github.com/ulid/spec). Generate one [here](https://ulidtools.com/).
|
||||
- `client_secret` - client secret for the automated tool. Ideally long and cryptographically secure. Keep it a secret!
|
||||
- `client_secret_filepath` - path to a plaintext file containing the client secret. If set, this is used instead of `client_secret`.
|
||||
|
||||
Example configuration:
|
||||
|
||||
@@ -81,19 +81,19 @@ Then, add the following to your MAS config file:
|
||||
|
||||
```yaml
|
||||
policy:
|
||||
data:
|
||||
admin_clients:
|
||||
- 000000000000000000000G0EST
|
||||
data:
|
||||
admin_clients:
|
||||
- 000000000000000000000G0EST
|
||||
|
||||
# ...
|
||||
|
||||
clients:
|
||||
# The `client_id` must be a valid ULID https://github.com/ulid/spec
|
||||
# Generate ULID's easily at: https://ulidtools.com/
|
||||
- client_id: 000000000000000000000G0EST
|
||||
# The guest module uses the client_secret_basic authentication method.
|
||||
client_auth_method: client_secret_basic
|
||||
client_secret: your-client-secret
|
||||
# The `client_id` must be a valid ULID https://github.com/ulid/spec
|
||||
# Generate ULID's easily at: https://ulidtools.com/
|
||||
- client_id: 000000000000000000000G0EST
|
||||
# The guest module uses the client_secret_basic authentication method.
|
||||
client_auth_method: client_secret_basic
|
||||
client_secret: your-client-secret
|
||||
```
|
||||
|
||||
## Production installation
|
||||
|
||||
@@ -24,9 +24,9 @@ from synapse.module_api.errors import ConfigError
|
||||
from synapse.types import UserID
|
||||
|
||||
from synapse_guest_module.config import GuestModuleConfig, MasConfig
|
||||
from synapse_guest_module.mas_admin_client import MasAdminClient
|
||||
from synapse_guest_module.guest_registration_servlet import GuestRegistrationServlet
|
||||
from synapse_guest_module.guest_user_reaper import GuestUserReaper
|
||||
from synapse_guest_module.mas_admin_client import MasAdminClient
|
||||
|
||||
logger = logging.getLogger("synapse.contrib." + __name__)
|
||||
|
||||
@@ -106,22 +106,30 @@ class GuestModule:
|
||||
raise ConfigError("Config option 'mas' must be an object")
|
||||
|
||||
admin_api_base_url = mas_config.get("admin_api_base_url")
|
||||
if not isinstance(admin_api_base_url, str) or len(admin_api_base_url.strip()) == 0:
|
||||
raise ConfigError("Config option 'mas.admin_api_base_url' is required and must be a string")
|
||||
if (
|
||||
not isinstance(admin_api_base_url, str)
|
||||
or len(admin_api_base_url.strip()) == 0
|
||||
):
|
||||
raise ConfigError(
|
||||
"Config option 'mas.admin_api_base_url' is required and must be a string"
|
||||
)
|
||||
|
||||
oauth_base_url = mas_config.get("oauth_base_url", admin_api_base_url)
|
||||
if not isinstance(oauth_base_url, str) or len(oauth_base_url.strip()) == 0:
|
||||
raise ConfigError(
|
||||
"Config option 'mas.oauth_base_url' must be a string"
|
||||
)
|
||||
raise ConfigError("Config option 'mas.oauth_base_url' must be a string")
|
||||
|
||||
client_id = mas_config.get("client_id")
|
||||
if not isinstance(client_id, str) or len(client_id.strip()) == 0:
|
||||
raise ConfigError("Config option 'mas.client_id' is required and must be a string")
|
||||
raise ConfigError(
|
||||
"Config option 'mas.client_id' is required and must be a string"
|
||||
)
|
||||
|
||||
client_secret = mas_config.get("client_secret")
|
||||
if client_secret is not None:
|
||||
if not isinstance(client_secret, str) or len(client_secret.strip()) == 0:
|
||||
if (
|
||||
not isinstance(client_secret, str)
|
||||
or len(client_secret.strip()) == 0
|
||||
):
|
||||
raise ConfigError(
|
||||
"Config option 'mas.client_secret' must be a string"
|
||||
)
|
||||
@@ -129,7 +137,10 @@ class GuestModule:
|
||||
|
||||
client_secret_filepath = mas_config.get("client_secret_filepath")
|
||||
if client_secret_filepath is not None:
|
||||
if not isinstance(client_secret_filepath, str) or len(client_secret_filepath.strip()) == 0:
|
||||
if (
|
||||
not isinstance(client_secret_filepath, str)
|
||||
or len(client_secret_filepath.strip()) == 0
|
||||
):
|
||||
raise ConfigError(
|
||||
"Config option 'mas.client_secret_filepath' must be a string"
|
||||
)
|
||||
@@ -139,7 +150,7 @@ class GuestModule:
|
||||
raise ConfigError(
|
||||
"Config option 'mas.client_secret' or 'mas.client_secret_filepath' is required"
|
||||
)
|
||||
|
||||
|
||||
if client_secret is not None and client_secret_filepath is not None:
|
||||
raise ConfigError(
|
||||
"Config option 'mas.client_secret' and 'mas.client_secret_filepath' are mutually exclusive"
|
||||
|
||||
+7
-10
@@ -87,9 +87,7 @@ class GuestRegistrationServlet(DirectServeJsonResource):
|
||||
localpart, displayname + self._config.display_name_suffix
|
||||
)
|
||||
|
||||
device_id, access_token, _, _ = await self._api.register_device(
|
||||
user_id
|
||||
)
|
||||
device_id, access_token, _, _ = await self._api.register_device(user_id)
|
||||
else:
|
||||
logger.info("Registering MAS guest user with username '%s'", localpart)
|
||||
mas_user_id = await self._mas_admin_client.create_user(localpart)
|
||||
@@ -112,10 +110,11 @@ class GuestRegistrationServlet(DirectServeJsonResource):
|
||||
if self._config.enable_user_reaper
|
||||
else 0
|
||||
)
|
||||
device_id, access_token = (
|
||||
await self._mas_admin_client.create_personal_session(
|
||||
mas_user_id, expires_in
|
||||
)
|
||||
(
|
||||
device_id,
|
||||
access_token,
|
||||
) = await self._mas_admin_client.create_personal_session(
|
||||
mas_user_id, expires_in
|
||||
)
|
||||
|
||||
logger.debug("Registered user '%s'", user_id)
|
||||
@@ -145,6 +144,4 @@ class GuestRegistrationServlet(DirectServeJsonResource):
|
||||
},
|
||||
)
|
||||
|
||||
await self._api.run_db_interaction(
|
||||
"guest_module_store_mas_user", store_user
|
||||
)
|
||||
await self._api.run_db_interaction("guest_module_store_mas_user", store_user)
|
||||
|
||||
@@ -106,6 +106,12 @@ class GuestUserReaper:
|
||||
logger.error('Failed to delete user "%s": %s', user_id, e)
|
||||
|
||||
async def _deactivate_expired_mas_users(self) -> None:
|
||||
"""Deactivate all MAS users that are older than the specified expiration
|
||||
interval. This uses the MAS admin API to disable the user.
|
||||
"""
|
||||
|
||||
assert self._mas_admin_client is not None
|
||||
|
||||
if self._mas_tables_ready is not None:
|
||||
await self._mas_tables_ready.wait()
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ class MasAdminClient:
|
||||
|
||||
async def create_user(self, username: str) -> str:
|
||||
"""Creates a new user in MAS with the given username.
|
||||
|
||||
|
||||
Args:
|
||||
username: The username (localpart) of the user to create.
|
||||
|
||||
|
||||
Returns:
|
||||
The MAS ID of the created user.
|
||||
"""
|
||||
@@ -40,8 +40,8 @@ class MasAdminClient:
|
||||
post_json={"username": username},
|
||||
headers={"Authorization": [f"Bearer {token}"]},
|
||||
)
|
||||
|
||||
mas_user_id = response.get("data", {}).get("id")
|
||||
|
||||
mas_user_id: str = response.get("data", {}).get("id")
|
||||
if mas_user_id is None or not isinstance(mas_user_id, str):
|
||||
raise ValueError("MAS user creation response missing `data.id` field")
|
||||
|
||||
@@ -109,7 +109,7 @@ class MasAdminClient:
|
||||
if not isinstance(access_token, str) or len(access_token) == 0:
|
||||
raise ValueError("MAS token response missing access_token")
|
||||
return access_token
|
||||
|
||||
|
||||
def _load_client_secret(self) -> str:
|
||||
"""Source the MAS client secret from either configuration or a file."""
|
||||
if self._config.client_secret_filepath is not None:
|
||||
@@ -141,13 +141,13 @@ class MasAdminClient:
|
||||
self, url: str, data: Dict[str, str], headers: Dict[str, Any]
|
||||
) -> Any:
|
||||
http_client = self._api.http_client
|
||||
post_urlencoded = getattr(http_client, "post_urlencoded_get_json", None)
|
||||
if callable(post_urlencoded):
|
||||
post_urlencoded: Optional[Awaitable[Any]] = getattr(
|
||||
http_client, "post_urlencoded_get_json", None
|
||||
)
|
||||
if post_urlencoded is not None and callable(post_urlencoded):
|
||||
return await post_urlencoded(url, data, headers=headers)
|
||||
|
||||
logger.debug(
|
||||
"MAS client falling back to post_json_get_json for %s", url
|
||||
)
|
||||
logger.debug("MAS client falling back to post_json_get_json for %s", url)
|
||||
return await http_client.post_json_get_json(
|
||||
uri=url, post_json=data, headers=headers
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user