docs/production: Revise doc on authentication methods.

Hopefully this version makes it somewhat clearer how the different
methods relate to each other, how to choose between them, what
`ZulipRemoteUserBackend` is for, and how the latter works.
This commit is contained in:
Greg Price
2018-01-18 17:43:23 -08:00
parent 9b7b600772
commit e68f426286

View File

@@ -1,139 +1,172 @@
# Authentication methods
Zulip supports several different authentications methods:
Zulip supports a wide variety of authentication methods. Some of them
require configuration to set up.
* `EmailAuthBackend` - Email/password authentication.
* `ZulipLDAPAuthBackend` - LDAP username/password authentication.
* `GoogleMobileOauth2Backend` - Google authentication.
* `GitHubAuthBackend` - GitHub authentication.
* `ZulipRemoteUserBackend` - Authentication using an existing
Single-Sign-On (SSO) system that can set REMOTE_USER in Apache.
* `DevAuthBackend` - Only for development, passwordless login as any user.
To configure or disable authentication methods on your Zulip server,
edit the `AUTHENTICATION_BACKENDS` setting in
`/etc/zulip/settings.py`, as well as any additional configuration your
chosen authentication methods require; then restart the Zulip server.
It's easy to add more; see the docs on `python-social-auth` below.
Details on each method below.
The setup documentation for most of these is simple enough that we've
included it inline in `/etc/zulip/settings.py`, right above to the
settings used to configure them. The remote user authentication
backend is more complex since it requires interfacing with a generic
third-party authentication system, and so we've documented it in
detail below.
## Email and password
## Adding additional methods using python-social-auth
The `EmailAuthBackend` method is the one method enabled by default,
and it requires no additional configuration.
The implementation for GitHubAuthBackend is a small wrapper around the
popular [python-social-auth] library. So if you'd like to integrate
Zulip with another authentication provider (e.g. Facebook, Twitter,
etc.), you can do this by writing a class similar to
`GitHubAuthBackend` in `zproject/backends.py` and adding a few
settings. Pull requests to add new backends are welcome; they should
be tested using the framework in `test_auth_backends.py`.
Users set a password with the Zulip server, and log in with their
email and password.
[python-social-auth]: https://python-social-auth.readthedocs.io/en/latest/
When first setting up your Zulip server, this method must be used for
creating the initial realm and user. You can disable it after that.
## Remote User SSO Authentication
## Plug-and-play SSO (Google, GitHub, LDAP)
Zulip supports integrating with a Single-Sign-On solution. There are
a few ways to do it, but this section documents how to configure Zulip
to use an SSO solution that best supports Apache and will set the
`REMOTE_USER` variable:
With just a few lines of configuration, your Zulip server can
authenticate users with any of several single-sign-on (SSO)
authentication providers:
* Google accounts, with `GoogleMobileOauth2Backend`
* GitHub accounts, with `GitHubAuthBackend`
* Your LDAP server, with `ZulipLDAPAuthBackend`
(0) Check that `/etc/zulip/settings.py` has
`zproject.backends.ZulipRemoteUserBackend` as the only enabled value
in the `AUTHENTICATION_BACKENDS` list, and that `SSO_APPEND_DOMAIN` is
correct set depending on whether your SSO system uses email addresses
or just usernames in `REMOTE_USER`.
Each of these requires one to a handful of lines of configuration in
`settings.py`, as well as a secret in `zulip-secrets.conf`. Details
are documented in your `settings.py`.
Make sure that you've restarted the Zulip server since making this
configuration change.
## Apache-based SSO with `REMOTE_USER`
(1) Edit `/etc/zulip/zulip.conf` and change the `puppet_classes` line to read:
If you have any existing SSO solution where a preferred way to deploy
it (a) runs inside Apache, and (b) sets the `REMOTE_USER` environment
variable, then the `ZulipRemoteUserBackend` method provides you with a
straightforward way to deploy that SSO solution with Zulip.
```
puppet_classes = zulip::voyager, zulip::apache_sso
```
### Setup instructions for Apache-based SSO
(2) As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`
to install our SSO integration.
1. In `/etc/zulip/settings.py`, configure two settings:
(3) To configure our SSO integration, edit
`/etc/apache2/sites-available/zulip-sso.example` and fill in the
configuration required for your SSO service to set `REMOTE_USER` and
place your completed configuration file at `/etc/apache2/sites-available/zulip-sso.conf`
* `AUTHENTICATION_BACKENDS`: `'zproject.backends.ZulipRemoteUserBackend'`,
and no other entries.
`zulip-sso.example` is correct configuration for using an `htpasswd`
file for `REMOTE_USER` authentication, which is useful for testing
quickly. You can set it up by doing the following:
* `SSO_APPEND_DOMAIN`: see documentation in `settings.py`.
```
/home/zulip/deployments/current/scripts/restart-server
cd /etc/apache2/sites-available/
cp zulip-sso.example zulip-sso.conf
htpasswd -c /home/zulip/zpasswd username@example.com # prompts for a password
```
Make sure that you've restarted the Zulip server since making this
configuration change.
and then continuing with the steps below.
2. Edit `/etc/zulip/zulip.conf` and change the `puppet_classes` line to read:
(4) Run `a2ensite zulip-sso` to enable the Apache integration site.
```
puppet_classes = zulip::voyager, zulip::apache_sso
```
(5) Run `service apache2 reload` to use your new configuration. If
Apache isn't already running, you may need to run `service apache2
start` instead.
3. As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`
to install our SSO integration.
Now you should be able to visit `https://zulip.example.com/` and
login via the SSO solution.
4. To configure our SSO integration, edit a copy of
`/etc/apache2/sites-available/zulip-sso.example`, saving the result
as `/etc/apache2/sites-available/zulip-sso.conf`. The example sets
up HTTP basic auth, with an `htpasswd` file; you'll want to replace
that with configuration for your SSO solution to authenticate the
user and set `REMOTE_USER`.
For testing, you may want to move ahead with the rest of the setup
using the `htpasswd` example configuration and demonstrate that
working end-to-end, before returning later to configure your SSO
solution. You can do that with the following steps:
```
/home/zulip/deployments/current/scripts/restart-server
cd /etc/apache2/sites-available/
cp zulip-sso.example zulip-sso.conf
htpasswd -c /home/zulip/zpasswd username@example.com # prompts for a password
```
### Troubleshooting Remote User SSO
5. Run `a2ensite zulip-sso` to enable the SSO integration within Apache.
This system is a little finicky to networking setup (e.g. common
issues have to do with `/etc/hosts` not mapping
`settings.EXTERNAL_HOST` to the Apache listening on
`127.0.0.1/localhost`, for example). It can often help while debugging
to temporarily change the Apache config in
`/etc/apache2/sites-available/zulip-sso` to listen on all interfaces
rather than just `127.0.0.1` as you debug this. It can also be helpful
to change `/etc/nginx/zulip-include/app.d/external-sso.conf` to
`proxy_pass` to a more explicit URL possibly not over HTTPS when
debugging. The following log files can be helpful when debugging this
setup:
6. Run `service apache2 reload` to use your new configuration. If
Apache isn't already running, you may need to run `service apache2
start` instead.
* `/var/log/zulip/{errors.log,server.log}` (the usual places)
* `/var/log/nginx/access.log` (nginx access logs)
* `/var/log/apache2/zulip_auth_access.log` (you may want to change
`LogLevel` to "debug" in the Apache config file to make this more
verbose)
Now you should be able to visit your Zulip server in a browser (e.g.,
at `https://zulip.example.com/`) and log in via the SSO solution.
Here's a summary of how the remote user SSO system works assuming
you're using HTTP basic auth; this summary should help with
understanding what's going on as you try to debug:
### Troubleshooting Apache-based SSO
Most issues with this setup tend to be subtle issues with the
hostname/DNS side of the configuration. Suggestions for how to
improve this SSO setup documentation are very welcome!
* For example, common issues have to do with `/etc/hosts` not mapping
`settings.EXTERNAL_HOST` to the Apache listening on
`127.0.0.1`/`localhost`.
* While debugging, it can often help to temporarily change the Apache
config in `/etc/apache2/sites-available/zulip-sso` to listen on all
interfaces rather than just `127.0.0.1`.
* While debugging, it can also be helpful to change `proxy_pass` in
`/etc/nginx/zulip-include/app.d/external-sso.conf` to point to a
more explicit URL, possibly not over HTTPS.
* The following log files can be helpful when debugging this setup:
* `/var/log/zulip/{errors.log,server.log}` (the usual places)
* `/var/log/nginx/access.log` (nginx access logs)
* `/var/log/apache2/zulip_auth_access.log` (from the
`zulip-sso.conf` Apache config file; you may want to change
`LogLevel` in that file to "debug" to make this more verbose)
### Life of an Apache-based SSO login attempt
Here's a summary of how the Apache `REMOTE_USER` SSO system works,
assuming you're using the example configuration with HTTP basic auth.
This summary should help with understanding what's going on as you try
to debug.
* Since you've configured `/etc/zulip/settings.py` to only define the
`zproject.backends.ZulipRemoteUserBackend`, `zproject/settings.py`
configures `/accounts/login/sso` as `HOME_NOT_LOGGED_IN`, which
configures `/accounts/login/sso` as `HOME_NOT_LOGGED_IN`. This
makes `https://zulip.example.com/` (a.k.a. the homepage for the main
Zulip Django app running behind nginx) redirect to
`/accounts/login/sso` if you're not logged in.
`/accounts/login/sso` for a user that isn't logged in.
* nginx proxies requests to `/accounts/login/sso/` to an Apache instance
listening on `localhost:8888` apache via the config in
`/etc/nginx/zulip-include/app.d/external-sso.conf` (using the upstream
`localhost:8888` defined in `/etc/nginx/zulip-include/upstreams`).
* nginx proxies requests to `/accounts/login/sso/` to an Apache
instance listening on `localhost:8888`, via the config in
`/etc/nginx/zulip-include/app.d/external-sso.conf` (using the
upstream `localhost_sso`, defined in `/etc/nginx/zulip-include/upstreams`).
* The Apache `zulip-sso` site which you've enabled listens on
`localhost:8888` and presents the `htpasswd` dialogue; you provide
correct login information and the request reaches a second Zulip
Django app instance that is running behind Apache with with
`localhost:8888` and (in the example config) presents the `htpasswd`
dialogue. (In a real configuration, it takes the user through
whatever more complex interaction your SSO solution performs.) The
user provides correct login information, and the request reaches a
second Zulip Django app instance, running behind Apache, with
`REMOTE_USER` set. That request is served by
`zerver.views.remote_user_sso`, which just checks the `REMOTE_USER`
variable and either logs in (sets a cookie) or registers the new
user (depending whether they have an account).
variable and either logs the user in or, if they don't have an
account already, registers them. The login sets a cookie.
* After succeeding, that redirects the user back to `/` on port 443
(hosted by nginx); the main Zulip Django app sees the cookie and
proceeds to load the site homepage with them logged in (just as if
they'd logged in normally via username/password).
* After succeeding, that redirects the user back to `/` on port 443.
This request is sent by nginx to the main Zulip Django app, which
sees the cookie, treats them as logged in, and proceeds to serve
them the main app page normally.
Again, most issues with this setup tend to be subtle issues with the
hostname/DNS side of the configuration. Suggestions for how to
improve this SSO setup documentation are very welcome!
## Adding more authentication backends
Adding an integration with another authentication provider (e.g.,
Facebook, Twitter, etc.) is easy to do if you're willing to write a
bit of code, and pull requests to add new backends are welcome.
To write such an integration, look in `zproject/backends.py` at the
implementation of `GitHubAuthBackend`, which is a small wrapper around
the popular [python-social-auth] library. You can write a similar
class, and add a few settings to control it. To test your backend
(which we'd require for a pull request to the main Zulip codebase,)
see the framework in `test_auth_backends.py`.
[python-social-auth]: https://python-social-auth.readthedocs.io/en/latest/
## Development only
The `DevAuthBackend` method is used only in development, to allow
passwordless login as any user in a development environment. It's
mentioned on this page only for completeness.