This repository has been archived by the owner on Mar 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from toolness/oauth2
[WIP] Implement id.webmaker.org OAuth2 integration
- Loading branch information
Showing
13 changed files
with
260 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,9 @@ variables are given default values: `SECRET_KEY`, `PORT`, `ORIGIN`. | |
(this should always be false in production). | ||
* `BROWSERID_AUTOLOGIN_EMAIL` specifies an email address to auto-login | ||
as when Persona login buttons are clicked. It is useful for offline | ||
development and is only valid if `DEBUG` is true. | ||
development and is only valid if `DEBUG` is true. Make sure an | ||
existing Django user account exists for the email associated with | ||
this address. | ||
* `PORT` is the port that the server binds to. | ||
* `ORIGIN` is the origin of the server, as it appears | ||
to users. If `DEBUG` is enabled, this defaults to | ||
|
@@ -79,11 +81,21 @@ variables are given default values: `SECRET_KEY`, `PORT`, `ORIGIN`. | |
Defaults to `https://login.webmaker.org`. | ||
* `LOGINAPI_AUTH` is the *username:password* pair that will be | ||
used to authenticate with the Webmaker login server, e.g. | ||
`john:1234`. | ||
`john:1234`. This is needed for Persona-based authentication only. | ||
* `IDAPI_URL` is the URL of the Webmaker ID (OAuth2) server. Defaults | ||
to `https://id.webmaker.org`. If it is set to a value of the | ||
form `fake:username:email`, e.g. `fake:foo:[email protected]`, and if | ||
`DEBUG` is true, then the given username/email will always be | ||
logged in when the OAuth2 authorize endpoint is contacted, which | ||
is useful for offline development. | ||
* `IDAPI_CLIENT_ID` is the server's OAuth2 client ID. | ||
* `IDAPI_CLIENT_SECRET` is the server's OAuth2 client secret. | ||
* `CORS_API_PERSONA_ORIGINS` is a comma-separated list of origins that | ||
can submit Persona assertions to the API server in exchange for API | ||
tokens. This list should not contain any whitespace. If `DEBUG` is | ||
enabled, any origin can submit Persona assertions. | ||
tokens. It's also a list of origins that can delegate login to | ||
the API server and obtain API tokens. This list should not | ||
contain any whitespace. If `DEBUG` is enabled, any origin can | ||
submit Persona assertions or delegate login to the API server. | ||
|
||
## Deployment | ||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.db import models | ||
|
||
# Create your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django.conf.urls import url | ||
|
||
from . import views | ||
|
||
urlpatterns = [ | ||
url(r'^login/oauth/authorize$', views.authorize), | ||
url(r'^login/oauth/access_token$', views.access_token), | ||
url(r'^user$', views.user), | ||
url(r'^logout$', views.logout), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import urllib | ||
import json | ||
from django.views.decorators.csrf import csrf_exempt | ||
from django.views.decorators.http import require_POST, require_GET | ||
from django.conf import settings | ||
from django.http import HttpResponse, HttpResponseRedirect | ||
from django.core.urlresolvers import reverse | ||
|
||
def expect(a, b): | ||
if a != b: | ||
print "Warning: Expected %s to equal %s." % (a, b) | ||
|
||
@require_GET | ||
def authorize(request): | ||
expect(request.GET.get('client_id'), settings.IDAPI_CLIENT_ID) | ||
expect(request.GET.get('response_type'), 'code') | ||
expect(request.GET.get('scopes'), 'user email') | ||
|
||
url = reverse('teach.views.oauth2_callback') | ||
qs = urllib.urlencode({ | ||
'state': request.GET['state'], | ||
'code': 'fake_oauth2_code', | ||
}) | ||
return HttpResponseRedirect('%s?%s' % (url, qs)) | ||
|
||
@csrf_exempt | ||
@require_POST | ||
def access_token(request): | ||
expect(request.POST.get('code'), 'fake_oauth2_code') | ||
expect(request.POST.get('client_id'), settings.IDAPI_CLIENT_ID) | ||
expect(request.POST.get('client_secret'), settings.IDAPI_CLIENT_SECRET) | ||
expect(request.POST.get('grant_type'), 'authorization_code') | ||
|
||
res = HttpResponse() | ||
res['content-type'] = 'application/json' | ||
res.content = json.dumps({ | ||
'access_token': 'fake_oauth2_access_token' | ||
}) | ||
|
||
return res | ||
|
||
@require_GET | ||
def user(request): | ||
expect(request.META.get('HTTP_AUTHORIZATION'), | ||
'token fake_oauth2_access_token') | ||
|
||
res = HttpResponse() | ||
res['content-type'] = 'application/json' | ||
res.content = json.dumps({ | ||
'username': settings.IDAPI_FAKE_OAUTH2_USERNAME, | ||
'email': settings.IDAPI_FAKE_OAUTH2_EMAIL | ||
}) | ||
|
||
return res | ||
|
||
@require_GET | ||
def logout(request): | ||
url = reverse('teach.views.oauth2_callback') | ||
qs = 'logout=true' | ||
return HttpResponseRedirect('%s?%s' % (url, qs)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import urllib | ||
import requests | ||
from django.contrib.auth.models import User | ||
from django.conf import settings | ||
|
||
def get_idapi_url(path, query=None): | ||
if query is not None: | ||
qs = urllib.urlencode(query) | ||
path = '%s?%s' % (path, qs) | ||
if settings.IDAPI_ENABLE_FAKE_OAUTH2: | ||
return '%s/fake_oauth2%s' % (settings.ORIGIN, path) | ||
else: | ||
return '%s%s' % (settings.IDAPI_URL, path) | ||
|
||
class WebmakerOAuth2Backend(object): | ||
def authenticate(self, webmaker_oauth2_code=None, **kwargs): | ||
if webmaker_oauth2_code is None: | ||
return None | ||
|
||
payload = { | ||
'client_id': settings.IDAPI_CLIENT_ID, | ||
'client_secret': settings.IDAPI_CLIENT_SECRET, | ||
'grant_type': 'authorization_code', | ||
'code': webmaker_oauth2_code | ||
} | ||
token_req = requests.post(get_idapi_url('/login/oauth/access_token'), | ||
data=payload) | ||
access_token = token_req.json()['access_token'] | ||
user_req = requests.get(get_idapi_url('/user'), headers={ | ||
'authorization': 'token %s' % access_token | ||
}) | ||
user_info = user_req.json() | ||
|
||
users = User.objects.filter(username=user_info['username']) | ||
if len(users) == 0: | ||
user = User.objects.create_user(user_info['username'], | ||
user_info['email']) | ||
return user | ||
else: | ||
return users[0] | ||
|
||
def get_user(self, user_id): | ||
try: | ||
return User.objects.get(pk=user_id) | ||
except User.DoesNotExist: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters