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