This is an automated email from the ASF dual-hosted git repository. smarru pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/airavata-custos-portal.git
commit b23c5e5ad2ac30d1bd2349a635c5c5ee31197985 Author: Shivam Rastogi <shivam_r...@yahoo.com> AuthorDate: Wed Mar 25 02:41:16 2020 -0400 Integrated with custos python sdk, and added openID logon using Cilogon --- custos_portal/custos_portal/__init__.py | 5 + custos_portal/custos_portal/apps/auth/backends.py | 92 +++++++++++++++-- custos_portal/custos_portal/apps/auth/forms.py | 21 ++-- custos_portal/custos_portal/apps/auth/urls.py | 7 +- custos_portal/custos_portal/apps/auth/views.py | 110 ++++++++++++++++++--- custos_portal/custos_portal/apps/workspace/apps.py | 8 +- custos_portal/custos_portal/apps/workspace/urls.py | 2 +- .../custos_portal/apps/workspace/views.py | 3 +- custos_portal/custos_portal/cert.pem | 31 ++++++ custos_portal/custos_portal/context_processors.py | 16 ++- custos_portal/custos_portal/settings.ini | 4 + custos_portal/custos_portal/settings.py | 59 ++++++++++- custos_portal/custos_portal/settings_local.py | 26 +++++ custos_portal/custos_portal/templates/base.html | 7 +- .../custos_portal_auth/callback-error.html | 2 +- custos_portal/custos_portal/views.py | 2 +- requirements.txt | 3 +- 17 files changed, 352 insertions(+), 46 deletions(-) diff --git a/custos_portal/custos_portal/__init__.py b/custos_portal/custos_portal/__init__.py index e69de29..11a6430 100644 --- a/custos_portal/custos_portal/__init__.py +++ b/custos_portal/custos_portal/__init__.py @@ -0,0 +1,5 @@ +from clients.identity_management_client import IdentityManagementClient +from clients.user_management_client import UserManagementClient + +user_management_client = UserManagementClient() +identity_management_client = IdentityManagementClient() diff --git a/custos_portal/custos_portal/apps/auth/backends.py b/custos_portal/custos_portal/apps/auth/backends.py index 3ee9427..5f2df5a 100644 --- a/custos_portal/custos_portal/apps/auth/backends.py +++ b/custos_portal/custos_portal/apps/auth/backends.py @@ -1,33 +1,109 @@ +import json import logging +import time +from pprint import pprint +from django.conf import settings +from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import User from django.views.decorators.debug import sensitive_variables +from google.auth import jwt +from google.protobuf.json_format import MessageToJson, MessageToDict + +from custos_portal import identity_management_client logger = logging.getLogger(__name__) -class CustosAuthBackend(object): +class CustosAuthBackend(ModelBackend): """Django authentication backend for custos admin portal""" @sensitive_variables('password') def authenticate(self, request=None, username=None, password=None, refresh_token=None): - if username and password: - return - - return None + try: + if username and password: + token = self._get_token_and_userinfo_password_flow( + username, password) + userinfo = self._get_userinfo_from_token(token) + self._process_token(request, token) + return self._process_userinfo(request, userinfo) + # user is already logged in and can use refresh token + else: + token = self._get_token_and_userinfo_redirect_flow(request) + userinfo = self._get_userinfo_from_token(token) + self._process_token(request, token) + return self._process_userinfo(request, userinfo) + except Exception as e: + logger.exception("login failed") + return None def get_user(self, user_id): try: - User.objects.get(pk=user_id) + logger.debug("Checking for user: {}".format(user_id)) + return User.objects.get(pk=user_id) except User.DoesNotExist: return None + def _get_token_and_userinfo_password_flow(self, username, password): + token = identity_management_client.authenticate(settings.CUSTOS_TOKEN, username, password) + print(type(token)) + logger.info(token["access_token"]) + + # TODO: Add user info + # userinfo = None + return token, userinfo + + def _get_token_and_userinfo_redirect_flow(self, request): + + code = request.GET.get('code') + state = request.GET.get('state') + session_state = request.GET.get('session_state') + + saved_state = request.session['OAUTH2_STATE'] + redirect_uri = request.session['OAUTH2_REDIRECT_URI'] + logger.debug("Code: {}, State: {}, Saved_state: {}, session_state: {}".format(code, state, saved_state, + session_state)) + + if state == saved_state: + response = identity_management_client.token(settings.CUSTOS_TOKEN, redirect_uri, code) + token = MessageToDict(response) + + logger.debug(token["access_token"]) + return token + + return + + def _process_token(self, request, token): + # TODO validate the JWS signature + logger.debug("token: {}".format(token)) + now = time.time() + # Put access_token into session to be used for authenticating with API + # server + sess = request.session + sess['ACCESS_TOKEN'] = token['access_token'] + sess['ACCESS_TOKEN_EXPIRES_AT'] = now + token['expires_in'] + sess['REFRESH_TOKEN'] = token['refresh_token'] + sess['REFRESH_TOKEN_EXPIRES_AT'] = now + token['refresh_expires_in'] + + def _get_userinfo_from_token(self, token): + userinfo = {} + + decoded_id_token = jwt.decode(token["id_token"], verify=False) + + userinfo["username"] = decoded_id_token["preferred_username"] + userinfo["first_name"] = decoded_id_token["given_name"] + userinfo["last_name"] = decoded_id_token["family_name"] + userinfo["email"] = decoded_id_token["email"] + return userinfo + def _process_userinfo(self, request, userinfo): - logger.debug("userinfo: {}".format(userinfo)) + logger.debug("Userinfo: {}".format(userinfo)) + username = userinfo['username'] email = userinfo['email'] first_name = userinfo['first_name'] last_name = userinfo['last_name'] + request.session['USERINFO'] = userinfo try: @@ -36,6 +112,7 @@ class CustosAuthBackend(object): user.email = email user.first_name = first_name user.last_name = last_name + logger.debug("User already exists, updating it now") # Save the user locally in Django database user.save() except User.DoesNotExist: @@ -43,5 +120,6 @@ class CustosAuthBackend(object): first_name=first_name, last_name=last_name, email=email) + logger.debug("User does not already exists, adding it now") user.save() return user diff --git a/custos_portal/custos_portal/apps/auth/forms.py b/custos_portal/custos_portal/apps/auth/forms.py index e44d5e5..d4970ff 100644 --- a/custos_portal/custos_portal/apps/auth/forms.py +++ b/custos_portal/custos_portal/apps/auth/forms.py @@ -1,9 +1,13 @@ import logging +from clients.user_management_client import UserManagementClient +from custos.core import IamAdminService_pb2 from django import forms +from django.conf import settings from django.core import validators logger = logging.getLogger(__name__) +user_management_client = UserManagementClient() USERNAME_VALIDATOR = validators.RegexValidator( regex=r"^[a-z0-9_-]+$", @@ -188,6 +192,7 @@ class CreateAccountForm(forms.Form): def clean(self): cleaned_data = super().clean() + print(cleaned_data) password = cleaned_data.get('password') password_again = cleaned_data.get('password_again') @@ -212,20 +217,24 @@ class CreateAccountForm(forms.Form): ) username = cleaned_data.get('username') - # Check here if username is available. + + check_username = user_management_client.is_username_available(settings.CUSTOS_TOKEN, username) + print(check_username.is_exist) try: - if username: + if user_management_client.is_username_available(settings.CUSTOS_TOKEN, username).is_exist: + logger.info("Username is available"); + else: + logger.info("Username is not available"); self.add_error( 'username', forms.ValidationError("That username is not available") ) except Exception as e: - logger.exception("Failed to check if username is available") self.add_error( 'username', - forms.ValidationError("Error occurred while checking if " - "username is available: " + str(e))) - + forms.ValidationError("Error occurred while checking the username.") + ) + logger.info("Username is not available") return cleaned_data diff --git a/custos_portal/custos_portal/apps/auth/urls.py b/custos_portal/custos_portal/apps/auth/urls.py index e7f41a8..6b339d0 100644 --- a/custos_portal/custos_portal/apps/auth/urls.py +++ b/custos_portal/custos_portal/apps/auth/urls.py @@ -7,5 +7,10 @@ app_name = 'custos_portal_auth' urlpatterns = [ path('login/', views.start_login, name='login'), url(r'^redirect_login/(\w+)/$', views.redirect_login, name='redirect_login'), - url(r'^create-account$', views.create_account, name='create_account') + url(r'^create-account$', views.create_account, name='create_account'), + url(r'^redirect_login/(\w+)/$', views.redirect_login, name='redirect_login'), + url(r'^callback/$', views.callback, name='callback'), + url(r'^callback-error/(?P<idp_alias>\w+)/$', views.callback_error, + name='callback-error'), + ] diff --git a/custos_portal/custos_portal/apps/auth/views.py b/custos_portal/custos_portal/apps/auth/views.py index d949ccb..4afc3b1 100644 --- a/custos_portal/custos_portal/apps/auth/views.py +++ b/custos_portal/custos_portal/apps/auth/views.py @@ -1,8 +1,23 @@ +import logging +import json +from urllib.parse import quote + +from clients.identity_management_client import IdentityManagementClient +from clients.user_management_client import UserManagementClient from django.conf import settings +from django.contrib import messages +from django.contrib.auth import authenticate, login +from django.core.exceptions import ValidationError from django.forms import formset_factory -from django.shortcuts import render +from django.shortcuts import render, redirect +from django.urls import reverse +from requests_oauthlib import OAuth2Session from . import forms +from ... import identity_management_client +from ... import user_management_client + +logger = logging.getLogger(__name__) def start_login(request): @@ -13,10 +28,74 @@ def start_login(request): def redirect_login(request, idp_alias): - print("redirect login is called") + _validate_idp_alias(idp_alias) + + client_id = settings.KEYCLOAK_CLIENT_ID + + auth_base_url = identity_management_client.get_oidc_configuration(settings.CUSTOS_TOKEN, client_id) + # auth_base_url = json.loads(auth_base_url.) + # print(auth_base_url) + base_authorize_url = settings.KEYCLOAK_AUTHORIZE_URL + + redirect_uri = request.build_absolute_uri( + reverse('custos_portal_auth:callback')) + + oauth2_session = OAuth2Session( + client_id, scope='openid', redirect_uri=redirect_uri) + authorization_url, state = oauth2_session.authorization_url( + base_authorize_url) + authorization_url += '&kc_idp_hint=' + quote("oidc") + + # Store state in session for later validation (see backends.py) + request.session['OAUTH2_STATE'] = state + request.session['OAUTH2_REDIRECT_URI'] = redirect_uri + + logger.debug('Redirect URI: {}'.format(redirect_uri)) + logger.debug('Authorization URL for OpenID: {}'.format(authorization_url)) + return redirect(authorization_url) + + +def _validate_idp_alias(idp_alias): + external_auth_options = settings.AUTHENTICATION_OPTIONS['external'] + valid_idp_aliases = [ext['idp_alias'] for ext in external_auth_options] + if idp_alias not in valid_idp_aliases: + raise Exception("idp_alias is not valid: {}".format(idp_alias)) + + +def callback(request): + try: + user = authenticate(request=request) + logger.debug("Saving user to session: {}".format(user)) + + login(request, user) + + return redirect(reverse('custos_portal_workspace:list_requests')) + except Exception as err: + logger.exception("An error occurred while processing OAuth2 " + "callback: {}".format(request.build_absolute_uri())) + idp_alias = "cilogon" + return redirect(reverse('custos_portal_auth:callback-error', + args=(idp_alias,))) + + +def callback_error(request, idp_alias): + _validate_idp_alias(idp_alias) + # Create a filtered options object with just the given idp_alias + options = { + 'external': [] + } + for ext in settings.AUTHENTICATION_OPTIONS['external']: + if ext['idp_alias'] == idp_alias: + options['external'].append(ext.copy()) + + return render(request, 'custos_portal_auth/callback-error.html', { + 'idp_alias': idp_alias, + 'options': options, + }) def create_account(request): + print("Create account is called") if request.method == 'POST': form = forms.CreateAccountForm(request.POST) if form.is_valid(): @@ -26,30 +105,31 @@ def create_account(request): first_name = form.cleaned_data['first_name'] last_name = form.cleaned_data['last_name'] password = form.cleaned_data['password'] - success = iam_admin_client.register_user( - username, email, first_name, last_name, password) - if not success: - form.add_error(None, ValidationError( - "Failed to register user with IAM service")) - else: - _create_and_send_email_verification_link( - request, username, email, first_name, last_name) + is_temp_password = True + result = user_management_client.register_user(settings.CUSTOS_TOKEN, + username, email, first_name, last_name, password, + is_temp_password) + if result.is_registered: messages.success( request, "Account request processed successfully. Before you " "can login you need to confirm your email address. " "We've sent you an email with a link that you should " "click on to complete the account creation process.") - return redirect( - reverse('django_airavata_auth:create_account')) - except Exception as e: + else: + form.add_error(None, ValidationError( + "Failed to register the user with IAM service")) + except TypeError as e: logger.exception( "Failed to create account for user", exc_info=e) - form.add_error(None, ValidationError(e.message)) + form.add_error(None, ValidationError(e)) + return render(request, 'custos_portal_auth/create_account.html', { + 'options': settings.AUTHENTICATION_OPTIONS, + 'form': form + }) else: form = forms.CreateAccountForm() return render(request, 'custos_portal_auth/create_account.html', { 'options': settings.AUTHENTICATION_OPTIONS, 'form': form }) - diff --git a/custos_portal/custos_portal/apps/workspace/apps.py b/custos_portal/custos_portal/apps/workspace/apps.py index 1a35ee5..cfafc19 100644 --- a/custos_portal/custos_portal/apps/workspace/apps.py +++ b/custos_portal/custos_portal/apps/workspace/apps.py @@ -3,10 +3,10 @@ from custos_portal.app_config import CustosAppConfig class WorkspaceConfig(CustosAppConfig): name = 'custos_portal.apps.workspace' - label = 'custos_admin_portal_workspace' + label = 'custos_portal_workspace' verbose_name = 'Workspace' app_order = 0 - url_home = 'custos_admin_portal_workspace:request_new_tenant' + url_home = 'custos_portal_workspace:request_new_tenant' fa_icon_class = 'fa-flask' app_description = """ Launch applications and manage your experiments and projects. @@ -15,13 +15,13 @@ class WorkspaceConfig(CustosAppConfig): { 'label': 'Create new tenant request', 'icon': 'fa fa-plus-square', - 'url': 'custos_admin_portal_workspace:request_new_tenant', + 'url': 'custos_portal_workspace:request_new_tenant', 'active_prefixes': ['applications', 'request-new-tenant'] }, { 'label': 'List of all existing tenant requests', 'icon': 'fa fa-list', - 'url': 'custos_admin_portal_workspace:list_requests', + 'url': 'custos_portal_workspace:list_requests', 'active_prefixes': ['applications', 'list-requests'] } ] \ No newline at end of file diff --git a/custos_portal/custos_portal/apps/workspace/urls.py b/custos_portal/custos_portal/apps/workspace/urls.py index 29c5c34..cd01d39 100644 --- a/custos_portal/custos_portal/apps/workspace/urls.py +++ b/custos_portal/custos_portal/apps/workspace/urls.py @@ -2,7 +2,7 @@ from django.conf.urls import url from . import views -app_name = 'custos_admin_portal_workspace' +app_name = 'custos_portal_workspace' urlpatterns = [ url(r'^request-new-tenant', views.request_new_tenant, name='request_new_tenant'), url(r'^list-requests', views.list_new_tenant_requests, name='list_requests'), diff --git a/custos_portal/custos_portal/apps/workspace/views.py b/custos_portal/custos_portal/apps/workspace/views.py index 8a89243..6766cb5 100644 --- a/custos_portal/custos_portal/apps/workspace/views.py +++ b/custos_portal/custos_portal/apps/workspace/views.py @@ -11,7 +11,8 @@ def request_new_tenant(request): def list_new_tenant_requests(request): request.active_nav_item = 'list-requests' - + if request.user: + print("hell") return render(request, 'workspace/list_requests.html', { 'bundle_name': 'list-requests', }) diff --git a/custos_portal/custos_portal/cert.pem b/custos_portal/custos_portal/cert.pem new file mode 100644 index 0000000..90c5116 --- /dev/null +++ b/custos_portal/custos_portal/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWzCCBEOgAwIBAgISAwh6tCQR1vA9YW6Z/b2ZPCofMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDAxMDIxODM3NDJaFw0y +MDA0MDExODM3NDJaMBwxGjAYBgNVBAMTEWN1c3Rvcy5zY2lnYXAub3JnMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Zak1I69TqrZA+x/nd+4EuIW8m2e +z7Bk7RHL/ZMJ6Z6KImI4SyrdK+0v6b9nrf+NxS/3T8sIHlWKRHs4bp9ufsJdStfP +xhSwUdcB6x3wkdJNWiwAV9gBxJAyWt4d5HfSX4v2JaYy4AwUCRJ01jGnrwXBA8GE +hsjNoS/IGW5Qoc5+XCFKnYGZRgYVGy8fbvAAD384lS7CxnNth+CAxe/EdWmNCP9p +hk5tGko0cjk/anXNSUh8Usj3H62+4LDrdNoILL94tZiNE2eRkFn/QLFPBHYoF2Q0 +C+pDj8EfIUq1ZFwghyBRFpGbLM4e+XNMb+8oE2wiqlf6BqsH+PTrASoJKQIDAQAB +o4ICZzCCAmMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr +BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRzsXEOBr9ibNTT8PrlOt7+ +a58C7jAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB +AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw +dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw +dC5vcmcvMBwGA1UdEQQVMBOCEWN1c3Rvcy5zY2lnYXAub3JnMEwGA1UdIARFMEMw +CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j +cHMubGV0c2VuY3J5cHQub3JnMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHcA8JWk +WfIA0YJAEC0vk4iOrUv+HUfjmeHQNKawqKqOsnMAAAFvZ8N7sgAABAMASDBGAiEA +h2XJzftCmUlLaj5Ub2ed/yjIcYHctJlP8pLCI251fQICIQDuZ5cWCkEd5MJVkTZt +yzPgmJ3NXtE3ewZHUuIcQ3u7aAB2AAe3XBvlfWj/8bDGHSMVx7rmV3xXlLdq7rxh +Ohpp06IcAAABb2fDe9QAAAQDAEcwRQIhAMDZgnBnBtWqMBeYdhEMbcfSVFC8jCBu +JugiMai+8zVEAiA7tVSVntNg3AVNy8nCdTmSa463JkvvJguneo5mSjVbcTANBgkq +hkiG9w0BAQsFAAOCAQEAAH/VAOo7rFemkiL7NYJDyA/ZV42Akg0+sGHCshKNDpqU +se00Rg7hVqhFk6uOY7UwT5W+CF/IPUV7kB4R5/DzTygnxR8MvIWbwGKrWFOtR3jd +nnTIUkyJLeLaY8t01Rx85AuSFDAwibSoJs2QrIFse0bcxr9ScTxOf/aJuTTADacn +mVpK7Jy/o8cliUr5DlArOhByn/v1fXMddK+GQJnmz8a2g3HiU9e5jitXkC92Zp3j +oFrHqrggYyYoPjZWPOovahjUZgnEKi6C9Sk1PRgJxtIOaD+9zVpzDtH9u0xqIfFW +wQSKuCdeNlOBS3PopNhzjOCWxhtj7+Z9eCxLyi395A== +-----END CERTIFICATE----- diff --git a/custos_portal/custos_portal/context_processors.py b/custos_portal/custos_portal/context_processors.py index 0cbb601..f106bf8 100644 --- a/custos_portal/custos_portal/context_processors.py +++ b/custos_portal/custos_portal/context_processors.py @@ -2,6 +2,8 @@ import copy import logging import re +from clients.identity_management_client import IdentityManagementClient +from clients.user_management_client import UserManagementClient from django.apps import apps from django.conf import settings @@ -10,11 +12,19 @@ from custos_portal.app_config import CustosAppConfig logger = logging.getLogger(__name__) +# load APIServerClient with default configuration +client = UserManagementClient() +id_client = IdentityManagementClient() + +token = "Y3VzdG9zLTZud29xb2RzdHBlNW12Y3EwOWxoLTEwMDAwMTAxOkdpS3JHR1ZMVzd6RG9QWnd6Z0NpRk03V1V6M1BoSXVtVG1GeEFrcjc="; + +def register_user(): + + response = client.register_user(token, "TestingUser", "Jhon", "Smith", "12345", "j...@iu.edu", True) + print(response) + def airavata_app_registry(request): """Put airavata django apps into the context.""" - print([app for app in apps.app_configs]) - print([app for app in apps.get_app_configs()]) - airavata_apps = [app for app in apps.get_app_configs() if isinstance(app, CustosAppConfig)] print("Custos apps", airavata_apps) diff --git a/custos_portal/custos_portal/settings.ini b/custos_portal/custos_portal/settings.ini new file mode 100644 index 0000000..ce676b8 --- /dev/null +++ b/custos_portal/custos_portal/settings.ini @@ -0,0 +1,4 @@ +[CustosServer] +SERVER_HOST = custos.scigap.org +SERVER_SSL_PORT = 32036 +CERTIFICATE_FILE_PATH = ../cert.pem \ No newline at end of file diff --git a/custos_portal/custos_portal/settings.py b/custos_portal/custos_portal/settings.py index 6e58c9f..1d79883 100644 --- a/custos_portal/custos_portal/settings.py +++ b/custos_portal/custos_portal/settings.py @@ -21,6 +21,9 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '3=(o1!l-)1p#evd@aviv56^piimx)!p=^t=#5))yn547yr9f2&' +# Custos server secret key +CUSTOS_TOKEN = 'Y3VzdG9zLTZud29xb2RzdHBlNW12Y3EwOWxoLTEwMDAwMTAxOkdpS3JHR1ZMVzd6RG9QWnd6Z0NpRk03V1V6M1BoSXVtVG1GeEFrcjc=' + # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -29,6 +32,7 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ + 'custos_portal.apps.admin.apps.AdminConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -39,7 +43,6 @@ INSTALLED_APPS = [ 'custos_portal.apps.auth.apps.AuthConfig', 'custos_portal.apps.workspace.apps.WorkspaceConfig', - 'custos_portal.apps.admin.apps.AdminConfig' ] MIDDLEWARE = [ @@ -138,6 +141,9 @@ AUTHENTICATION_OPTIONS = { ] } +AUTHENTICATION_BACKENDS = [ + 'custos_portal.apps.auth.backends.CustosAuthBackend' +] WEBPACK_LOADER = { 'COMMON': { @@ -151,4 +157,53 @@ WEBPACK_LOADER = { 'dist', 'webpack-stats.json'), } -} \ No newline at end of file +} + + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'formatters': { + 'verbose': { + 'format': '[%(asctime)s %(name)s:%(lineno)d %(levelname)s] %(message)s' + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose' + }, + 'mail_admins': { + 'filters': ['require_debug_false'], + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'include_html': True, + } + }, + 'loggers': { + 'custos_portal': { + 'handlers': ['console'], + 'level': 'DEBUG' if DEBUG else 'INFO' + }, + 'root': { + 'handlers': ['console'], + 'level': 'WARNING' + } + }, +} + + + +# Allow all settings to be overridden by settings_local.py file +try: + from custos_portal.settings_local import * # noqa +except ImportError: + pass diff --git a/custos_portal/custos_portal/settings_local.py b/custos_portal/custos_portal/settings_local.py new file mode 100644 index 0000000..414b83e --- /dev/null +++ b/custos_portal/custos_portal/settings_local.py @@ -0,0 +1,26 @@ +""" +Override default Django settings for a particular instance. + +Copy this file to settings_local.py and modify as appropriate. This file will +be imported into settings.py last of all so settings in this file override any +defaults specified in settings.py. +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Keycloak Configuration +KEYCLOAK_CLIENT_ID = 'custos-6nwoqodstpe5mvcq09lh-10000101' +KEYCLOAK_CLIENT_SECRET = 'GiKrGGVLW7zDoPZwzgCiFM7WUz3PhIumTmFxAkr7' +KEYCLOAK_AUTHORIZE_URL = 'https://keycloak.custos.scigap.org:31000/auth/realms/10000101/protocol/openid-connect/auth' +KEYCLOAK_TOKEN_URL = 'https://airavata.host:8443/auth/realms/default/protocol/openid-connect/token' +KEYCLOAK_USERINFO_URL = 'https://keycloak.custos.scigap.org:31000/auth/realms/10000101/protocol/openid-connect/auth' +KEYCLOAK_LOGOUT_URL = 'https://airavata.host:8443/auth/realms/default/protocol/openid-connect/logout' +# Optional: specify if using self-signed certificate or certificate from unrecognized CA +#KEYCLOAK_CA_CERTFILE = os.path.join(BASE_DIR, "django_airavata", "resources", "incommon_rsa_server_ca.pem") +KEYCLOAK_VERIFY_SSL = False + + +SESSION_COOKIE_SECURE = False \ No newline at end of file diff --git a/custos_portal/custos_portal/templates/base.html b/custos_portal/custos_portal/templates/base.html index 07e2425..94361e8 100644 --- a/custos_portal/custos_portal/templates/base.html +++ b/custos_portal/custos_portal/templates/base.html @@ -149,7 +149,8 @@ {% endblock %} <div class=c-header__title><a href="/">{% block title %}Custos Portal{% endblock %}</a> </div> - {% if not user.is_authenticated %} + + {% if user.is_authenticated %} <div class=c-header__controls> <div class="btn-group"> <div class=dropdown> @@ -199,8 +200,8 @@ <a href=# class="dropdown-toggle text-dark" id=dropdownMenuButton data-toggle=dropdown aria-haspopup=true aria-expanded=false> <i class="fa fa-user mr-2"></i> - {{ request.session.USERINFO.given_name }} - {{ request.session.USERINFO.family_name }} + {{ request.session.USERINFO.first_name }} + {{ request.session.USERINFO.last_name }} </a> <div class=dropdown-menu aria-labelledby=dropdownMenuButton> <a class=dropdown-item href=#>User settings</a> diff --git a/custos_portal/custos_portal/templates/custos_portal_auth/callback-error.html b/custos_portal/custos_portal/templates/custos_portal_auth/callback-error.html index 79eed2c..d2133c4 100644 --- a/custos_portal/custos_portal/templates/custos_portal_auth/callback-error.html +++ b/custos_portal/custos_portal/templates/custos_portal_auth/callback-error.html @@ -13,7 +13,7 @@ <div class="row"> <div class="col"> <p> - <small>See <a href="{% url 'django_airavata_auth:login' %}" class="text-muted">all login options</small> + <small>See <a href="{% url 'custos_portal_auth:login' %}" class="text-muted">all login options</small> </p> </div> </div> diff --git a/custos_portal/custos_portal/views.py b/custos_portal/custos_portal/views.py index c3a26fa..ac106d3 100644 --- a/custos_portal/custos_portal/views.py +++ b/custos_portal/custos_portal/views.py @@ -2,5 +2,5 @@ from django.shortcuts import render def home(request): - return render(request, 'custos_portal/home.html', {}) + return render(request, 'custos_portal/home.html') diff --git a/requirements.txt b/requirements.txt index 232301c..ebd8e97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -Django==3.0.3 +Django>=3.0.0,<=4.0.0 django-webpack-loader==0.6.0 +requests-oauthlib==1.3.0 \ No newline at end of file