/orthanc-auth-service

Web service to run next to orthanc to handle sharing of studies

Primary LanguagePythonGNU Affero General Public License v3.0AGPL-3.0

REUSE status

orthanc-auth-service

This repository contains web services to run next to orthanc to handle user permissions through an integration with Keycloak and secure sharing of studies by issuing JWT that can then be passed in authorization headers. The HTTP headers are then checked by the Orthanc authorization plugin to validate the access.

These web services integrates with Orthanc Explorer 2.

This initial solution for study sharing has been presented at OrthancCon 2022. The user permissions handling was not available at that time.

Features:

Sharing a study in OE2

Release notes

Check the release notes.

Users and roles management

There are 2 different locations to consider for users and roles management:

  • the Keycloak management interface
  • the configuration file

Manage users and roles in Keycloak interface

The first step is the creation of users in keycloak web app (http://localhost/keycloak/), the Keycloak official documentation will give you all the information. The current setup comes with 2 pre-defined users:

  • orthanc
  • doctor

And 2 pre-defined roles:

  • admin: this role is assigned to the orthanc user
  • doctor: this role is assigned to the doctor user

Manage permissions in the configuration file

The last step is the binding between roles and permissions. This is done in the permissions.json file. Here is the default file:

{
  "roles" : {
    "admin": ["all"],
    "doctor": ["view", "download", "share", "send"]
  }
}

This file has to be provided to the orthanc-auth-service container via the env var PERMISSIONS_FILE_PATH. Here is the list of available permissions:

all
view
download
delete
send
modify
anonymize
upload
q-r-remote-modalities
settings
api-view
share

These permissions are also configured in the Orthanc authorization plugin (in the Authorization.Permissions configuration). The default configuration is suitable to work with this sample.

how it works (internals) ?

  • orthanc-auth-service is a web service that generates token to grant access to a particular study in Orthanc.
    • You must configure the orthanc-auth-service web-service by providing these environment variables (or Docker secrets)
      • SECRET_KEY is a high entropy text that will be used to encode and decode the JWT
      • To enable orthanc standard shares (without anonymization):
        • PUBLIC_ORTHANC_ROOT is the root url of the public Orthanc
        • PUBLIC_LANDING_ROOT is the url of a OE2 page that will display a message to the user when the token has expired or is invalid
        • SERVER_ID is the identifier defined in the Authorization plugin configuration of the standard Orthanc (optional)
      • USERS is an optional environment variable that should contain a json array of allowed usernames/passwords to access the service.
        {
          "user1": "pwd1",
          "user2": "pwd2"
        }
        If not defined, the token-service is available without authentication. If you expose the web-service publicly, you should always configure authentication.
  • A script or application requests the orthanc-auth-service to generate such a token via the Rest API:
curl -X PUT http://localhost:8000/tokens/stone-viewer-publication -H 'Content-Type: application/json' \
  -d '{"id": "toto",
       "resources" : [{
         "dicom-uid": "1.2",
         "level": "study"
       }],
       "type": "stone-viewer-publication", 
       "expiration-date": "2026-12-31T11:00:00Z"}'

Note that a user that is authenticated to Orthanc and that has the permission to access this url can also call the auth-plugin directly with an orthanc flavored API call:

curl -X PUT http://localhost:8042/auth/tokens/stone-viewer-publication -H 'Content-Type: application/json' \
  -d '{"ID": "toto",
       "Resources" : [{
         "DicomUid": "1.2",
         "OrthancId": "",
         "Level": "study"
       }],
       "Type": "stone-viewer-publication", 
       "ExpirationDate": "2026-12-31T11:00:00Z"}'
  • the orthanc-auth-service replies with a share with the token and a link to the viewer:
  {
    "request":{
      "id":"toto",
      "resources" : [
        {
          "dicom-uid": "1.2"
        }],  
      "type":"stone-viewer-publication",
      "expiration-date":"2026-07-07T11:00:00+00:00"
    },
    "token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6InRvdG8iLCJyZXNvdXJjZXMiOlt7ImRpY29tX3VpZCI6IjEuMiIsIm9ydGhhbmNfaWQiOm51bGwsInVybCI6bnVsbCwibGV2ZWwiOiJzdHVkeSJ9XSwidHlwZSI6InN0b25lLXZpZXdlci1wdWJsaWNhdGlvbiIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMjYtMTItMzFUMTE6MDA6MDArMDA6MDAifQ.RlB9x56eQSaJNt3t4hDxAHdM7BhBbah5CWWBBZQf7x0",
    "url":"http://localhost/ui/app/token-landing.html?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6InRvdG8iLCJyZXNvdXJjZXMiOlt7ImRpY29tX3VpZCI6IjEuMiIsIm9ydGhhbmNfaWQiOm51bGwsInVybCI6bnVsbCwibGV2ZWwiOiJzdHVkeSJ9XSwidHlwZSI6InN0b25lLXZpZXdlci1wdWJsaWNhdGlvbiIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMjYtMTItMzFUMTE6MDA6MDArMDA6MDAifQ.RlB9x56eQSaJNt3t4hDxAHdM7BhBbah5CWWBBZQf7x0"
  }
  • once the users clicks on this link, the token-landing page will check the token validity and redirect the browser to the Stone Viewer

  • once the Viewer tries to access the study, the authorization plugin will issue a request to orthanc-auth-service to validate the token. Since orthanc-auth-service is the only one to know the secret key, it is able to validate the token to grant access to this particular study.

  • sample request issued to orthanc-auth-service to validate a token

curl -X POST http://localhost:8000/tokens/validate -H 'token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6InRvdG8iLCJyZXNvdXJjZXMiOlt7ImRpY29tX3VpZCI6IjEuMiIsIm9ydGhhbmNfaWQiOm51bGwsInVybCI6bnVsbCwibGV2ZWwiOiJzdHVkeSJ9XSwidHlwZSI6InN0b25lLXZpZXdlci1wdWJsaWNhdGlvbiIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMjYtMTItMzFUMTE6MDA6MDArMDA6MDAifQ.RlB9x56eQSaJNt3t4hDxAHdM7BhBbah5CWWBBZQf7x0' \
  -H 'Content-Type: application/json' \
  -d '{"dicom-uid": "1.2", 
       "orthanc-id": "0195f13e-4afe6822-8b494cc4-5162c50d-0daf66aa",
       "server-id": "server-id", 
       "level": "study", 
       "method": "get"}'
  • in response, the orthanc-auth-service will reply with this payload (required by the authorization plugin):
  {
    "granted":false,
    "validity":60
  }

Working with MedDream

  • If you want to generate links to MedDream Viewer, you should also define:
    • MEDDREAM_TOKEN_SERVICE_URL is the url of the MedDream token web service (MedDream has its own webservice to generate short term tokens)
    • PUBLIC_MEDDREAM_ROOT is the public root url where the MedDream Viewer can be accessed
  • A script or application requests the orthanc-auth-service to generate such a token via the Rest API:
curl -X PUT http://localhost:8000/tokens/meddream-instant-link -H 'Content-Type: application/json' \
-d '{"id": "toto",
       "resources" : [{
         "dicom-uid": "1.2.276.0.37.1.322.201502.11033927",
         "level": "study"
       }],
       "type": "meddream-instant-link", 
       "expiration-date": "2026-12-31T11:00:00Z"}'

