Skip to content

Commit

Permalink
Merge pull request #3 from unicef-drp/feature-authorization-server
Browse files Browse the repository at this point in the history
Feature authorization server
  • Loading branch information
danangmassandy authored Jul 27, 2023
2 parents 0ee05cd + 813adcc commit ac39f54
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 5 deletions.
18 changes: 16 additions & 2 deletions django_project/azure_auth/admin.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -11,4 +12,17 @@ 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)
22 changes: 22 additions & 0 deletions django_project/azure_auth/migrations/0003_thirdpartyapplication.py
Original file line number Diff line number Diff line change
@@ -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)),
],
),
]
11 changes: 11 additions & 0 deletions django_project/azure_auth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
)
95 changes: 95 additions & 0 deletions django_project/azure_auth/templates/third_party.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<!-- templates/third_party.html -->
{% load static %}
{% load randombg %}
{% randombg as random_bg_image %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GeoRepo | Sign In</title>
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Rubik:300,300i,500,500i"/>
<link rel="stylesheet" href={% static 'base.css' %}>
<link rel="stylesheet" href={% static 'login.css' %}>
<link rel="stylesheet" href={% static 'navbar.css' %}>
<style>
.login-main .background {
background: url('{% static random_bg_image %}');
background-size: cover;
}

#loading {
display: flex;
flex-direction: row;
align-items: center;
padding-top: 20px;
padding-bottom: 20px;
}

#loading > span {
margin-left: 10px;
}

#loading-spinner {
display: inline-block;
width: 30px;
height: 30px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: var(--primary-color);
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
to { -webkit-transform: rotate(360deg); }
}

</style>
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<script>
$(function() {
if (window.opener == null) window.location = "/";
setTimeout(function() {
window.opener.postMessage("{{ access_token }}", "{{ requester }}");
$('#loading').hide();
// show success message
$('#success-message').show();
}, 1500);
});
</script>
</head>
<body>
<div class="login-app">
<div class="login-root">
<div class="login-header">
{% include "navbar.html" %}
</div>
<div class="login-main">
<div class="background">
</div>
<div class="login-container signup-form">
<div class="login-form-header">
GeoRepo Sign In
</div>
<div class="login-form">
<div id="loading">
<div id="loading-spinner"></div>
<span>Logging in to GeoRepo...</span>
</div>
<p id="success-message" style="display: none;">You have successfully logged in. You may close this browser tab.</p>
<p id="error-message" style="display: none;">There is an unexpected error during sign in process. Please try again or contact administrator!</p>
</div>
</div>
</div>

</div>
</div>

</body>
</html>
2 changes: 2 additions & 0 deletions django_project/azure_auth/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
azure_auth_login,
azure_auth_logout,
azure_auth_redirect,
azure_auth_third_party
)

from django.urls import path
Expand All @@ -15,6 +16,7 @@
path("azure-auth/logout", azure_auth_logout, name="logout"),
path("signin-oidc", azure_auth_callback, name="callback"),
path("redirect", azure_auth_redirect, name="redirect"),
path("azure-auth/third-party", azure_auth_third_party, name="third-party"),
]


Expand Down
24 changes: 23 additions & 1 deletion django_project/azure_auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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)
4 changes: 4 additions & 0 deletions django_project/core/settings/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
5 changes: 3 additions & 2 deletions django_project/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,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

Expand Down Expand Up @@ -88,7 +89,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"))
]
Expand Down

1 comment on commit ac39f54

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for django_project/dashboard

St.
Category Percentage Covered / Total
🔴 Statements 5.9% 392/6641
🔴 Branches 0.93% 34/3671
🔴 Functions 2.94% 50/1700
🔴 Lines 5.94% 387/6511

Test suite run success

12 tests passing in 5 suites.

Report generated by 🧪jest coverage report action from ac39f54

Please sign in to comment.