Skip to content

Commit a2ffa74

Browse files
authored
Merge pull request #34 from inab/feature/mod_auth_openidc
Authenticate at the proxy and remove anonymous users
2 parents d4ce85d + a7ed87d commit a2ffa74

26 files changed

Lines changed: 481 additions & 832 deletions

.env.sample

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
# Configuration applicable across multiple components
33

44
# FOR WINDOWS/WSL USE IP
5-
FQDN_HOST=localhost # or external FQDN
5+
SERVER_DOMAIN_PROTOCOL=http
6+
SERVER_DOMAIN=localhost # or external FQDN
67
NETWORK_NAME=open-vre-network
78

89
# KEYCLOAK CONFIGURATION

.env.sample-prod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
# Configuration applicable across multiple components
33

44
# FOR WINDOWS/WSL USE IP
5-
FQDN_HOST=localhost # or external FQDN
5+
SERVER_DOMAIN_PROTOCOL=https
6+
SERVER_DOMAIN=localhost # or external FQDN
67
NETWORK_NAME=open-vre-network
78

89
# POSTGRES_CONFIGURATION

docker-compose-prod.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ services:
120120
MONGO_MAIN_DB: ${MONGO_MAIN_DB}
121121
MONGO_SERVER: ${MONGO_SERVER}
122122
MONGO_TLS_MODE: ${MONGO_TLS_MODE}
123-
SERVER_DOMAIN: ${FQDN_HOST}
123+
NETWORK_NAME: ${NETWORK_NAME}
124+
SERVER_DOMAIN: ${SERVER_DOMAIN}
125+
SERVER_DOMAIN_PROTOCOL: ${SERVER_DOMAIN_PROTOCOL}
124126
SERVER_PORT: ${FRONTEND_PORT}
125127
VAULT_ADDR: ${VAULT_ADDR}
126128
VAULT_API_VERSION: ${VAULT_API_VERSION}
@@ -132,6 +134,7 @@ services:
132134
- ./front_end/openVRE/public/:/var/www/html/openVRE/public
133135
- ./front_end/openVRE/config:/var/www/html/openVRE/config
134136
- ./front_end/openVRE/data:/var/www/html/openVRE/data
137+
- ./front_end/openVRE/apache/check_tool_access.lua:/opt/docker/etc/httpd/check_tool_access.lua
135138
- ./front_end/openVRE/apache/server.conf:/opt/docker/etc/httpd/conf.d/10-server.conf
136139
- ./tools/front:/var/www/html/openVRE/public/tools
137140
- ./shared_data:/shared_data

docker-compose.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ services:
8181
MONGO_CREDENTIALS: ${MONGO_INITDB_USERNAME}:${MONGO_INITDB_PASSWORD}
8282
MONGO_MAIN_DB: ${MONGO_MAIN_DB}
8383
MONGO_SERVER: ${MONGO_SERVER}
84-
SERVER_DOMAIN: ${FQDN_HOST}
84+
NETWORK_NAME: ${NETWORK_NAME}
85+
SERVER_DOMAIN: ${SERVER_DOMAIN}
8586
SERVER_PORT: ${FRONTEND_PORT}
87+
SERVER_DOMAIN_PROTOCOL: ${SERVER_DOMAIN_PROTOCOL}
8688
VAULT_ADDR: ${VAULT_ADDR}
8789
VAULT_API_VERSION: ${VAULT_API_VERSION}
8890
VAULT_ROLENAME: ${VAULT_ROLENAME}
@@ -92,6 +94,7 @@ services:
9294
- ./front_end/openVRE/public/:/var/www/html/openVRE/public
9395
- ./front_end/openVRE/config:/var/www/html/openVRE/config
9496
- ./front_end/openVRE/data:/var/www/html/openVRE/data
97+
- ./front_end/openVRE/apache/check_tool_access.lua:/opt/docker/etc/httpd/check_tool_access.lua
9598
- ./front_end/openVRE/apache/server.conf:/opt/docker/etc/httpd/conf.d/10-server.conf
9699
- ./tools/front:/var/www/html/openVRE/public/tools/front
97100
- ./shared_data:/shared_data

front_end/Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ FROM webdevops/php-apache:8.3
44
ARG DEBIAN_FRONTEND=noninteractive
55

66
RUN apt-get update
7-
RUN a2enmod proxy proxy_http
87
RUN apt install -y nodejs npm
9-
RUN apt-get install -y autoconf pkg-config libssl-dev
8+
RUN apt-get install -y autoconf pkg-config libssl-dev libapache2-mod-auth-openidc lua5.4 lua-socket
9+
RUN a2enmod proxy proxy_http ssl auth_openidc lua
1010
RUN docker-php-ext-install bcmath
1111
RUN echo "extension=mongodb.so" >> /usr/local/etc/php/conf.d/mongodb.ini
1212
RUN apt install -y docker.io
@@ -52,6 +52,7 @@ USER application
5252

5353
WORKDIR /var/www/html/openVRE/public
5454
RUN pwd
55-
EXPOSE 88 443
55+
EXPOSE 80
56+
# EXPOSE 443
5657

5758
CMD setup.sh && /opt/docker/bin/entrypoint.sh supervisord
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require "apache2"
2+
3+
function check_access(r)
4+
r:err("check_tool_access: START uri=" .. r.uri)
5+
6+
local tool_segment = r.uri:match("^/interactive%-tool/([^/]+)")
7+
if not tool_segment then
8+
r:err("check_tool_access: no tool_segment found, passing through")
9+
return 200
10+
end
11+
r:err("check_tool_access: tool_segment=" .. tool_segment)
12+
13+
local project_id = tool_segment:match("__PROJ.+$")
14+
if not project_id then
15+
r:err("check_tool_access: could not parse project_id from: " .. tool_segment)
16+
return 403
17+
end
18+
r:err("check_tool_access: project_id=" .. project_id)
19+
20+
local user = r.user or ""
21+
r:err("check_tool_access: oidc_user=" .. user)
22+
23+
local handle = io.popen("curl -s -o /dev/null -w '%{http_code}' "
24+
.. "'http://127.0.0.1/checkToolAccess.php"
25+
.. "?project=" .. project_id
26+
.. "&user=" .. user .. "'")
27+
local status = handle:read("*a")
28+
handle:close()
29+
30+
r:err("check_tool_access: http status=" .. tostring(status))
31+
32+
if status == "200" then
33+
return 200
34+
else
35+
r:err("check_tool_access: denied user=" .. user .. " project=" .. project_id)
36+
return 403
37+
end
38+
end

front_end/openVRE/apache/server.conf

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,97 @@
33
DocumentRoot /var/www/html/openVRE/public/
44
DirectoryIndex index.php
55

6-
<Directory "/var/www/html/openVRE/public/api">
7-
AllowOverride All
6+
OIDCXForwardedHeaders X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto
7+
OIDCProviderMetadataURL ${KEYCLOAK_SERVER}/realms/${KEYCLOAK_REALM}/.well-known/openid-configuration
8+
OIDCRedirectURI ${SERVER_DOMAIN_PROTOCOL}://${SERVER_DOMAIN}:${SERVER_PORT}/redirect_uri
9+
OIDCClientID ${KEYCLOAK_CLIENT}
10+
OIDCClientSecret ${KEYCLOAK_SECRET}
11+
OIDCCryptoPassphrase 0123456789
12+
OIDCRemoteUserClaim email
13+
14+
<Location /assets/>
815
Require all granted
9-
</Directory>
16+
</Location>
1017

11-
RewriteEngine On
12-
RewriteRule ^/interactive-tool/([^/]+)/?(.*) http://$1:8787/$2 [P,L]
18+
<Location /htmlib/>
19+
Require all granted
20+
</Location>
1321

14-
<Location /interactive-tool/cbioportal-webapp/>
15-
RequestHeader set X-Forwarded-Prefix "/interactive-tool/cbioportal-webapp"
22+
<Location /logout.php>
23+
Require all granted
1624
</Location>
1725

18-
<Location /interactive-tool/rstudio/>
19-
RequestHeader set X-RStudio-Root-Path "/interactive-tool/rstudio"
26+
<Location /checkToolAccess.php>
27+
AuthType none
28+
Require all granted
2029
</Location>
2130

31+
<Location /interactive-tool/>
32+
AuthType openid-connect
33+
Require valid-user
34+
LuaHookAuthChecker /opt/docker/etc/httpd/check_tool_access.lua check_access
35+
</Location>
36+
37+
<LocationMatch "^(?!^\/logout\.php$|^\/checkToolAccess\.php$|/assets/|/htmlib/)">
38+
AuthType openid-connect
39+
Require valid-user
40+
</LocationMatch>
41+
42+
RewriteRule ^/interactive-tool/([^/]+)/?(.*) http://$1:8787/$2 [P,L]
43+
2244
ErrorLog /var/log/apache/vre-error.log
2345
CustomLog /var/log/apache/vre.log combined
2446
</VirtualHost>
47+
48+
# <VirtualHost *:80>
49+
# ServerName ${SERVER_DOMAIN}
50+
# Redirect permanent / ${SERVER_DOMAIN_PROTOCOL}://${SERVER_DOMAIN}/
51+
# </VirtualHost>
52+
53+
# <VirtualHost *:443>
54+
# ServerName ${SERVER_DOMAIN}
55+
# DocumentRoot /var/www/html/openVRE/public/
56+
# DirectoryIndex index.php
57+
58+
# SSLEngine on
59+
# SSLCertificateFile ${FRONTEND_CERT_PEM}
60+
# SSLCertificateKeyFile ${FRONTEND_CERT_KEY}
61+
62+
# # <Directory "/var/www/html/openVRE/public/api">
63+
# # AllowOverride All
64+
# # Require all granted
65+
# # </Directory>
66+
67+
# <Location /logout.php>
68+
# Require all granted
69+
# </Location>
70+
71+
# <Location /checkToolAccess.php>
72+
# Require all granted
73+
# AuthType none
74+
# </Location>
75+
76+
# <Location /interactive-tool/>
77+
# AuthType openid-connect
78+
# Require valid-user
79+
80+
# LuaHookAuthChecker /opt/docker/etc/httpd/check_tool_access.lua check_access
81+
# </Location>
82+
83+
# <LocationMatch "^(?!^\/logout\.php$|^\/checkToolAccess\.php$)">
84+
# AuthType openid-connect
85+
# Require valid-user
86+
# </LocationMatch>
87+
88+
# ProxyPass "/auth" "http://keycloak:8080"
89+
# ProxyPassReverse "/auth" "http://keycloak:8080"
90+
91+
# RewriteEngine on
92+
93+
# # Generic rule for interactive tools
94+
# RewriteRule ^/interactive-tool/([^/]+)/?(.*) https://$1:8787/$2 [P,L]
95+
96+
# ErrorLog /var/log/apache/vre-error.log
97+
# CustomLog /var/log/apache/vre.log combined
98+
99+
# </VirtualHost>

front_end/openVRE/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"auth0/auth0-php": "^8.0",
55
"chadicus/slim-oauth2": "^3.1",
66
"erusev/parsedown": "^1.7",
7-
"firebase/php-jwt": "^6.11",
7+
"firebase/php-jwt": "^7.0",
88
"guzzlehttp/guzzle": "*",
99
"justinrainbow/json-schema": "^5.2",
1010
"league/oauth2-google": "^2.0",

front_end/openVRE/config/globals.inc.php.sample

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ $GLOBALS['EGA_METADATA_API'] = 'https://metadata.ega-archive.org';
8484

8585

8686
// Default names and local path for VRE
87-
$GLOBALS['URL'] = "https://" . getenv('SERVER_DOMAIN') . $GLOBALS['BASEURL']; // full VRE URL
87+
$GLOBALS['URL'] = getenv('SERVER_DOMAIN_PROTOCOL') . "://" . getenv('SERVER_DOMAIN') . ":" . getenv('SERVER_PORT') . $GLOBALS['BASEURL']; // full VRE URL
8888
$GLOBALS['URL_login'] = $GLOBALS['URL']."login.php"; // Default for auth server login
89+
$GLOBALS['URL_logout'] = $GLOBALS['URL'] . "logout.php"; // Default for auth server logout
8990
$GLOBALS['htmlPath'] = $GLOBALS['root']. "/public/"; // Default path for public folder
9091
$GLOBALS['htmlib'] = $GLOBALS['htmlPath']."htmlib"; // Default path for html templates
9192
$GLOBALS['appsDir'] = $GLOBALS['shared']."apps/soft/"; // Default path for 3rd party soft in validation
@@ -125,7 +126,6 @@ $GLOBALS['ROLES'] = array(
125126
"0"=>"Admin",
126127
"1"=>"Tool Dev.",
127128
"2"=>"Common",
128-
"3" =>"Anonymous"
129129
);
130130
$GLOBALS['NO_GUEST'] = array(0,1,2,100,101); // 100, 101?
131131
$GLOBALS['PREMIUM'] = array(0,1);

front_end/openVRE/public/applib/loginToken.php

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?php
22

3-
require __DIR__ . "/../../config/bootstrap.php";
3+
require_once __DIR__ . "/../../config/bootstrap.php";
44

5+
use League\OAuth2\Client\Token\AccessToken;
56
use OpenVRE\LoggerFactory;
67
use OpenVRE\Oauth2Provider;
78

@@ -18,15 +19,43 @@ function getLoginLogger()
1819
}
1920

2021

