Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OIDC Auth via OAuth2-proxy #14

Merged
merged 9 commits into from
Feb 10, 2025
Merged
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
20 changes: 10 additions & 10 deletions dev/alive/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
"Enabled": true,
"URI": "https://www.github.com"
"URI": "LEAF_LOGOUT_URI"
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
21 changes: 11 additions & 10 deletions dev/alive/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ services:
LEAF_APP_DB: Server=alive-mssql,1433;Database=LeafDB;uid=sa;Password=${MSSQL_SA_PASSWORD}
LEAF_CLIN_DB: Server=clin-db,3306;Database=alive;uid=db-user;Password=${MYSQL_PASSWORD};Pooling=false
labels:
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt
# https://leafdocs.rit.uw.edu/installation/installation_steps/9_saml2/#route-protection-setup
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && Path(`/api/user`)
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME},leaf-groups-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && PathPrefix(`/api`) && !Path(`/api/user`)
- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
node:
labels:
- traefik.enable=true
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`)
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && !PathPrefix(`/api`)
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
volumes:
leaf-alive-mssql:
2 changes: 2 additions & 0 deletions dev/common-services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ services:
- internal

coreapi:
environment:
LEAF_LOGOUT_URI: https://${LEAF_DOMAIN}/oauth2/sign_out
image: ghcr.io/uwcirg/leaf-api:${LEAF_API_IMAGE_TAG:-latest}
build:
context: ../src/leaf/src/server
Expand Down
8 changes: 8 additions & 0 deletions dev/default.env
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ HYMTRUTH_JWT_KEY_PW=
MASH_JWT_KEY_PW=
MSTUDY_JWT_KEY_PW=
RADAR_JWT_KEY_PW=

# generate via: python3 -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'
ivan-c marked this conversation as resolved.
Show resolved Hide resolved
OAUTH2_PROXY_COOKIE_SECRET=

# obtain from Keycloak/OIDC provider
OAUTH2_PROXY_CLIENT_ID=
OAUTH2_PROXY_CLIENT_SECRET=
OAUTH2_PROXY_OIDC_ISSUER_URL=
20 changes: 10 additions & 10 deletions dev/gateway/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
"Enabled": true,
"URI": "https://www.github.com"
"URI": "LEAF_LOGOUT_URI"
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
223 changes: 223 additions & 0 deletions dev/gateway/config/auth-proxy/templates/sign_in.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
{{define "sign_in.html"}}
<!DOCTYPE html>
<html lang="en" charset="utf-8">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<title>Sign In HIV SUCCESS Data Query Tool</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css"
/>

<style>
:root {
--primary-color: #0057ff;
--primary-dark-color: #003bac;
--secondary-color: #009959;
}
html,
body {
height: 100vh;
}
body {
display: flex;
flex-direction: column;
}
section.main {
flex: 2;
}
.title {
font-size: 2.4rem;
margin-bottom: 8px;
}
button {
border-radius: 50vwh;
text-transform: uppercase;
}
button.is-primary {
background-color: var(--primary-dark-color) !important;
font-size: 1.2rem;
border-radius: 12px;
max-width: 100%;
word-break: break-word;
white-space: normal;
line-height: 1.2;
}
.logo-box img {
width: 26%;
display: block;
margin: auto;
min-width: 240px;
}
#sideBar {
background: linear-gradient(
120deg,
var(--primary-dark-color) 4.69%,
var(--primary-color) 40.63%,
var(--secondary-color) 95.31%
);
color: #fff;
cursor: default;
position: fixed;
top: 0;
overflow-x: hidden;
overflow-y: auto;
text-align: right;
z-index: 10000;
width: 100%;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
text-transform: uppercase;
font-weight: 400;
}
.sign-in-box {
max-width: 80%;
margin: 1rem auto;
text-align: left;
}
.sign-in-box p:not(:last-of-type) {
margin-bottom: 8px;
}
.logo-box {
margin: 1.2rem 3rem;
}
.button-container {
margin-top: 8px;
}
footer {
padding: 8px !important;
}
footer a {
text-decoration: underline;
}
</style>
</head>
<body class="has-background-light">
<section id="sideBar">HIV SUCCESS data query tool</section>
<section class="main section has-background-light">
<div class="box block sign-in-box">
{{ if .LogoData }}
<div class="block logo-box">{{.LogoData}}</div>
{{ end }}

<form method="GET" action="{{.ProxyPrefix}}/start">
<input type="hidden" name="rd" value="{{.Redirect}}" />
<h1 class="title has-text-centered">
Welcome to the HIV SUCCESS Data Query Tool
</h1>
<p>
HIV SUCCESS is the consortium of NIDA substance use and HIV cohorts.
Data across all cohorts is harmonized and available for use by
others for cross cohort analyses to support research and
organizations for planning and understanding the HIV and substance
use syndemics.
</p>
<p>
This data query tool allows prospective data users to determine if
data of interest might be available for future analyses. For the
protection of participants, only aggregated data are shown for
groups of 10 or more people. For further access to data, please
complete and submit an HIV SUCCESS concept proposal for review.
(Form can be found
<a href="https://hivsuccess.uw.edu/data.html" target="_blank"
>here</a
>.)
</p>
<p>
All users are asked to login using their Google or UW Net ID
accounts or register through our system. We collect details on
names and emails to help with password support and organization/
institution to understand who views our data. All information are
held securely and confidentially. User information is not shared
outside of HIV SUCCESS with the exception of aggregated information
on what types of organizations and geographic regions view the data.
</p>
<br />
<div class="has-text-centered button-container">
<button type="submit" class="button block is-primary">
Sign in to HIV SUCCESS data query tool
</button>
</div>
<br />
</form>

{{ if .CustomLogin }}
<hr />

<form method="POST" action="{{.ProxyPrefix}}/sign_in" class="block">
<input type="hidden" name="rd" value="{{.Redirect}}" />

<div class="field">
<label class="label" for="username">Username</label>
<div class="control">
<input
class="input"
type="text"
placeholder="e.g. [email protected]"
name="username"
id="username"
/>
</div>
</div>

<div class="field">
<label class="label" for="password">Password</label>
<div class="control">
<input
class="input"
type="password"
placeholder="********"
name="password"
id="password"
/>
</div>
</div>
<button class="button is-primary">Sign in</button>
</form>
{{ end }}
</div>
</section>

<script>
if (window.location.hash) {
(function () {
var inputs = document.getElementsByName("rd");
for (var i = 0; i < inputs.length; i++) {
// Add hash, but make sure it is only added once
var idx = inputs[i].value.indexOf("#");
if (idx >= 0) {
// Remove existing hash from URL
inputs[i].value = inputs[i].value.substr(0, idx);
}
inputs[i].value += window.location.hash;
}
})();
}
</script>

<footer class="footer has-text-grey has-background-light is-size-7">
<div class="content has-text-centered">
{{ if eq .Footer "-" }} {{ else if eq .Footer ""}}
<p>
Secured with
<a
href="https://github.com/oauth2-proxy/oauth2-proxy#oauth2_proxy"
class="has-text-grey"
>OAuth2 Proxy</a
>
version {{.Version}}
</p>
{{ else }}
<p>{{.Footer}}</p>
{{ end }}
</div>
</footer>
</body>
</html>
{{end}}
Loading