Skip to content

Commit

Permalink
fixes bug 1367513 - add mozilla-django-oidc (#127)
Browse files Browse the repository at this point in the history
* fixes bug 1367513 - add mozilla-django-oidc

* python-jose wheel sha

* fake OIDC_RP_CLIENT_ID in tests
  • Loading branch information
Peter Bengtsson committed May 31, 2017
1 parent 8b03d8f commit 252fa66
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .env-dist
Expand Up @@ -17,3 +17,6 @@ AWS_DEFAULT_REGION=us-west-2
#DJANGO_STATSD_HOST=localhost
#DJANGO_STATSD_PORT=8125
#DJANGO_STATSD_NAMESPACE=

#DJANGO_OIDC_RP_CLIENT_ID=
#DJANGO_OIDC_RP_CLIENT_SECRET=
35 changes: 35 additions & 0 deletions docs/configuration.rst
Expand Up @@ -143,3 +143,38 @@ The three environment variables to control the statsd are as follows
2. ``DJANGO_STATSD_PORT`` (*8125*)

3. ``DJANGO_STATSD_NAMESPACE`` (*''* (empty string))


Auth0
=====

For authentication to work, you need to have an Auth0 account and its
credentials. You also need a domain so you can figure out certain
URLs. You need the client ID and the client secret. Put these into
the environment variables like this:

.. code-block:: shell
DJANGO_OIDC_RP_CLIENT_ID=clientidhereclientidhere
DJANGO_OIDC_RP_CLIENT_SECRET=clientsecrethereclientsecrethere
The default domain is ``auth.mozilla.auth0.com``. That has consequently
been used to set up the following defaults:

.. code-block:: shell
DJANGO_OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.mozilla.auth0.com/authorize
DJANGO_OIDC_OP_TOKEN_ENDPOINT=https://auth.mozilla.auth0.com/oauth/token
DJANGO_OIDC_OP_USER_ENDPOINT=https://auth.mozilla.auth0.com/userinfo
If your domain is different, override these above three environment
variables with your domain.

Note! Tecken uses `Auth0`_ which follows the OpenID Connect protocol.
The configuration actually requires the above mentioned URLs and when
you use Auth0, the URLs are quite constant. But if you use another OpenID
Connect provider, use the domain (e.g. ``myoidc.example.com``) and go to
``https://myoidc.example.com/.well-known/openid-configuration`` and from
there it should publish the authorization, token and user endpoints.

.. _`Auth0`: https://auth0.com/
11 changes: 11 additions & 0 deletions requirements.txt
Expand Up @@ -275,6 +275,17 @@ vine==1.1.3 \
django_celery_results==1.0.1 \
--hash=sha256:dfa240fb535a1a2d01c9e605ad71629909318eae6b893c5009eafd7265fde10b \
--hash=sha256:8bca2605eeff4418be7ce428a6958d64bee0f5bdf1f8e563fbc09a9e2f3d990f
mozilla-django-oidc==0.1.10 \
--hash=sha256:620029825c6fb66da26a79426595ee8d863c0610ca706dc0c83bbcd8cde25242 \
--hash=sha256:f674ad617c0a0d73c9ea8f85bfa6067bd45fbd802c8437ad8faa21899b41cb3b
python-jose==1.3.2 \
--hash=sha256:35eca894ab91db1774251296949679396c46d6bc506ea03804b8f7a7d0204392 \
--hash=sha256:968254f57ccd0fc99ab9557f82b90a5b23ccaf3716e8817d8edaa9f21c21bb2d
pycrypto==2.6.1 \
--hash=sha256:f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c
ecdsa==0.13 \
--hash=sha256:40d002cf360d0e035cf2cb985e1308d41aaa087cbfc135b2dc2d844296ea546c \
--hash=sha256:64cf1ee26d1cde3c73c6d7d107f835fed7c6a2904aef9eac223d57ad800c43fa


#
Expand Down
33 changes: 31 additions & 2 deletions tecken/settings.py
Expand Up @@ -118,6 +118,9 @@ class Core(CSP, AWS, Configuration, Celery):
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

# Third party apps, that need to be listed last
'mozilla_django_oidc',
]

MIDDLEWARE_CLASSES = (
Expand All @@ -131,6 +134,7 @@ class Core(CSP, AWS, Configuration, Celery):
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'csp.middleware.CSPMiddleware',
'mozilla_django_oidc.contrib.auth0.middleware.RefreshIDToken',
)

ROOT_URLCONF = 'tecken.urls'
Expand All @@ -140,8 +144,7 @@ class Core(CSP, AWS, Configuration, Celery):
# Add the django-allauth authentication backend.
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
# 'allauth.account.auth_backends.AuthenticationBackend',
# 'guardian.backends.ObjectPermissionBackend',
'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
)

