Skip to content
Commits on Source (2)
......@@ -21,11 +21,13 @@
from django.conf import settings
from django.contrib.auth import login
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView as DjangoLoginView
from django.http import Http404
from django.http import HttpResponse
from django.shortcuts import redirect
from django.utils.translation import check_for_language
from django.views.generic import View
from fido2 import cbor
from fido2.client import ClientData
......@@ -36,7 +38,7 @@ from fido2.server import Fido2Server
from fido2.utils import websafe_decode
from fido2.utils import websafe_encode
from fido2.webauthn import PublicKeyCredentialRpEntity
from stronghold.decorators import public
from stronghold.views import StrongholdPublicMixin
from castellum.utils.views import get_next_url
......@@ -81,62 +83,64 @@ def get_credentials(user):
raw = user.fido2_credential_data
if not raw:
raise Http404
return [AttestedCredentialData(websafe_decode(raw)))]
def register_begin(request):
registration_data, state = fido2.register_begin(
{
'id': str(request.user.id).encode('utf-8'),
'name': request.user.username,
'displayName': request.user.get_full_name(),
},
[],
)
request.session['fido2_state'] = state
return HttpResponse(cbor.encode(registration_data), content_type='application/cbor')
def register_complete(request):
data = cbor.decode(request.body)
auth_data = fido2.register_complete(
request.session.pop('fido2_state'),
ClientData(data['clientData']),
AttestationObject(data['attestationObject']),
)
request.user.fido2_credential_data = websafe_encode(auth_data.credential_data)
request.user.save()
return HttpResponse()
@public
def authenticate_begin(request):
user = User.objects.get(pk=request.session['fido2_user']['pk'])
auth_data, state = fido2.authenticate_begin(get_credentials(user))
request.session['fido2_state'] = state
return HttpResponse(cbor.encode(auth_data), content_type='application/cbor')
@public
def authenticate_complete(request):
user_data = request.session.pop('fido2_user')
user = User.objects.get(pk=user_data['pk'])
user.backend = user_data['backend']
data = cbor.decode(request.body)
fido2.authenticate_complete(
request.session.pop('fido2_state'),
get_credentials(user),
data['credentialId'],
ClientData(data['clientData']),
AuthenticatorData(data['authenticatorData']),
data['signature'],
)
login(request, user)
return HttpResponse()
return [AttestedCredentialData(websafe_decode(raw))]
class FIDO2RegisterView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
registration_data, state = fido2.register_begin(
{
'id': str(request.user.id).encode('utf-8'),
'name': request.user.username,
'displayName': request.user.get_full_name(),
},
[],
)
request.session['fido2_state'] = state
return HttpResponse(cbor.encode(registration_data), content_type='application/cbor')
def post(self, request, *args, **kwargs):
data = cbor.decode(request.body)
auth_data = fido2.register_complete(
request.session.pop('fido2_state'),
ClientData(data['clientData']),
AttestationObject(data['attestationObject']),
)
request.user.fido2_credential_data = websafe_encode(auth_data.credential_data)
request.user.save()
return HttpResponse()
class FIDO2AuhenticateView(StrongholdPublicMixin, View):
def get(self, request, *args, **kwargs):
if not 'fido2_user' in request.session:
raise Http404
user = User.objects.get(pk=request.session['fido2_user']['pk'])
auth_data, state = fido2.authenticate_begin(get_credentials(user))
request.session['fido2_state'] = state
return HttpResponse(cbor.encode(auth_data), content_type='application/cbor')
def post(self, request, *args, **kwargs):
if not 'fido2_user' in request.session:
raise Http404
user_data = request.session.pop('fido2_user')
user = User.objects.get(pk=user_data['pk'])
user.backend = user_data['backend']
data = cbor.decode(request.body)
fido2.authenticate_complete(
request.session.pop('fido2_state'),
get_credentials(user),
data['credentialId'],
ClientData(data['clientData']),
AuthenticatorData(data['authenticatorData']),
data['signature'],
)
login(request, user)
return HttpResponse()
......@@ -17,10 +17,10 @@
};
var register = function() {
return fetch('/fido2/register/begin/', {credentials: 'same-origin'})
return fetch('/fido2/register/', {credentials: 'same-origin'})
.then(fromCBOR)
.then(options => navigator.credentials.create(options))
.then(attestation => fetch('/fido2/register/complete/', {
.then(attestation => fetch('/fido2/register/', {
method: 'POST',
credentials: 'same-origin',
headers: {'X-CSRFToken': csrfToken},
......@@ -35,10 +35,10 @@
};
var authenticate = function() {
return fetch('/fido2/authenticate/begin/', {credentials: 'same-origin'})
return fetch('/fido2/authenticate/', {credentials: 'same-origin'})
.then(fromCBOR)
.then(options => navigator.credentials.get(options))
.then(assertion => fetch('/fido2/authenticate/complete/', {
.then(assertion => fetch('/fido2/authenticate/', {
method: 'POST',
credentials: 'same-origin',
headers: {'X-CSRFToken': csrfToken},
......
......@@ -37,11 +37,9 @@ from django.views.static import serve
from stronghold.decorators import public
from castellum.castellum_auth.forms import AuthenticationForm
from castellum.castellum_auth.views import FIDO2AuhenticateView
from castellum.castellum_auth.views import FIDO2RegisterView
from castellum.castellum_auth.views import LoginView
from castellum.castellum_auth.views import authenticate_begin
from castellum.castellum_auth.views import authenticate_complete
from castellum.castellum_auth.views import register_begin
from castellum.castellum_auth.views import register_complete
from castellum.castellum_auth.views import set_language
from castellum.studies.models import Resource
from castellum.studies.models import Study
......@@ -107,10 +105,8 @@ urlpatterns = [
path(
'data-protection/', include('castellum.data_protection.urls', namespace='data_protection')
),
path('fido2/register/begin/', register_begin),
path('fido2/register/complete/', register_complete),
path('fido2/authenticate/begin/', authenticate_begin),
path('fido2/authenticate/complete/', authenticate_complete),
path('fido2/register/', FIDO2RegisterView.as_view()),
path('fido2/authenticate/', FIDO2AuhenticateView.as_view()),
]
if settings.PROTECTED_MEDIA_SERVER:
......