Skip to content

Commit

Permalink
Merge pull request #23 from rdmorganiser/shibboleth
Browse files Browse the repository at this point in the history
Shibboleth
  • Loading branch information
jochenklar authored Mar 2, 2017
2 parents ae535b8 + 59cabd5 commit 49b0b98
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 31 deletions.
15 changes: 15 additions & 0 deletions apps/core/management/commands/promote-user-to-superuser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User


class Command(BaseCommand):

def add_arguments(self, parser):
parser.add_argument('username', action='store', help='Username of the new admin.')

def handle(self, *args, **options):
user = User.objects.get(username=options['username'])
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save()
3 changes: 3 additions & 0 deletions apps/core/static/core/css/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ form {
.navbar-default {
border-bottom: none;
}
.navbar-default .dropdown li.divider:first-child {
display: none;
}

/* content */

Expand Down
12 changes: 10 additions & 2 deletions apps/core/templates/core/base_navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,35 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% full_name user %}<span class="caret"></span></a>
<ul class="dropdown-menu">
{% if settings.ACCOUNT_UPDATE_PROFILE %}
<li>
<a href="{% url 'profile_update' %}">{% trans 'Update profile' %}</a>
</li>
{% endif %}
{% if settings.ACCOUNT_UPDATE_EMAIL %}
<li>
<a href="{% url 'account_email' %}">{% trans 'Update email' %}</a>
</li>
{% endif %}
{% if settings.ACCOUNT_UPDATE_PASSWORD %}
<li>
<a href="{% url 'account_change_password' %}">{% trans 'Change password' %}</a>
</li>
{% endif %}
{% if settings.SOCIALACCOUNT %}
<li>
<a href="{% url 'socialaccount_connections' %}">{% trans 'Account connections' %}</a>
</li>
{% endif %}
<li role="separator" class="divider"></li>
<li>
<a href="{% url 'account_logout' %}">{% trans 'Logout' %}</a>
<a href="{{ settings.LOGOUT_URL }}">{% trans 'Logout' %}</a>
</li>
</ul>
</li>
{% else %}
<li>
<a href="{% url 'account_login' %}">{% trans 'Login' %}</a>
<a href="{{ settings.LOGIN_URL }}">{% trans 'Login' %}</a>
</li>
{% endif %}
</ul>
Expand Down
7 changes: 0 additions & 7 deletions apps/core/templatetags/core_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,9 @@
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe

from ..utils import get_script_alias

register = template.Library()


@register.simple_tag(takes_context=True)
def base_url(context):
return get_script_alias(context.request) + '/'


@register.simple_tag()
def i18n_switcher():
string = ''
Expand Down
7 changes: 1 addition & 6 deletions apps/core/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
from django.test.client import RequestFactory
from django.utils import translation

# from apps.core.testing.mixins import (

# )


class CoreTestCase(TestCase):

Expand Down Expand Up @@ -65,8 +61,7 @@ def test_i18n_switcher(self):
self.assertIn('en', response['Content-Language'])


class CoreTagsTests(CoreTestCase):

class CoreTagsTests(TestCase):
def setUp(self):
self.request = RequestFactory().get('/')

Expand Down
87 changes: 87 additions & 0 deletions docs/shibboleth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Shibboleth
==========

In order to use Shibboleth with RDMO it needs to be deployed in a production environment using Apache2. The Setup is documented [here](docs/production-setup.md).

Next install the Shibboleth Apache module for service providers from your distirbutions repository, e.g. for debian/Ubuntu:

```
apt-get install libapache2-mod-shib2
```

In addition, [django-shibboleth-remoteuser](https://github.com/Brown-University-Library/django-shibboleth-remoteuser) needs to be installed in your RDMO virtual environment:

```
pip install -r requirements/shibboleth.txt
```

Configure your Shibboleth service provider using the files in `/etc/shibboleth/`. This may vary depending on your Identity Provider. RDMO needs the `RDMOTE_SERVER` to be set and 4 attributes from your identity provider:

* a username (usually `eppn`)
* an email address (usually `mail` or `email`)
* a first name (usually `givenName`)
* a last name (usually `sn`)

In our test environent this is accomplished by editing '/etc/shibboleth/shibboleth2.xml':

```
<ApplicationDefaults entityID="https://sp.vbox/shibboleth"
REMOTE_USER="uid eppn persistent-id targeted-id">
```

and '/etc/shibboleth/attribute-map.xml':

```
<Attribute name="urn:oid:0.9.2342.19200300.100.1.1" id="uid"/>
<Attribute name="urn:oid:2.5.4.4" id="sn"/>
<Attribute name="urn:oid:2.5.4.42" id="givenName"/>
<Attribute name="urn:oid:0.9.2342.19200300.100.1.3" id="mail"/>
```

Restart the Shibboleth service provider demon.

```
service shibd restart
```

In your Apache2 virtual host configuration, add:

```
<Location /Shibboleth.sso>
SetHandler shib
</Location>
<Location />
AuthType shibboleth
require shibboleth
ShibRequireSession On
ShibUseHeaders On
</Location>
```

In your `rdmo/settings/local.py` add:

```
INSTALLED_APPS += ['shibboleth']
SHIBBOLETH_ATTRIBUTE_MAP = {
'uid': (True, 'username'),
'givenName': (True, 'first_name'),
'sn': (True, 'last_name'),
'mail': (True, 'email'),
}
```

where the keys of `SHIBBOLETH_ATTRIBUTE_MAP` need to be modified according to your setup.

Restart the webserver.

```
service apache2 restart
```

From now on, you will be directed to your identity provider login when visiting RDMO.

Since you cannot log in using the admin account created with `createsuperuser` anymore, you need to promote your Shibboleth user to superuser status using:

```
./manage.py promote-user-to-superuser YOURUSERNAME
```
53 changes: 45 additions & 8 deletions rdmo/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
]

MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
Expand All @@ -55,7 +56,6 @@
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware'
]

Expand All @@ -71,7 +71,8 @@
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages'
'django.contrib.messages.context_processors.messages',
'django_settings_export.settings_export',
],
},
},
Expand All @@ -90,6 +91,12 @@
}
}

ACCOUNT_SIGNUP = True

ACCOUNT_UPDATE_PROFILE = True
ACCOUNT_UPDATE_EMAIL = True
ACCOUNT_UPDATE_PASSWORD = True

ACCOUNT_SIGNUP_FORM_CLASS = 'apps.accounts.forms.SignupForm'
ACCOUNT_USER_DISPLAY = 'apps.accounts.utils.get_full_name'
ACCOUNT_EMAIL_REQUIRED = True
Expand All @@ -100,6 +107,8 @@
ACCOUNT_USERNAME_MIN_LENGTH = 4
ACCOUNT_PASSWORD_MIN_LENGTH = 4

SOCIALACCOUNT = False

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Europe/Berlin'
Expand Down Expand Up @@ -156,6 +165,16 @@
'UNICODE_JSON': False
}

SETTINGS_EXPORT = [
'LOGIN_URL',
'LOGOUT_URL',
'ACCOUNT_SIGNUP',
'ACCOUNT_UPDATE_PROFILE',
'ACCOUNT_UPDATE_EMAIL',
'ACCOUNT_UPDATE_PASSWORD',
'SOCIALACCOUNT',
]

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_FROM = '[email protected]'

Expand All @@ -178,13 +197,30 @@
except ImportError:
pass

try:
ADDITIONAL_APPS
except NameError:
pass
else:
INSTALLED_APPS = INSTALLED_APPS + ADDITIONAL_APPS
# check if any socialaccount providers are enabled
if any([app.startswith('allauth.socialaccount.providers') for app in INSTALLED_APPS]):
SOCIALACCOUNT = True

# add Shibboleth configuration if local.SHIBBOLETH_ATTRIBUTE_LIST is set
if 'shibboleth' in INSTALLED_APPS:
AUTHENTICATION_BACKENDS = (
'shibboleth.backends.ShibbolethRemoteUserBackend',
'django.contrib.auth.backends.ModelBackend',
)

MIDDLEWARE_CLASSES.insert(
MIDDLEWARE_CLASSES.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
'shibboleth.middleware.ShibbolethRemoteUserMiddleware'
)

LOGIN_URL = '/Shibboleth.sso/Login'
LOGOUT_URL = '/Shibboleth.sso/Logout'

ACCOUNT_UPDATE_PROFILE = False
ACCOUNT_UPDATE_EMAIL = False
ACCOUNT_UPDATE_PASSWORD = False

# add static and templates from local.THEME_DIR to STATICFILES_DIRS and TEMPLATES
try:
THEME_DIR
except NameError:
Expand All @@ -195,6 +231,7 @@
]
TEMPLATES[0]['DIRS'].append(os.path.join(THEME_DIR, 'templates/'))

# prepend the local.BASE_URL to the different URL settings
try:
BASE_URL
except NameError:
Expand Down
36 changes: 28 additions & 8 deletions rdmo/settings/sample.local.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from base import INSTALLED_APPS

'''
Secret key, use something random in production
'''
Expand All @@ -21,14 +23,9 @@
'''
Additional Django app to be used.
'''
# ADDITIONAL_APPS = (
# 'django_extensions',
# 'allauth.socialaccount.providers.facebook',
# 'allauth.socialaccount.providers.github',
# 'allauth.socialaccount.providers.google',
# 'allauth.socialaccount.providers.orcid',
# 'allauth.socialaccount.providers.twitter',
# )
# INSTALLED_APPS += [
# 'django_extensions'
# ]

'''
A directory with a `static` and a `templates` directory containing customisation.
Expand Down Expand Up @@ -94,6 +91,18 @@
# EMAIL_HOST_PASSWORD = ''
# EMAIL_USE_TLS = True

'''
Social accounts configuration
'''
# INSTALLED_APPS += [
# 'django_extensions',
# 'allauth.socialaccount.providers.facebook',
# 'allauth.socialaccount.providers.github',
# 'allauth.socialaccount.providers.google',
# 'allauth.socialaccount.providers.orcid',
# 'allauth.socialaccount.providers.twitter',
# ]

'''
LDAP configuration
'''
Expand All @@ -110,3 +119,14 @@
# "last_name": "sn",
# 'email': 'mail'
# }

'''
SHIBBOLETH configuration
'''
# INSTALLED_APPS += ['shibboleth']
# SHIBBOLETH_ATTRIBUTE_MAP = {
# 'uid': (True, 'username'),
# 'givenName': (True, 'first_name'),
# 'sn': (True, 'last_name'),
# 'mail': (True, 'email'),
# }
1 change: 1 addition & 0 deletions rdmo/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin

Expand Down
1 change: 1 addition & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ django-mptt==0.8.6
django-compressor>=2.0
django-libsass>=0.4
django-bower==5.2.0
django-settings-export==1.2.1

jsonfield>=1.0.0
Markdown==2.6.7
Expand Down
1 change: 1 addition & 0 deletions requirements/shibboleth.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
git+https://github.com/Brown-University-Library/django-shibboleth-remoteuser.git

0 comments on commit 49b0b98

Please sign in to comment.