Skip to content

Commit

Permalink
add google iap middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv committed Dec 6, 2023
1 parent eea3eef commit 2cbd694
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 8 deletions.
Empty file.
114 changes: 114 additions & 0 deletions plugins/quetz_googleiap/quetz_googleiap/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import logging
import uuid

from starlette.middleware.base import BaseHTTPMiddleware

import quetz.authentication.base as auth_base
from quetz import rest_models
from quetz.config import Config, ConfigEntry, ConfigSection
from quetz.dao import Dao
from quetz.deps import get_config, get_db

logger = logging.getLogger("quetz.googleiam")


def email_to_channel_name(email):
name = email.split("@")[0]
name = name.replace(".", "-")
name = name.replace("_", "-")
return name


class GoogleIAMMiddleware(BaseHTTPMiddleware):
"""
Handles Google IAM headers and authorizes users based on the
Google IAM headers.
"""

def __init__(self, app, config: Config):
if config is not None:
self.configure(config)
self.last_checked = dict()
super().__init__(app)

def configure(self, config: Config):
config.register(
[
ConfigSection(
"googleiam",
[
ConfigEntry("server_admin_emails", list, default=[]),
],
)
]
)

# load configuration values
if config.configured_section("googleiam"):
self.server_admin_emails = config.googleiam_server_admin_emails
else:
raise Exception("Google IAM is not configured")

async def dispatch(self, request, call_next):
# Check if the session has a specific key, for example 'count'.
# If it does, increment its value. If it doesn't, set it to 1.
count = request.session.get("count", 0)
request.session["count"] = count + 1

db = next(get_db(get_config()))
dao = Dao(db)

user_id = request.headers.get("x-goog-authenticated-user-id")
email = request.headers.get("x-goog-authenticated-user-email")

if user_id and email:
_, email = email.split(":", 1)
_, user_id = user_id.split(":", 1)

user = dao.get_user_by_username(email)
if not user:
email_data: auth_base.Email = {
"email": email,
"verified": True,
"primary": True,
}
user = dao.create_user_with_profile(
email, "google", user_id, email, "", None, True, [email_data]
)
user_channel = email_to_channel_name(email)

logger.info(f"Creating channel for user: {user_channel}")
if dao.get_channel(email_to_channel_name(user_channel)) is None:
channel = rest_models.Channel(
name=user_channel,
private=False,
description="Channel for user: " + email,
)
dao.create_channel(channel, user.id, "owner")

self.google_role_for_user(user_id, dao)

# we also need to find the role of the user
request.session['identity_provider'] = "dummy"
request.session["user_id"] = str(uuid.UUID(bytes=user.id))
else:
request.session["user_id"] = None
request.session["identity_provider"] = None

response = await call_next(request)
return response

def google_role_for_user(self, user_id, dao):
if not user_id:
return

if user_id in self.server_admin_emails:
logger.info(f"User {user_id} is server admin")
dao.set_user_role(user_id, "owner")
else:
logger.info(f"User {user_id} is not a server admin")
dao.set_user_role(user_id, "member")


def middleware():
return GoogleIAMMiddleware
14 changes: 14 additions & 0 deletions plugins/quetz_googleiap/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from setuptools import setup

plugin_name = "quetz-googleiap"

setup(
name=plugin_name,
install_requires=[],
entry_points={
"quetz.middlewares": [f"{plugin_name} = quetz_googleiap.middleware"],
},
packages=[
"quetz_googleiap",
],
)
20 changes: 12 additions & 8 deletions quetz/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,6 @@

logger = logging.getLogger("quetz")

app.add_middleware(
SessionMiddleware,
secret_key=config.session_secret,
https_only=config.session_https_only,
)

if config.general_redirect_http_to_https:
logger.info("Configuring http to https redirect ")
app.add_middleware(HTTPSRedirectMiddleware)
Expand Down Expand Up @@ -163,6 +157,18 @@ async def dispatch(self, request, call_next):

app.add_middleware(CondaTokenMiddleware)

plugin_middlewares: List[Type[BaseHTTPMiddleware]] = [
ep.load() for ep in entry_points().select(group='quetz.middlewares')
]

for middleware in plugin_middlewares:
app.add_middleware(middleware.middleware(), config=config)

app.add_middleware(
SessionMiddleware,
secret_key=config.session_secret,
https_only=config.session_https_only,
)

if config.configured_section("profiling") and config.profiling_enable_sampling:
from pyinstrument.profiler import Profiler
Expand All @@ -187,8 +193,6 @@ async def profile_request(
pkgstore = config.get_package_store()

# authenticators


builtin_authenticators: List[Type[BaseAuthenticator]] = [
authenticator
for authenticator in [
Expand Down

0 comments on commit 2cbd694

Please sign in to comment.