Merge pull request #28 from IcyNet/oauth

Implement OAuth for IcyNet.eu
This commit is contained in:
Tsa6 2017-09-22 17:54:13 -04:00 committed by GitHub
commit eb2b357b7b
6 changed files with 109 additions and 3 deletions

View File

@ -14,10 +14,12 @@ import dj_database_url
import os import os
import configparser import configparser
import warnings import warnings
import base64
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read('options.ini') config.read('options.ini')
options = config['General'] options = config['General']
oauth_options = config['OAuth']
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -128,3 +130,9 @@ USE_TZ = True
# https://docs.djangoproject.com/en/1.11/howto/static-files/ # https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
AUTH_TOKEN_ENDPOINT = oauth_options.get('token_endpoint','https://icynet.eu/oauth/')
AUTH_CLIENT_ID = oauth_options.get('client_id')
AUTH_B64 = base64.b64encode(bytearray('%s:%s'%(AUTH_CLIENT_ID,oauth_options.get('client_secret')),'utf-8')).decode("utf-8")
AUTH_REDIRECT_URL = oauth_options.get('redirect_url')

View File

@ -13,9 +13,10 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include 1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
""" """
from django.conf.urls import url from django.conf.urls import url, include
from django.contrib import admin from django.contrib import admin
urlpatterns = [ urlpatterns = [
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),
url(r'^', include('LandingPage.urls'))
] ]

View File

@ -70,8 +70,9 @@ class Show(TimestampedModel):
) )
class User(TimestampedModel): class User(TimestampedModel):
user_id = models.IntegerField( user_id = models.CharField(
help_text='The user id assigned to this user by IcyNet\'s auth servers' max_length=36,
help_text='The UUID assigned to this user by IcyNet\'s auth servers'
) )
email = models.EmailField( email = models.EmailField(
help_text='This user\'s email address' help_text='This user\'s email address'

9
LandingPage/urls.py Normal file
View File

@ -0,0 +1,9 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^login/redirect$', views.LoginRedirect.as_view()),
url(r'^login$', views.Login.as_view()),
]

View File

@ -1,3 +1,79 @@
from django.shortcuts import render from django.shortcuts import render
from django.views import View
from django.conf import settings
from django.http import HttpResponse
from django.http import HttpResponseRedirect
import requests
import hashlib
import json
from .models import User
# Create your views here. # Create your views here.
# Redirect url should point to this view
class LoginRedirect(View):
def get(self, req):
# Check request has correct arguments
request_valid = 'state' in req.GET and 'code' in req.GET
if not request_valid:
r = HttpResponse('<h1>Error</h1><p>There was an error in your request. Please <a href=/login>try again</a></p>')
r.status = 400
return r
# Check state
userstate = generateState(req)
if userstate == req.GET['state']:
code = req.GET['code']
resp = requests.post(
settings.AUTH_TOKEN_ENDPOINT+"token",
data={
'grant_type':'authorization_code',
'code':code,
'redirect_uri':settings.AUTH_REDIRECT_URL,
'client_id':settings.AUTH_CLIENT_ID
},
headers = {
'Authorization':'Basic %s'%settings.AUTH_B64
}
)
resp_json = resp.json()
if 'error' in resp_json:
r = HttpResponse('<h1>OAuth Error</h1><pre>%s</pre>'%json.dumps(resp_json))
r.status = 500
return r
else:
user_info = requests.get(
settings.AUTH_TOKEN_ENDPOINT+"user",
headers = {
'Authorization': 'Bearer ' + resp_json['access_token']
}
).json()
req.session['user_id'] = user_info['uuid']
matches = User.objects.filter(user_id=user_info['uuid'])
if not len(matches):
user = User(
user_id = user_info['uuid'],
email = user_info['email'],
display_name = user_info['display_name']
)
user.save()
req.session['token'] = resp_json['access_token']
return HttpResponseRedirect('/')
else:
return HttpResponse('<h1>Unmatching state tokens</h1><br><p>It looks like the request to login wasn\'t started by you. Try going back to the home page and logging in again.</p>', status=400)
class Login(View):
def get(self, req):
url = '%sauthorize?response_type=code&client_id=%s&redirect_uri=%s&scope=email&state=%s'%(settings.AUTH_TOKEN_ENDPOINT,settings.AUTH_CLIENT_ID,settings.AUTH_REDIRECT_URL, generateState(req))
response = HttpResponse("Redirecting you to the IcyNet auth page...")
response.status_code = 302
response['Location'] = url
return response
def generateState(request):
request.session.save()
m = hashlib.sha256()
m.update(bytearray(request.session.session_key, 'utf-8'))
m.update(bytearray(settings.SECRET_KEY, 'utf-8'))
return m.hexdigest()

View File

@ -9,3 +9,14 @@ secret_key=5up3r s3cr3t k3y
#For configuration details #For configuration details
database=sqlite:///database.sqlite3 database=sqlite:///database.sqlite3
[OAuth]
#The root of the oauth endpoint you are using for oauth settings
token_endpoint=https://icynet.eu/oauth/
#The client id, client secret, and redirect url used in the confguration
#of your oauth client on the site that you plan to use for oauth.
#The redirect url should probably point to the appropriate view, and
#needs to be fully qualified.
client_id=CLIENT ID HERE
client_secret=CLIENT SECRET HERE
redirect_url=REDIRECT URL HERE