Merge branch 'release-v1.1.0' into matrix-org-hotfixes
commit
24e48bc9ff
|
@ -4,6 +4,7 @@ about: I need support for Synapse
|
|||
|
||||
---
|
||||
|
||||
# Please ask for support in [**#matrix:matrix.org**](https://matrix.to/#/#matrix:matrix.org)
|
||||
Please don't file github issues asking for support.
|
||||
|
||||
## Don't file an issue as a support request.
|
||||
Instead, please join [`#synapse:matrix.org`](https://matrix.to/#/#synapse:matrix.org)
|
||||
(from a matrix.org account if necessary), and ask there.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[**#matrix:matrix.org**](https://matrix.to/#/#matrix:matrix.org) is the official support room for Matrix, and can be accessed by any client from https://matrix.org/docs/projects/try-matrix-now.html
|
||||
|
||||
It can also be access via IRC bridge at irc://irc.freenode.net/matrix or on the web here: https://webchat.freenode.net/?channels=matrix
|
||||
[**#synapse:matrix.org**](https://matrix.to/#/#synapse:matrix.org) is the official support room for
|
||||
Synapse, and can be accessed by any client from https://matrix.org/docs/projects/try-matrix-now.html.
|
||||
Please ask for support there, rather than filing github issues.
|
||||
|
|
104
CHANGES.md
104
CHANGES.md
|
@ -1,3 +1,107 @@
|
|||
Synapse 1.1.0rc1 (2019-07-02)
|
||||
=============================
|
||||
|
||||
As of v1.1.0, Synapse no longer supports Python 2, nor Postgres version 9.4.
|
||||
See the [upgrade notes](UPGRADE.rst#upgrading-to-v110) for more details.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Added possibilty to disable local password authentication. Contributed by Daniel Hoffend. ([\#5092](https://github.com/matrix-org/synapse/issues/5092))
|
||||
- Add monthly active users to phonehome stats. ([\#5252](https://github.com/matrix-org/synapse/issues/5252))
|
||||
- Allow expired user to trigger renewal email sending manually. ([\#5363](https://github.com/matrix-org/synapse/issues/5363))
|
||||
- Statistics on forward extremities per room are now exposed via Prometheus. ([\#5384](https://github.com/matrix-org/synapse/issues/5384), [\#5458](https://github.com/matrix-org/synapse/issues/5458), [\#5461](https://github.com/matrix-org/synapse/issues/5461))
|
||||
- Add --no-daemonize option to run synapse in the foreground, per issue #4130. Contributed by Soham Gumaste. ([\#5412](https://github.com/matrix-org/synapse/issues/5412), [\#5587](https://github.com/matrix-org/synapse/issues/5587))
|
||||
- Fully support SAML2 authentication. Contributed by [Alexander Trost](https://github.com/galexrt) - thank you! ([\#5422](https://github.com/matrix-org/synapse/issues/5422))
|
||||
- Allow server admins to define implementations of extra rules for allowing or denying incoming events. ([\#5440](https://github.com/matrix-org/synapse/issues/5440), [\#5474](https://github.com/matrix-org/synapse/issues/5474), [\#5477](https://github.com/matrix-org/synapse/issues/5477))
|
||||
- Add support for handling pagination APIs on client reader worker. ([\#5505](https://github.com/matrix-org/synapse/issues/5505), [\#5513](https://github.com/matrix-org/synapse/issues/5513), [\#5531](https://github.com/matrix-org/synapse/issues/5531))
|
||||
- Improve help and cmdline option names for --generate-config options. ([\#5512](https://github.com/matrix-org/synapse/issues/5512))
|
||||
- Allow configuration of the path used for ACME account keys. ([\#5516](https://github.com/matrix-org/synapse/issues/5516), [\#5521](https://github.com/matrix-org/synapse/issues/5521), [\#5522](https://github.com/matrix-org/synapse/issues/5522))
|
||||
- Add --data-dir and --open-private-ports options. ([\#5524](https://github.com/matrix-org/synapse/issues/5524))
|
||||
- Split public rooms directory auth config in two settings, in order to manage client auth independently from the federation part of it. Obsoletes the "restrict_public_rooms_to_local_users" configuration setting. If "restrict_public_rooms_to_local_users" is set in the config, Synapse will act as if both new options are enabled, i.e. require authentication through the client API and deny federation requests. ([\#5534](https://github.com/matrix-org/synapse/issues/5534))
|
||||
- The minimum TLS version used for outgoing federation requests can now be set with `federation_client_minimum_tls_version`. ([\#5550](https://github.com/matrix-org/synapse/issues/5550))
|
||||
- Optimise devices changed query to not pull unnecessary rows from the database, reducing database load. ([\#5559](https://github.com/matrix-org/synapse/issues/5559))
|
||||
- Add new metrics for number of forward extremities being persisted and number of state groups involved in resolution. ([\#5476](https://github.com/matrix-org/synapse/issues/5476))
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix bug processing incoming events over federation if call to `/get_missing_events` fails. ([\#5042](https://github.com/matrix-org/synapse/issues/5042))
|
||||
- Prevent more than one room upgrade happening simultaneously on the same room. ([\#5051](https://github.com/matrix-org/synapse/issues/5051))
|
||||
- Fix a bug where running synapse_port_db would cause the account validity feature to fail because it didn't set the type of the email_sent column to boolean. ([\#5325](https://github.com/matrix-org/synapse/issues/5325))
|
||||
- Warn about disabling email-based password resets when a reset occurs, and remove warning when someone attempts a phone-based reset. ([\#5387](https://github.com/matrix-org/synapse/issues/5387))
|
||||
- Fix email notifications for unnamed rooms with multiple people. ([\#5388](https://github.com/matrix-org/synapse/issues/5388))
|
||||
- Fix exceptions in federation reader worker caused by attempting to renew attestations, which should only happen on master worker. ([\#5389](https://github.com/matrix-org/synapse/issues/5389))
|
||||
- Fix handling of failures fetching remote content to not log failures as exceptions. ([\#5390](https://github.com/matrix-org/synapse/issues/5390))
|
||||
- Fix a bug where deactivated users could receive renewal emails if the account validity feature is on. ([\#5394](https://github.com/matrix-org/synapse/issues/5394))
|
||||
- Fix missing invite state after exchanging 3PID invites over federaton. ([\#5464](https://github.com/matrix-org/synapse/issues/5464))
|
||||
- Fix intermittent exceptions on Apple hardware. Also fix bug that caused database activity times to be under-reported in log lines. ([\#5498](https://github.com/matrix-org/synapse/issues/5498))
|
||||
- Fix logging error when a tampered event is detected. ([\#5500](https://github.com/matrix-org/synapse/issues/5500))
|
||||
- Fix bug where clients could tight loop calling `/sync` for a period. ([\#5507](https://github.com/matrix-org/synapse/issues/5507))
|
||||
- Fix bug with `jinja2` preventing Synapse from starting. Users who had this problem should now simply need to run `pip install matrix-synapse`. ([\#5514](https://github.com/matrix-org/synapse/issues/5514))
|
||||
- Fix a regression where homeservers on private IP addresses were incorrectly blacklisted. ([\#5523](https://github.com/matrix-org/synapse/issues/5523))
|
||||
- Fixed m.login.jwt using unregistred user_id and added pyjwt>=1.6.4 as jwt conditional dependencies. Contributed by Pau Rodriguez-Estivill. ([\#5555](https://github.com/matrix-org/synapse/issues/5555), [\#5586](https://github.com/matrix-org/synapse/issues/5586))
|
||||
- Fix a bug that would cause invited users to receive several emails for a single 3PID invite in case the inviter is rate limited. ([\#5576](https://github.com/matrix-org/synapse/issues/5576))
|
||||
|
||||
|
||||
Updates to the Docker image
|
||||
---------------------------
|
||||
- Add ability to change Docker containers [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) with the `TZ` variable. ([\#5383](https://github.com/matrix-org/synapse/issues/5383))
|
||||
- Update docker image to use Python 3.7. ([\#5546](https://github.com/matrix-org/synapse/issues/5546))
|
||||
- Deprecate the use of environment variables for configuration, and make the use of a static configuration the default. ([\#5561](https://github.com/matrix-org/synapse/issues/5561), [\#5562](https://github.com/matrix-org/synapse/issues/5562), [\#5566](https://github.com/matrix-org/synapse/issues/5566), [\#5567](https://github.com/matrix-org/synapse/issues/5567))
|
||||
- Increase default log level for docker image to INFO. It can still be changed by editing the generated log.config file. ([\#5547](https://github.com/matrix-org/synapse/issues/5547))
|
||||
- Send synapse logs to the docker logging system, by default. ([\#5565](https://github.com/matrix-org/synapse/issues/5565))
|
||||
- Open the non-TLS port by default. ([\#5568](https://github.com/matrix-org/synapse/issues/5568))
|
||||
- Fix failure to start under docker with SAML support enabled. ([\#5490](https://github.com/matrix-org/synapse/issues/5490))
|
||||
- Use a sensible location for data files when generating a config file. ([\#5563](https://github.com/matrix-org/synapse/issues/5563))
|
||||
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Python 2.7 is no longer a supported platform. Synapse now requires Python 3.5+ to run. ([\#5425](https://github.com/matrix-org/synapse/issues/5425))
|
||||
- PostgreSQL 9.4 is no longer supported. Synapse requires Postgres 9.5+ or above for Postgres support. ([\#5448](https://github.com/matrix-org/synapse/issues/5448))
|
||||
- Remove support for cpu_affinity setting. ([\#5525](https://github.com/matrix-org/synapse/issues/5525))
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
- Improve README section on performance troubleshooting. ([\#4276](https://github.com/matrix-org/synapse/issues/4276))
|
||||
- Add information about how to install and run `black` on the codebase to code_style.rst. ([\#5537](https://github.com/matrix-org/synapse/issues/5537))
|
||||
- Improve install docs on choosing server_name. ([\#5558](https://github.com/matrix-org/synapse/issues/5558))
|
||||
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
- Add logging to 3pid invite signature verification. ([\#5015](https://github.com/matrix-org/synapse/issues/5015))
|
||||
- Update example haproxy config to a more compatible setup. ([\#5313](https://github.com/matrix-org/synapse/issues/5313))
|
||||
- Track deactivated accounts in the database. ([\#5378](https://github.com/matrix-org/synapse/issues/5378), [\#5465](https://github.com/matrix-org/synapse/issues/5465), [\#5493](https://github.com/matrix-org/synapse/issues/5493))
|
||||
- Clean up code for sending federation EDUs. ([\#5381](https://github.com/matrix-org/synapse/issues/5381))
|
||||
- Add a sponsor button to the repo. ([\#5382](https://github.com/matrix-org/synapse/issues/5382), [\#5386](https://github.com/matrix-org/synapse/issues/5386))
|
||||
- Don't log non-200 responses from federation queries as exceptions. ([\#5383](https://github.com/matrix-org/synapse/issues/5383))
|
||||
- Update Python syntax in contrib/ to Python 3. ([\#5446](https://github.com/matrix-org/synapse/issues/5446))
|
||||
- Update federation_client dev script to support `.well-known` and work with python3. ([\#5447](https://github.com/matrix-org/synapse/issues/5447))
|
||||
- SyTest has been moved to Buildkite. ([\#5459](https://github.com/matrix-org/synapse/issues/5459))
|
||||
- Demo script now uses python3. ([\#5460](https://github.com/matrix-org/synapse/issues/5460))
|
||||
- Synapse can now handle RestServlets that return coroutines. ([\#5475](https://github.com/matrix-org/synapse/issues/5475), [\#5585](https://github.com/matrix-org/synapse/issues/5585))
|
||||
- The demo servers talk to each other again. ([\#5478](https://github.com/matrix-org/synapse/issues/5478))
|
||||
- Add an EXPERIMENTAL config option to try and periodically clean up extremities by sending dummy events. ([\#5480](https://github.com/matrix-org/synapse/issues/5480))
|
||||
- Synapse's codebase is now formatted by `black`. ([\#5482](https://github.com/matrix-org/synapse/issues/5482))
|
||||
- Some cleanups and sanity-checking in the CPU and database metrics. ([\#5499](https://github.com/matrix-org/synapse/issues/5499))
|
||||
- Improve email notification logging. ([\#5502](https://github.com/matrix-org/synapse/issues/5502))
|
||||
- Fix "Unexpected entry in 'full_schemas'" log warning. ([\#5509](https://github.com/matrix-org/synapse/issues/5509))
|
||||
- Improve logging when generating config files. ([\#5510](https://github.com/matrix-org/synapse/issues/5510))
|
||||
- Refactor and clean up Config parser for maintainability. ([\#5511](https://github.com/matrix-org/synapse/issues/5511))
|
||||
- Make the config clearer in that email.template_dir is relative to the Synapse's root directory, not the `synapse/` folder within it. ([\#5543](https://github.com/matrix-org/synapse/issues/5543))
|
||||
- Update v1.0.0 release changelog to include more information about changes to password resets. ([\#5545](https://github.com/matrix-org/synapse/issues/5545))
|
||||
- Remove non-functioning check_event_hash.py dev script. ([\#5548](https://github.com/matrix-org/synapse/issues/5548))
|
||||
- Synapse will now only allow TLS v1.2 connections when serving federation, if it terminates TLS. As Synapse's allowed ciphers were only able to be used in TLSv1.2 before, this does not change behaviour. ([\#5550](https://github.com/matrix-org/synapse/issues/5550))
|
||||
- Logging when running GC collection on generation 0 is now at the DEBUG level, not INFO. ([\#5557](https://github.com/matrix-org/synapse/issues/5557))
|
||||
- Reduce the amount of stuff we send in the docker context. ([\#5564](https://github.com/matrix-org/synapse/issues/5564))
|
||||
- Point the reverse links in the Purge History contrib scripts at the intended location. ([\#5570](https://github.com/matrix-org/synapse/issues/5570))
|
||||
|
||||
|
||||
Synapse 1.0.0 (2019-06-11)
|
||||
==========================
|
||||
|
||||
|
|
|
@ -49,16 +49,16 @@ returned by the Client-Server API:
|
|||
# configured on port 443.
|
||||
curl -kv https://<host.name>/_matrix/client/versions 2>&1 | grep "Server:"
|
||||
|
||||
Upgrading to v1.1
|
||||
=================
|
||||
Upgrading to v1.1.0
|
||||
===================
|
||||
|
||||
Synapse 1.1 removes support for older Python and PostgreSQL versions, as
|
||||
Synapse v1.1.0 removes support for older Python and PostgreSQL versions, as
|
||||
outlined in `our deprecation notice <https://matrix.org/blog/2019/04/08/synapse-deprecating-postgres-9-4-and-python-2-x>`_.
|
||||
|
||||
Minimum Python Version
|
||||
----------------------
|
||||
|
||||
Synapse v1.1 has a minimum Python requirement of Python 3.5. Python 3.6 or
|
||||
Synapse v1.1.0 has a minimum Python requirement of Python 3.5. Python 3.6 or
|
||||
Python 3.7 are recommended as they have improved internal string handling,
|
||||
significantly reducing memory usage.
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Improve README section on performance troubleshooting.
|
|
@ -1 +0,0 @@
|
|||
Add logging to 3pid invite signature verification.
|
|
@ -1 +0,0 @@
|
|||
Fix bug processing incoming events over federation if call to `/get_missing_events` fails.
|
|
@ -1 +0,0 @@
|
|||
Prevent >1 room upgrades happening simultaneously on the same room.
|
|
@ -1 +0,0 @@
|
|||
Added possibilty to disable local password authentication. Contributed by Daniel Hoffend.
|
|
@ -1 +0,0 @@
|
|||
Add monthly active users to phonehome stats.
|
|
@ -1 +0,0 @@
|
|||
Update example haproxy config to a more compatible setup.
|
|
@ -1 +0,0 @@
|
|||
Fix a bug where running synapse_port_db would cause the account validity feature to fail because it didn't set the type of the email_sent column to boolean.
|
|
@ -1 +0,0 @@
|
|||
Allow expired user to trigger renewal email sending manually.
|
|
@ -1 +0,0 @@
|
|||
Track deactivated accounts in the database.
|
|
@ -1 +0,0 @@
|
|||
Clean up code for sending federation EDUs.
|
|
@ -1 +0,0 @@
|
|||
Add a sponsor button to the repo.
|
|
@ -1 +0,0 @@
|
|||
Don't log non-200 responses from federation queries as exceptions.
|
|
@ -1 +0,0 @@
|
|||
Statistics on forward extremities per room are now exposed via Prometheus.
|
|
@ -1 +0,0 @@
|
|||
Add a sponsor button to the repo.
|
|
@ -1 +0,0 @@
|
|||
Warn about disabling email-based password resets when a reset occurs, and remove warning when someone attempts a phone-based reset.
|
|
@ -1 +0,0 @@
|
|||
Fix email notifications for unnamed rooms with multiple people.
|
|
@ -1 +0,0 @@
|
|||
Fix exceptions in federation reader worker caused by attempting to renew attestations, which should only happen on master worker.
|
|
@ -1 +0,0 @@
|
|||
Fix handling of failures fetching remote content to not log failures as exceptions.
|
|
@ -1 +0,0 @@
|
|||
Fix a bug where deactivated users could receive renewal emails if the account validity feature is on.
|
|
@ -1 +0,0 @@
|
|||
Add --no-daemonize option to run synapse in the foreground, per issue #4130. Contributed by Soham Gumaste.
|
|
@ -1 +0,0 @@
|
|||
Python 2.7 is no longer a supported platform. Synapse now requires Python 3.5+ to run.
|
|
@ -1 +0,0 @@
|
|||
Allow server admins to define implementations of extra rules for allowing or denying incoming events.
|
|
@ -1 +0,0 @@
|
|||
Update Python syntax in contrib/ to Python 3.
|
|
@ -1 +0,0 @@
|
|||
Update federation_client dev script to support `.well-known` and work with python3.
|
|
@ -1 +0,0 @@
|
|||
PostgreSQL 9.4 is no longer supported. Synapse requires Postgres 9.5+ or above for Postgres support.
|
|
@ -1 +0,0 @@
|
|||
Statistics on forward extremities per room are now exposed via Prometheus.
|
|
@ -1 +0,0 @@
|
|||
SyTest has been moved to Buildkite.
|
|
@ -1 +0,0 @@
|
|||
Demo script now uses python3.
|
|
@ -1 +0,0 @@
|
|||
Statistics on forward extremities per room are now exposed via Prometheus.
|
|
@ -1 +0,0 @@
|
|||
Fix missing invite state after exchanging 3PID invites over federaton.
|
|
@ -1,2 +0,0 @@
|
|||
Track deactivated accounts in the database.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Allow server admins to define implementations of extra rules for allowing or denying incoming events.
|
|
@ -1 +0,0 @@
|
|||
Add new metrics for number of forward extremities being persisted and number of state groups involved in resolution.
|
|
@ -1 +0,0 @@
|
|||
Allow server admins to define implementations of extra rules for allowing or denying incoming events.
|
|
@ -1 +0,0 @@
|
|||
The demo servers talk to each other again.
|
|
@ -1 +0,0 @@
|
|||
Add an EXPERIMENTAL config option to try and periodically clean up extremities by sending dummy events.
|
|
@ -1 +0,0 @@
|
|||
Synapse's codebase is now formatted by `black`.
|
|
@ -1 +0,0 @@
|
|||
Fix failure to start under docker with SAML support enabled.
|
|
@ -1 +0,0 @@
|
|||
Track deactivated accounts in the database.
|
|
@ -1 +0,0 @@
|
|||
Fix intermittent exceptions on Apple hardware. Also fix bug that caused database activity times to be under-reported in log lines.
|
|
@ -1 +0,0 @@
|
|||
Some cleanups and sanity-checking in the CPU and database metrics.
|
|
@ -1 +0,0 @@
|
|||
Fix logging error when a tampered event is detected.
|
|
@ -1 +0,0 @@
|
|||
Improve email notification logging.
|
|
@ -1 +0,0 @@
|
|||
Add support for handling pagination APIs on client reader worker.
|
|
@ -1 +0,0 @@
|
|||
Fix "Unexpected entry in 'full_schemas'" log warning.
|
|
@ -1 +0,0 @@
|
|||
Improve logging when generating config files.
|
|
@ -1 +0,0 @@
|
|||
Refactor and clean up Config parser for maintainability.
|
|
@ -1 +0,0 @@
|
|||
Improve help and cmdline option names for --generate-config options.
|
|
@ -1 +0,0 @@
|
|||
Add support for handling pagination APIs on client reader worker.
|
|
@ -1 +0,0 @@
|
|||
Fix bug with `jinja2` preventing Synapse from starting. Users who had this problem should now simply need to run `pip install matrix-synapse`.
|
|
@ -1 +0,0 @@
|
|||
Allow configuration of the path used for ACME account keys.
|
|
@ -1 +0,0 @@
|
|||
Allow configuration of the path used for ACME account keys.
|
|
@ -1 +0,0 @@
|
|||
Allow configuration of the path used for ACME account keys.
|
|
@ -1 +0,0 @@
|
|||
Fix a regression where homeservers on private IP addresses were incorrectly blacklisted.
|
|
@ -1 +0,0 @@
|
|||
Add --data-dir and --open-private-ports options.
|
|
@ -1 +0,0 @@
|
|||
Remove support for cpu_affinity setting.
|
|
@ -1 +0,0 @@
|
|||
Add support for handling pagination APIs on client reader worker.
|
|
@ -1 +0,0 @@
|
|||
Split public rooms directory auth config in two settings, in order to manage client auth independently from the federation part of it. Obsoletes the "restrict_public_rooms_to_local_users" configuration setting. If "restrict_public_rooms_to_local_users" is set in the config, Synapse will act as if both new options are enabled, i.e. require authentication through the client API and deny federation requests.
|
|
@ -1 +0,0 @@
|
|||
Add information about how to install and run `black` on the codebase to code_style.rst.
|
|
@ -1 +0,0 @@
|
|||
Make the config clearer in that email.template_dir is relative to the Synapse's root directory, not the `synapse/` folder within it.
|
|
@ -1 +0,0 @@
|
|||
Update v1.0.0 release changelog to include more information about changes to password resets.
|
|
@ -1 +0,0 @@
|
|||
Update docker image to use Python 3.7.
|
|
@ -1 +0,0 @@
|
|||
Increase default log level for docker image to INFO. It can still be changed by editing the generated log.config file.
|
|
@ -1 +0,0 @@
|
|||
Remove non-functioning check_event_hash.py dev script.
|
|
@ -1 +0,0 @@
|
|||
The minimum TLS version used for outgoing federation requests can now be set with `federation_client_minimum_tls_version`.
|
|
@ -1 +0,0 @@
|
|||
Synapse will now only allow TLS v1.2 connections when serving federation, if it terminates TLS. As Synapse's allowed ciphers were only able to be used in TLSv1.2 before, this does not change behaviour.
|
|
@ -0,0 +1 @@
|
|||
Update github templates.
|
|
@ -1 +0,0 @@
|
|||
Fixed m.login.jwt using unregistred user_id and added pyjwt>=1.6.4 as jwt conditional dependencies. Contributed by Pau Rodriguez-Estivill.
|
|
@ -1 +0,0 @@
|
|||
Improve install docs on choosing server_name.
|
|
@ -1 +0,0 @@
|
|||
Optimise devices changed query to not pull unnecessary rows from the database, reducing database load.
|
|
@ -1 +0,0 @@
|
|||
Update Docker image to deprecate the use of environment variables for configuration, and make the use of a static configuration the default.
|
|
@ -1 +0,0 @@
|
|||
Update Docker image to deprecate the use of environment variables for configuration, and make the use of a static configuration the default.
|
|
@ -1 +0,0 @@
|
|||
Docker: Use a sensible location for data files when generating a config file.
|
|
@ -1 +0,0 @@
|
|||
Reduce the amount of stuff we send in the docker context.
|
|
@ -1 +0,0 @@
|
|||
Docker: Send synapse logs to the docker logging system, by default.
|
|
@ -1 +0,0 @@
|
|||
Update Docker image to deprecate the use of environment variables for configuration, and make the use of a static configuration the default.
|
|
@ -1 +0,0 @@
|
|||
Update Docker image to deprecate the use of environment variables for configuration, and make the use of a static configuration the default.
|
|
@ -1 +0,0 @@
|
|||
Docker image: open the non-TLS port by default.
|
|
@ -1 +0,0 @@
|
|||
Point the reverse links in the Purge History contrib scripts at the intended location.
|
|
@ -66,6 +66,7 @@ RUN apk add --no-cache --virtual .runtime_deps \
|
|||
libpq \
|
||||
zlib \
|
||||
su-exec \
|
||||
tzdata \
|
||||
xmlsec
|
||||
|
||||
COPY --from=builder /install /usr/local
|
||||
|
|
|
@ -63,7 +63,6 @@ The following environment variables are supported in `generate` mode:
|
|||
* `UID`, `GID`: the user id and group id to use for creating the data
|
||||
directories. Defaults to `991`, `991`.
|
||||
|
||||
|
||||
## Running synapse
|
||||
|
||||
Once you have a valid configuration file, you can start synapse as follows:
|
||||
|
@ -91,6 +90,7 @@ The following environment variables are supported in run mode:
|
|||
* `SYNAPSE_CONFIG_PATH`: path to the config file. Defaults to
|
||||
`<SYNAPSE_CONFIG_DIR>/homeserver.yaml`.
|
||||
* `UID`, `GID`: the user and group id to run Synapse as. Defaults to `991`, `991`.
|
||||
* `TZ`: the [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) the container will run with. Defaults to `UTC`.
|
||||
|
||||
## TLS support
|
||||
|
||||
|
|
|
@ -997,6 +997,12 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
|
|||
# so it is not normally necessary to specify them unless you need to
|
||||
# override them.
|
||||
#
|
||||
# Once SAML support is enabled, a metadata file will be exposed at
|
||||
# https://<server>:<port>/_matrix/saml2/metadata.xml, which you may be able to
|
||||
# use to configure your SAML IdP with. Alternatively, you can manually configure
|
||||
# the IdP to use an ACS location of
|
||||
# https://<server>:<port>/_matrix/saml2/authn_response.
|
||||
#
|
||||
#saml2_config:
|
||||
# sp_config:
|
||||
# # point this to the IdP's metadata. You can use either a local file or
|
||||
|
@ -1006,7 +1012,15 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
|
|||
# remote:
|
||||
# - url: https://our_idp/metadata.xml
|
||||
#
|
||||
# # The rest of sp_config is just used to generate our metadata xml, and you
|
||||
# # By default, the user has to go to our login page first. If you'd like to
|
||||
# # allow IdP-initiated login, set 'allow_unsolicited: True' in a
|
||||
# # 'service.sp' section:
|
||||
# #
|
||||
# #service:
|
||||
# # sp:
|
||||
# # allow_unsolicited: True
|
||||
#
|
||||
# # The examples below are just used to generate our metadata xml, and you
|
||||
# # may well not need it, depending on your setup. Alternatively you
|
||||
# # may need a whole lot more detail - see the pysaml2 docs!
|
||||
#
|
||||
|
@ -1029,6 +1043,12 @@ signing_key_path: "CONFDIR/SERVERNAME.signing.key"
|
|||
# # separate pysaml2 configuration file:
|
||||
# #
|
||||
# config_path: "CONFDIR/sp_conf.py"
|
||||
#
|
||||
# # the lifetime of a SAML session. This defines how long a user has to
|
||||
# # complete the authentication process, if allow_unsolicited is unset.
|
||||
# # The default is 5 minutes.
|
||||
# #
|
||||
# # saml_session_lifetime: 5m
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -35,4 +35,4 @@ try:
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.1.0rc1"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from synapse.python_dependencies import DependencyException, check_requirements
|
||||
|
||||
from ._base import Config, ConfigError
|
||||
|
||||
|
@ -25,6 +26,11 @@ class SAML2Config(Config):
|
|||
if not saml2_config or not saml2_config.get("enabled", True):
|
||||
return
|
||||
|
||||
try:
|
||||
check_requirements("saml2")
|
||||
except DependencyException as e:
|
||||
raise ConfigError(e.message)
|
||||
|
||||
self.saml2_enabled = True
|
||||
|
||||
import saml2.config
|
||||
|
@ -37,6 +43,11 @@ class SAML2Config(Config):
|
|||
if config_path is not None:
|
||||
self.saml2_sp_config.load_file(config_path)
|
||||
|
||||
# session lifetime: in milliseconds
|
||||
self.saml2_session_lifetime = self.parse_duration(
|
||||
saml2_config.get("saml_session_lifetime", "5m")
|
||||
)
|
||||
|
||||
def _default_saml_config_dict(self):
|
||||
import saml2
|
||||
|
||||
|
@ -72,6 +83,12 @@ class SAML2Config(Config):
|
|||
# so it is not normally necessary to specify them unless you need to
|
||||
# override them.
|
||||
#
|
||||
# Once SAML support is enabled, a metadata file will be exposed at
|
||||
# https://<server>:<port>/_matrix/saml2/metadata.xml, which you may be able to
|
||||
# use to configure your SAML IdP with. Alternatively, you can manually configure
|
||||
# the IdP to use an ACS location of
|
||||
# https://<server>:<port>/_matrix/saml2/authn_response.
|
||||
#
|
||||
#saml2_config:
|
||||
# sp_config:
|
||||
# # point this to the IdP's metadata. You can use either a local file or
|
||||
|
@ -81,7 +98,15 @@ class SAML2Config(Config):
|
|||
# remote:
|
||||
# - url: https://our_idp/metadata.xml
|
||||
#
|
||||
# # The rest of sp_config is just used to generate our metadata xml, and you
|
||||
# # By default, the user has to go to our login page first. If you'd like to
|
||||
# # allow IdP-initiated login, set 'allow_unsolicited: True' in a
|
||||
# # 'service.sp' section:
|
||||
# #
|
||||
# #service:
|
||||
# # sp:
|
||||
# # allow_unsolicited: True
|
||||
#
|
||||
# # The examples below are just used to generate our metadata xml, and you
|
||||
# # may well not need it, depending on your setup. Alternatively you
|
||||
# # may need a whole lot more detail - see the pysaml2 docs!
|
||||
#
|
||||
|
@ -104,6 +129,12 @@ class SAML2Config(Config):
|
|||
# # separate pysaml2 configuration file:
|
||||
# #
|
||||
# config_path: "%(config_dir_path)s/sp_conf.py"
|
||||
#
|
||||
# # the lifetime of a SAML session. This defines how long a user has to
|
||||
# # complete the authentication process, if allow_unsolicited is unset.
|
||||
# # The default is 5 minutes.
|
||||
# #
|
||||
# # saml_session_lifetime: 5m
|
||||
""" % {
|
||||
"config_dir_path": config_dir_path
|
||||
}
|
||||
|
|
|
@ -1017,11 +1017,28 @@ class PresenceEventSource(object):
|
|||
if from_key is not None:
|
||||
from_key = int(from_key)
|
||||
|
||||
max_token = self.store.get_current_presence_token()
|
||||
if from_key == max_token:
|
||||
# This is necessary as due to the way stream ID generators work
|
||||
# we may get updates that have a stream ID greater than the max
|
||||
# token (e.g. max_token is N but stream generator may return
|
||||
# results for N+2, due to N+1 not having finished being
|
||||
# persisted yet).
|
||||
#
|
||||
# This is usually fine, as it just means that we may send down
|
||||
# some presence updates multiple times. However, we need to be
|
||||
# careful that the sync stream either actually does make some
|
||||
# progress or doesn't return, otherwise clients will end up
|
||||
# tight looping calling /sync due to it immediately returning
|
||||
# the same token repeatedly.
|
||||
#
|
||||
# Hence this guard where we just return nothing so that the sync
|
||||
# doesn't return. C.f. #5503.
|
||||
defer.returnValue(([], max_token))
|
||||
|
||||
presence = self.get_presence_handler()
|
||||
stream_change_cache = self.store.presence_stream_cache
|
||||
|
||||
max_token = self.store.get_current_presence_token()
|
||||
|
||||
users_interested_in = yield self._get_interested_in(user, explicit_room_id)
|
||||
|
||||
user_ids_changed = set()
|
||||
|
|
|
@ -843,6 +843,7 @@ class RoomMemberHandler(object):
|
|||
"sender": user.to_string(),
|
||||
"state_key": token,
|
||||
},
|
||||
ratelimit=False,
|
||||
txn_id=txn_id,
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import logging
|
||||
|
||||
import attr
|
||||
import saml2
|
||||
from saml2.client import Saml2Client
|
||||
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.http.servlet import parse_string
|
||||
from synapse.rest.client.v1.login import SSOAuthHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SamlHandler:
|
||||
def __init__(self, hs):
|
||||
self._saml_client = Saml2Client(hs.config.saml2_sp_config)
|
||||
self._sso_auth_handler = SSOAuthHandler(hs)
|
||||
|
||||
# a map from saml session id to Saml2SessionData object
|
||||
self._outstanding_requests_dict = {}
|
||||
|
||||
self._clock = hs.get_clock()
|
||||
self._saml2_session_lifetime = hs.config.saml2_session_lifetime
|
||||
|
||||
def handle_redirect_request(self, client_redirect_url):
|
||||
"""Handle an incoming request to /login/sso/redirect
|
||||
|
||||
Args:
|
||||
client_redirect_url (bytes): the URL that we should redirect the
|
||||
client to when everything is done
|
||||
|
||||
Returns:
|
||||
bytes: URL to redirect to
|
||||
"""
|
||||
reqid, info = self._saml_client.prepare_for_authenticate(
|
||||
relay_state=client_redirect_url
|
||||
)
|
||||
|
||||
now = self._clock.time_msec()
|
||||
self._outstanding_requests_dict[reqid] = Saml2SessionData(creation_time=now)
|
||||
|
||||
for key, value in info["headers"]:
|
||||
if key == "Location":
|
||||
return value
|
||||
|
||||
# this shouldn't happen!
|
||||
raise Exception("prepare_for_authenticate didn't return a Location header")
|
||||
|
||||
def handle_saml_response(self, request):
|
||||
"""Handle an incoming request to /_matrix/saml2/authn_response
|
||||
|
||||
Args:
|
||||
request (SynapseRequest): the incoming request from the browser. We'll
|
||||
respond to it with a redirect.
|
||||
|
||||
Returns:
|
||||
Deferred[none]: Completes once we have handled the request.
|
||||
"""
|
||||
resp_bytes = parse_string(request, "SAMLResponse", required=True)
|
||||
relay_state = parse_string(request, "RelayState", required=True)
|
||||
|
||||
# expire outstanding sessions before parse_authn_request_response checks
|
||||
# the dict.
|
||||
self.expire_sessions()
|
||||
|
||||
try:
|
||||
saml2_auth = self._saml_client.parse_authn_request_response(
|
||||
resp_bytes,
|
||||
saml2.BINDING_HTTP_POST,
|
||||
outstanding=self._outstanding_requests_dict,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Exception parsing SAML2 response: %s", e)
|
||||
raise SynapseError(400, "Unable to parse SAML2 response: %s" % (e,))
|
||||
|
||||
if saml2_auth.not_signed:
|
||||
logger.warning("SAML2 response was not signed")
|
||||
raise SynapseError(400, "SAML2 response was not signed")
|
||||
|
||||
if "uid" not in saml2_auth.ava:
|
||||
logger.warning("SAML2 response lacks a 'uid' attestation")
|
||||
raise SynapseError(400, "uid not in SAML2 response")
|
||||
|
||||
self._outstanding_requests_dict.pop(saml2_auth.in_response_to, None)
|
||||
|
||||
username = saml2_auth.ava["uid"][0]
|
||||
displayName = saml2_auth.ava.get("displayName", [None])[0]
|
||||
|
||||
return self._sso_auth_handler.on_successful_auth(
|
||||
username, request, relay_state, user_display_name=displayName
|
||||
)
|
||||
|
||||
def expire_sessions(self):
|
||||
expire_before = self._clock.time_msec() - self._saml2_session_lifetime
|
||||
to_expire = set()
|
||||
for reqid, data in self._outstanding_requests_dict.items():
|
||||
if data.creation_time < expire_before:
|
||||
to_expire.add(reqid)
|
||||
for reqid in to_expire:
|
||||
logger.debug("Expiring session id %s", reqid)
|
||||
del self._outstanding_requests_dict[reqid]
|
||||
|
||||
|
||||
@attr.s
|
||||
class Saml2SessionData:
|
||||
"""Data we track about SAML2 sessions"""
|
||||
|
||||
# time the session was created, in milliseconds
|
||||
creation_time = attr.ib()
|
|
@ -16,10 +16,11 @@
|
|||
|
||||
import cgi
|
||||
import collections
|
||||
import http.client
|
||||
import logging
|
||||
|
||||
from six import PY3
|
||||
from six.moves import http_client, urllib
|
||||
import types
|
||||
import urllib
|
||||
from io import BytesIO
|
||||
|
||||
from canonicaljson import encode_canonical_json, encode_pretty_printed_json, json
|
||||
|
||||
|
@ -41,11 +42,6 @@ from synapse.api.errors import (
|
|||
from synapse.util.caches import intern_dict
|
||||
from synapse.util.logcontext import preserve_fn
|
||||
|
||||
if PY3:
|
||||
from io import BytesIO
|
||||
else:
|
||||
from cStringIO import StringIO as BytesIO
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
HTML_ERROR_TEMPLATE = """<!DOCTYPE html>
|
||||
|
@ -75,10 +71,9 @@ def wrap_json_request_handler(h):
|
|||
deferred fails with any other type of error we send a 500 reponse.
|
||||
"""
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def wrapped_request_handler(self, request):
|
||||
async def wrapped_request_handler(self, request):
|
||||
try:
|
||||
yield h(self, request)
|
||||
await h(self, request)
|
||||
except SynapseError as e:
|
||||
code = e.code
|
||||
logger.info("%s SynapseError: %s - %s", request, code, e.msg)
|
||||
|
@ -142,10 +137,12 @@ def wrap_html_request_handler(h):
|
|||
where "request" must be a SynapseRequest.
|
||||
"""
|
||||
|
||||
def wrapped_request_handler(self, request):
|
||||
d = defer.maybeDeferred(h, self, request)
|
||||
d.addErrback(_return_html_error, request)
|
||||
return d
|
||||
async def wrapped_request_handler(self, request):
|
||||
try:
|
||||
return await h(self, request)
|
||||
except Exception:
|
||||
f = failure.Failure()
|
||||
return _return_html_error(f, request)
|
||||
|
||||
return wrap_async_request_handler(wrapped_request_handler)
|
||||
|
||||
|
@ -171,7 +168,7 @@ def _return_html_error(f, request):
|
|||
exc_info=(f.type, f.value, f.getTracebackObject()),
|
||||
)
|
||||
else:
|
||||
code = http_client.INTERNAL_SERVER_ERROR
|
||||
code = http.client.INTERNAL_SERVER_ERROR
|
||||
msg = "Internal server error"
|
||||
|
||||
logger.error(
|
||||
|
@ -201,10 +198,9 @@ def wrap_async_request_handler(h):
|
|||
logged until the deferred completes.
|
||||
"""
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def wrapped_async_request_handler(self, request):
|
||||
async def wrapped_async_request_handler(self, request):
|
||||
with request.processing():
|
||||
yield h(self, request)
|
||||
await h(self, request)
|
||||
|
||||
# we need to preserve_fn here, because the synchronous render method won't yield for
|
||||
# us (obviously)
|
||||
|
@ -270,12 +266,11 @@ class JsonResource(HttpServer, resource.Resource):
|
|||
def render(self, request):
|
||||
""" This gets called by twisted every time someone sends us a request.
|
||||
"""
|
||||
self._async_render(request)
|
||||
defer.ensureDeferred(self._async_render(request))
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render(self, request):
|
||||
async def _async_render(self, request):
|
||||
""" This gets called from render() every time someone sends us a request.
|
||||
This checks if anyone has registered a callback for that method and
|
||||
path.
|
||||
|
@ -292,26 +287,19 @@ class JsonResource(HttpServer, resource.Resource):
|
|||
# Now trigger the callback. If it returns a response, we send it
|
||||
# here. If it throws an exception, that is handled by the wrapper
|
||||
# installed by @request_handler.
|
||||
|
||||
def _unquote(s):
|
||||
if PY3:
|
||||
# On Python 3, unquote is unicode -> unicode
|
||||
return urllib.parse.unquote(s)
|
||||
else:
|
||||
# On Python 2, unquote is bytes -> bytes We need to encode the
|
||||
# URL again (as it was decoded by _get_handler_for request), as
|
||||
# ASCII because it's a URL, and then decode it to get the UTF-8
|
||||
# characters that were quoted.
|
||||
return urllib.parse.unquote(s.encode("ascii")).decode("utf8")
|
||||
|
||||
kwargs = intern_dict(
|
||||
{
|
||||
name: _unquote(value) if value else value
|
||||
name: urllib.parse.unquote(value) if value else value
|
||||
for name, value in group_dict.items()
|
||||
}
|
||||
)
|
||||
|
||||
callback_return = yield callback(request, **kwargs)
|
||||
callback_return = callback(request, **kwargs)
|
||||
|
||||
# Is it synchronous? We'll allow this for now.
|
||||
if isinstance(callback_return, (defer.Deferred, types.CoroutineType)):
|
||||
callback_return = await callback_return
|
||||
|
||||
if callback_return is not None:
|
||||
code, response = callback_return
|
||||
self._send_response(request, code, response)
|
||||
|
@ -360,6 +348,23 @@ class JsonResource(HttpServer, resource.Resource):
|
|||
)
|
||||
|
||||
|
||||
class DirectServeResource(resource.Resource):
|
||||
def render(self, request):
|
||||
"""
|
||||
Render the request, using an asynchronous render handler if it exists.
|
||||
"""
|
||||
render_callback_name = "_async_render_" + request.method.decode("ascii")
|
||||
|
||||
if hasattr(self, render_callback_name):
|
||||
# Call the handler
|
||||
callback = getattr(self, render_callback_name)
|
||||
defer.ensureDeferred(callback(request))
|
||||
|
||||
return NOT_DONE_YET
|
||||
else:
|
||||
super().render(request)
|
||||
|
||||
|
||||
def _options_handler(request):
|
||||
"""Request handler for OPTIONS requests
|
||||
|
||||
|
|
|
@ -437,7 +437,10 @@ def runUntilCurrentTimer(func):
|
|||
counts = gc.get_count()
|
||||
for i in (2, 1, 0):
|
||||
if threshold[i] < counts[i]:
|
||||
logger.info("Collecting gc %d", i)
|
||||
if i == 0:
|
||||
logger.debug("Collecting gc %d", i)
|
||||
else:
|
||||
logger.info("Collecting gc %d", i)
|
||||
|
||||
start = time.time()
|
||||
unreachable = gc.collect(i)
|
||||
|
|
|
@ -86,6 +86,7 @@ class LoginRestServlet(RestServlet):
|
|||
self.jwt_enabled = hs.config.jwt_enabled
|
||||
self.jwt_secret = hs.config.jwt_secret
|
||||
self.jwt_algorithm = hs.config.jwt_algorithm
|
||||
self.saml2_enabled = hs.config.saml2_enabled
|
||||
self.cas_enabled = hs.config.cas_enabled
|
||||
self.auth_handler = self.hs.get_auth_handler()
|
||||
self.registration_handler = hs.get_registration_handler()
|
||||
|
@ -97,6 +98,9 @@ class LoginRestServlet(RestServlet):
|
|||
flows = []
|
||||
if self.jwt_enabled:
|
||||
flows.append({"type": LoginRestServlet.JWT_TYPE})
|
||||
if self.saml2_enabled:
|
||||
flows.append({"type": LoginRestServlet.SSO_TYPE})
|
||||
flows.append({"type": LoginRestServlet.TOKEN_TYPE})
|
||||
if self.cas_enabled:
|
||||
flows.append({"type": LoginRestServlet.SSO_TYPE})
|
||||
|
||||
|
@ -319,12 +323,12 @@ class LoginRestServlet(RestServlet):
|
|||
raise LoginError(401, "Invalid JWT", errcode=Codes.UNAUTHORIZED)
|
||||
|
||||
user_id = UserID(user, self.hs.hostname).to_string()
|
||||
device_id = login_submission.get("device_id")
|
||||
initial_display_name = login_submission.get("initial_device_display_name")
|
||||
|
||||
auth_handler = self.auth_handler
|
||||
registered_user_id = yield auth_handler.check_user_exists(user_id)
|
||||
if registered_user_id:
|
||||
device_id = login_submission.get("device_id")
|
||||
initial_display_name = login_submission.get("initial_device_display_name")
|
||||
device_id, access_token = yield self.registration_handler.register_device(
|
||||
registered_user_id, device_id, initial_display_name
|
||||
)
|
||||
|
@ -338,11 +342,8 @@ class LoginRestServlet(RestServlet):
|
|||
user_id, access_token = (
|
||||
yield self.registration_handler.register(localpart=user)
|
||||
)
|
||||
|
||||
device_id = login_submission.get("device_id")
|
||||
initial_display_name = login_submission.get("initial_device_display_name")
|
||||
device_id, access_token = yield self.registration_handler.register_device(
|
||||
registered_user_id, device_id, initial_display_name
|
||||
user_id, device_id, initial_display_name
|
||||
)
|
||||
|
||||
result = {
|
||||
|
@ -354,27 +355,49 @@ class LoginRestServlet(RestServlet):
|
|||
defer.returnValue(result)
|
||||
|
||||
|
||||
class CasRedirectServlet(RestServlet):
|
||||
class BaseSSORedirectServlet(RestServlet):
|
||||
"""Common base class for /login/sso/redirect impls"""
|
||||
|
||||
PATTERNS = client_patterns("/login/(cas|sso)/redirect", v1=True)
|
||||
|
||||
def on_GET(self, request):
|
||||
args = request.args
|
||||
if b"redirectUrl" not in args:
|
||||
return 400, "Redirect URL not specified for SSO auth"
|
||||
client_redirect_url = args[b"redirectUrl"][0]
|
||||
sso_url = self.get_sso_url(client_redirect_url)
|
||||
request.redirect(sso_url)
|
||||
finish_request(request)
|
||||
|
||||
def get_sso_url(self, client_redirect_url):
|
||||
"""Get the URL to redirect to, to perform SSO auth
|
||||
|
||||
Args:
|
||||
client_redirect_url (bytes): the URL that we should redirect the
|
||||
client to when everything is done
|
||||
|
||||
Returns:
|
||||
bytes: URL to redirect to
|
||||
"""
|
||||
# to be implemented by subclasses
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class CasRedirectServlet(BaseSSORedirectServlet):
|
||||
def __init__(self, hs):
|
||||
super(CasRedirectServlet, self).__init__()
|
||||
self.cas_server_url = hs.config.cas_server_url.encode("ascii")
|
||||
self.cas_service_url = hs.config.cas_service_url.encode("ascii")
|
||||
|
||||
def on_GET(self, request):
|
||||
args = request.args
|
||||
if b"redirectUrl" not in args:
|
||||
return (400, "Redirect URL not specified for CAS auth")
|
||||
def get_sso_url(self, client_redirect_url):
|
||||
client_redirect_url_param = urllib.parse.urlencode(
|
||||
{b"redirectUrl": args[b"redirectUrl"][0]}
|
||||
{b"redirectUrl": client_redirect_url}
|
||||
).encode("ascii")
|
||||
hs_redirect_url = self.cas_service_url + b"/_matrix/client/r0/login/cas/ticket"
|
||||
service_param = urllib.parse.urlencode(
|
||||
{b"service": b"%s?%s" % (hs_redirect_url, client_redirect_url_param)}
|
||||
).encode("ascii")
|
||||
request.redirect(b"%s/login?%s" % (self.cas_server_url, service_param))
|
||||
finish_request(request)
|
||||
return b"%s/login?%s" % (self.cas_server_url, service_param)
|
||||
|
||||
|
||||
class CasTicketServlet(RestServlet):
|
||||
|
@ -457,6 +480,16 @@ class CasTicketServlet(RestServlet):
|
|||
return user, attributes
|
||||
|
||||
|
||||
class SAMLRedirectServlet(BaseSSORedirectServlet):
|
||||
PATTERNS = client_patterns("/login/sso/redirect", v1=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
self._saml_handler = hs.get_saml_handler()
|
||||
|
||||
def get_sso_url(self, client_redirect_url):
|
||||
return self._saml_handler.handle_redirect_request(client_redirect_url)
|
||||
|
||||
|
||||
class SSOAuthHandler(object):
|
||||
"""
|
||||
Utility class for Resources and Servlets which handle the response from a SSO
|
||||
|
@ -532,3 +565,5 @@ def register_servlets(hs, http_server):
|
|||
if hs.config.cas_enabled:
|
||||
CasRedirectServlet(hs).register(http_server)
|
||||
CasTicketServlet(hs).register(http_server)
|
||||
elif hs.config.saml2_enabled:
|
||||
SAMLRedirectServlet(hs).register(http_server)
|
||||
|
|
|
@ -24,12 +24,14 @@ import jinja2
|
|||
from jinja2 import TemplateNotFound
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
from synapse.api.errors import NotFoundError, StoreError, SynapseError
|
||||
from synapse.config import ConfigError
|
||||
from synapse.http.server import finish_request, wrap_html_request_handler
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
finish_request,
|
||||
wrap_html_request_handler,
|
||||
)
|
||||
from synapse.http.servlet import parse_string
|
||||
from synapse.types import UserID
|
||||
|
||||
|
@ -47,7 +49,7 @@ else:
|
|||
return a == b
|
||||
|
||||
|
||||
class ConsentResource(Resource):
|
||||
class ConsentResource(DirectServeResource):
|
||||
"""A twisted Resource to display a privacy policy and gather consent to it
|
||||
|
||||
When accessed via GET, returns the privacy policy via a template.
|
||||
|
@ -87,7 +89,7 @@ class ConsentResource(Resource):
|
|||
Args:
|
||||
hs (synapse.server.HomeServer): homeserver
|
||||
"""
|
||||
Resource.__init__(self)
|
||||
super().__init__()
|
||||
|
||||
self.hs = hs
|
||||
self.store = hs.get_datastore()
|
||||
|
@ -118,18 +120,12 @@ class ConsentResource(Resource):
|
|||
|
||||
self._hmac_secret = hs.config.form_secret.encode("utf-8")
|
||||
|
||||
def render_GET(self, request):
|
||||
self._async_render_GET(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_html_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render_GET(self, request):
|
||||
async def _async_render_GET(self, request):
|
||||
"""
|
||||
Args:
|
||||
request (twisted.web.http.Request):
|
||||
"""
|
||||
|
||||
version = parse_string(request, "v", default=self._default_consent_version)
|
||||
username = parse_string(request, "u", required=False, default="")
|
||||
userhmac = None
|
||||
|
@ -145,7 +141,7 @@ class ConsentResource(Resource):
|
|||
else:
|
||||
qualified_user_id = UserID(username, self.hs.hostname).to_string()
|
||||
|
||||
u = yield self.store.get_user_by_id(qualified_user_id)
|
||||
u = await defer.maybeDeferred(self.store.get_user_by_id, qualified_user_id)
|
||||
if u is None:
|
||||
raise NotFoundError("Unknown user")
|
||||
|
||||
|
@ -165,13 +161,8 @@ class ConsentResource(Resource):
|
|||
except TemplateNotFound:
|
||||
raise NotFoundError("Unknown policy version")
|
||||
|
||||
def render_POST(self, request):
|
||||
self._async_render_POST(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_html_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render_POST(self, request):
|
||||
async def _async_render_POST(self, request):
|
||||
"""
|
||||
Args:
|
||||
request (twisted.web.http.Request):
|
||||
|
@ -188,12 +179,12 @@ class ConsentResource(Resource):
|
|||
qualified_user_id = UserID(username, self.hs.hostname).to_string()
|
||||
|
||||
try:
|
||||
yield self.store.user_set_consent_version(qualified_user_id, version)
|
||||
await self.store.user_set_consent_version(qualified_user_id, version)
|
||||
except StoreError as e:
|
||||
if e.code != 404:
|
||||
raise
|
||||
raise NotFoundError("Unknown user")
|
||||
yield self.registration_handler.post_consent_actions(qualified_user_id)
|
||||
await self.registration_handler.post_consent_actions(qualified_user_id)
|
||||
|
||||
try:
|
||||
self._render_template(request, "success.html")
|
||||
|
|
|
@ -16,18 +16,20 @@ import logging
|
|||
from io import BytesIO
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
from synapse.api.errors import Codes, SynapseError
|
||||
from synapse.crypto.keyring import ServerKeyFetcher
|
||||
from synapse.http.server import respond_with_json_bytes, wrap_json_request_handler
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
respond_with_json_bytes,
|
||||
wrap_json_request_handler,
|
||||
)
|
||||
from synapse.http.servlet import parse_integer, parse_json_object_from_request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RemoteKey(Resource):
|
||||
class RemoteKey(DirectServeResource):
|
||||
"""HTTP resource for retreiving the TLS certificate and NACL signature
|
||||
verification keys for a collection of servers. Checks that the reported
|
||||
X.509 TLS certificate matches the one used in the HTTPS connection. Checks
|
||||
|
@ -94,13 +96,8 @@ class RemoteKey(Resource):
|
|||
self.clock = hs.get_clock()
|
||||
self.federation_domain_whitelist = hs.config.federation_domain_whitelist
|
||||
|
||||
def render_GET(self, request):
|
||||
self.async_render_GET(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def async_render_GET(self, request):
|
||||
async def _async_render_GET(self, request):
|
||||
if len(request.postpath) == 1:
|
||||
server, = request.postpath
|
||||
query = {server.decode("ascii"): {}}
|
||||
|
@ -114,20 +111,15 @@ class RemoteKey(Resource):
|
|||
else:
|
||||
raise SynapseError(404, "Not found %r" % request.postpath, Codes.NOT_FOUND)
|
||||
|
||||
yield self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
|
||||
def render_POST(self, request):
|
||||
self.async_render_POST(request)
|
||||
return NOT_DONE_YET
|
||||
await self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def async_render_POST(self, request):
|
||||
async def _async_render_POST(self, request):
|
||||
content = parse_json_object_from_request(request)
|
||||
|
||||
query = content["server_keys"]
|
||||
|
||||
yield self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
await self.query_keys(request, query, query_remote_on_cache_miss=True)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def query_keys(self, request, query, query_remote_on_cache_miss=False):
|
||||
|
|
|
@ -14,31 +14,28 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
from synapse.http.server import respond_with_json, wrap_json_request_handler
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
respond_with_json,
|
||||
wrap_json_request_handler,
|
||||
)
|
||||
|
||||
|
||||
class MediaConfigResource(Resource):
|
||||
class MediaConfigResource(DirectServeResource):
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, hs):
|
||||
Resource.__init__(self)
|
||||
super().__init__()
|
||||
config = hs.get_config()
|
||||
self.clock = hs.get_clock()
|
||||
self.auth = hs.get_auth()
|
||||
self.limits_dict = {"m.upload.size": config.max_upload_size}
|
||||
|
||||
def render_GET(self, request):
|
||||
self._async_render_GET(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render_GET(self, request):
|
||||
yield self.auth.get_user_by_req(request)
|
||||
async def _async_render_GET(self, request):
|
||||
await self.auth.get_user_by_req(request)
|
||||
respond_with_json(request, 200, self.limits_dict, send_cors=True)
|
||||
|
||||
def render_OPTIONS(self, request):
|
||||
|
|
|
@ -14,37 +14,31 @@
|
|||
# limitations under the License.
|
||||
import logging
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
import synapse.http.servlet
|
||||
from synapse.http.server import set_cors_headers, wrap_json_request_handler
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
set_cors_headers,
|
||||
wrap_json_request_handler,
|
||||
)
|
||||
|
||||
from ._base import parse_media_id, respond_404
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DownloadResource(Resource):
|
||||
class DownloadResource(DirectServeResource):
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, hs, media_repo):
|
||||
Resource.__init__(self)
|
||||
|
||||
super().__init__()
|
||||
self.media_repo = media_repo
|
||||
self.server_name = hs.hostname
|
||||
|
||||
# this is expected by @wrap_json_request_handler
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
def render_GET(self, request):
|
||||
self._async_render_GET(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render_GET(self, request):
|
||||
async def _async_render_GET(self, request):
|
||||
set_cors_headers(request)
|
||||
request.setHeader(
|
||||
b"Content-Security-Policy",
|
||||
|
@ -58,7 +52,7 @@ class DownloadResource(Resource):
|
|||
)
|
||||
server_name, media_id, name = parse_media_id(request)
|
||||
if server_name == self.server_name:
|
||||
yield self.media_repo.get_local_media(request, media_id, name)
|
||||
await self.media_repo.get_local_media(request, media_id, name)
|
||||
else:
|
||||
allow_remote = synapse.http.servlet.parse_boolean(
|
||||
request, "allow_remote", default=True
|
||||
|
@ -72,4 +66,4 @@ class DownloadResource(Resource):
|
|||
respond_404(request)
|
||||
return
|
||||
|
||||
yield self.media_repo.get_remote_media(request, server_name, media_id, name)
|
||||
await self.media_repo.get_remote_media(request, server_name, media_id, name)
|
||||
|
|
|
@ -32,12 +32,11 @@ from canonicaljson import json
|
|||
|
||||
from twisted.internet import defer
|
||||
from twisted.internet.error import DNSLookupError
|
||||
from twisted.web.resource import Resource
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
from synapse.api.errors import Codes, SynapseError
|
||||
from synapse.http.client import SimpleHttpClient
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
respond_with_json,
|
||||
respond_with_json_bytes,
|
||||
wrap_json_request_handler,
|
||||
|
@ -58,11 +57,11 @@ _charset_match = re.compile(br"<\s*meta[^>]*charset\s*=\s*([a-z0-9-]+)", flags=r
|
|||
_content_type_match = re.compile(r'.*; *charset="?(.*?)"?(;|$)', flags=re.I)
|
||||
|
||||
|
||||
class PreviewUrlResource(Resource):
|
||||
class PreviewUrlResource(DirectServeResource):
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, hs, media_repo, media_storage):
|
||||
Resource.__init__(self)
|
||||
super().__init__()
|
||||
|
||||
self.auth = hs.get_auth()
|
||||
self.clock = hs.get_clock()
|
||||
|
@ -98,16 +97,11 @@ class PreviewUrlResource(Resource):
|
|||
def render_OPTIONS(self, request):
|
||||
return respond_with_json(request, 200, {}, send_cors=True)
|
||||
|
||||
def render_GET(self, request):
|
||||
self._async_render_GET(request)
|
||||
return NOT_DONE_YET
|
||||
|
||||
@wrap_json_request_handler
|
||||
@defer.inlineCallbacks
|
||||
def _async_render_GET(self, request):
|
||||
async def _async_render_GET(self, request):
|
||||
|
||||
# XXX: if get_user_by_req fails, what should we do in an async render?
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
url = parse_string(request, "url")
|
||||
if b"ts" in request.args:
|
||||
ts = parse_integer(request, "ts")
|
||||
|
@ -159,7 +153,7 @@ class PreviewUrlResource(Resource):
|
|||
else:
|
||||
logger.info("Returning cached response")
|
||||
|
||||
og = yield make_deferred_yieldable(observable.observe())
|
||||
og = await make_deferred_yieldable(defer.maybeDeferred(observable.observe))
|
||||
respond_with_json_bytes(request, 200, og, send_cors=True)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue