Skip to content

Commit

Permalink
Updating README. Adding warning when SITE_URL doesn't look right.
Browse files Browse the repository at this point in the history
  • Loading branch information
ozten committed Dec 1, 2011
1 parent c0c5d6e commit c0dcead
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 30 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.rst
@@ -1,9 +1,15 @@
CHANGELOG
---------

0.9.2 - *NOTE* get_audience API breakage - Train 2011-10-20 now accepts the scheme and port number as part of the audience.
0.9.2a - **API breakage** - BrowserID Train 2011-10-20 now accepts the scheme and port number as part of the audience.

get_audience(self, host, port) has become get_audience(self, request, host, port)
``get_audience(host, port)`` has become ``get_audience(request)``
``authenticate(assertion, host, port)`` has become ``authenticate(assertion, audience)``

``verify`` has been updated, so if you use the basic integration with browserid_verify, you should be fine. This mainly
breaks sites that have custom account creation or use the ``auth.authenticate`` function.

To improve security, you should add ``SITE_URL`` to your Django settings. See README.rst for details.

0.9.1 - Create User refactoring, navigator.id, httplib2/verify fixes

Expand Down
58 changes: 38 additions & 20 deletions README.rst
Expand Up @@ -62,21 +62,6 @@ You can also set the following optional config in ``settings.py``
# Path to redirect to on unsuccessful login attempt.
LOGIN_REDIRECT_URL_FAILURE = '/'

Unless your really noodling around with BrowserID, you probably won't need these
optional config in ``settings.py`` (they have sensible defaults): ::

# URL of a BrowserID verification service.
BROWSERID_VERIFICATION_URL = 'https://browserid.org/verify'

# Proxy Info, see httplib2 documentation
BROWSERID_PROXY_INFO = None

# CA cert file for validating SSL certificate
BROWSERID_CACERT_FILE = None

# Disable SSL cert validation
BROWSERID_DISABLE_CERT_CHECK = False

# Create user accounts automatically if no user is found.
BROWSERID_CREATE_USER = True

Expand Down Expand Up @@ -115,12 +100,27 @@ Finally, you'll need some Javascript to handle the onclick event. If you use ``d
});
});

Automatic Account Creation
--------------------------

``django-browserid`` will automatically create a user account for new users if the setting ``BROWSERID_CREATE_USER`` is set to ``True`` in ``settings.py``. The user account will be created with the verified email returned from the BrowserID verification service, and a URL safe base64 encoded SHA1 of the email with the padding removed as the username.

To provide a customized username, you can provide a different algorytm via your settings.py. ::

# settings.py
BROWSERID_CREATE_USER = True
def username(email):
return email.split('@')[0]
BROWSERID_USERNAME_ALGO = username

You can __disable account creation__, but continue to use the ``browserid_verify`` view to authenticate existing users with the following: ::

BROWSERID_CREATE_USER = False

Creating User Accounts
----------------------

``django-browserid`` will automatically create a user account for new users if the setting ``BROWSERID_CREATE_USER`` is set to ``True`` in ``settings.py``. The user account will be created with the verified email returned from the BrowserID verification service, and a URL safe base64 encoded SHA1 of the email with the padding removed as the username.

If you do not wish to automatically create user accounts, you may manually verify a BrowserID assertion with something like the following: ::
If you want full control over account creation, don't use django-browserid's browserid_verify view. Create your own view and use ``verify`` to manually verify a BrowserID assertion with something like the following: ::

from django_browserid.auth import get_audience, verify
from django_browserid.forms import BrowserIDForm
Expand All @@ -131,12 +131,12 @@ If you do not wish to automatically create user accounts, you may manually verif
if request.method == 'POST':
form = BrowserIDForm(data=request.POST)
if not form.is_valid():
result = verify(form.cleaned_data['assertion'], get_audience())
result = verify(form.cleaned_data['assertion'], get_audience(request))
if result:
# check for user account, create account for new users, etc
user = my_get_or_create_user(result.email)

``result`` will be False if the assertion failed, or a dictionary similar to the following: ::
``result`` will be ``False`` if the assertion failed, or a dictionary similar to the following: ::

{
u'audience': u'https://mysite.com:443',
Expand All @@ -148,6 +148,24 @@ If you do not wish to automatically create user accounts, you may manually verif

You are of course then free to store the email in the session and prompt the user to sign up using a chosen identifier as their username, or whatever else makes sense for your site.

Obscure Options
-------

Unless your really noodling around with BrowserID, you probably won't need these
optional config in ``settings.py`` (they have sensible defaults): ::

# URL of a BrowserID verification service.
BROWSERID_VERIFICATION_URL = 'https://browserid.org/verify'

# Proxy Info, see httplib2 documentation
BROWSERID_PROXY_INFO = None

# CA cert file for validating SSL ceprtificate
BROWSERID_CACERT_FILE = None

# Disable SSL cert validation
BROWSERID_DISABLE_CERT_CHECK = False

License
-------

Expand Down
28 changes: 21 additions & 7 deletions django_browserid/auth.py
Expand Up @@ -47,30 +47,44 @@ def get_audience(request):
"""
site_url = getattr(settings, 'SITE_URL', False)

# Note audience based on request for developer warnings
if request.is_secure():
req_proto = 'https://'
else:
req_proto = 'http://'
req_domain = request.get_host()

# If we don't define it explicitly
if not site_url:
if request.is_secure():
req_proto = 'https://'
else:
req_proto = 'http://'
protocol = getattr(settings, 'PROTOCOL', req_proto)
req_domain = request.get_host()
if not getattr(settings, 'DOMAIN'):
log.warning('django-browserid WARNING you are missing '
'settings.SITE_URL. This is not a secure way '
'to verify assertions. Please fix me. '
'Setting domain to %s.' % req_domain)

domain = getattr(settings, 'DOMAIN', req_domain)
# DOMAIN is example.com req_domain is example.com:8001
domain = getattr(settings, 'DOMAIN', req_domain.split(':')[0])

standards = {'https://': 443, 'http://': 80}
port = getattr(settings, 'PORT', standards[protocol])
if ':' in req_domain:
req_port = req_domain.split(':')[1]
else:
req_port = None
port = getattr(settings, 'PORT', req_port or standards[protocol])
if port == standards[protocol]:
site_url = ''.join(map(str, (protocol, domain)))
else:
site_url = ''.join(map(str, (protocol, domain, ':', port)))

req_url = "%s%s" % (req_proto, req_domain)
if site_url != "%s%s" % (req_proto, req_domain):
log.warning('Misconfigured SITE_URL? settings has [%s], but '
'actual request was [%s] BrowserID may fail on '
'audience' % (site_url, req_url))
return site_url


def default_username_algo(email):
# store the username as a base64 encoded sha1 of the email address
# this protects against data leakage because usernames are often
Expand Down
3 changes: 2 additions & 1 deletion django_browserid/tests/test_verification.py
Expand Up @@ -83,7 +83,8 @@ def test_authenticate_create_user(fake):
"""Test that automatic user creation works when enabled."""
with positive_assertion(fake):
setattr(settings, 'BROWSERID_CREATE_USER', True)
delattr(settings, 'BROWSERID_USERNAME_ALGO')
if getattr(settings, 'BROWSERID_USERNAME_ALGO', None):
delattr(settings, 'BROWSERID_USERNAME_ALGO')
user = auth.authenticate(**authenticate_kwargs)
# user should have been created
assert user
Expand Down

0 comments on commit c0dcead

Please sign in to comment.