Temporary fix for authentication. Update readme. Add gitignore.

This commit is contained in:
Anatoly Sablin 2020-01-24 01:08:15 +03:00
parent d99b856cd9
commit ed377fb705
3 changed files with 230 additions and 18 deletions

204
.gitignore vendored Normal file
View File

@ -0,0 +1,204 @@
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
*.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View File

@ -4,11 +4,6 @@
- [Configure](#configure) - [Configure](#configure)
- [Integrate](#integrate) - [Integrate](#integrate)
- [Support](#support) - [Support](#support)
---
**This project is no longer maintained.**
---
## Overview ## Overview
This synapse's password provider allows you to validate a password for a given username and return a user profile using an existing backend, like: This synapse's password provider allows you to validate a password for a given username and return a user profile using an existing backend, like:
@ -18,7 +13,7 @@ This synapse's password provider allows you to validate a password for a given u
- CRMs (Wordpress, ...) - CRMs (Wordpress, ...)
- self-hosted clouds (Nextcloud, ownCloud, ...) - self-hosted clouds (Nextcloud, ownCloud, ...)
It is mainly used with [mxisd](https://github.com/kamax-matrix/mxisd), the Federated Matrix Identity Server, to provide It is mainly used with [ma1sd](https://github.com/ma1uta/ma1sd), the Federated Matrix Identity Server, to provide
missing features and offer a fully integrated solution (directory, authentication, search). missing features and offer a fully integrated solution (directory, authentication, search).
**NOTE:** This module doesn't provide direct integration with any backend. If you do not use mxisd, you will need to write **NOTE:** This module doesn't provide direct integration with any backend. If you do not use mxisd, you will need to write
@ -31,7 +26,7 @@ Copy in whichever directory python3.x can pick it up as a module.
If you installed synapse using the Matrix debian repos: If you installed synapse using the Matrix debian repos:
``` ```
sudo curl https://raw.githubusercontent.com/kamax-matrix/matrix-synapse-rest-auth/master/rest_auth_provider.py -o /opt/venvs/matrix-synapse/lib/python3.5/site-packages/rest_auth_provider.py sudo curl https://raw.githubusercontent.com/ma1uta/matrix-synapse-rest-password-provider/master/rest_auth_provider.py -o /opt/venvs/matrix-synapse/lib/python3.7/site-packages/rest_auth_provider.py
``` ```
If the command fail, double check that the python version still matches. If not, please let us know by opening an issue. If the command fail, double check that the python version still matches. If not, please let us know by opening an issue.
@ -40,7 +35,7 @@ Copy in whichever directory python2.x can pick it up as a module.
If you installed synapse using the Matrix debian repos: If you installed synapse using the Matrix debian repos:
``` ```
sudo curl https://raw.githubusercontent.com/kamax-matrix/matrix-synapse-rest-auth/master/rest_auth_provider.py -o /usr/lib/python2.7/dist-packages/rest_auth_provider.py sudo curl https://raw.githubusercontent.com/ma1uta/matrix-synapse-rest-password-provider/master/rest_auth_provider.py -o /usr/lib/python2.7/dist-packages/rest_auth_provider.py
``` ```
If the command fail, double check that the python version still matches. If not, please let us know by opening an issue. If the command fail, double check that the python version still matches. If not, please let us know by opening an issue.

View File

@ -23,9 +23,11 @@ import logging
from twisted.internet import defer from twisted.internet import defer
import requests import requests
import json import json
import time
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class RestAuthProvider(object): class RestAuthProvider(object):
def __init__(self, config, account_handler): def __init__(self, config, account_handler):
@ -37,15 +39,15 @@ class RestAuthProvider(object):
self.endpoint = config.endpoint self.endpoint = config.endpoint
self.regLower = config.regLower self.regLower = config.regLower
self.config = config self.config = config
logger.info('Endpoint: %s', self.endpoint) logger.info('Endpoint: %s', self.endpoint)
logger.info('Enforce lowercase username during registration: %s', self.regLower) logger.info('Enforce lowercase username during registration: %s', self.regLower)
@defer.inlineCallbacks @defer.inlineCallbacks
def check_password(self, user_id, password): def check_password(self, user_id, password):
logger.info("Got password check for " + user_id) logger.info("Got password check for " + user_id)
data = {'user':{'id':user_id, 'password':password}} data = {'user': {'id': user_id, 'password': password}}
r = requests.post(self.endpoint + '/_matrix-internal/identity/v1/check_credentials', json = data) r = requests.post(self.endpoint + '/_matrix-internal/identity/v1/check_credentials', json=data)
r.raise_for_status() r.raise_for_status()
r = r.json() r = r.json()
if not r["auth"]: if not r["auth"]:
@ -64,11 +66,11 @@ class RestAuthProvider(object):
registration = False registration = False
if not (yield self.account_handler.check_user_exists(user_id)): if not (yield self.account_handler.check_user_exists(user_id)):
logger.info("User %s does not exist yet, creating...", user_id) logger.info("User %s does not exist yet, creating...", user_id)
if localpart != localpart.lower() and self.regLower: if localpart != localpart.lower() and self.regLower:
logger.info('User %s was cannot be created due to username lowercase policy', localpart) logger.info('User %s was cannot be created due to username lowercase policy', localpart)
defer.returnValue(False) defer.returnValue(False)
user_id, access_token = (yield self.account_handler.register(localpart=localpart)) user_id, access_token = (yield self.account_handler.register(localpart=localpart))
registration = True registration = True
logger.info("Registration based on REST data was successful for %s", user_id) logger.info("Registration based on REST data was successful for %s", user_id)
@ -79,14 +81,19 @@ class RestAuthProvider(object):
logger.info("Handling profile data") logger.info("Handling profile data")
profile = auth["profile"] profile = auth["profile"]
store = yield self.account_handler.hs.get_profile_handler().store # fixme: temporary fix
try:
store = yield self.account_handler._hs.get_profile_handler().store # for synapse >= 1.9.0
except AttributeError:
store = yield self.account_handler.hs.get_profile_handler().store # for synapse < 1.9.0
if "display_name" in profile and ((registration and self.config.setNameOnRegister) or (self.config.setNameOnLogin)): if "display_name" in profile and ((registration and self.config.setNameOnRegister) or (self.config.setNameOnLogin)):
display_name = profile["display_name"] display_name = profile["display_name"]
logger.info("Setting display name to '%s' based on profile data", display_name) logger.info("Setting display name to '%s' based on profile data", display_name)
yield store.set_profile_displayname(localpart, display_name) yield store.set_profile_displayname(localpart, display_name)
else: else:
logger.info("Display name was not set because it was not given or policy restricted it") logger.info("Display name was not set because it was not given or policy restricted it")
if (self.config.updateThreepid): if (self.config.updateThreepid):
if "three_pids" in profile: if "three_pids" in profile:
logger.info("Handling 3PIDs") logger.info("Handling 3PIDs")
@ -98,7 +105,7 @@ class RestAuthProvider(object):
external_3pids.append({"medium": medium, "address": address}) external_3pids.append({"medium": medium, "address": address})
logger.info("Looking for 3PID %s:%s in user profile", medium, address) logger.info("Looking for 3PID %s:%s in user profile", medium, address)
validated_at = self.account_handler.hs.get_clock().time_msec() validated_at = time_msec()
if not (yield store.get_user_id_by_threepid(medium, address)): if not (yield store.get_user_id_by_threepid(medium, address)):
logger.info("3PID is not present, adding") logger.info("3PID is not present, adding")
yield store.user_add_threepid( yield store.user_add_threepid(
@ -123,7 +130,6 @@ class RestAuthProvider(object):
address address
) )
else: else:
logger.info("3PIDs were not updated due to policy") logger.info("3PIDs were not updated due to policy")
else: else:
@ -164,7 +170,7 @@ class RestAuthProvider(object):
except KeyError: except KeyError:
# we don't care # we don't care
pass pass
try: try:
rest_config.setNameOnLogin = config['policy']['login']['profile']['name'] rest_config.setNameOnLogin = config['policy']['login']['profile']['name']
except TypeError: except TypeError:
@ -194,6 +200,7 @@ class RestAuthProvider(object):
return rest_config return rest_config
def _require_keys(config, required): def _require_keys(config, required):
missing = [key for key in required if key not in config] missing = [key for key in required if key not in config]
if missing: if missing:
@ -202,3 +209,9 @@ def _require_keys(config, required):
", ".join(missing) ", ".join(missing)
) )
) )
def time_msec():
"""Get the current timestamp in milliseconds
"""
return int(time.time() * 1000)