Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
# solvebio-recipes only available in python3
extras_requires = {}
else:
extra['use_2to3'] = True
extra['use_2to3'] = False

with open('README.md') as f:
long_description = f.read()
Expand Down
8 changes: 7 additions & 1 deletion solvebio/contrib/streamlit/solvebio_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

from httpx_oauth.oauth2 import BaseOAuth2

import logging
logger = logging.getLogger('solvebio')


class SolveBioOAuth2(BaseOAuth2[Dict[str, Any]]):
"""Class implementing OAuth2 for SolveBio API"""
Expand All @@ -16,6 +19,7 @@ class SolveBioOAuth2(BaseOAuth2[Dict[str, Any]]):
SOLVEBIO_URL = os.environ.get('SOLVEBIO_URL', 'https://my.solvebio.com')
OAUTH2_TOKEN_URL = "/v1/oauth2/token"
OAUTH2_REVOKE_TOKEN_URL = "/v1/oauth2/revoke_token"
OAUTH2_REVOKE_TOKEN_AUTH = "client_secret_basic"

def __init__(self, client_id, client_secret, name="solvebio"):
super().__init__(
Expand All @@ -26,6 +30,7 @@ def __init__(self, client_id, client_secret, name="solvebio"):
revoke_token_endpoint=urljoin(
solvebio.api_host, self.OAUTH2_REVOKE_TOKEN_URL
),
revocation_endpoint_auth_method=self.OAUTH2_REVOKE_TOKEN_AUTH,
name=name,
)

Expand All @@ -38,4 +43,5 @@ def get_authorization_url(self, redirect_uri):
"redirect_uri": redirect_uri,
}

return "{}/authorize?{}".format(self.authorize_endpoint, urlencode(params))
auth_url = "{}/authorize?{}".format(self.authorize_endpoint, urlencode(params))
return auth_url
30 changes: 18 additions & 12 deletions solvebio/contrib/streamlit/solvebio_streamlit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@
import streamlit as st
import solvebio

from solvebio_auth import SolveBioOAuth2
from .solvebio_auth import SolveBioOAuth2

import logging
logger = logging.getLogger('solvebio')


class SolveBioStreamlit:
"""SolveBio OAuth2 wrapper for restricting access to Streamlit apps"""

# App settings loaded from environment variables or .env file
CLIENT_ID = os.environ.get("CLIENT_ID", "Application (client) Id")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET", "Application (client) secret")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
APP_URL = os.environ.get("APP_URL", "http://localhost:5000")

def solvebio_login_component(self, authorization_url):
"""Streamlit component for logging into SolveBio"""
"""Streamlit component for logging into QuartzBio"""

st.title("Secure Streamlit App")
st.write(
"""
<h4>
<a target="_self" href="{}">Log in to SolveBio to continue</a>
<a target="_self" href="{}">Log in to QuartzBio EDP to continue</a>
</h4>
This app requires a SolveBio account. <br>
<a href="mailto:support@solvebio.com">Contact Support</a>
This app requires a QuartzBio account. <br>
<a href="qb-help@precisionformedicine.com">Contact Support</a>
""".format(
authorization_url
),
Expand All @@ -48,6 +51,8 @@ def get_token_from_session(self):
def wrap(self, streamlit_app):
"""SolveBio OAuth2 wrapper around streamlit app"""

logger.info("Wrapping streamlit application")

# SolveBio OAuth2 client
oauth_client = SolveBioOAuth2(self.CLIENT_ID, self.CLIENT_SECRET)
authorization_url = oauth_client.get_authorization_url(
Expand All @@ -56,17 +61,17 @@ def wrap(self, streamlit_app):

# Authorization token from Streamlit session state
oauth_token = self.get_token_from_session()
debug_message = str(oauth_token)[:4] if oauth_token else ""
logger.debug("OAuth token: " + debug_message)

if oauth_token is None:
# User is not authrized to use the app
try:
# Trying to get the authorization token from the url if successfully authorized
code = st.experimental_get_query_params()["code"]
code = st.query_params.get("code")

# Remove authorization token from the url params
params = {}
st.experimental_set_query_params(**params)

st.query_params.clear()
except:
# Display SolveBio login until user is successfully authorized
self.solvebio_login_component(authorization_url)
Expand All @@ -76,10 +81,11 @@ def wrap(self, streamlit_app):
oauth_token = asyncio.run(
oauth_client.get_access_token(code, self.APP_URL)
)
except:
except Exception as e:
st.error(
"This account is not allowed or page was refreshed. Please login again."
"This account is not allowed or page was refreshed. Please login again.",
)
st.error(e)
self.solvebio_login_component(authorization_url)
else:
# Check if token has expired:
Expand Down