Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Issue #144. Add persona authentication

* add persona authentication
* add settings_local.py-dist file
* update documentation to talk about settings_local.py-dist file
* tweak some settings

Fixes #144
  • Loading branch information...
commit f91740997ea47fe7321c4d219da02c17238a7312 1 parent 1a25518
Will Kahn-Greene authored
33 docs/contributors/dev_hacking.rst
View
@@ -103,20 +103,18 @@ handle things for you.
Configuration
=============
-Default configuration for the project goes in ``richard/settings.py``.
-
You will need to override some of those settings for your
instance. To do that:
-1. create a file ``richard/settings_local.py``
-2. add configuration for your instance in that file
+1. ``cp richard/settings_local.py-dist richard/settings_local.py``
+2. Edit ``richard/settings_local.py``
+
-Make sure to set a ``SECRET_KEY``::
+Make sure to do at least the following:
- # Make this unique, and don't share it with anybody.
- SECRET_KEY = 'long secret key'
+1. Set a ``SECRET_KEY``. Make it unique! Don't share it with anyone!
-.. todo:: list configuration settings that should be in settings_local.py
+TODO: Finish this up
Setting up database schema and creating admin user
@@ -138,3 +136,22 @@ If you want to set up some initial data, do::
$ ./manage.py generatedata
This is useful to see how the site works.
+
+
+Troubleshooting
+===============
+
+I can't log in
+--------------
+
+First, make sure your administrator account has an email address associated
+with it. This is the email address you will log in with Persona.
+
+Second, if you're seeing a "Misconfigured" kind of error, make sure the
+``SITE_URL`` in your ``settings_local.py`` file matches the domain and port
+that the server is running on. If it doesn't match, then django-browserid
+won't work.
+
+See `the django-browserid troubleshooting docs
+<https://django-browserid.readthedocs.org/en/latest/details/troubleshooting.html>`_
+for more details.
5 requirements/base.txt
View
@@ -5,6 +5,8 @@ bleach
requests
markdown
south
+
+# Jingo never really does releases.
-e git://github.com/jbalogh/jingo.git#egg=jingo
# We're using 2.0 alpha or 2.0 beta or something, so until 2.0 is released, we're
@@ -17,3 +19,6 @@ south
# eadred is in development
-e git://github.com/willkg/django-eadred@master#egg=django-eadred
+
+# Using django-browserid master tip to pick up improvements
+-e git://github.com/mozilla/django-browserid.git@0ed6fef4#egg=django-browserid
19 richard/settings.py
View
@@ -12,6 +12,16 @@
# site_root is the parent directory
SITE_ROOT = os.path.dirname(os.path.dirname(__file__))
+# site_url is the url for this site. it's important it's
+# correct otherwise browserid authentication won't work.
+SITE_URL = 'http://127.0.0.1:8000'
+LOGIN_URL = '/'
+LOGIN_REDIRECT_URL = '/'
+LOGIN_REDIRECT_URL_FAILURE = '/login-failure'
+
+# For now, we don't create new users.
+BROWSERID_CREATE_USER = False
+
# root is this directory
ROOT = os.path.dirname(__file__)
@@ -153,7 +163,7 @@
)
# Make this unique, and don't share it with anybody.
-SECRET_KEY = 'SEKRETKEY'
+SECRET_KEY = ''
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
@@ -191,6 +201,7 @@
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
+ 'django_browserid.context_processors.browserid',
'richard.context_processors.base',
)
@@ -203,6 +214,7 @@
# This is the template name passed to jingo that is used to derive the app
# name and check if it should be excluded.
'sitemap.xml',
+ 'browserid',
)
JINJA_CONFIG = {
@@ -211,6 +223,7 @@
INSTALLED_APPS = (
'django.contrib.auth',
+ 'django_browserid',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
@@ -230,6 +243,10 @@
'richard.suggestions',
)
+AUTHENTICATION_BACKENDS = (
+ 'django_browserid.auth.BrowserIDBackend',
+)
+
try:
# Add django_nose for testing but only if it's installed.
imp.find_module('django_nose')
27 richard/settings_local.py-dist
View
@@ -0,0 +1,27 @@
+# This is a sample settings_local.py file. To use it, do:
+#
+# 1. cp settings_local.py-dist settings_local.py
+# 2. edit with your editor
+#
+# See settings.py and documentation for other things you can configure.
+
+DEBUG = TEMPLATE_DEBUG = True
+
+SECRET_KEY = 'secret key'
+
+DATABASES = {
+ 'default': {
+ # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+ 'ENGINE': 'django.db.backends.sqlite3',
+ # Or path to database file if using sqlite3.
+ 'NAME': os.path.join(SITE_ROOT, 'database.db'),
+
+ # The following settings are not used with sqlite3.
+ 'USER': '',
+ 'PASSWORD': '',
+ # Set to empty string for localhost.
+ 'HOST': '',
+ # Set to empty string for default.
+ 'PORT': '',
+ }
+}
67 richard/static/js/browserid.js
View
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+(function($) {
+ 'use strict';
+
+ $(function() {
+ // State? Ewwwwww.
+ var logoutButton = null;
+ var requestOptions = [
+ 'siteName',
+ 'siteLogo',
+ 'oncancel',
+ 'privacyPolicy',
+ 'returnTo',
+ 'termsOfService'
+ ];
+
+ $(document).delegate('.browserid-login, #browserid', 'click', function(e) {
+ e.preventDefault();
+
+ // Arguments to navigator.id.request can be specified by data-attributes
+ // on the BrowserID link: <a href="#" data-site-name="Site Name">
+ var options = {};
+ var $link = $(e.target);
+ for (var k = 0; k < requestOptions.length; k++) {
+ var name = requestOptions[k];
+ var value = $link.data(name);
+ if (value !== undefined) {
+ options[name] = value;
+ }
+ }
+
+ navigator.id.request(options); // Triggers BrowserID login dialog.
+ });
+
+ $('.browserid-logout').bind('click', function(e) {
+ e.preventDefault();
+ logoutButton = e.target;
+ navigator.id.logout(); // Clears User Agent BrowserID state.
+ });
+
+ navigator.id.watch({
+ onlogin: function(assertion) {
+ // Don't bother if login just failed.
+ if (location.search.indexOf('bid_login_failed=1') !== -1) {
+ navigator.id.logout();
+ } else if (assertion) {
+ var $e = $('#id_assertion');
+ $e.val(assertion.toString());
+ $e.parent().submit();
+ }
+ },
+
+ onlogout: function() {
+ var currentButton = logoutButton;
+ if (currentButton !== null) {
+ logoutButton = null;
+ if (currentButton.href) {
+ window.location = currentButton.href;
+ }
+ }
+ }
+ });
+ });
+})(jQuery);
27 richard/templates/base.html
View
@@ -30,6 +30,7 @@
{% block additional_head %}{% endblock %}
</head>
<body>
+ {{ browserid_info }}
<div class="navbar navbar-inverse">
<div class="navbar-inner">
<div class="container">
@@ -55,12 +56,29 @@
<li><a href="{{ url('suggestions-list') }}">Submit</a></li>
<li><a href="{{ url('stats') }}">Stats</a></li>
<li><a href="{{ url('pages-page', page='about') }}">About</a></li>
+
+ {% if user.is_authenticated() %}
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ Greetings {{ user.username }}! <b class="caret"></b>
+ </a>
+ <ul class="dropdown-menu">
+ {% if user.is_superuser %}
+ <li><a href="{{ url('admin:index') }}">Admin</a></li>
+ {% endif %}
+ <li>{{ browserid_button(sign_in='Sign in', sign_out='Sign out')|safe }}</li>
+ </ul>
+ </li>
+ {% else %}
+ <li>{{ browserid_button(sign_in='Sign in', sign_out='Sign out')|safe }}</li>
+
+ {% endif %}
</ul>
+
</div>
</div>
</div>
-
<div id="content" class="container">
{% if notifications -%}
<div class="row">
@@ -86,9 +104,14 @@
</div>
</div>
+ {% block additional_body %}
+ {% endblock %}
+
+ {% block site_js %}
<script type="text/javascript" src="{{ settings.STATIC_URL }}js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="{{ settings.STATIC_URL }}bootstrap/js/bootstrap.min.js"></script>
- {% block additional_body %}
+ <script type="text/javascript" src="{{ settings.STATIC_URL }}js/browserid.js"></script>
+ <script type="text/javascript" src="https://login.persona.org/include.js"></script>
{% endblock %}
</body>
</html>
32 richard/templates/login_failure.html
View
@@ -0,0 +1,32 @@
+{#
+# richard -- video index system
+# Copyright (C) 2012 richard contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+-#}
+{% extends "base.html" %}
+{% block content %}
+
+<div class="row">
+ <div class="span12">
+ <p>
+ Your login has failed.
+ </p>
+ <p>
+ <a href="{{ url('home') }}">Back to the front page</a>
+ </p>
+ </div>
+</div>
+
+{% endblock %}
6 richard/urls.py
View
@@ -17,10 +17,12 @@
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
+from django.contrib.auth.decorators import login_required
# enable the admin
from django.contrib import admin
admin.autodiscover()
+admin.site.login = login_required(admin.site.login)
from richard.pages.sitemaps import PageSitemap
from richard.videos.sitemaps import (CategorySitemap, SpeakerSitemap,
@@ -38,6 +40,8 @@
'',
url(r'^$', 'richard.views.home', name='home'),
+ url(r'^login-failure$', 'richard.views.login_failure',
+ name='login_failure'),
url(r'^stats/$', 'richard.views.stats', name='stats'),
(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap',
{'sitemaps': sitemaps}),
@@ -48,4 +52,6 @@
url(r'^pages/', include('richard.pages.urls')),
url(r'^suggestions/', include('richard.suggestions.urls')),
url(r'', include('richard.videos.urls')),
+
+ url(r'^browserid/', include('django_browserid.urls')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
4 richard/views.py
View
@@ -41,6 +41,10 @@ def home(request):
return ret
+def login_failure(request):
+ return render(request, 'login_failure.html')
+
+
def stats(request):
"""List statistics about the collection.
Please sign in to comment.
Something went wrong with that request. Please try again.