21-
// Setting auth server
22-
$provider = new Oauth2Provider(['redirectUri' => $GLOBALS['URL'] . "applib/loginToken.php"]);
22+
if (isset($_SERVER['OIDC_access_token'])) {
23+
getLoginLogger()->info("Get OIDC claims.");
24+
$userInfo = [];
25+
foreach ($_SERVER as $key => $value) {
26+
if (strpos($key, 'OIDC_CLAIM_') === 0) {
27+
$claim = substr($key, strlen('OIDC_CLAIM_'));
28+
$userInfo[$claim] = $value;
29+
}
30+
}
2331

24-
// Get auth code. Redirect user to the authorization URL
25-
if (!isset($_GET['code'])) {
32+
$userToken = [];
33+
$userToken['access_token'] = $_SERVER['OIDC_access_token'];
34+
$userToken['expires'] = $_SERVER['OIDC_access_token_expires'];
35+
$accessToken = new AccessToken($userToken);
2636

37+
$user = getUserById(sanitizeString($_SERVER['OIDC_CLAIM_email']));
38+
if (is_null($user)) {
39+
try {
40+
$user = createUserFromToken($_SERVER['OIDC_CLAIM_email'], $accessToken, $userInfo, false);
41+
getLoginLogger()->info("Created new user from user access token.");
42+
} catch (\Exception $e) {
43+
exit('Login error: failed to create local VRE user: ' . $e->getMessage());
44+
}
45+
}
46+
47+
$user = loadUserWithToken($user, $userInfo, $accessToken);
48+
getLoginLogger()->info("Loaded existing user from access token.");
49+
50+
if ($user) {
51+
redirect("../home/redirect.php");
52+
} else {
53+
redirect($GLOBALS['URL']);
54+
}
55+
} elseif (!isset($_GET['code'])) {
56+
$provider = new Oauth2Provider(['redirectUri' => $GLOBALS['URL'] . "applib/loginToken.php"]);
2757
// Fetch the authorization URL from the provider; returns urlAuthorize and generates state
2858
$authorizationUrl = $provider->getAuthorizationUrl();
29-
getLoginLogger()->info("Redirect user to the authorization URL: " . $authorizationUrl);
3059

3160
header('Location: ' . $authorizationUrl);
3261
exit;
@@ -37,10 +66,9 @@ function getLoginLogger()
3766
if (isset($_SESSION['oauth2state'])) {
3867
unset($_SESSION['oauth2state']);
3968
}
40-
4169
exit('Login error: invalid state. Start login process again, please.');
4270
} else {
43-
71+
$provider = new Oauth2Provider(['redirectUri' => $GLOBALS['URL'] . "applib/loginToken.php"]);
4472
// Get an access token using the authorization code grant.
4573
try {
4674
$accessToken = $provider->getAccessToken('authorization_code', ['code' => $_GET['code']]);
@@ -65,35 +93,6 @@ function getLoginLogger()
6593
redirect("../home/redirect.php");
6694
}
6795

68-
function base64UrlDecode($input)
69-
{
70-
$remainder = strlen($input) % 4;
71-
if ($remainder) {
72-
$padlen = 4 - $remainder;
73-
$input .= str_repeat('=', $padlen);
74-
}
75-
return base64_decode(strtr($input, '-_', '+/'));
76-
}
77-
78-
$_SESSION['allowedDatasetIds'] = [];
79-
if (isset($userInfo['ga4gh_passport_v1'])) {
80-
$gh4ghPassport = $userInfo['ga4gh_passport_v1'];
81-
82-
foreach ($gh4ghPassport as $gh4ghVisaJwt) {
83-
$gh4ghVisaTokenParts = explode(".", $gh4ghVisaJwt);
84-
$gh4ghTokenHeader = base64UrlDecode($gh4ghVisaTokenParts[0]);
85-
$gh4ghTokenPayload = base64UrlDecode($gh4ghVisaTokenParts[1]);
86-
$gh4ghJwtHeader = json_decode($gh4ghTokenHeader);
87-
$gh4ghJwtPayload = json_decode($gh4ghTokenPayload);
88-
89-
if ($gh4ghJwtPayload->ga4gh_visa_v1->type == "ControlledAccessGrants") {
90-
array_push($_SESSION['allowedDatasetIds'], $gh4ghJwtPayload->ga4gh_visa_v1->value);
91-
}
92-
}
93-
94-
getLoginLogger()->info("GA4GH passport obtained from user access token and included into user session info.");
95-
}
96-
9796
// Check if user exists.
9897
$user = getUserById(sanitizeString($userInfo['email']));
9998

0 commit comments

Comments
 (0)