You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by sm...@apache.org on 2020/05/01 03:07:18 UTC

[airavata-custos-portal] 07/20: Integrated with custos python sdk, and added openID logon using Cilogon

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 <sh...@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", "jhon@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