-
Notifications
You must be signed in to change notification settings - Fork 1
Keycloak Implementation Guide
KeyCloak is used to handle access authorisation requests for the SIDeR Shared Care Record.
The SIDeR application will pass the KeyCloak token to the FHIR endpoint in the Authorization
header of the request in the format Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1...
. The SSO page in the wiki (https://github.com/Somerset-SIDeR-Programme/SIDeR-interop-patterns/wiki/Single-Sign-On) reflects this. The JWT standard resources on https://jwt.io/introduction/ are generally very good. There’s also a more detailed document at https://tools.ietf.org/html/rfc7519 .
The endpoints will need to verify that the token has been correctly signed and is in date, then map it against the RBAC matrix to check that the token provides access to the route being requested e.g. if the user is an Administrator they should be able to get data from the /Patient
route but not the /Encounter
one. In the event that a user has a valid token but it does not grant access to the resource being requested, the endpoint should return a 403 status. The content of the token payload (and therefore how the role mapping should work) is dictated by the KeyCloak implementation. Black Pear engineers have access to example dev SIDeR KeyCloak tokens but not live ones.
An example dev token payload looks like:
{
"jti": "c2c385cc-7c44-4478-987e-2dc1fa327932",
"exp": 1579717896,
"nbf": 0,
"iat": 1579717596,
"iss": "https://devtest.tst.nhs.uk/auth/realms/SIDER";,
"aud": "sider-dev",
"sub": "e9893505-bc5b-4437-80bc-4b5585b2c753",
"typ": "Bearer",
"azp": "rio-dev",
"auth_time": 0,
"session_state": "d42cb9f6-d327-48c7-9983-8e9398cfe9ab",
"acr": "1",
"scope": "",
"odscode": "RBA",
"sideraccessdev": [
"SIDeR Health and Care Professional"
]
}
The possible values for RBA are: "SIDeR Health and Care Professional" "SIDeR Care Service Administrator" "SIDeR System Administrator"
The "aud" (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected. [https://tools.ietf.org/html/rfc7519#section-4.1.3]
The Keycloak endpoints that will be reflected in the token are as follows:
Dev - https://devtest.tst.nhs.uk/auth/realms/SIDER UAT - https://ssouat.tst.nhs.uk/auth/realms/SIDER Production - https://sso.tst.nhs.uk/auth/realms/SIDER
The certificate endpoints to obtain a JWK to verify the JWT Dev - https://devtest.tst.nhs.uk/auth/realms/SIDER/protocol/openid-connect/certs UAT - https://ssouat.tst.nhs.uk/auth/realms/SIDER/protocol/openid-connect/certs Production - https://sso.tst.nhs.uk/auth/realms/SIDER/protocol/openid-connect/certs
The level and verification that endpoints implement is a decision that each organisation needs to make, but they should do at least some even if it is just verifying the signature is valid. SIDeR would recommend implementing the following:
- Token Signature is valid
- Token comes from a known issuer
- Current date/time is between token
nbf
(not before) andexp
(expiry) date/time - Access claim is present and appropriate to the environment; sideraccessdev (dev), sideraccessuat (UAT) or sideraccessprd (Prod)
- Role within the claim is valid (see RBAC above)
- Role is appropriate to access the information requested
- Token is intended for the consuming endpoint (is the URL of the endpoint in the
aud
array on the token) - Token is signed using an accepted algorithm (or at the very least the algorithm is not “none”)
In addition to this the endpoint should record each request in an audit. Here is an example of the decoded token following the config change.
{
"jti": "b28dd5fe-12c3-4537-9f95-2551062c2757",
"exp": 1583428653,
"nbf": 0,
"iat": 1583428353,
"iss": "https://mph-epruatsso1.tst.nhs.uk/auth/realms/SIDER",
"aud": "sider-dev",
"sub": "0245792b-98bd-4154-94fb-bac9286b674b",
"typ": "Bearer",
"azp": "mh-dev",
"auth_time": 0,
"session_state": "7c822c55-dd8f-44b8-85d8-95210e76ac93",
"acr": "1",
"scope": "profile",
"odscode": "RBA",
"sideraccessdev": [
" SIDeR Health and Care Professional"
],
"name": "Test User Clinical User Clinical Professional",
"preferred_username": "[email protected]",
"given_name": "Test User Clinical",
"family_name": "User Clinical Professional"
}
Here is an example of token verification in NodeJS (from another project): https://github.com/TauntonandSomersetNHSTrust/HealthStorage/blob/master/src/handlers/verify-token.js
Here is an example of the full release of the gateway https://github.com/TauntonandSomersetNHSTrust/FHIRGateway