Commit a2fed3ac authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Rework and move the authentication

parent 9e3ae5c2
...@@ -4,3 +4,4 @@ env ...@@ -4,3 +4,4 @@ env
db.cnf db.cnf
static static
deployment deployment
deploy
#!/bin/zsh
rsync -ra --exclude=__pycache__ ~/ba/src/backend/django_backend hdf-portal.data.kit.edu:/home/hdf/backend/
ssh hdf-portal.data.kit.edu systemctl restart uwsgi
from django.contrib import admin from django.contrib import admin
from . import models from . import models
from .auth.models import OIDCConfig from .auth.v1.models import OIDCConfig
admin.site.register(models.User) admin.site.register(models.User)
......
from django.db import models as db_models from django.db import models as db_models
from oic.oic import Client from oic.oic import Client
from oic.utils.authn.client import CLIENT_AUTHN_METHOD from oic.utils.authn.client import CLIENT_AUTHN_METHOD
from oic.oic.message import RegistrationResponse from oic.oic.message import RegistrationResponse
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
from .. import models from ... import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings from django.conf import settings
import json import json
oidc_client = None oidc_client = {}
class OIDCConfig(db_models.Model): class OIDCConfig(db_models.Model):
...@@ -17,6 +16,8 @@ class OIDCConfig(db_models.Model): ...@@ -17,6 +16,8 @@ class OIDCConfig(db_models.Model):
client_secret = db_models.CharField(max_length=200) client_secret = db_models.CharField(max_length=200)
redirect_uri = db_models.CharField(max_length=200) redirect_uri = db_models.CharField(max_length=200)
issuer_uri = db_models.CharField(max_length=200) issuer_uri = db_models.CharField(max_length=200)
enabled = db_models.BooleanField(default=False)
name = db_models.CharField(max_length=200)
@property @property
def registration_response(self): def registration_response(self):
...@@ -27,16 +28,21 @@ class OIDCConfig(db_models.Model): ...@@ -27,16 +28,21 @@ class OIDCConfig(db_models.Model):
@property @property
def oidc_client(self): def oidc_client(self):
global oidc_client global oidc_client
if oidc_client is None: if self.id not in oidc_client:
oidc_client = Client(client_authn_method=CLIENT_AUTHN_METHOD) new_oidc_client = Client(client_authn_method=CLIENT_AUTHN_METHOD)
oidc_client.provider_config(self.issuer_uri) new_oidc_client.provider_config(self.issuer_uri)
oidc_client.store_registration_info(self.registration_response) new_oidc_client.store_registration_info(self.registration_response)
return oidc_client oidc_client[self.id] = new_oidc_client
return oidc_client[self.id]
@property @property
def provider_info(self): def provider_info(self):
return self.oidc_client.provider_info return self.oidc_client.provider_info
@property
def name(self):
return self.issuer_uri
def get_auth_request(self, client, state): def get_auth_request(self, client, state):
args = { args = {
'client_id': self.client_id, 'client_id': self.client_id,
...@@ -51,7 +57,7 @@ class OIDCConfig(db_models.Model): ...@@ -51,7 +57,7 @@ class OIDCConfig(db_models.Model):
return auth_req.request(client.authorization_endpoint) return auth_req.request(client.authorization_endpoint)
def __str__(self): def __str__(self):
return self.issuer_uri return self.name
def get_oidc_client(): def get_oidc_client():
......
from rest_framework import serializers
from .views import OIDCConfig
class OIDCConfigSerializer(serializers.ModelSerializer):
class Meta:
model = OIDCConfig
fields = ['name', 'id']
class AuthInfoSerializer(serializers.Serializer):
idps = OIDCConfigSerializer(many=True)
default = serializers.IntegerField()
from django.conf.urls import url
from . import views
from ...frontend import views as frontend_views
urlpatterns = [
url(r'^info/', views.AuthInfo.as_view()),
url(r'^request/', views.Auth.as_view()),
url(r'^callback/', views.AuthCallback.as_view()),
url(r'^logout/', frontend_views.LogoutView.as_view()),
]
from .models import OIDCConfig
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.db.utils import OperationalError from django.db.utils import OperationalError
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.views import View from django.views import View
from oic import rndstr from oic import rndstr
from oic.oic.message import AuthorizationResponse from oic.oic.message import AuthorizationResponse
from rest_framework.permissions import AllowAny
from rest_framework import generics
import json import json
from .models import OIDCConfig
from .serializers import AuthInfoSerializer
def oidc_config_for_request(request):
idp_id = request.GET.get('idp', None)
if idp_id is not None:
try:
return OIDCConfig.objects.get(id=idp_id)
except Exception:
print('No OIDCConfig with id {}'.format(idp_id))
raise
else:
return OIDCConfig.objects.first()
class AuthInfo(generics.RetrieveAPIView):
permission_classes = (AllowAny,)
serializer_class = AuthInfoSerializer
def get_object(self):
idps = OIDCConfig.objects.filter(enabled=True)
return {
'idps': idps,
'default': idps.first().id,
}
class Auth(View): class Auth(View):
...@@ -15,15 +43,17 @@ class Auth(View): ...@@ -15,15 +43,17 @@ class Auth(View):
request.session['state'] = state request.session['state'] = state
# request.session['nonce'] = rndstr() # request.session['nonce'] = rndstr()
except OperationalError: except OperationalError:
return redirect('/?error=not_operational') return redirect('/')
oidc_config = OIDCConfig.objects.all()[0] oidc_config = oidc_config_for_request(request)
oidc_client = oidc_config.oidc_client
login_url = oidc_config.get_auth_request( try:
oidc_client, return redirect(oidc_config.get_auth_request(
state) oidc_config.oidc_client,
return redirect(login_url) state))
except Exception:
print('Malformed oidc config: {}'.format(oidc_config))
return redirect('/')
class AuthCallback(View): class AuthCallback(View):
...@@ -32,7 +62,7 @@ class AuthCallback(View): ...@@ -32,7 +62,7 @@ class AuthCallback(View):
try: try:
state = request.session['state'] state = request.session['state']
except OperationalError: except OperationalError:
return redirect('/?error=not_operational') return redirect('/')
oidc_config = OIDCConfig.objects.all()[0] oidc_config = OIDCConfig.objects.all()[0]
oidc_client = oidc_config.oidc_client oidc_client = oidc_config.oidc_client
...@@ -71,7 +101,7 @@ class AuthCallback(View): ...@@ -71,7 +101,7 @@ class AuthCallback(View):
else: else:
# redirect back to the frontend # redirect back to the frontend
login(request, user) login(request, user)
response = redirect('https://hdf-portal.data.kit.edu/') response = redirect('/')
response.set_cookie('sessionid', request.COOKIES['sessionid']) response.set_cookie('sessionid', request.COOKIES['sessionid'])
return response return response
...@@ -2,15 +2,13 @@ from django.conf.urls import include, url ...@@ -2,15 +2,13 @@ from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
from .clientapi import urls as clientapi_urls from .clientapi import urls as clientapi_urls
from .frontend import urls as frontend_urls, views as frontend_views from .frontend import urls as frontend_urls
from .auth import views as auth_views from .auth.v1 import urls as auth_urls
urlpatterns = [ urlpatterns = [
url(r'^clientapi/', include(clientapi_urls.urlpatterns)), url(r'^clientapi/', include(clientapi_urls.urlpatterns)),
url(r'^api/', include(frontend_urls.urlpatterns)), url(r'^api/', include(frontend_urls.urlpatterns)),
url(r'^auth/', auth_views.Auth.as_view()), url(r'^auth/v1/', include(auth_urls.urlpatterns)),
url(r'^auth_callback/', auth_views.AuthCallback.as_view()),
url(r'^auth_logout', frontend_views.LogoutView.as_view()),
url(r'^admin', admin.site.urls), url(r'^admin', admin.site.urls),
] ]
...@@ -103,7 +103,7 @@ DATABASES = { ...@@ -103,7 +103,7 @@ DATABASES = {
CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_ALLOW_ALL = True
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS = [
'django_backend.backend.auth.models.OIDCTokenAuthBackend', 'django_backend.backend.auth.v1.models.OIDCTokenAuthBackend',
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
] ]
...@@ -148,7 +148,7 @@ STATIC_ROOT = 'static' ...@@ -148,7 +148,7 @@ STATIC_ROOT = 'static'
REST_FRAMEWORK = { REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [ 'DEFAULT_AUTHENTICATION_CLASSES': [
'django_backend.backend.auth.auth_class.CsrfExemptSessionAuthentication', 'django_backend.backend.auth.v1.auth_class.CsrfExemptSessionAuthentication',
'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.TokenAuthentication',
], ],
'DEFAULT_PERMISSION_CLASSES': [ 'DEFAULT_PERMISSION_CLASSES': [
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment