machristie commented on code in PR #167:
URL: 
https://github.com/apache/airavata-custos-portal/pull/167#discussion_r1088364693


##########
airavata_custos_portal/apps/api/views.py:
##########
@@ -0,0 +1,197 @@
+from django.conf import settings
+from django.http import HttpResponse
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+
+from django.shortcuts import redirect, render
+import requests
+import base64
+import jwt
+
+import os
+import environ
+
+env = environ.Env()
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+environ.Env.read_env('.env')
+
+CUSTOS_CLIENT_ID = env("CUSTOS_CLIENT_ID")
+CUSTOS_CLIENT_SEC = env("CUSTOS_CLIENT_SEC")
+CUSTOS_API_URL = env("CUSTOS_API_URL")
+CUSTOS_SUPER_CLIENT_ID = env("CUSTOS_SUPER_CLIENT_ID")
+UNDER_MAINTENANCE = env("UNDER_MAINTENANCE")

Review Comment:
   I think it would be better to consolidate configuration in the settings.py 
file, so I would recommend moving this code there.



##########
airavata_custos_portal/apps/api/views.py:
##########
@@ -0,0 +1,197 @@
+from django.conf import settings
+from django.http import HttpResponse
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+
+from django.shortcuts import redirect, render
+import requests
+import base64
+import jwt
+
+import os
+import environ
+
+env = environ.Env()
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+environ.Env.read_env('.env')
+
+CUSTOS_CLIENT_ID = env("CUSTOS_CLIENT_ID")
+CUSTOS_CLIENT_SEC = env("CUSTOS_CLIENT_SEC")
+CUSTOS_API_URL = env("CUSTOS_API_URL")
+CUSTOS_SUPER_CLIENT_ID = env("CUSTOS_SUPER_CLIENT_ID")
+UNDER_MAINTENANCE = env("UNDER_MAINTENANCE")
+
+ENDPOINTS = {
+    "IDENTITY": "identity-management/v1.0.0",
+    "USERS": "user-management/v1.0.0",
+    "GROUPS": "group-management/v1.0.0",
+    "TENANTS": "tenant-management/v1.0.0",
+    "SHARING": "sharing-management/v1.0.0",
+    "SECRETS": "resource-secret-management/v1.0.0"
+}
+
+
+# Create your views here.
+@api_view()
+def get_config(request):
+    # Just a simple REST API view to show how to access VUE_APP_* settings
+    return Response({
+        "VUE_APP_CLIENT_ID": CUSTOS_CLIENT_ID,
+        "VUE_APP_CUSTOS_API_URL": request.build_absolute_uri('/api/custos'),
+        "VUE_APP_SUPER_CLIENT_ID": CUSTOS_SUPER_CLIENT_ID
+    })
+
+
+@api_view()
+def get_userinfo(request):
+    if 'access_token' not in request.session:
+        return HttpResponse('Unauthorized', status=401)
+    else:
+        payload = jwt.decode(jwt=request.session['access_token'], verify=False)
+        return Response(payload)
+
+
+def get_client_sec(request, client_id):
+    response = requests.get(
+        url=f"{CUSTOS_API_URL}/{ENDPOINTS['IDENTITY']}/credentials",
+        params={'client_id': client_id},
+        headers={
+            'Accept': '*/*',
+            'Content-Type': 'application/json',
+            'Authorization': f"Bearer {request.session['access_token']}"
+        }
+    )
+
+    response_json = response.json()
+    client_sec = response_json["custos_client_secret"]
+
+    return client_sec
+
+
+def get_client_auth_base64(request, client_id=None, client_sec=None):
+    if client_id is None and client_sec is None:
+        client_id = CUSTOS_CLIENT_ID
+        client_sec = CUSTOS_CLIENT_SEC
+    elif client_id is not None and client_sec is None:
+        client_sec = get_client_sec(request, client_id)
+
+    client_auth_base64 = f"{client_id}:{client_sec}"
+    client_auth_base64 = client_auth_base64.encode("utf-8")
+    client_auth_base64 = base64.b64encode(client_auth_base64).decode('utf-8')
+    client_auth_base64 = f"Bearer {client_auth_base64}"
+
+    return client_auth_base64
+
+
+@api_view()
+def get_auth_callback(request):
+    CUSTOS_REDIRECT_URI = request.build_absolute_uri('/api/callback')
+    code = request.GET.get("code", None)
+
+    client_auth_base64 = get_client_auth_base64(request)
+
+    response = requests.post(
+        url=f"{CUSTOS_API_URL}/{ENDPOINTS['IDENTITY']}/token",
+        json={'code': code, 'redirect_uri': CUSTOS_REDIRECT_URI,
+              'grant_type': 'authorization_code'},
+        headers={
+            'Accept': '*/*',
+            'Content-Type': 'application/json',
+            'Authorization': client_auth_base64
+        }
+    )
+
+    set_token_response_session(request, response)
+
+    return redirect("/")
+
+
+def set_token_response_session(request, response):
+    response_json = response.json()
+    request.session.set_expiry(response_json["expires_in"])
+    request.session['access_token'] = response_json["access_token"]
+    request.session['refresh_token'] = response_json["refresh_token"]
+    request.session['id_token'] = response_json["id_token"]
+
+
+def remove_token_response_session(request):
+    del request.session['access_token']
+    del request.session['refresh_token']
+    del request.session['id_token']
+
+
+custos_resource_map = {
+    "credentials": f"{ENDPOINTS['IDENTITY']}/credentials"
+}
+
+
+@api_view(["GET", "POST", "PUT", "DELETE"])
+def get_custos_api(request, endpoint_path=""):
+    CUSTOS_REDIRECT_URI = request.build_absolute_uri('/api/callback')
+
+    client_auth_base64 = get_client_auth_base64(request)
+    client_auth_cases_map = {
+        "token_password": endpoint_path == f"{ENDPOINTS['IDENTITY']}/token" 
and "grant_type" in request.data
+                          and request.data["grant_type"] == "password",
+        "token_refresh_token": endpoint_path == 
f"{ENDPOINTS['IDENTITY']}/token" and "grant_type" in request.data
+                               and request.data["grant_type"] == 
"refresh_token",
+        "token_authorization_code": endpoint_path == 
f"{ENDPOINTS['IDENTITY']}/token" and "grant_type" in request.data
+                                    and request.data["grant_type"] == 
"authorization_code",
+        "token_openid-configuration": endpoint_path == 
f"{ENDPOINTS['IDENTITY']}/.well-known/openid-configuration",
+        "logout": endpoint_path == f"{ENDPOINTS['IDENTITY']}/user/logout",
+        "tenant_create": endpoint_path == 
f"{ENDPOINTS['TENANTS']}/oauth2/tenant" and request.method == "POST"
+    }
+
+    authorization_header = None
+    if True in client_auth_cases_map.values():
+        authorization_header = client_auth_base64
+    elif "access_token" in request.session:
+        authorization_header = f"Bearer {request.session['access_token']}"
+
+    if client_auth_cases_map["tenant_create"] and "parent_client_id" in 
request.data:
+        if request.data["parent_client_id"] == CUSTOS_SUPER_CLIENT_ID:
+            authorization_header = None

Review Comment:
   What does this line do? Is it that the parent_client_id isn't allowed to be 
the SUPER_CLIENT_ID?



##########
src/App.vue:
##########
@@ -13,13 +12,12 @@
 import Header from "./lib/components/block/Header";
 import store from "./lib/store";
 import Footer from "./lib/components/block/Footer";
-import Maintenance from "@/lib/components/pages/Maintenance";

Review Comment:
   What happened to the Maintenance view?



##########
airavata_custos_portal/apps/frontend/urls.py:
##########
@@ -0,0 +1,28 @@
+from django.urls import path
+
+from . import views
+
+
+app_name = "airavata_custos_portal_frontend"
+urlpatterns = [
+    path('', views.home, name="home"),

Review Comment:
   You can leave this if you want but you can use re_path to match multiple 
paths so you don't have to list them all out like this.



##########
setup.py:
##########
@@ -0,0 +1,45 @@
+import os
+
+from setuptools import find_packages, setup
+
+
+def read(fname):
+    with open(os.path.join(os.path.dirname(__file__), fname)) as f:
+        return f.read()
+
+
+setup(
+    name="airavata_custos_portal",
+    version="0.0.3",
+    url="https://github.com/apache/airavata-custos-portal";,
+    author="Apache Software Foundation",
+    author_email="[email protected]",
+    description=(
+        "The Airavata Custos Portal SDK is a library that makes "
+        "it easier to develop Airavata Custos Portal customizations."
+    ),
+    long_description=read("README.md"),
+    long_description_content_type='text/markdown',
+    license="Apache License 2.0",
+    packages=['airavata_custos_portal.apps.frontend', 
'airavata_custos_portal.apps.api'],
+    package_data={'airavata_custos_portal.apps.frontend': ['static/**/*', 
'templates/**/*']},
+    install_requires=[
+        "Django==3.2.16",
+        "django-webpack-loader==0.6.0",
+        "djangorestframework==3.14.0",
+        "requests==2.28.2",
+        "PyJWT==0.4.3",

Review Comment:
   Typically you don't require exact versions in setup.py. If you know that, 
for example, this Django app doesn't work with 4.0 or greater, then you might 
say you require `"Django<4.0"`. Or if you need at least a version you can do 
that too. I think you can just list the required packages without version 
numbers.



##########
airavata_custos_portal/settings.py:
##########
@@ -0,0 +1,156 @@
+"""
+Django settings for airavata_custos_portal project.
+
+Generated by 'django-admin startproject' using Django 3.2.16.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/3.2/ref/settings/
+"""
+
+import json
+import os
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = os.environ.get(
+    "DJANGO_SECRET_KEY",
+    "django-insecure-=3_8+_&j54+-&(j(s2v=p#7%#$)oihyl)rdmp8(^5#r3y2wbs)",
+)
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True #os.environ.get("DJANGO_DEBUG", "true") == "true"

Review Comment:
   I think the environment variable should be kept. In production we'll want to 
turn off DEBUG.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to