MESSAGE_TAGS = {
Expand Down Expand Up @@ -194,6 +197,25 @@ class Core(CSP, AWS, Configuration, Celery):
},
]

OIDC_RP_CLIENT_ID = values.SecretValue()
OIDC_RP_CLIENT_SECRET = values.SecretValue()

OIDC_OP_AUTHORIZATION_ENDPOINT = values.URLValue(
'https://auth.mozilla.auth0.com/authorize'
)
OIDC_OP_TOKEN_ENDPOINT = values.URLValue(
'https://auth.mozilla.auth0.com/oauth/token'
)
OIDC_OP_USER_ENDPOINT = values.URLValue(
'https://auth.mozilla.auth0.com/userinfo'
)

# Let cookies last quite a long time.
SESSION_COOKIE_AGE = values.IntegerValue(60 * 60 * 24 * 100)

# Where users get redirected after successfully signing in
LOGIN_REDIRECT_URL = '/?signedin=true'


class Base(Core):
"""Settings that may change per-environment, some with defaults."""
Expand Down Expand Up @@ -401,6 +423,9 @@ class Test(Dev):

SECRET_KEY = values.Value('not-so-secret-after-all')

OIDC_RP_CLIENT_ID = values.Value('not-so-secret-after-all')
OIDC_RP_CLIENT_SECRET = values.Value('not-so-secret-after-all')

PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
Expand All @@ -410,6 +435,10 @@ class Test(Dev):
'https://s3.example.com/private/prefix/',
])

AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)


class Stage(Base):
"""Configuration to be used in stage environment"""
Expand Down
8 changes: 6 additions & 2 deletions tecken/urls.py
Expand Up @@ -16,13 +16,17 @@
urlpatterns = [
url(r'^$', views.dashboard, name='dashboard'),
url(r'^__task_tester__$', views.task_tester, name='task_tester'),
url(r'', include('tecken.download.urls', namespace='download')),

url(
r'',
include('tecken.download.urls', namespace='download')
),
url(
r'symbolicate/',
include('tecken.symbolicate.urls', namespace='symbolicate')
),

url(r'^oidc/', include('mozilla_django_oidc.urls')),

url(
r'^(?P<path>contribute\.json)$',
static.serve,
Expand Down
21 changes: 18 additions & 3 deletions tecken/views.py
Expand Up @@ -6,9 +6,9 @@

from django import http
from django.template import TemplateDoesNotExist, loader
from django.template.response import TemplateResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.cache import cache
from django.core.urlresolvers import reverse

from .symbolicate.views import symbolicate_json
from tecken.tasks import sample_task
Expand All @@ -23,8 +23,23 @@ def dashboard(request):
if request.method == 'POST' and request.body:
return symbolicate_json(request)

context = {}
return TemplateResponse(request, 'tecken/dashboard.html', context=context)
user = {}
if request.user.is_authenticated:
user['email'] = request.user.email
user['active'] = request.user.is_active
user['sign_out_url'] = request.build_absolute_uri(
reverse('oidc_logout')
)
else:
user['sign_in_url'] = request.build_absolute_uri(
reverse('oidc_authentication_init')
)

context = {
'user': user,
'documentation': 'https://tecken.readthedocs.io',
}
return http.JsonResponse(context)


def server_error(request, template_name='500.html'):
Expand Down
32 changes: 27 additions & 5 deletions tests/test_dashboard.py
Expand Up @@ -2,12 +2,10 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at http://mozilla.org/MPL/2.0/.

# import pytest
# from django.core.urlresolvers import reverse
# from django.utils import timezone
import pytest

from django.contrib.auth.models import User

# from atmo.clusters.models import Cluster
# from atmo.jobs.models import SparkJob
from tecken.views import server_error


Expand All @@ -18,3 +16,27 @@ def test_server_error(rf):

response = server_error(request, template_name='non-existing.html')
assert response.status_code == 500


@pytest.mark.django_db
def test_dashboard(client):
response = client.get('/')
assert response.status_code == 200
information = response.json()
assert 'documentation' in information
assert 'sign_in_url' in information['user']

# Now pretend the user goes through the OIDC steps to sign in
user = User.objects.create(username='peterbe', email='peterbe@example.com')
user.set_password('secret')
user.save()
assert client.login(username='peterbe', password='secret')

response = client.get('/')
assert response.status_code == 200
information = response.json()
assert 'documentation' in information
assert 'sign_in_url' not in information['user']
assert 'sign_out_url' in information['user']
assert information['user']['email'] == 'peterbe@example.com'
assert information['user']['active']

0 comments on commit 252fa66

Please sign in to comment.