diff options
author | Sawyer Bergeron <sbergeron@iol.unh.edu> | 2021-10-15 17:03:58 -0400 |
---|---|---|
committer | Sawyer Bergeron <sbergeron@iol.unh.edu> | 2021-10-28 15:32:26 -0400 |
commit | 104470ee008817df4a3b78d24e524e8c92eac9a0 (patch) | |
tree | a4a6b70043f34c37b568bbe6a4b6e72d8c619716 /src/account | |
parent | afcee3cad5c091e78e909b83f8df49accf1af5b6 (diff) |
WIP merge of master into cobblercobbler
Squashed commit of the following:
commit 35b9f39178cc502a5283a1b37a65f7dd0838ae05
Author: Sawyer Bergeron <sbergeron@iol.unh.edu>
Date: Fri Oct 15 14:14:46 2021 -0400
Merge User Booking API Rev 1 (Try 3)
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
Change-Id: Ie1eee0a59929f8da39f16bb6bc17ae3de4f1cba9
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
commit b3ed8ebcf536c021330e7ccbc0376f6b89189348
Author: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Date: Tue Jul 20 09:55:04 2021 -0400
Additional changes for rebrand
Signed-off-by: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Change-Id: Ibd525f966b3ed3aebdbe688e5ee5daa4ea1cf294
Signed-off-by: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Signed-off-by: Raven Hodgdon <jhodgdon@iol.unh.edu>
commit 17b6c7809771ac8bf3879add033d2169f671591a
Author: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Date: Fri May 14 15:42:56 2021 -0400
Color fixes for rebrand
Signed-off-by: Jacob Hodgdon <jhodgdon@iol.unh.edu>
Change-Id: I5cf4ede598afa377db7ecec17d8dfef085e130ac
Change-Id: I55494d24bcef74def85236b09168508e428d368e
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
Diffstat (limited to 'src/account')
-rw-r--r-- | src/account/jira_util.py | 65 | ||||
-rw-r--r-- | src/account/models.py | 1 | ||||
-rw-r--r-- | src/account/tasks.py | 37 | ||||
-rw-r--r-- | src/account/urls.py | 36 | ||||
-rw-r--r-- | src/account/views.py | 148 |
5 files changed, 27 insertions, 260 deletions
diff --git a/src/account/jira_util.py b/src/account/jira_util.py deleted file mode 100644 index a522594..0000000 --- a/src/account/jira_util.py +++ /dev/null @@ -1,65 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -import base64 -import os - -import oauth2 as oauth -from django.conf import settings -from jira import JIRA -from tlslite.utils import keyfactory - - -class SignatureMethod_RSA_SHA1(oauth.SignatureMethod): - name = 'RSA-SHA1' - - def signing_base(self, request, consumer, token): - if not hasattr(request, 'normalized_url') or request.normalized_url is None: - raise ValueError("Base URL for request is not set.") - - sig = ( - oauth.escape(request.method), - oauth.escape(request.normalized_url), - oauth.escape(request.get_normalized_parameters()), - ) - - key = '%s&' % oauth.escape(consumer.secret) - if token: - key += oauth.escape(token.secret) - raw = '&'.join(sig) - return key, raw - - def sign(self, request, consumer, token): - """Build the base signature string.""" - key, raw = self.signing_base(request, consumer, token) - - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - data = f.read() - privateKeyString = data.strip() - privatekey = keyfactory.parsePrivateKey(privateKeyString) - raw = str.encode(raw) - signature = privatekey.hashAndSign(raw) - return base64.b64encode(signature) - - -def get_jira(user): - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - key_cert = f.read() - - oauth_dict = { - 'access_token': user.userprofile.oauth_token, - 'access_token_secret': user.userprofile.oauth_secret, - 'consumer_key': settings.OAUTH_CONSUMER_KEY, - 'key_cert': key_cert - } - - return JIRA(server=settings.JIRA_URL, oauth=oauth_dict) diff --git a/src/account/models.py b/src/account/models.py index 2501be6..32229b1 100644 --- a/src/account/models.py +++ b/src/account/models.py @@ -51,6 +51,7 @@ class UserProfile(models.Model): oauth_secret = models.CharField(max_length=1024, blank=False) jira_url = models.CharField(max_length=100, null=True, blank=True, default='') + full_name = models.CharField(max_length=100, null=True, blank=True, default='') booking_privledge = models.BooleanField(default=False) diff --git a/src/account/tasks.py b/src/account/tasks.py deleted file mode 100644 index df98c73..0000000 --- a/src/account/tasks.py +++ /dev/null @@ -1,37 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from celery import shared_task -from django.contrib.auth.models import User -from jira import JIRAError - -from account.jira_util import get_jira - - -@shared_task -def sync_jira_accounts(): - users = User.objects.all() - for user in users: - jira = get_jira(user) - try: - user_dict = jira.myself() - except JIRAError: - # User can be anonymous (local django admin account) - continue - try: - user.email = user_dict['emailAddress'] - except KeyError: - pass - user.userprofile.url = user_dict['self'] - user.userprofile.full_name = user_dict['displayName'] - - user.userprofile.save() - user.save() diff --git a/src/account/urls.py b/src/account/urls.py index 97d8c77..6d4ef2f 100644 --- a/src/account/urls.py +++ b/src/account/urls.py @@ -30,46 +30,30 @@ from django.urls import path from account.views import ( AccountSettingsView, - JiraAuthenticatedView, - JiraLoginView, OIDCLoginView, - JiraLogoutView, + LogoutView, UserListView, account_resource_view, account_booking_view, account_images_view, - account_configuration_view, account_detail_view, - resource_delete_view, + template_delete_view, booking_cancel_view, image_delete_view, - configuration_delete_view ) -from laas_dashboard import settings +app_name = 'account' - -def get_login_view(): - if (settings.AUTH_SETTING == 'LFID'): - return OIDCLoginView.as_view() - else: - return JiraLoginView.as_view() - - -app_name = "account" urlpatterns = [ url(r'^settings/', AccountSettingsView.as_view(), name='settings'), - url(r'^authenticated/$', JiraAuthenticatedView.as_view(), name='authenticated'), - url(r'^login/$', get_login_view(), name='login'), - url(r'^logout/$', JiraLogoutView.as_view(), name='logout'), + url(r'^login/$', OIDCLoginView.as_view(), name='login'), + url(r'^logout/$', LogoutView.as_view(), name='logout'), url(r'^users/$', UserListView.as_view(), name='users'), - url(r'^my/resources/$', account_resource_view, name="my-resources"), - path('my/resources/delete/<int:resource_id>', resource_delete_view), - url(r'^my/bookings/$', account_booking_view, name="my-bookings"), + url(r'^my/resources/$', account_resource_view, name='my-resources'), + path('my/resources/delete/<int:resource_id>', template_delete_view), + url(r'^my/bookings/$', account_booking_view, name='my-bookings'), path('my/bookings/cancel/<int:booking_id>', booking_cancel_view), - url(r'^my/images/$', account_images_view, name="my-images"), + url(r'^my/images/$', account_images_view, name='my-images'), path('my/images/delete/<int:image_id>', image_delete_view), - url(r'^my/configurations/$', account_configuration_view, name="my-configurations"), - path('my/configurations/delete/<int:config_id>', configuration_delete_view), - url(r'^my/$', account_detail_view, name="my-account"), + url(r'^my/$', account_detail_view, name='my-account'), ] diff --git a/src/account/views.py b/src/account/views.py index b74126e..8976ff9 100644 --- a/src/account/views.py +++ b/src/account/views.py @@ -10,13 +10,10 @@ import os -import urllib -import oauth2 as oauth -from django.conf import settings from django.utils import timezone from django.contrib import messages -from django.contrib.auth import logout, authenticate, login +from django.contrib.auth import logout from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User @@ -26,13 +23,11 @@ from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.views.generic import RedirectView, TemplateView, UpdateView from django.shortcuts import render -from jira import JIRA from rest_framework.authtoken.models import Token from mozilla_django_oidc.auth import OIDCAuthenticationBackend from account.forms import AccountSettingsForm -from account.jira_util import SignatureMethod_RSA_SHA1 from account.models import UserProfile from booking.models import Booking from resource_inventory.models import ResourceTemplate, Image @@ -69,7 +64,7 @@ class MyOIDCAB(OIDCAuthenticationBackend): If this changes we will need to match users based on some other criterea. """ - username = claims.get(os.environ['CLAIMS_ENDPOINT'] + 'username') + username = claims.get(os.environ.get('CLAIMS_ENDPOINT') + 'username') if not username: return HttpResponse('No username provided, contact support.') @@ -101,109 +96,17 @@ class MyOIDCAB(OIDCAuthenticationBackend): return user -class JiraLoginView(RedirectView): - def get_redirect_url(self, *args, **kwargs): - consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) - client = oauth.Client(consumer) - client.set_signature_method(SignatureMethod_RSA_SHA1()) - - # Step 1. Get a request token from Jira. - try: - resp, content = client.request(settings.OAUTH_REQUEST_TOKEN_URL, "POST") - except Exception: - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - if resp['status'] != '200': - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - - # Step 2. Store the request token in a session for later use. - self.request.session['request_token'] = dict(urllib.parse.parse_qsl(content.decode())) - # Step 3. Redirect the user to the authentication URL. - url = settings.OAUTH_AUTHORIZE_URL + '?oauth_token=' + \ - self.request.session['request_token']['oauth_token'] + \ - '&oauth_callback=' + settings.OAUTH_CALLBACK_URL - return url - - class OIDCLoginView(RedirectView): def get_redirect_url(self, *args, **kwargs): return reverse('oidc_authentication_init') -class JiraLogoutView(LoginRequiredMixin, RedirectView): +class LogoutView(LoginRequiredMixin, RedirectView): def get_redirect_url(self, *args, **kwargs): logout(self.request) return '/' -class JiraAuthenticatedView(RedirectView): - def get_redirect_url(self, *args, **kwargs): - # Step 1. Use the request token in the session to build a new client. - consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) - token = oauth.Token(self.request.session['request_token']['oauth_token'], - self.request.session['request_token']['oauth_token_secret']) - client = oauth.Client(consumer, token) - client.set_signature_method(SignatureMethod_RSA_SHA1()) - - # Step 2. Request the authorized access token from Jira. - try: - resp, content = client.request(settings.OAUTH_ACCESS_TOKEN_URL, "POST") - except Exception: - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - if resp['status'] != '200': - messages.add_message(self.request, messages.ERROR, - 'Error: Connection to Jira failed. Please contact an Administrator') - return '/' - - access_token = dict(urllib.parse.parse_qsl(content.decode())) - - module_dir = os.path.dirname(__file__) # get current directory - with open(module_dir + '/rsa.pem', 'r') as f: - key_cert = f.read() - - oauth_dict = { - 'access_token': access_token['oauth_token'], - 'access_token_secret': access_token['oauth_token_secret'], - 'consumer_key': settings.OAUTH_CONSUMER_KEY, - 'key_cert': key_cert - } - - jira = JIRA(server=settings.JIRA_URL, oauth=oauth_dict) - username = jira.current_user() - email = "" - try: - email = jira.user(username).emailAddress - except AttributeError: - email = "" - url = '/' - # Step 3. Lookup the user or create them if they don't exist. - try: - user = User.objects.get(username=username) - except User.DoesNotExist: - # Save our permanent token and secret for later. - user = User.objects.create_user(username=username, - password=access_token['oauth_token_secret']) - profile = UserProfile() - profile.user = user - profile.save() - user.userprofile.email_addr = email - url = reverse('account:settings') - user.userprofile.oauth_token = access_token['oauth_token'] - user.userprofile.oauth_secret = access_token['oauth_token_secret'] - user.userprofile.save() - user.set_password(access_token['oauth_token_secret']) - user.save() - user = authenticate(username=username, password=access_token['oauth_token_secret']) - login(self.request, user) - # redirect user to settings page to complete profile - return url - - @method_decorator(login_required, name='dispatch') class UserListView(TemplateView): template_name = "account/user_list.html" @@ -232,9 +135,9 @@ def account_resource_view(request): template = "account/resource_list.html" active_bundles = [book.resource for book in Booking.objects.filter( - owner=request.user, end__gte=timezone.now())] + owner=request.user, end__gte=timezone.now(), resource__template__temporary=False)] active_resources = [bundle.template.id for bundle in active_bundles] - resource_list = list(ResourceTemplate.objects.filter(owner=request.user)) + resource_list = list(ResourceTemplate.objects.filter(owner=request.user, temporary=False)) context = { "resources": resource_list, @@ -262,15 +165,6 @@ def account_booking_view(request): return render(request, template, context=context) -def account_configuration_view(request): - if not request.user.is_authenticated: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - template = "account/configuration_list.html" - configs = list(ResourceTemplate.objects.filter(owner=request.user)) - context = {"title": "Configuration List", "configurations": configs} - return render(request, template, context=context) - - def account_images_view(request): if not request.user.is_authenticated: return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) @@ -290,28 +184,18 @@ def account_images_view(request): return render(request, template, context=context) -def resource_delete_view(request, resource_id=None): - if not request.user.is_authenticated: - return HttpResponse('no') # 403? - grb = get_object_or_404(ResourceTemplate, pk=resource_id) - if not request.user.id == grb.owner.id: - return HttpResponse('no') # 403? - if Booking.objects.filter(resource__template=grb, end__gt=timezone.now()).exists(): - return HttpResponse('no') # 403? - grb.delete() - return HttpResponse('') - - -def configuration_delete_view(request, config_id=None): +def template_delete_view(request, resource_id=None): if not request.user.is_authenticated: - return HttpResponse('no') # 403? - config = get_object_or_404(ResourceTemplate, pk=config_id) - if not request.user.id == config.owner.id: - return HttpResponse('no') # 403? - if Booking.objects.filter(resource__template=config, end__gt=timezone.now()).exists(): - return HttpResponse('no') - config.delete() - return HttpResponse('') + return HttpResponse(status=403) + template = get_object_or_404(ResourceTemplate, pk=resource_id) + if not request.user.id == template.owner.id: + return HttpResponse(status=403) + if Booking.objects.filter(resource__template=template, end__gt=timezone.now()).exists(): + return HttpResponse(status=403) + template.public = False + template.temporary = True + template.save() + return HttpResponse(status=200) def booking_cancel_view(request, booking_id=None): |