feat: shared secret auth
This commit is contained in:
parent
13edf77ece
commit
1e8b616cba
|
@ -111,3 +111,7 @@ ALLOWED_LIFETIME_MAX=4w
|
|||
#SECRET_SIGNAL_AS_TOKEN_VERSION=v1
|
||||
#SECRET_SIGNAL_DB_PASSWORD_VERSION=v1
|
||||
#SECRET_SIGNAL_HS_TOKEN_VERSION=v1
|
||||
|
||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.shared_secret_auth.yml"
|
||||
#SHARED_SECRET_AUTH_ENABLED=1
|
||||
#SECRET_SHARED_SECRET_AUTH_VERSION=v1 # length=128
|
||||
|
|
7
abra.sh
7
abra.sh
|
@ -1,6 +1,7 @@
|
|||
export ENTRYPOINT_CONF_VERSION=v1
|
||||
export HOMESERVER_YAML_VERSION=v12
|
||||
export HOMESERVER_YAML_VERSION=v13
|
||||
export LOG_CONFIG_VERSION=v2
|
||||
export TELEGRAM_BRIDGE_YAML_VERSION=v2
|
||||
export TELEGRAM_BRIDGE_YAML_VERSION=v3
|
||||
export DISCORD_BRIDGE_YAML_VERSION=v1
|
||||
export SIGNAL_BRIDGE_YAML_VERSION=v1
|
||||
export SIGNAL_BRIDGE_YAML_VERSION=v2
|
||||
export SHARED_SECRET_AUTH_VERSION=v1
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
- SHARED_SECRET_AUTH_ENABLED
|
||||
secrets:
|
||||
- shared_secret_auth
|
||||
configs:
|
||||
- source: shared_secret_auth
|
||||
target: /usr/local/lib/python3.9/site-packages/shared_secret_authenticator.py
|
||||
|
||||
configs:
|
||||
shared_secret_auth:
|
||||
name: ${STACK_NAME}_shared_secret_auth_${SHARED_SECRET_AUTH_VERSION}
|
||||
file: shared_secret_authenticator.py
|
||||
|
||||
secrets:
|
||||
shared_secret_auth:
|
||||
external: true
|
||||
name: ${STACK_NAME}_shared_secret_auth_${SECRET_SHARED_SECRET_AUTH_VERSION}
|
|
@ -20,7 +20,12 @@ modules:
|
|||
# do_thing: true
|
||||
# - module: my_other_super_module.SomeClass
|
||||
# config: {}
|
||||
|
||||
{{ if eq (env "SHARED_SECRET_AUTH_ENABLED") "1" }}
|
||||
- module: shared_secret_authenticator.SharedSecretAuthProvider
|
||||
config:
|
||||
shared_secret: {{ secret "shared_secret_auth" }}
|
||||
m_login_password_support_enabled: true
|
||||
{{ end }}
|
||||
|
||||
## Server ##
|
||||
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Shared Secret Authenticator module for Matrix Synapse
|
||||
# Copyright (C) 2018 Slavi Pantaleev
|
||||
#
|
||||
# https://devture.com/
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Awaitable, Callable, Optional, Tuple
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
|
||||
import synapse
|
||||
from synapse import module_api
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SharedSecretAuthProvider:
|
||||
def __init__(self, config: dict, api: module_api):
|
||||
for k in ('shared_secret',):
|
||||
if k not in config:
|
||||
raise KeyError('Required `{0}` configuration key not found'.format(k))
|
||||
|
||||
m_login_password_support_enabled = bool(config['m_login_password_support_enabled']) if 'm_login_password_support_enabled' in config else False
|
||||
com_devture_shared_secret_auth_support_enabled = bool(config['com_devture_shared_secret_auth_support_enabled']) if 'com_devture_shared_secret_auth_support_enabled' in config else True
|
||||
|
||||
self.api = api
|
||||
self.shared_secret = config['shared_secret']
|
||||
|
||||
auth_checkers: Optional[Dict[Tuple[str, Tuple], CHECK_AUTH_CALLBACK]] = {}
|
||||
if com_devture_shared_secret_auth_support_enabled:
|
||||
auth_checkers[("com.devture.shared_secret_auth", ("token",))] = self.check_com_devture_shared_secret_auth
|
||||
if m_login_password_support_enabled:
|
||||
auth_checkers[("m.login.password", ("password",))] = self.check_m_login_password
|
||||
|
||||
enabled_login_types = [k[0] for k in auth_checkers]
|
||||
|
||||
if len(enabled_login_types) == 0:
|
||||
raise RuntimeError('At least one login type must be enabled')
|
||||
|
||||
logger.info('Enabled login types: %s', enabled_login_types)
|
||||
|
||||
api.register_password_auth_provider_callbacks(
|
||||
auth_checkers=auth_checkers,
|
||||
)
|
||||
|
||||
async def check_com_devture_shared_secret_auth(
|
||||
self,
|
||||
username: str,
|
||||
login_type: str,
|
||||
login_dict: "synapse.module_api.JsonDict",
|
||||
) -> Optional[
|
||||
Tuple[
|
||||
str,
|
||||
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||
]
|
||||
]:
|
||||
if login_type != "com.devture.shared_secret_auth":
|
||||
return None
|
||||
return await self._log_in_username_with_token("com.devture.shared_secret_auth", username, login_dict.get("token"))
|
||||
|
||||
async def check_m_login_password(
|
||||
self,
|
||||
username: str,
|
||||
login_type: str,
|
||||
login_dict: "synapse.module_api.JsonDict",
|
||||
) -> Optional[
|
||||
Tuple[
|
||||
str,
|
||||
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||
]
|
||||
]:
|
||||
if login_type != "m.login.password":
|
||||
return None
|
||||
return await self._log_in_username_with_token("m.login.password", username, login_dict.get("password"))
|
||||
|
||||
async def _log_in_username_with_token(
|
||||
self,
|
||||
login_type: str,
|
||||
username: str,
|
||||
token: str,
|
||||
) -> Optional[
|
||||
Tuple[
|
||||
str,
|
||||
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||
]
|
||||
]:
|
||||
logger.info('Authenticating user `%s` with login type `%s`', username, login_type)
|
||||
|
||||
full_user_id = self.api.get_qualified_user_id(username)
|
||||
|
||||
# The password (token) is supposed to be an HMAC of the full user id, keyed with the shared secret.
|
||||
given_hmac = token.encode('utf-8')
|
||||
|
||||
h = hmac.new(self.shared_secret.encode('utf-8'), full_user_id.encode('utf-8'), hashlib.sha512)
|
||||
computed_hmac = h.hexdigest().encode('utf-8')
|
||||
|
||||
if not hmac.compare_digest(computed_hmac, given_hmac):
|
||||
logger.info('Bad hmac value for user: %s', full_user_id)
|
||||
return None
|
||||
|
||||
user_info = await self.api.get_userinfo_by_id(full_user_id)
|
||||
if user_info is None:
|
||||
logger.info('Refusing to authenticate missing user: %s', full_user_id)
|
||||
return None
|
||||
|
||||
logger.info('Authenticated user: %s', full_user_id)
|
||||
|
||||
return full_user_id, None
|
|
@ -145,7 +145,7 @@ bridge:
|
|||
double_puppet_allow_discovery: false
|
||||
# Servers to allow double puppeting from, even if double_puppet_allow_discovery is false.
|
||||
double_puppet_server_map:
|
||||
example.com: https://example.com
|
||||
{{ env "HOMESERVER_DOMAIN" }}: {{ env "HOMESERVER_URL" }}
|
||||
# Shared secret for https://github.com/devture/matrix-synapse-shared-secret-auth
|
||||
#
|
||||
# If set, custom puppets will be enabled automatically for local users
|
||||
|
@ -154,7 +154,7 @@ bridge:
|
|||
# If using this for other servers than the bridge's server,
|
||||
# you must also set the URL in the double_puppet_server_map.
|
||||
login_shared_secret_map:
|
||||
example.com: foo
|
||||
{{ env "HOMESERVER_DOMAIN" }}: {{ secret "shared_secret_auth" }}
|
||||
# Whether or not created rooms should have federation enabled.
|
||||
# If false, created portal rooms will never be federated.
|
||||
federate_rooms: true
|
||||
|
|
|
@ -189,7 +189,7 @@ bridge:
|
|||
sync_direct_chat_list: false
|
||||
# Servers to always allow double puppeting from
|
||||
double_puppet_server_map:
|
||||
example.com: https://example.com
|
||||
{{ env "HOMESERVER_DOMAIN" }}: {{ env "HOMESERVER_URL" }}
|
||||
# Allow using double puppeting from any server with a valid client .well-known file.
|
||||
double_puppet_allow_discovery: false
|
||||
# Shared secrets for https://github.com/devture/matrix-synapse-shared-secret-auth
|
||||
|
@ -200,7 +200,7 @@ bridge:
|
|||
# If using this for other servers than the bridge's server,
|
||||
# you must also set the URL in the double_puppet_server_map.
|
||||
login_shared_secret_map:
|
||||
example.com: foobar
|
||||
{{ env "HOMESERVER_DOMAIN" }}: {{ secret "shared_secret_auth" }}
|
||||
# Set to false to disable link previews in messages sent to Telegram.
|
||||
telegram_link_preview: true
|
||||
# Whether or not the !tg join command should do a HTTP request
|
||||
|
|
Loading…
Reference in New Issue