Thanks for your quick response Bruno!
The flow of my traffic goes like this:
1) User enters
https://commentconext.com/protected/dashboard/ in their
browser.
2)
Commentconext.com resolves to a public IP that points to a VM on
DigitalOcean where I run Docker.
3) The traffic hits Nginx proxy that handles the HTTPS traffic and then
makes the traffic HTTP for the rest of the flow.
4) The traffic hits Gatekeeper, and if needed, Gatekeeper authenticates
with Keycloak which I have hosted on another VM on DigitalOcean where I
also run Docker.
5) KeyCloak, if needed, authenticates with the identity provider(Google).
6) Gatekeeper proxies my traffic to
http://webapp
I am running Keycloak and Gatekeeper in docker containers. Below is the
configuration of both:
Keycloak docker config:
version: '3'
services:
keycloak:
container_name: keycloak
image: jboss/keycloak
container_name: keycloak
restart: always
ports:
- 0.0.0.0:8080:8080
environment:
DB_DATABASE: ${DB_DATABASE}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
JDBC_PARAMS: ${JDBC_PARAMS}
KEYCLOAK_HOSTNAME: ${KEYCLOAK_HOSTNAME}
KEYCLOAK_HTTP_PORT: ${KEYCLOAK_HTTP_PORT}
KEYCLOAK_USER: ${KEYCLOAK_USER}
KEYCLOAK_PASSWORD: ${KEYCLOAK_PASSWORD}
VIRTUAL_HOST: ${VIRTUAL_HOST}
VIRTUAL_PORT: ${VIRTUAL_PORT}
PROXY_ADDRESS_FORWARDING: ${PROXY_ADDRESS_FORWARDING}
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
depends_on:
- postgres
Here is my .env file, that sets the environment variables above:
DB_DATABASE=keycloak_db
DB_USER=keycloak_db_user
DB_PASSWORD="<snip>"
KEYCLOAK_HOSTNAME=auth.clearauth.com
KEYCLOAK_HTTP_PORT=8080
KEYCLOAK_USER=admin
KEYCLOAK_PASSWORD="<snip>"
JDBC_PARAMS="ssl=false"
PROXY_ADDRESS_FORWARDING=true
VIRTUAL_HOST=auth.clearauth.com
VIRTUAL_PORT=8080
Gatekeeper docker config:
gatekeeper:
container_name: gatekeeper
restart: always
image: keycloak/keycloak-gatekeeper:latest
ports:
- 0.0.0.0:3001:3001
environment:
VIRTUAL_HOST: ${VIRTUAL_HOST}
VIRTUAL_PORT: ${VIRTUAL_PORT}
LETSENCRYPT_HOST: ${LETSENCRYPT_HOST}
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
volumes:
- ./conf/gatekeeper.yml:/etc/gatekeeper.yml
depends_on:
- letsencrypt
- nginx-proxy
- webapp
command: --config /etc/gatekeeper.yml
Here is my .env file, that sets the environment variables above:
VIRTUAL_HOST=commentcontext.com
VIRTUAL_PORT=3001
LETSENCRYPT_HOST=commentcontext.com
LETSENCRYPT_EMAIL=certs(a)commentcontext.com
Here is my gatekeeper.yml file:
discovery-url:
http://auth.clearauth.com/auth/realms/user
client-id: context
client-secret: <snip>
listen: 0.0.0.0:3001
enable-token-header: false
enable-authorization-header: false
http-only-cookie: true
enable-refresh-tokens: true
enable-logging: true
enable-json-logging: true
enable-encrypted-token: false
no-redirects: false
redirection-url:
https://commentcontext.com/
encryption-key: <snip>
cookie-access-name: sso-token
cookie-refresh-name: sso-refresh
upstream-url:
http://webapp
upstream-keepalives: true
skip-upstream-tls-verify: true
enable-security-filter: true
headers:
myheader_name: my_header_value
resources:
- uri: /protected/*
methods:
- GET
- uri: /*
methods:
- PUT
Below are the logs from Gatekeeper under several different scenarios:
Logs from gatekeeper during successful attempt from desktop(chrome):
{"level":"error","ts":1568035870.989644,"msg":"no
session found in request,
redirecting for authorization","error":"authentication session not
found"}
{"level":"info","ts":1568035870.990942,"msg":"client
request","latency":0.004156151,"status":307,"bytes":95,"client_ip":"
192.168.64.3:55072","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568035871.037399,"msg":"client
request","latency":0.000132817,"status":307,"bytes":296,"client_ip":"
192.168.64.3:55074","method":"GET","path":"/oauth/authorize"}
{"level":"info","ts":1568035895.414867,"msg":"issuing
access token for
user","email":"nick@nickpowers.info
","expires":"2019-09-09T13:36:35Z","duration":"4m59.585136403s"}
{"level":"info","ts":1568035895.4164033,"msg":"client
request","latency":0.165521442,"status":307,"bytes":57,"client_ip":"
192.168.64.3:55076","method":"GET","path":"/oauth/callback"}
{"level":"info","ts":1568035896.4183657,"msg":"client
request","latency":0.954246584,"status":200,"bytes":159843,"client_ip":"
192.168.64.3:55080","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568035896.5251906,"msg":"client
request","latency":0.00505199,"status":200,"bytes":6341,"client_ip":"
192.168.64.3:55110
","method":"GET","path":"/protected/dashboard/styles/extras.1.3.1.min.css"}
{"level":"info","ts":1568035896.5272646,"msg":"client
request","latency":0.00889763,"status":200,"bytes":1208,"client_ip":"
192.168.64.3:55112
","method":"GET","path":"/protected/dashboard/images/shards-dashboards-logo.svg"}
{"level":"info","ts":1568035896.6020262,"msg":"client
request","latency":0.082489547,"status":200,"bytes":805628,"client_ip":"
192.168.64.3:55108
","method":"GET","path":"/protected/dashboard/styles/shards-dashboards.1.3.1.css"}
{"level":"info","ts":1568035896.7910855,"msg":"client
request","latency":0.009341256,"status":200,"bytes":8807,"client_ip":"
192.168.64.3:55124
","method":"GET","path":"/protected/dashboard/scripts/app/app-analytics-overview.1.3.1.js"}
{"level":"info","ts":1568035896.7940302,"msg":"client
request","latency":0.011186249,"status":200,"bytes":3898,"client_ip":"
192.168.64.3:55120
","method":"GET","path":"/protected/dashboard/scripts/extras.1.3.1.min.js"}
{"level":"info","ts":1568035896.7954087,"msg":"client
request","latency":0.011887251,"status":200,"bytes":6614,"client_ip":"
192.168.64.3:55122
","method":"GET","path":"/protected/dashboard/scripts/shards-dashboards.1.3.1.min.js"}
{"level":"info","ts":1568035897.4635108,"msg":"client
request","latency":0.001947231,"status":404,"bytes":281,"client_ip":"
192.168.64.3:55132","method":"GET","path":"/favicon.ico"}
Logs from gatekeeper during unsuccessful attempt from desktop(chrome), this
is from a redirect in the app, after the successful login above.
{"level":"info","ts":1568036254.6685731,"msg":"client
request","latency":0.551675736,"status":302,"bytes":0,"client_ip":"
192.168.64.3:55272","method":"GET","path":"/protected/dashboard/delete.php"}
Here is the delete.php, that calls the redirect that seems to cause this
issue. It works fine, as long as I have the correct REFERER and it doesn't
need to do the redirect. But, if I just type the link in directly, so it
doesn't have a REFERER then it hits that header("Location:
/protected/dashboard"); which should redirect to
https://commentcontext.com/protected/dashboard but instead it sends me to
https://webapp/protected/dashboard. To me this seems to indicate that
Gatekeeper cannot proxy the redirect.
<?php require_once '../include/YouTube.php';
if( 'https://commentcontext.com/protected/dashboard/index.php' !=
$_SERVER['HTTP_REFERER'] ) {
#
# Invalid location, refresh to dashboard
#
header("Location: /protected/dashboard");
exit;
}
#
# Delete comment from youtube
#
$youtube->comments->delete($_POST["commentId"]);
echo "comment deleted<br>";
Logs from Gatekeeper when trying to connect from my tablet (android
chrome). NOTE: this failed every attempt up until now, when I just tried
it actually sent me to my site, like it should. I'm not sure what changed.
{"level":"error","ts":1568036488.9318864,"msg":"no
session found in
request, redirecting for authorization","error":"authentication
session not
found"}
{"level":"info","ts":1568036488.933154,"msg":"client
request","latency":0.00135279,"status":307,"bytes":95,"client_ip":"
192.168.64.3:55284","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568036488.9949393,"msg":"client
request","latency":0.00016756,"status":307,"bytes":296,"client_ip":"
192.168.64.3:55286","method":"GET","path":"/oauth/authorize"}
{"level":"info","ts":1568036496.060338,"msg":"issuing
access token for
user","email":"nick@nickpowers.info
","expires":"2019-09-09T13:46:36Z","duration":"4m59.939664871s"}
{"level":"info","ts":1568036496.0613837,"msg":"client
request","latency":0.047718755,"status":307,"bytes":57,"client_ip":"
192.168.64.3:55288","method":"GET","path":"/oauth/callback"}
{"level":"info","ts":1568036496.7325685,"msg":"client
request","latency":0.597993206,"status":200,"bytes":159843,"client_ip":"
192.168.64.3:55292","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568036496.933339,"msg":"client
request","latency":0.008060276,"status":200,"bytes":6341,"client_ip":"
192.168.64.3:55324
","method":"GET","path":"/protected/dashboard/styles/extras.1.3.1.min.css"}
{"level":"info","ts":1568036496.9355507,"msg":"client
request","latency":0.011554557,"status":200,"bytes":1208,"client_ip":"
192.168.64.3:55326
","method":"GET","path":"/protected/dashboard/images/shards-dashboards-logo.svg"}
{"level":"info","ts":1568036496.9998045,"msg":"client
request","latency":0.080612073,"status":200,"bytes":805628,"client_ip":"
192.168.64.3:55320
","method":"GET","path":"/protected/dashboard/styles/shards-dashboards.1.3.1.css"}
{"level":"info","ts":1568036497.2263498,"msg":"client
request","latency":0.006648847,"status":200,"bytes":3898,"client_ip":"
192.168.64.3:55332
","method":"GET","path":"/protected/dashboard/scripts/extras.1.3.1.min.js"}
{"level":"info","ts":1568036497.231792,"msg":"client
request","latency":0.01331805,"status":200,"bytes":6614,"client_ip":"
192.168.64.3:55334
","method":"GET","path":"/protected/dashboard/scripts/shards-dashboards.1.3.1.min.js"}
{"level":"info","ts":1568036497.2363207,"msg":"client
request","latency":0.006584008,"status":200,"bytes":8807,"client_ip":"
192.168.64.3:55340
","method":"GET","path":"/protected/dashboard/scripts/app/app-analytics-overview.1.3.1.js"}
{"level":"info","ts":1568036498.20545,"msg":"client
request","latency":0.00212513,"status":404,"bytes":281,"client_ip":"
192.168.64.3:55344","method":"GET","path":"/favicon.ico"}
{"level":"error","ts":1568036488.9318864,"msg":"no
session found in
request, redirecting for authorization","error":"authentication
session not
found"}
{"level":"info","ts":1568036488.933154,"msg":"client
request","latency":0.00135279,"status":307,"bytes":95,"client_ip":"
192.168.64.3:55284","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568036488.9949393,"msg":"client
request","latency":0.00016756,"status":307,"bytes":296,"client_ip":"
192.168.64.3:55286","method":"GET","path":"/oauth/authorize"}
{"level":"info","ts":1568036496.060338,"msg":"issuing
access token for
user","email":"nick@nickpowers.info
","expires":"2019-09-09T13:46:36Z","duration":"4m59.939664871s"}
{"level":"info","ts":1568036496.0613837,"msg":"client
request","latency":0.047718755,"status":307,"bytes":57,"client_ip":"
192.168.64.3:55288","method":"GET","path":"/oauth/callback"}
{"level":"info","ts":1568036496.7325685,"msg":"client
request","latency":0.597993206,"status":200,"bytes":159843,"client_ip":"
192.168.64.3:55292","method":"GET","path":"/protected/dashboard/"}
{"level":"info","ts":1568036496.933339,"msg":"client
request","latency":0.008060276,"status":200,"bytes":6341,"client_ip":"
192.168.64.3:55324
","method":"GET","path":"/protected/dashboard/styles/extras.1.3.1.min.css"}
{"level":"info","ts":1568036496.9355507,"msg":"client
request","latency":0.011554557,"status":200,"bytes":1208,"client_ip":"
192.168.64.3:55326
","method":"GET","path":"/protected/dashboard/images/shards-dashboards-logo.svg"}
{"level":"info","ts":1568036496.9998045,"msg":"client
request","latency":0.080612073,"status":200,"bytes":805628,"client_ip":"
192.168.64.3:55320
","method":"GET","path":"/protected/dashboard/styles/shards-dashboards.1.3.1.css"}
{"level":"info","ts":1568036497.2263498,"msg":"client
request","latency":0.006648847,"status":200,"bytes":3898,"client_ip":"
192.168.64.3:55332
","method":"GET","path":"/protected/dashboard/scripts/extras.1.3.1.min.js"}
{"level":"info","ts":1568036497.231792,"msg":"client
request","latency":0.01331805,"status":200,"bytes":6614,"client_ip":"
192.168.64.3:55334
","method":"GET","path":"/protected/dashboard/scripts/shards-dashboards.1.3.1.min.js"}
{"level":"info","ts":1568036497.2363207,"msg":"client
request","latency":0.006584008,"status":200,"bytes":8807,"client_ip":"
192.168.64.3:55340
","method":"GET","path":"/protected/dashboard/scripts/app/app-analytics-overview.1.3.1.js"}
{"level":"info","ts":1568036498.20545,"msg":"client
request","latency":0.00212513,"status":404,"bytes":281,"client_ip":"
192.168.64.3:55344","method":"GET","path":"/favicon.ico"}
Please let me know if you would like to see any other info on this.
Thank you so much! :)
Nick
On Mon, Sep 9, 2019 at 3:30 AM Bruno Oliveira <bruno(a)abstractj.org> wrote:
Hi Nick,
I've never seen this behavior before, in order to understand exactly
what's going on would be nice to have a Jira in place describing the
whole scenario, the steps to reproduce and also code snippets if
possible.
The more details you provide the better.
On 2019-09-07, Nick Powers wrote:
> I have Keycloak and Gatekeeper configured to use Google as an identity
> provider to front end my PHP application and most of the time it works
> great but sometimes it exposes my internal host (which Gatekeeper should
be
> proxying for). If I login from my desktop(chrome) it works fine unless
> instead of clicking on a link my app tries to use a redirect header.
i.e.
> my PHP example: header("Location: /protected/dashboard"); When that
> happens instead of redirecting to
>
https://commentcontext.com/protected/dashboard, like it should, I see
>
https://webapp/protected/dashboard in the URL field. This fails because
> there is no DNS for webapp. webapp is the name I use internally and it
> should never be exposed externally. Also, if I try to connect using my
> phone or tablet (both android) I get through the Google authentication
fine
> but then it tries to send me to
https://webapp/protected/dashboard,
which
> again is a FAIL :(
>
> Why is Gatekeeper failing to proxy sessions when initiated via a redirect
> or when they come from mobile browser? Has anyone seen this behavior
> before? Any help anyone could provide on this issue would be greatly
> appreciated.
>
> Thanks,
>
> Nick
> _______________________________________________
> keycloak-user mailing list
> keycloak-user(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/keycloak-user
--
abstractj