2016-08-09 22:21:19 +02:00
|
|
|
# Authentication methods
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
Zulip supports a wide variety of authentication methods. Some of them
|
|
|
|
require configuration to set up.
|
2016-07-30 00:02:32 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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.
|
|
|
|
|
|
|
|
Details on each method below.
|
|
|
|
|
|
|
|
## Email and password
|
|
|
|
|
|
|
|
The `EmailAuthBackend` method is the one method enabled by default,
|
|
|
|
and it requires no additional configuration.
|
|
|
|
|
|
|
|
Users set a password with the Zulip server, and log in with their
|
|
|
|
email and password.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2018-09-27 22:35:57 +02:00
|
|
|
## Plug-and-play SSO (Google, GitHub)
|
2018-01-19 02:43:23 +01:00
|
|
|
|
|
|
|
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`
|
|
|
|
|
|
|
|
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`.
|
|
|
|
|
2018-09-25 23:29:03 +02:00
|
|
|
```eval_rst
|
|
|
|
.. _ldap:
|
|
|
|
```
|
|
|
|
## LDAP (including Active Directory)
|
|
|
|
|
|
|
|
Zulip supports retrieving information about users via LDAP, and
|
|
|
|
optionally using LDAP as an authentication mechanism.
|
|
|
|
|
|
|
|
In either configuration, you will need to do the following:
|
|
|
|
|
|
|
|
1. Tell Zulip how to connect to your LDAP server:
|
|
|
|
* Fill out the section of your `/etc/zulip/settings.py` headed "LDAP
|
|
|
|
integration, part 1: Connecting to the LDAP server".
|
|
|
|
* If a password is required, put it in
|
|
|
|
`/etc/zulip/zulip-secrets.conf` by setting
|
|
|
|
`auth_ldap_bind_password`. For example: `auth_ldap_bind_password
|
|
|
|
= abcd1234`.
|
|
|
|
|
2018-09-26 00:55:51 +02:00
|
|
|
2. Decide how you want to map the information in your LDAP database to
|
|
|
|
users' experience in Zulip. For each Zulip user, two closely
|
|
|
|
related concepts are:
|
|
|
|
* their **email address**. Zulip needs this in order to send, for
|
|
|
|
example, a notification when they're offline and another user
|
|
|
|
sends a PM.
|
|
|
|
* their **Zulip username**. This means the name the user types into the
|
|
|
|
Zulip login form. You might choose for this to be the user's
|
|
|
|
email address (`sam@example.com`), or look like a traditional
|
|
|
|
"username" (`sam`), or be something else entirely, depending on
|
|
|
|
your environment.
|
|
|
|
|
|
|
|
Either or both of these might be an attribute of the user records
|
|
|
|
in your LDAP database.
|
|
|
|
|
|
|
|
3. Tell Zulip how to map the user information in your LDAP database to
|
|
|
|
the form it needs. There are three supported ways to set up the
|
|
|
|
username and/or email mapping:
|
|
|
|
|
|
|
|
(A) Using email addresses as usernames, if LDAP has each user's
|
|
|
|
email address. To do this, just set `AUTH_LDAP_USER_SEARCH` to
|
|
|
|
query by email address.
|
|
|
|
|
|
|
|
(B) Using LDAP usernames as Zulip usernames, with email addresses
|
|
|
|
formed consistently like `sam` -> `sam@example.com`. To do
|
|
|
|
this, set `AUTH_LDAP_USER_SEARCH` to query by LDAP username, and
|
|
|
|
`LDAP_APPEND_DOMAIN = "example.com"`.
|
|
|
|
|
|
|
|
(C) Using LDAP usernames as Zulip usernames, with email addresses
|
|
|
|
taken from some other attribute in LDAP (for example, `email`).
|
|
|
|
To do this, set `AUTH_LDAP_USER_SEARCH` to query by LDAP
|
|
|
|
username, and `LDAP_EMAIL_ATTR = "email"`.
|
2018-09-25 23:29:03 +02:00
|
|
|
|
|
|
|
You can quickly test whether your configuration works by running:
|
|
|
|
```
|
|
|
|
./manage.py query_ldap username@example.com
|
|
|
|
```
|
2018-09-26 00:05:58 +02:00
|
|
|
from the root of your Zulip installation. If your configuration is working,
|
2018-09-25 23:29:03 +02:00
|
|
|
that will output the full name for your user.
|
|
|
|
|
2018-09-26 00:05:58 +02:00
|
|
|
**If you are using LDAP for authentication**: you will need to enable
|
|
|
|
the `zproject.backends.ZulipLDAPAuthBackend` auth backend, in
|
|
|
|
`AUTHENTICATION_BACKENDS` in `/etc/zulip/settings.py`. After doing
|
|
|
|
so (and as always [restarting the Zulip server](settings.html) to ensure
|
|
|
|
your settings changes take effect), you should be able to log into
|
|
|
|
Zulip by entering your email address and LDAP password on the Zulip
|
|
|
|
login form.
|
2018-09-25 23:29:03 +02:00
|
|
|
|
2018-09-26 00:05:58 +02:00
|
|
|
**If you are using LDAP to populate names in Zulip**: once you finish
|
2018-09-25 23:29:03 +02:00
|
|
|
configuring this integration, you will need to run:
|
|
|
|
```
|
|
|
|
./manage.py sync_ldap_user_data
|
|
|
|
```
|
2018-09-26 00:05:58 +02:00
|
|
|
to sync names for existing users. You may want to run this in a cron
|
2018-09-25 23:29:03 +02:00
|
|
|
job to pick up name changes made on your LDAP server.
|
|
|
|
|
2018-09-26 00:05:58 +02:00
|
|
|
### Multiple LDAP searches
|
|
|
|
|
|
|
|
To do the union of multiple LDAP searches, use `LDAPSearchUnion`. For example:
|
|
|
|
```
|
|
|
|
AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
|
|
|
|
LDAPSearch("ou=users,dc=example,dc=com", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"),
|
|
|
|
LDAPSearch("ou=otherusers,dc=example,dc=com", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"),
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
## Apache-based SSO with `REMOTE_USER`
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
### Setup instructions for Apache-based SSO
|
2016-07-13 01:05:04 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
1. In `/etc/zulip/settings.py`, configure two settings:
|
2016-07-13 01:05:04 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* `AUTHENTICATION_BACKENDS`: `'zproject.backends.ZulipRemoteUserBackend'`,
|
|
|
|
and no other entries.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* `SSO_APPEND_DOMAIN`: see documentation in `settings.py`.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
Make sure that you've restarted the Zulip server since making this
|
|
|
|
configuration change.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
2. Edit `/etc/zulip/zulip.conf` and change the `puppet_classes` line to read:
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
```
|
|
|
|
puppet_classes = zulip::voyager, zulip::apache_sso
|
|
|
|
```
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
3. As root, run `/home/zulip/deployments/current/scripts/zulip-puppet-apply`
|
|
|
|
to install our SSO integration.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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`.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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
|
|
|
|
```
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
5. Run `a2ensite zulip-sso` to enable the SSO integration within Apache.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
### Troubleshooting Apache-based SSO
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
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`.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* 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`.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* 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.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* The following log files can be helpful when debugging this setup:
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* `/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)
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
### 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.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2016-10-23 02:49:43 +02:00
|
|
|
* Since you've configured `/etc/zulip/settings.py` to only define the
|
|
|
|
`zproject.backends.ZulipRemoteUserBackend`, `zproject/settings.py`
|
2018-01-19 02:43:23 +01:00
|
|
|
configures `/accounts/login/sso` as `HOME_NOT_LOGGED_IN`. This
|
2016-10-23 02:49:43 +02:00
|
|
|
makes `https://zulip.example.com/` (a.k.a. the homepage for the main
|
|
|
|
Zulip Django app running behind nginx) redirect to
|
2018-01-19 02:43:23 +01:00
|
|
|
`/accounts/login/sso` for a user that isn't logged in.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* 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`).
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2016-10-23 02:49:43 +02:00
|
|
|
* The Apache `zulip-sso` site which you've enabled listens on
|
2018-01-19 02:43:23 +01:00
|
|
|
`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
|
2016-10-23 02:49:43 +02:00
|
|
|
`REMOTE_USER` set. That request is served by
|
|
|
|
`zerver.views.remote_user_sso`, which just checks the `REMOTE_USER`
|
2018-01-19 02:43:23 +01:00
|
|
|
variable and either logs the user in or, if they don't have an
|
|
|
|
account already, registers them. The login sets a cookie.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
* 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.
|
2016-07-12 23:32:12 +02:00
|
|
|
|
2018-01-19 02:43:23 +01:00
|
|
|
## 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.
|