Skip to content

Commit

Permalink
Ensure sso access token is always refreshed on expiry (#1933)
Browse files Browse the repository at this point in the history
* improve background polling error handling

* add docker folder to debug SSO

* move error handling into the routerless read call

* extra layer of reconnection handling

* add e2e for single sign on

* update snapshots

* reduce flakyness

* remove outdated connectivity loss filter
OskarDamkjaer authored Sep 8, 2023
1 parent d74a15a commit 1b37e03
Showing 18 changed files with 1,069 additions and 47 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/pr-sso-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: 'Browser PR single sign on tests'

on:
pull_request:
branches: [master]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- run: npm -g install yarn serve
- run: yarn install --frozen-lockfile
- run: yarn build
- run: sudo apt-get update
- run: sudo apt-get -y install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
- name: Setup Keycloak and Neo4j
working-directory: ./docker/sso-keycloak
run: docker-compose -f docker-compose.yml up -d --remove-orphans
- name: Wait for Keycloak and Neo4j config containers to finish
run: sleep 90
- run: npx serve -l 8080 dist & npm run wait-on-neo4j && yarn wait-on-dev
- run: echo "Servers ready!"
- run: yarn e2e-sso
- name: Upload test screenshots
if: failure()
uses: actions/upload-artifact@v3
with:
name: test-screenshots-sso
path: |
./e2e_tests/screenshots
./e2e_tests/videos
6 changes: 6 additions & 0 deletions docker/sso-keycloak/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
NEO4J_VERSION=4.4.9-enterprise
NEO4J_PASSWORD=password
KEYCLOAK_VERSION=19.0.1
KEYCLOAK_ADMIN_USER=admin
KEYCLOAK_ADMIN_PASSWORD=password
KEYCLOAK_CONFIG_VERSION=latest-19.0.3
81 changes: 81 additions & 0 deletions docker/sso-keycloak/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
version: '3.7'
services:
neo4j:
image: neo4j:${NEO4J_VERSION}
ports:
- '7474:7474'
- '7687:7687'
environment:
- NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
- NEO4J_AUTH=neo4j/${NEO4J_PASSWORD:-password}
- NEO4J_dbms_connector_bolt_advertised__address=0.0.0.0:7687
- NEO4J_apoc_trigger_enabled=true
- NEO4J_dbms_security_authentication__providers=oidc-keycloak,native
- NEO4J_dbms_security_authorization__providers=oidc-keycloak,native
- NEO4J_dbms_security_oidc_keycloak_display__name=Keycloak
- NEO4J_dbms_security_oidc_keycloak_.auth__flow=pkce
- NEO4J_dbms_security_oidc_keycloak_auth__endpoint=http://127.0.0.1:8180/realms/my-realm/protocol/openid-connect/auth
- NEO4J_dbms_security_oidc_keycloak_token__endpoint=http://127.0.0.1:8180/realms/my-realm/protocol/openid-connect/token
- NEO4J_dbms_security_oidc_keycloak_jwks__uri=http://keycloak:8180/realms/my-realm/protocol/openid-connect/certs
- NEO4J_dbms_security_oidc_keycloak_params=client_id=neo4j-sso;response_type=code;scope=openid email roles
- NEO4J_dbms_security_oidc_keycloak_audience=account
- NEO4J_dbms_security_oidc_keycloak_issuer=http://127.0.0.1:8180/realms/my-realm
- NEO4J_dbms_security_oidc_keycloak_client__id=neo4j-sso
- NEO4J_dbms_security_oidc_keycloak_claims_username=preferred_username
- NEO4J_dbms_security_oidc_keycloak_claims_groups=roles
- NEO4J_browser_allow__outgoing__connections=false
volumes:
- 'neo4j_data:/data'
neo4j-config-cli:
image: graphaware/neo4j-config-cli:2.5.0
environment:
- NEO4J_USER=neo4j
- NEO4J_PASSWORD=password
- NEO4J_URI=bolt://neo4j:7687
- IMPORT_PATH=/config
volumes:
- './resources/neo4j-config:/config'
keycloak:
image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}
environment:
- KEYCLOAK_ADMIN=${KEYCLOAK_ADMIN_USER}
- KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
- KC_DB_URL=jdbc:postgresql://postgres/keycloak
- KC_DB_USERNAME=keycloak
- KC_DB_PASSWORD=password
- KC_HTTP_ENBALED=true
- KC_HTTP_PORT=8180
- KC_HOSTNAME=127.0.0.1
- KC_HOSTNAME_PORT=8180
- KC_HOSTNAME_ADMIN=localhost
command:
- start-dev --db=postgres
ports:
- '8180:8180'
depends_on:
- postgres
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
command: -p 5432
expose:
- '5433' # Publishes 5433 to other containers but NOT to host machine
volumes:
- 'keycloak_data:/var/lib/postgresql@15/data'
keycloak-config:
image: adorsys/keycloak-config-cli:${KEYCLOAK_CONFIG_VERSION}
environment:
- KEYCLOAK_URL=http://keycloak:8180
- KEYCLOAK_USER=admin
- KEYCLOAK_PASSWORD=password
- KEYCLOAK_AVAILABILITYCHECK_ENABLED=true
- KEYCLOAK_AVAILABILITYCHECK_TIMEOUT=90s
- IMPORT_PATH=/config
volumes:
- ./resources/keycloak-config:/config
volumes:
neo4j_data:
keycloak_data:
141 changes: 141 additions & 0 deletions docker/sso-keycloak/resources/keycloak-config/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"enabled": true,
"realm": "my-realm",
"users": [
{
"username": "admin",
"email": "dave.lister@example.com",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password"
}
],
"clientRoles": {
"neo4j-sso": ["admin"]
}
},
{
"username": "analyst",
"email": "analyst@example.com",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password"
}
],
"clientRoles": {
"neo4j-sso": ["analyst"]
}
}
],
"roles": {
"realm": [],
"client": {
"neo4j-sso": [
{
"name": "admin",
"description": "neo4j admin role",
"composite": false,
"clientRole": true,
"attributes": {}
},
{
"name": "analyst",
"description": "neo4j analyst role",
"composite": false,
"clientRole": true,
"attributes": {}
}
]
}
},
"clients": [
{
"clientId": "neo4j-sso",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"redirectUris": ["*"],
"webOrigins": ["*"],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": true,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {
"saml.assertion.signature": "false",
"id.token.as.detached.signature": "false",
"saml.multivalued.roles": "false",
"saml.force.post.binding": "false",
"saml.encrypt": "false",
"oauth2.device.authorization.grant.enabled": "true",
"backchannel.logout.revoke.offline.tokens": "false",
"saml.server.signature": "false",
"saml.server.signature.keyinfo.ext": "false",
"use.refresh.tokens": "true",
"exclude.session.state.from.auth.response": "false",
"oidc.ciba.grant.enabled": "false",
"saml.artifact.binding": "false",
"backchannel.logout.session.required": "true",
"client_credentials.use_refresh_token": "false",
"saml_force_name_id_format": "false",
"saml.client.signature": "false",
"tls.client.certificate.bound.access.tokens": "false",
"require.pushed.authorization.requests": "false",
"saml.authnstatement": "false",
"display.on.consent.screen": "false",
"saml.onetimeuse.condition": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"protocolMappers": [
{
"name": "client-roles-to-roles-claim",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-client-role-mapper",
"consentRequired": false,
"config": {
"multivalued": "true",
"userinfo.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "roles",
"jsonType.label": "String",
"usermodel.clientRoleMapping.clientId": "neo4j-sso"
}
},
{
"name": "username",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-property-mapper",
"consentRequired": false,
"config": {
"userinfo.token.claim": "true",
"user.attribute": "username",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "email",
"jsonType.label": "String"
}
}
],
"defaultClientScopes": ["web-origins", "roles", "profile", "email"],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
]
}
]
}
16 changes: 16 additions & 0 deletions docker/sso-keycloak/resources/neo4j-config/admin-db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"kind": "Database",
"name": "admins",
"dropIfExists": true,
"skipCreate": false,
"indexes": {
"fulltext": [
{
"labels": ["Person"],
"properties": ["name"],
"name": "Person"
}
]
},
"seeds": ["admins.cypher"]
}
1 change: 1 addition & 0 deletions docker/sso-keycloak/resources/neo4j-config/admins.cypher
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE (n:Admin {name: "Dave Lister"});
24 changes: 24 additions & 0 deletions docker/sso-keycloak/resources/neo4j-config/movies-db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"kind": "Database",
"name": "movies",
"dropIfExists": true,
"skipCreate": false,
"indexes": {
"fulltext": [
{
"labels": ["Person"],
"properties": ["name"],
"name": "Person"
}
]
},
"constraints": {
"unique": [
{
"label": "Movie",
"property": "title"
}
]
},
"seeds": ["movies.cypher"]
}
Loading
Oops, something went wrong.

0 comments on commit 1b37e03

Please sign in to comment.