Part 2: Apache and Kerberos for Django Authentication + Authorization
This is part 2 of a series of posts on setting up Django to use external authentication. This post explains how to setup Apache for Django to use a corporate/internal authentication environment.
How do I Apache?
Alright, now that my application is done and the custom user is setup, how do I actually hook this into the internal network?
Apache is the anti-buzzword if you will, but often you don’t have a choice.
Configuring Apache
On the host machine that will be running the Apache instance, make sure to install mod_auth_kerb
for Kerberos, or mod_authnz_ldap
for LDAP.
Within /etc/httpd/conf.d/
, create another .conf
file, for instance: remote_user.conf
. You can also have this configuration within .htaccess
in the desired protected directory itself.
Configuration for Kerberos should look similar to:
# remote_user.conf or .htaccess
LoadModule auth_kerb_module modules/mod_auth_kerb.so
<Location />
AuthName "DjangoConKerberos"
AuthType Kerberos
KrbMethodNegotiate On
KrbMethodK5Passwd Off
KrbServiceName HTTP/$FQDN
KrbAuthRealms KERBEROS_DOMAIN
Krb5KeyTab /path/to/http.keytab
Require valid-user
Order Deny,Allow
Deny from all
</Location>
If using LDAP + Basic auth instead of Kerberos, Apache configuration should look similar to:
# remote_user.conf or .htaccess
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
<Location />
AuthName "DjangoConLDAP"
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative Off
AuthLDAPURL ldap://$LDAP_URL:389/CN=...
AuthLDAPBindDN cn=myusername,cn=Users,...
AuthLDAPBindPassword mypassword
Require valid-user
Order Deny,Allow
Deny from all
</Location>
An important part of setting up Apache for an internal Kerberized system is getting a keytab for Apache. Most likely, you won’t have access to get the needed keytab, and will need to request one from whoever manages the corporate identity system.
However, it’s quite easy to spin up a test environment to see if your configuration is working correctly. I detail how to set one up in part 3 of this series.
See here for more detailed information on the various configuration parameters for mod_auth_kerb
+ Apache, or here for LDAP + Apache configuration, and here for Active Directory with LDAP + Apache configuration.
You will need to setup wsgi configuration for Apache to actually serve your application.
If, by some odd reason, you want or can use something other than Apache, there is a mod_auth_kerb setup for nginx. Disclaimer: I have not used or tested nginx with Kerberos setup.
Does it negotiate? Testing setup
cURL
I’d suggest to first try with curl
to make sure the Apache + Kerberos setup is correct:
[vagrant@client]# kinit roguelynn
Password for [email protected]:
[vagrant@client]# curl -I --negotiate -u : \
https://synergizeapp.strategery.com
HTTP/1.1 401 Unauthorized
Date: Wed, 15 May 2013 09:10:18 GMT
Server: Apache/2.4.4 (Fedora)
WWW-Authenticate: Negotiate
Content-type text/html; charset=iso-8859-1
HTTP/1.1 200
Date: Wed, 15 May 2013 09:10:18 GMT
Server: Apache/2.4.4 (Fedora)
WWW-Authenticate: Negotiate sOmE_RanDom_T0k3n
...
The --negotiate
flag flips on SPNego for cURL, and the -u :
forces cURL to pick up the authenticated user’s cached ticket from kinit
’ing. You can see your cached ticket with klist
.
requests.py
For requests
fans:
$ kinit USERNAME
$ python
>>> import requests
>>> from requests_kerberos import HTTPKerberosAuth
>>> r = requests.get("$APACHE_PROTECTED_FQDN",\
auth=HTTPKerberosAuth())
>>> r.status_code
200
Browser
First, we’ll need to configure our browser to use Negotiate/SPNego:
- Safari – just “works”. Thanks, Apple.
Chrome
Mac:
open 'Google Chrome.app' --args\ --auth-server-whitelist="*ROGUECLOUD.COM"\ --auth-negotiate-delegate-whitelist="*KERBEROS_DOMAIN"\ --auth-schemes="basic,digest,ntlm,negotiate"
Linux:
google-chrome --enable-plugins --args\ --auth-server-whitelist="*KERBEROS_DOMAIN"\ --auth-negotiate-delegate-whitelist="*KERBEROS_DOMAIN"\ --auth-schemes="basic,digest,ntlm,negotiate"
Windows:
chrome.exe --auth-server-whitelist="*KERBEROS_DOMAIN"\ --auth-negotiate-delegate-whitelist="*ROGUECLOUD.COM"\ --auth-schemes="basic,digest,ntlm,negotiate"
Firefox
- Navigate to
about:config
- Search for “negotiate”
- For
network.negotiate-auth.delegation-uris
add.KERBEROS_DOMAIN
- For
network.negotiate-auth.trusted-uris
add.KERBEROS_DOMAIN
- Navigate to
IE
- Internet Options > Tools > Advanced Tab
- Within Security section, select “Enable Integrated Windows Authentication”
- Restart browser
Authenticate yourself with
kinit USERNAME
within the terminal.Finally, navigating to
$APACHE_PROTECTED_FQDN
within browser should then just work if everything is setup appropriately.If prompted for Kerberos username/password, then Apache configuration maybe incorrect if you did not intend that, but should still authenticate with Kerberos credentials
Authentication vs Authorization
So - I’m sure this isn’t news to anyone: there’s a difference between authentication and authorization. First is who you are, the second is what you can do.
Using RemoteUserBackend and Middleware doesn’t automatically grab what the user is authorized to do; it’s just authentication.
However, if needed, there are ways to hook into the user database to grab permissions.
Accessing Permissions
Say your app needs to know if a user is defined as an admin, or staff, a part of a particular group (e.g. “finance”, “engineering”) or something else that is already defined in your external auth system. Customizing a backend is needed to connect directly to the external user datastore.
Typically, LDAP holds users in groups, through memberOf
parameter or something similar. By binding to the LDAP to find what group the user is a member of, you can then define what authorization that a user has within your own app logic. e.g. if user is a member of “admins”, then create_superuser(user).
- django-auth-ldap and/or django-ldap-groups can be dropped into your Django app
- Or one of these snippets (they are focused on Active Directory but so long as the configuration variables within your
settings.py
are correct, it should work with a standard LDAP or IPA setup):
In a Kerberized environment, one approach may to be just getting another keytab for accessing the LDAP, although that requires the service to have wide read privileges.
How I would approach it though, at least within an IPA environment (which stores its user information in an LDAP), is to capitalize on IPA’s use of SSSD - System Security Services Daemon. You can execute local system calls, like getent group $USERNAME
and SSSD grabs the group the user is a member of.
Resources
∴
comments powered by Disqus