aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-24 14:37:18 +0300
committerFrederick Muriuki Muriithi2023-05-08 10:08:17 +0300
commit1608f1c092eb2011ecaf8485257648cc7971b213 (patch)
tree362557b80f39c09fcbcf18eb374922619f23ab74
parent5a8432adb56f9fddbc9e42a9eb8de5e4a0879ee6 (diff)
downloadgenenetwork2-1608f1c092eb2011ecaf8485257648cc7971b213.tar.gz
oauth2: Add auth-checking wrapper to `/show_trait?...` page
As a proof-of-concept, add some sort of wrapper to check whether the user has access to the given trait/dataset. This will probably need some improvement to check for edit access, curation access, etc.
-rw-r--r--wqflask/wqflask/oauth2/client.py8
-rw-r--r--wqflask/wqflask/templates/show_trait_error.html20
-rw-r--r--wqflask/wqflask/views.py81
3 files changed, 86 insertions, 23 deletions
diff --git a/wqflask/wqflask/oauth2/client.py b/wqflask/wqflask/oauth2/client.py
index 1d3e07ae..dba52644 100644
--- a/wqflask/wqflask/oauth2/client.py
+++ b/wqflask/wqflask/oauth2/client.py
@@ -1,4 +1,5 @@
"""Common oauth2 client utilities."""
+import requests
from typing import Optional
from urllib.parse import urljoin
@@ -46,3 +47,10 @@ def oauth2_post(
return Right(resp.json())
return Left(resp)
+
+def no_token_get(uri_path: str, **kwargs) -> Either:
+ config = app.config
+ resp = requests.get(urljoin(config["GN_SERVER_URL"], uri_path), **kwargs)
+ if resp.status_code == 200:
+ return Right(resp.json())
+ return Left(resp)
diff --git a/wqflask/wqflask/templates/show_trait_error.html b/wqflask/wqflask/templates/show_trait_error.html
new file mode 100644
index 00000000..c924d1f1
--- /dev/null
+++ b/wqflask/wqflask/templates/show_trait_error.html
@@ -0,0 +1,20 @@
+{%extends "base.html"%}
+{%block title%}Trait Data and Analysis{%endblock%}
+{%block css%}
+<link rel="stylesheet" type="text/css" href="/static/new/css/bar_chart.css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/box_plot.css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/prob_plot.css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/scatter-matrix.css" />
+<link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='d3-tip/d3-tip.css') }}" />
+<link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" />
+<link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='nouislider/nouislider.min.css') }}" />
+<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/trait_list.css" />
+<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" />
+
+{%endblock%}
+{%block content%} <!-- Start of body -->
+<div class="container">
+ {{flash_me()}}
+</div>
+{%endblock%} <!-- End of body -->
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 90747fc2..f14ccdd0 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -38,6 +38,8 @@ from flask import send_from_directory
from flask import redirect
from flask import send_file
from flask import url_for
+from flask import flash
+from flask import session
# Some of these (like collect) might contain endpoints, so they're still used.
# Blueprints should probably be used instead.
@@ -75,6 +77,9 @@ from wqflask.docs import Docs, update_text
from wqflask.decorators import edit_access_required
from wqflask.db_info import InfoPage
+from wqflask.oauth2.client import no_token_get
+from wqflask.oauth2.request_utils import process_error
+
from utility import temp_data
from utility.tools import TEMPDIR
from utility.tools import USE_REDIS
@@ -482,30 +487,60 @@ def show_temp_trait_page():
@app.route("/show_trait")
def show_trait_page():
- with database_connection() as conn, conn.cursor() as cursor:
- user_id = ((g.user_session.record.get(b"user_id") or b"").decode("utf-8")
- or g.user_session.record.get("user_id") or "")
- template_vars = show_trait.ShowTrait(cursor,
- user_id=user_id,
- kw=request.args)
- template_vars.js_data = json.dumps(template_vars.js_data,
- default=json_default_handler,
- indent=" ")
- # Should there be any mis-configurations, things will still
- # work.
- metadata = {}
- try:
- metadata = requests.get(
- urljoin(
- GN3_LOCAL_URL,
- f"/api/metadata/dataset/{request.args.get('dataset')}")
- ).json()
- except:
+ def __show_trait__():
+ with database_connection() as conn, conn.cursor() as cursor:
+
+ user_id = ((g.user_session.record.get(b"user_id") or b"").decode("utf-8")
+ or g.user_session.record.get("user_id") or "")
+ template_vars = show_trait.ShowTrait(cursor,
+ user_id=user_id,
+ kw=request.args)
+ template_vars.js_data = json.dumps(template_vars.js_data,
+ default=json_default_handler,
+ indent=" ")
+ # Should there be any mis-configurations, things will still
+ # work.
metadata = {}
- return render_template(
- "show_trait.html",
- metadata=metadata,
- **template_vars.__dict__)
+ try:
+ metadata = requests.get(
+ urljoin(
+ GN3_LOCAL_URL,
+ f"/api/metadata/dataset/{request.args.get('dataset')}")
+ ).json()
+ except:
+ metadata = {}
+ return render_template(
+ "show_trait.html",
+ metadata=metadata,
+ **template_vars.__dict__)
+ dataset = request.args["dataset"]
+ trait_id = request.args["trait_id"]
+ def __failure__(err):
+ error = process_error(err)
+ flash(f"{error['error']}: {error['error_description']}", "alert-error")
+ return render_template("show_trait_error.html")
+
+ def __success__(auth_results):
+ trait_privileges = auth_results[0]["privileges"]
+ if ("group:resource:view-resource" in trait_privileges or
+ "system:resource:public-read" in trait_privileges):
+ return __show_trait__()
+ flash(
+ f"AuthorisationError: You do not have access to trait '{trait_id}' "
+ f"from the '{dataset}' dataset.",
+ "alert-danger")
+ return render_template("show_trait_error.html")
+
+ return no_token_get(
+ "oauth2/data/authorisation",
+ headers={
+ "Content-Type": "application/json",
+ **({"Authorization": f"Bearer {session['token']}"}
+ if bool(session.get("token")) else {})
+ },
+ json={
+ "traits": [f"{dataset}::{trait_id}"]
+ }).either(__failure__, __success__)
@app.route("/heatmap", methods=('POST',))