Skip to content

Commit

Permalink
Add Mkdocs site (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
fredhersch authored Nov 29, 2024
1 parent 19447d7 commit 0b8476d
Show file tree
Hide file tree
Showing 21 changed files with 843 additions and 9 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ The requests to the access proxy should have the access token as a Bearer
Authorization header. Based on that, the proxy decides whether to grant access
for a FHIR query.

<img src="doc/summary.png" width=50% alt="Modules involved in FHIR authorization/access-control">
<img src="doc/docs/summary.png" width=50% alt="Modules involved in FHIR authorization/access-control">

For more information on the technical design,
[see the design doc](doc/design.md).
[see the design doc](doc/docs/design.md).

# Modules

Expand Down Expand Up @@ -177,7 +177,7 @@ accessing the proxy from an Android emulator, which runs on a separate network.
GCP note: if this is not on a VM with proper service account (e.g., on a local
host), you need to pass GCP credentials to it, for example by mapping the
`.config/gcloud` volume (i.e., add `-v ~/.config/gcloud:/root/.config/gcloud` to
the above command).
the docker command).

# How to use this proxy

Expand Down
1 change: 1 addition & 0 deletions doc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
site/**
2 changes: 2 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
To generate the documentation web-site content from `docs/` see instructions
[here](https://github.com/google/fhir-data-pipes/tree/master/doc#documentation-site).
201 changes: 201 additions & 0 deletions doc/docs/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Concepts

## Common Terminologies

These are some common terminologies that are important when dealing with access
control in general:

| Term | Description |
|---------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
| Authentication and Identity Provider (IDP) | Who the user is. Establishing the identity can be done through a shared service (e.g., Google, GitHub) or a special one. |
| Authorization (AuthZ) | Given the identity, what can a user access? Has context specific pieces (e.g., scopes) |
| Access-control | How to make sure users access authorized resources only. This is the **core focus of the info gateway**. |
| Client app | An app which needs to access FHIR resources on behalf of a user. |
| User | The user that is using the app; this is the identity being "authenticated". |
| Access Token | A JWT that is provided as a Bearer token when accessing FHIR resources. |
| OAuth2.0 | A standard to grant access to an application on behalf of a user. |
| [SMART-on-FHIR](https://hl7.org/fhir/smart-app-launch/) | Defines workflows that an application can use to securely request and access FHIR data. |

The following picture helps to visualise the relationship of these concepts.
A client app (e.g., a SMART-on-FHIR app) should first use a process to fetch an
_"access token"_ from the IDP+AuthZ service. For example, this process might
be OAuth's
[Authorization Code Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow).
This token is then provided on each request to the access-control gateway when
accessing FHIR resources.

![FHIR Info Gateway](images/Info_Gateway_Overview.png)

## Info Gateway Modules

The Info Gateway consists of a core, which is in
the [`server`](https://github.com/google/fhir-gateway/tree/main/server) module,
and a set of _access-checker_ plugins, which can be implemented by third parties
and added to the proxy server. Two sample plugins are implemented in the
[`plugins`](https://github.com/google/fhir-gateway/tree/main/plugins) module.

There is also a sample
[`exec`](https://github.com/google/fhir-gateway/tree/main/exec) module which
shows how all pieces can be woven together into a single Spring Boot app. It
also has examples for implementing custom end-points.

**Notes:**

* [1] Spring Boot is not a requirement for using FHIR Info Gateway; we just use
it to simplify the
[MainApp](https://github.com/google/fhir-gateway/tree/main/exec/src/main/java/com/google/fhir/gateway/MainApp.java).
* [2] The only Spring-related requirement is to do a
[@ComponentScan](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html)
to find all access-checker plugins in the classpath.

## Configuration parameters

The configuration parameters are provided through environment variables:

- `PROXY_TO`: The base url of the FHIR server e.g.:
```shell
export PROXY_TO=https://example.com/fhir
```

- `TOKEN_ISSUER`: The URL of the access token issuer, e.g.:
```shell
export TOKEN_ISSUER=http://localhost:9080/auth/realms/test
```
The above example is based on the default config of a test IDP+AuthZ
[Keycloak](https://www.keycloak.org/) server. To see how this server is
configured, check the
[docker/keycloak](docker/https://github.com/google/fhir-gateway/tree/main/docker/keycloak)
directory. If you want to use a SMART-on-FHIR (SoF) app use this realm instead
which is based on Keycloak's
[SoF extension](https://github.com/Alvearie/keycloak-extensions-for-fhir):
```shell
export TOKEN_ISSUER=http://localhost:9080/auth/realms/test-smart
```

- `ACCESS_CHECKER`: The access-checker to use. Each access-checker has a name
(see [plugins](https://github.com/google/fhir-gateway/tree/main/plugins) for
details) and this variable should be set to the name of the plugin to use. For
example, to use one of the sample plugins use one of:
```shell
export ACCESS_CHECKER=list
export ACCESS_CHECKER=patient
```
For more information on how access-checkers work and building your own,
see [section on access checkers](#access-checkers).

- `ALLOWED_QUERIES_FILE`: A list of URL requests that should bypass the access
checker and always be allowed.
[`AllowedQueriesChecker`](https://github.com/google/fhir-gateway/blob/main/server/src/main/java/com/google/fhir/gateway/AllowedQueriesChecker.java)
compares the incoming request with a configured set of allowed-queries. The
intended use of this checker is to override all other access-checkers for
certain user-defined criteria. The user defines their criteria in a config
file and if the URL query matches an entry in the config file, access is
granted. [`AllowedQueriesConfig`](https://github.com/google/fhir-gateway/blob/main/server/src/main/java/com/google/fhir/gateway/AllowedQueriesConfig.java)
shows all the supported configurations. An example config file is
[`hapi_page_url_allowed_queries.json`](https://github.com/google/fhir-gateway/blob/main/resources/hapi_page_url_allowed_queries.json).
To use this file with `ALLOWED_QUERIES_FILE`:
```shell
export ALLOWED_QUERIES_FILE="resources/hapi_page_url_allowed_queries.json"
```

- `BACKEND_TYPE`: The type of backend, either `HAPI` or `GCP`. `HAPI` should be
used for most FHIR servers, while `GCP` should be used for GCP FHIR stores.

## Access Checkers

FHIR Info Gateway uses _access checker plugins_ to define the logic it uses to
make decisions for access requests. Most users should create an access checker
plugin to implement the access control logic for a specific use case. You can
learn about access checker plugins by looking at the sample access checker
[plugins](https://github.com/google/fhir-gateway/tree/main/plugins/src/main/java/com/google/fhir/gateway/plugin).

See tutorial on
[creating an access checker plugin](tutorial_first_access_checker.md). The core
of FHIR Info Gateway, provides libraries that make it easier to create
access-checkers. For example,
[PatientFinder](https://github.com/google/fhir-gateway/blob/main/server/src/main/java/com/google/fhir/gateway/interfaces/PatientFinder.java)
can be used to limit access to a certain set of patients.

### Patient access checker plugin
The [`PatientAccessChecker` plugin](https://github.com/google/fhir-gateway/blob/main/plugins/src/main/java/com/google/fhir/gateway/plugin/PatientAccessChecker.java)
can be used if the client is a SMART-on-FHIR app that uses the
[standalone app launch flow](https://www.hl7.org/fhir/smart-app-launch/app-launch.html#launch-app-standalone-launch).
It expects a `patient_id` claim in the access-token and limits access to FHIR
resources that belong to that patient. It supports
[SoF scopes](https://www.hl7.org/fhir/smart-app-launch/scopes-and-launch-context.html#scopes-for-requesting-clinical-data)
(both v1 and v2).

### Explore the List access checker plugin

The [`ListAccessChecker` plugin](https://github.com/google/fhir-gateway/blob/main/plugins/src/main/java/com/google/fhir/gateway/plugin/ListAccessChecker.java)
is a simple example of list-based access control. It works by assigning each
user a [FHIR `List` resource](https://www.hl7.org/fhir/list.html) which contains
a list of references of `Patient` resources that the user should have access to.
When a client makes a request to FHIR Information Gateway,
the `ListAccessChecker` grants access if all patients that are referenced in
the query are on the user's patient access list.

The plugin expects the patient `List` resource's ID to be included as the value
to a claim named `patient_list` in the access token used to authorize requests
to the FHIR Information Gateway server. For example, following the
[test Docker deployment](https://github.com/google/fhir-access-proxy/wiki/Try-out-FHIR-Information-Gateway)
you may get a decoded JWT like the following (note if you use the default
settings you will get more claims that are not relevant to the access-checker
logic; so they are removed in this example):

```json
{
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "MnXk25Vp_W6X_UMi4sA3_iEMwuumZkwhOuE8eMY8LFo"
},
"payload": {
"exp": 1673990497,
"iat": 1673990197,
"jti": "5bb2b1a0-e9c6-442f-abfd-a22f1798fd11",
"iss": "http://localhost:9080/auth/realms/test",
"aud": "account",
"sub": "76315cd1-9681-4a4e-b733-e6d811058e40",
"typ": "Bearer",
"azp": "my-fhir-client",
"session_state": "967e82a2-0188-4774-abbc-6bb4ce26536f",
"acr": "1",
"scope": "email profile",
"sid": "967e82a2-0188-4774-abbc-6bb4ce26536f",
"email_verified": false,
"patient_list": "patient-list-example",
"preferred_username": "testuser",
"group": [
"fhirUser"
]
}
}
```

Here `patient_list` equals `patient-list-example`, so if your FHIR server is
at `http://localhost:8099/fhir/` then this user's patient access list resource
is `http://localhost:8099/fhir/List/patient-list-example`.

The decoded JWT is passed to the
[`AccessCheckerFactory`](https://github.com/google/fhir-gateway/blob/main/server/src/main/java/com/google/fhir/gateway/interfaces/AccessCheckerFactory.java)
implementation's `create()` function. The `ListAccessChecker` implementation
extracts the patient list ID from the JWT and saves it internally. Custom JWT
claims in the access token can be a good way to pass additional information to
your access checker beyond what your authentication server provides.

`ListAccessChecker`'s
[`checkAccess`](https://github.com/google/fhir-gateway/blob/19447d7152804d2b790f22cc44ad3b1ca21c7040/plugins/src/main/java/com/google/fhir/gateway/plugin/ListAccessChecker.java#L157)
function splits access logic according to the HTTP method. Simple yes/no access
decisions like `processGet()` use the
[`NoOpAccessDecision`](https://github.com/google/fhir-gateway/blob/main/server/src/main/java/com/google/fhir/gateway/interfaces/NoOpAccessDecision.java)
class which you may also use in your own implementations. Alternatively, you may
have more complex decision needs, such as doing additional processing after the
data access like
[`processPost()`](https://github.com/google/fhir-gateway/blob/19447d7152804d2b790f22cc44ad3b1ca21c7040/plugins/src/main/java/com/google/fhir/gateway/plugin/ListAccessChecker.java#L202).
In this case, implement your own version of
[`AccessDecision`](https://github.com/google/fhir-access-proxy/blob/main/server/src/main/java/com/google/fhir/gateway/interfaces/AccessDecision.java).
The `ListAccessChecker` allows clients to create new `Patient` resources without
restriction (always allow access), and then as a post-processing step adds the
new Patient id to the client's patient access list. You can see this implemented
in [`AccessGrantedAndUpdateList`](https://github.com/google/fhir-access-proxy/blob/main/plugins/src/main/java/com/google/fhir/gateway/plugin/AccessGrantedAndUpdateList.java).
31 changes: 31 additions & 0 deletions doc/docs/contribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# How to Contribute

We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement (CLA). You (or your employer) retain the copyright to your
contribution; this simply gives us permission to use and redistribute your
contributions as part of the project. Head over
to <https://cla.developers.google.com/> to see your current agreements on file
or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted
one (even if it was for a different project), you probably don't need to do it
again.

## Code reviews

All code changes require review. We use GitHub pull-requests for this purpose.

* Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/)
for more information on using pull requests.

* We use GitHub for issue tracking.

## Community Guidelines

This project
follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
10 changes: 4 additions & 6 deletions doc/design.md → doc/docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ For more context, please see the [Introduction](#introduction) section.
Here is a summary of proposals and decisions in this design document, for the
first version (V1) of the FHIR gateway:

<img src="summary.png" width=50% height=50%>
![High-level Architecture](images/summary.png)

- There are three main components responsible for access decisions: an Identity
Provider (IDP) which authenticates the user, an Authorization server (AuthZ)
Expand Down Expand Up @@ -198,8 +198,6 @@ sometimes referred to as the Identity and Access Management (IAM) or simply
We also have an "access gateway" which is responsible for processing any access
request for the FHIR server and is the main focus of this design doc.

<img src="summary.png" width=50% height=50%>

### Authentication and authorization flow

Before the user can access data, their identity should be established and based
Expand All @@ -226,7 +224,7 @@ to use
[PKCE](https://auth0.com/docs/authorization/flows/authorization-code-flow-with-proof-key-for-code-exchange-pkce)
which is not shown in this diagram)[^1]:

<img src="flow.png">
![flow](images/flow.png)

Here is a brief description of each step:

Expand Down Expand Up @@ -265,7 +263,7 @@ to AuthZ which in turn maps the user identity to some access rules to FHIR
resources. Popular IAM servers like [Keycloak](https://www.keycloak.org/),
support separate/3rd party IDPs.

<img src="separate.png" width=50% height=50%>
![separate](images/separate.png)

**Integrated AuthZ+Gateway**

Expand All @@ -277,7 +275,7 @@ simplifies the deployment architecture significantly, however we note that the
elimination of the access token might be incompatible with some use-cases like
SoF apps.

<img src="integrated.png" width=50% height=50%>
![integrated](images/integrated.png)

## Access gateway

Expand Down
Loading

0 comments on commit 0b8476d

Please sign in to comment.