Start implementation of OAuth client

harden
Yohann D'ANELLO 2 years ago
parent faf697d3cf
commit e2aa645bbf
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85

@ -169,6 +169,21 @@ AUTH_USER_MODEL = 'users.User'
MAX_EMPRUNT = 5 # Max emprunts
# AUTHLIB CLIENTS
AUTHLIB_OAUTH_CLIENTS = {
'notekfet': {
'client_id': 'qtElmOUj67YNvSZjA5l70ITUMxd3NJ9kksBsK5e9',
'client_secret': 'SwF909sLIeU5GhruXsFzKfdBhFNgs8nvkVpFKgP4pIQ80BmLLlf3ZkMoNL7Cpox6Ke3MXNWGswTtbKkM8AiB9v6pys8PNfYH0MDFWAi3tnffjwaMQBzRFhjx20qb6S4W',
'access_token_url': 'https://note-dev.crans.org/o/token/',
'refresh_token_url': 'https://note-dev.crans.org/o/token/',
'authorize_url': 'https://note-dev.crans.org/o/authorize/',
'userinfo_endpoint': 'https://note-dev.crans.org/api/me/',
'client_kwargs': {
'scope': '1_1 2_1 48_1',
}
}
}
try:
from .settings_local import *
except ImportError:

@ -1,3 +1,4 @@
authlib~=0.15
docutils~=0.16 # for Django-admin docs
Django~=2.2
django-filter~=2.4

@ -54,7 +54,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% if user.is_authenticated %}
<a href="{% url 'logout' %}">{% trans 'Log out' %}</a>
{% else %}
<a href="{% url 'login' %}">{% trans 'Log in' %}</a>
<a href="{% url 'users:login' %}">{% trans 'Log in' %}</a>
{% endif %}
{% endblock %}
</div>

@ -0,0 +1,31 @@
# Generated by Django 2.2.24 on 2021-11-02 15:11
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0042_delete_adhesion'),
]
operations = [
migrations.CreateModel(
name='AccessToken',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('access_token', models.CharField(max_length=32, verbose_name='access token')),
('expires_in', models.PositiveSmallIntegerField(verbose_name='expires in')),
('scopes', models.CharField(max_length=255, verbose_name='scopes')),
('refresh_token', models.CharField(max_length=32, verbose_name='refresh token')),
('expires_at', models.DateTimeField(verbose_name='expires at')),
('owner', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='owner')),
],
options={
'verbose_name': 'access token',
'verbose_name_plural': 'access tokens',
},
),
]

@ -2,6 +2,10 @@
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import datetime
from authlib.integrations.django_client import OAuth
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone
@ -44,3 +48,61 @@ class User(AbstractUser):
def is_member(self):
# FIXME Use NK20
return True
class AccessToken(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
default=None,
verbose_name=_('owner'),
)
access_token = models.CharField(
max_length=32,
verbose_name=_('access token'),
)
expires_in = models.PositiveSmallIntegerField(
verbose_name=_('expires in'),
)
scopes = models.CharField(
max_length=255,
verbose_name=_('scopes'),
)
refresh_token = models.CharField(
max_length=32,
verbose_name=_('refresh token'),
)
expires_at = models.DateTimeField(
verbose_name=_('expires at'),
)
def refresh(self):
"""
Refresh the access token.
"""
oauth = OAuth()
oauth.register('notekfet')
# Get the OAuth client
oauth_client = oauth.notekfet._get_oauth_client()
# Actually refresh the token
token = oauth_client.refresh_token(oauth.notekfet.access_token_url,
refresh_token=self.refresh_token)
self.access_token = token['access_token']
self.expires_in = token['expires_in']
self.scopes = token['scope']
self.refresh_token = token['refresh_token']
self.expires_at = timezone.utc.fromutc(
datetime.fromtimestamp(token['expires_at'])
)
self.save()
class Meta:
verbose_name = _('access token')
verbose_name_plural = _('access tokens')

@ -8,5 +8,6 @@ from . import views
app_name = 'users'
urlpatterns = [
url(r'^edit_info/$', views.edit_info, name='edit-info'),
url('login/', views.LoginView.as_view(), name='login'),
url('authorize/', views.AuthorizeView.as_view(), name='auth'),
]

@ -1,47 +1,42 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import datetime
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from authlib.integrations.django_client import OAuth
from django.contrib.auth.models import Group
from django.db import transaction
from django.shortcuts import redirect, render
from django.template.context_processors import csrf
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse
from django.utils import timezone
from django.views.generic import RedirectView
from rest_framework import viewsets
from reversion import revisions as reversion
from users.forms import BaseInfoForm
from users.models import User
from users.models import User, AccessToken
from .serializers import GroupSerializer, UserSerializer
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
@login_required
def edit_info(request):
"""
Edite son utilisateur
"""
user = BaseInfoForm(request.POST or None, instance=request.user)
if user.is_valid():
with transaction.atomic(), reversion.create_revision():
user.save()
reversion.set_user(request.user)
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
field for field in user.changed_data))
messages.success(request, "L'user a bien été modifié")
return redirect("index")
return form({
'form': user,
'password_change': True,
'title': _('Edit user profile'),
}, 'users/user.html', request)
class LoginView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
oauth = OAuth()
oauth.register('notekfet')
redirect_url = self.request.build_absolute_uri(reverse('users:auth'))
return oauth.notekfet.authorize_redirect(self.request, redirect_url).url
class AuthorizeView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
oauth = OAuth()
oauth.register('notekfet')
token = oauth.notekfet.authorize_access_token(self.request)
token_obj = AccessToken.objects.create(
access_token=token['access_token'],
expires_in=token['expires_in'],
scopes=token['scope'],
refresh_token=token['refresh_token'],
expires_at=timezone.utc.fromutc(
datetime.fromtimestamp(token['expires_at'])),
)
# TODO Log in or create user
return '/'
class UserViewSet(viewsets.ModelViewSet):

Loading…
Cancel
Save