Allowed values for type are meddream-instant-link and meddream-viewer-publication. The expiration-date is never used for meddream-instant-link since the validity is actually configured in the MedDream Token Service. Route has to be adapted to fit the type, for a publication: curl -X PUT http://localhost:8000/tokens/meddream-viewer-publication...

  • if generating a meddream-instant-link, orthanc-auth-service replies with a share with the token and a link to the MedDream viewer that shall be opened directly after (within a few minutes):
{
  "request":{
    "id":"demo-1",
    "resources":[{
      "dicom-uid":"1.2.276.0.37.1.322.201502.11033927",
      "orthanc-id":null,
      "url":null,
      "level":"study"
    }],
    "type":"meddream-instant-link",
    "expiration-date":null,
    "validity-duration":null},
  "token":"7VwozctM_1wdeYTyhCaSLi_PfVU7sn9ZVDd2h6Ilo7SlhZAinEa-oFFdfzeNN8J9zCWGEGTHsy0hqPishc7eLg-kqgx9N5LqNT5hZl8LTXAxL3zTIw4=",
  "url":"http://localhost/meddream/?study=1.2.276.0.37.1.322.201502.11033927&token=7VwozctM_1wdeYTyhCaSLi_PfVU7sn9ZVDd2h6Ilo7SlhZAinEa-oFFdfzeNN8J9zCWGEGTHsy0hqPishc7eLg-kqgx9N5LqNT5hZl8LTXAxL3zTIw4="
}
  • if generating a meddream-viewer-publication, orthanc-auth-service replies with a share with the token and a link to the token-landing page that will, once accessed, generate a new MedDream token that can be used within a few minutes:
{
  "request":{
    "id":"demo-1",
    "resources":[{
      "dicom-uid":"1.2.276.0.37.1.322.201502.11033927",
      "orthanc-id":null,
      "url":null,
      "level":"study"}],
    "type":"meddream-viewer-publication",
    "expiration-date":null,
    "validity-duration":null},
  "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImRlbW8tMSIsInJlc291cmNlcyI6W3siZGljb21fdWlkIjoiMS4yLjI3Ni4wLjM3LjEuMzIyLjIwMTUwMi4xMTAzMzkyNyIsIm9ydGhhbmNfaWQiOm51bGwsInVybCI6bnVsbCwibGV2ZWwiOiJzdHVkeSJ9XSwidHlwZSI6Im1lZGRyZWFtLXZpZXdlci1wdWJsaWNhdGlvbiIsImV4cGlyYXRpb25fZGF0ZSI6bnVsbCwidmFsaWRpdHlfZHVyYXRpb24iOm51bGx9.a2189RYDjlPueJ8QkquJylVJCOXDRyCltGcalnkyJQM",
  "url":"http://localhost/orthanc/ui/app/token-landing.html?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImRlbW8tMSIsInJlc291cmNlcyI6W3siZGljb21fdWlkIjoiMS4yLjI3Ni4wLjM3LjEuMzIyLjIwMTUwMi4xMTAzMzkyNyIsIm9ydGhhbmNfaWQiOm51bGwsInVybCI6bnVsbCwibGV2ZWwiOiJzdHVkeSJ9XSwidHlwZSI6Im1lZGRyZWFtLXZpZXdlci1wdWJsaWNhdGlvbiIsImV4cGlyYXRpb25fZGF0ZSI6bnVsbCwidmFsaWRpdHlfZHVyYXRpb24iOm51bGx9.a2189RYDjlPueJ8QkquJylVJCOXDRyCltGcalnkyJQM"
}
  • once the user tries to access the provided url, the token-landing page will reply with an HTTP redirect response redirecting the browser to the MedDreamViewer with a new token that is valid for a few minutes only.

updating settings (internals) ?

Specific users with the right permissions can read/update the permissions configuration directly from OE2, through the authorization-plugin that forwards the call to the orthanc-auth-service

curl -u share-user:change-me http://localhost:8000/settings/roles
curl -u share-user:change-me -H "Content-Type: application/json" http://localhost:8000/settings/roles -d '{"roles":{"admin-role":{"authorized-labels":["*"],"permissions":["all"]},"doctor-role":{"authorized-labels":["*"],"permissions":["view","download","share","send"]},"external-role":{"authorized-labels":["external"],"permissions":["view","download"]}},"available-labels":[]}'