From 7cbac9a8137e653c5f7a168dcd8621c208afe51c Mon Sep 17 00:00:00 2001 From: Danang Date: Thu, 27 Jul 2023 20:42:28 +0000 Subject: [PATCH] add third party login --- django_project/azure_auth/admin.py | 17 +++++++++++-- .../migrations/0003_thirdpartyapplication.py | 22 +++++++++++++++++ django_project/azure_auth/models.py | 11 +++++++++ .../azure_auth/templates/third_party.html | 13 ++++++++++ django_project/azure_auth/urls.py | 5 +++- django_project/azure_auth/views.py | 24 ++++++++++++++++++- django_project/core/settings/project.py | 4 ++++ django_project/core/urls.py | 6 +++-- 8 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 django_project/azure_auth/migrations/0003_thirdpartyapplication.py create mode 100644 django_project/azure_auth/templates/third_party.html diff --git a/django_project/azure_auth/admin.py b/django_project/azure_auth/admin.py index f3ad33a9..c2f14fa6 100644 --- a/django_project/azure_auth/admin.py +++ b/django_project/azure_auth/admin.py @@ -1,7 +1,8 @@ """Azure auth admin.""" from django.contrib import admin - -from azure_auth.models import RegisteredDomain +from django.urls import reverse +from django.contrib.sites.models import Site +from azure_auth.models import RegisteredDomain, ThirdPartyApplication class RegisteredDomainAdmin(admin.ModelAdmin): @@ -11,4 +12,16 @@ class RegisteredDomainAdmin(admin.ModelAdmin): list_editable = ('group',) +class ThirdPartyApplicationAdmin(admin.ModelAdmin): + """ThirdPartyApplication admin.""" + + list_display = ('name', 'origin', 'client_id', 'auth_url') + + def auth_url(self, obj: ThirdPartyApplication): + current_site = Site.objects.get_current() + scheme = 'https://' + url = reverse('azure_auth:third-party') + return f'{scheme}{current_site.domain}{url}?client_id={obj.client_id}' + admin.site.register(RegisteredDomain, RegisteredDomainAdmin) +admin.site.register(ThirdPartyApplication, ThirdPartyApplicationAdmin) diff --git a/django_project/azure_auth/migrations/0003_thirdpartyapplication.py b/django_project/azure_auth/migrations/0003_thirdpartyapplication.py new file mode 100644 index 00000000..858b1a41 --- /dev/null +++ b/django_project/azure_auth/migrations/0003_thirdpartyapplication.py @@ -0,0 +1,22 @@ +# Generated by Django 4.0.7 on 2023-07-27 18:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('azure_auth', '0002_remove_email_liveprefix'), + ] + + operations = [ + migrations.CreateModel( + name='ThirdPartyApplication', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=256, unique=True)), + ('client_id', models.CharField(max_length=256, unique=True)), + ('origin', models.CharField(help_text='Domain with protocol, e.g. https://domainA.com', max_length=256)), + ], + ), + ] diff --git a/django_project/azure_auth/models.py b/django_project/azure_auth/models.py index 87fd7cba..0c51dfe7 100644 --- a/django_project/azure_auth/models.py +++ b/django_project/azure_auth/models.py @@ -14,3 +14,14 @@ class RegisteredDomain(models.Model): 'Autoassign user under the domain to the group.' ) ) + + +class ThirdPartyApplication(models.Model): + """Registered third party application that can access GeoRepo Login.""" + + name = models.CharField(max_length=256, unique=True) + client_id = models.CharField(max_length=256, unique=True) + origin = models.CharField( + max_length=256, + help_text='Domain with protocol, e.g. https://domainA.com' + ) diff --git a/django_project/azure_auth/templates/third_party.html b/django_project/azure_auth/templates/third_party.html new file mode 100644 index 00000000..e1e318a6 --- /dev/null +++ b/django_project/azure_auth/templates/third_party.html @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/django_project/azure_auth/urls.py b/django_project/azure_auth/urls.py index e311eb16..83eb0773 100644 --- a/django_project/azure_auth/urls.py +++ b/django_project/azure_auth/urls.py @@ -4,6 +4,7 @@ azure_auth_login, azure_auth_logout, azure_auth_redirect, + azure_auth_third_party ) from django.urls import path @@ -13,8 +14,10 @@ urlpatterns = [ path("azure-auth/login", azure_auth_login, name="login"), path("azure-auth/logout", azure_auth_logout, name="logout"), - path("signin-oidc", azure_auth_callback, name="callback"), + # path("signin-oidc", azure_auth_callback, name="callback"), + path("auth/redirect", azure_auth_callback, name="callback"), path("redirect", azure_auth_redirect, name="redirect"), + path("azure-auth/third-party", azure_auth_third_party, name="third-party"), ] diff --git a/django_project/azure_auth/views.py b/django_project/azure_auth/views.py index afa940e5..8aa3a011 100644 --- a/django_project/azure_auth/views.py +++ b/django_project/azure_auth/views.py @@ -3,11 +3,13 @@ from django.conf import settings from django.contrib.auth import authenticate, login, logout -from django.shortcuts import resolve_url +from django.shortcuts import resolve_url, render, get_object_or_404 +from django.urls import reverse from django.http import HttpResponseRedirect from .handlers import AzureAuthHandler from .exceptions import InvalidUserError +from .models import ThirdPartyApplication logger = logging.getLogger(__name__) @@ -61,3 +63,23 @@ def azure_auth_redirect(request): logger.exception(e) logger.debug("azure_auth_redirect: %s", output) return output + + +def azure_auth_third_party(request): + client_id = request.GET.get('client_id') + # fetch client registered origin + app = get_object_or_404( + ThirdPartyApplication, + client_id=client_id + ) + # fetch access token and refresh token from session + token = AzureAuthHandler(request).get_token_from_cache() + if token and 'access_token' in token: + return render(request, 'third_party.html', context={ + 'access_token': token['access_token'], + 'requester': app.origin + }) + url_redirect = ( + reverse('login') + '?next=' + + request.path + '?' + request.GET.urlencode()) + return HttpResponseRedirect(url_redirect) diff --git a/django_project/core/settings/project.py b/django_project/core/settings/project.py index a4517637..3cf00e78 100644 --- a/django_project/core/settings/project.py +++ b/django_project/core/settings/project.py @@ -138,5 +138,9 @@ REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = [ 'azure_auth.backends.JWTAccessTokenAuthentication' ] + REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] + # add azure templates + TEMPLATES[0]['DIRS'] += [ + absolute_path('azure_auth', 'templates') + ] CODE_RELEASE_VERSION = code_release_version() diff --git a/django_project/core/urls.py b/django_project/core/urls.py index b9b03301..b125a14d 100644 --- a/django_project/core/urls.py +++ b/django_project/core/urls.py @@ -5,6 +5,7 @@ from drf_yasg import openapi from drf_yasg.generators import OpenAPISchemaGenerator from django.contrib.sites.models import Site +from django.http import HttpResponseRedirect from django.conf import settings from django.urls import re_path, include, path @@ -26,13 +27,14 @@ def get_schema(self, request=None, public=False): class CustomLoginView(LoginView): + redirect_authenticated_user = True def get_context_data(self, **kwargs): + next = self.request.GET.get('next', '') context = super().get_context_data(**kwargs) context['logged_out'] = self.request.GET.get('logged_out', False) context['no_access'] = self.request.GET.get('no_access', False) context['use_azure_auth'] = settings.USE_AZURE - next = self.request.GET.get('next', '') context['redirect_next_uri'] = next return context @@ -88,7 +90,7 @@ def get_api_description(): if settings.USE_AZURE: # azure auth urlpatterns += [ - path("login/", CustomLoginView.as_view(), name="login"), + re_path(r"^login[/]?", CustomLoginView.as_view(), name="login"), path("", include("azure_auth.urls", namespace="azure_auth")) ]