Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Mkdocs site #299

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions doc/docs/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# 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., “sign in with” Google, GitHub) |
| Authorization | 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. The **core focus of the info gateway** |
| oAuth2.0 | A standard to grant access to an application on behalf of a user |
| SMART-on-FHIR | Defines a workflow that an application can use to securely request access to FHIR data, and then receive and use that data |

## 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` module which shows how all pieces can be woven together into a single Spring Boot app.

**Notes:**

* [1]Spring Boot is not a requirement for using FHIR Info Gateway; we just use it to simplify the [MainApp](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 store 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://github.com/Alvearie/keycloak-extensions-for-fhir) 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 app use this realm instead:

```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 include 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) provides all the supported configurations. An example of this 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 `List` access checker plugin example (provided).

See tutorial on [creating an access checker plugin](tutorial_first_access_checker.md)

### Explore the List access checker plugin

The [`ListAccessChecker` plugin](https://github.com/google/fhir-access-proxy/blob/main/plugins/src/main/java/com/google/fhir/proxy/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 the request contains or references at least one `Patient` on that 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 decoded JWT of 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 access token like the following:


```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",
"realm_access":
{
"roles":
[
"default-roles-test",
"offline_access",
"uma_authorization"
]
},
"resource_access":
{
"account":
{
"roles":
[
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"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 client's patient access list resource is `http://localhost:8099/fhir/List/patient-list-example`.

The decoded JWT is passed to your `AccessCheckerFactory` 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` 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()`. 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).
21 changes: 21 additions & 0 deletions doc/docs/contribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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 submissions by non-project members, 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/).
File renamed without changes.
File renamed without changes.
109 changes: 109 additions & 0 deletions doc/docs/getting_started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Getting Started

!!! tip "Quick Start Guide"

The easiest way to get started is to follow the ["Run the Info Gateway in Docker" guide](getting_started_docker.md).

## Building from source
The proxy 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` module which shows how all pieces can be woven together into a single Spring Boot app.

To build all modules, from the root run:

```shell
mvn package -Dspotless.apply.skip=true
```

The server and the plugins can be run together through this executable jar (
`--server.port` is just one of the many default Spring Boot flags):

```shell
java -jar exec/target/exec-0.1.0.jar --server.port=8081
```

Note that extra access-checker plugins can be added through the `loader.path` property (although it is probably easier to build them into your server):

```shell
java -Dloader.path="PATH-TO-ADDITIONAL-PLUGINGS/custom-plugins.jar" \
-jar exec/target/exec-0.1.0.jar --server.port=8081
```

The plugin library can be swapped with any third party access-checker as described in the [plugins](https://github.com/google/fhir-gateway/tree/main/plugins) directory. Learn more about [AccessCheckers](concepts.md#access-checkers)


## Gateway to server access
The proxy must be able to send FHIR queries to the FHIR server. The FHIR server must be configured to accept connections from the proxy while rejecting most other requests.

If you use a [GCP FHIR store](https://cloud.google.com/healthcare-api/docs/concepts/fhir) you have the following options:

- If you have access to the FHIR store, you can use your own credentials by
doing [application-default login](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login). This is useful when testing the proxy on your local machine, and you have access to the FHIR server through your credentials.

- Use a service account with required access (e.g., "Healthcare FHIR Resource Reader", "Healthcare Dataset Viewer", "Healthcare FHIR Store Viewer"). You can then run the proxy in the same GCP project on a VM with this service account.

- [not-recommended] You can create and download a key file for the above service account, then use it with:

```shell
export GOOGLE_APPLICATION_CREDENTIALS="PATH_TO_THE_JSON_KEY_FILE"
```

## Running the proxy server
Once you have set all the above, you can run the proxy server. The sample `exec` module uses [Apache Tomcat](https://tomcat.apache.org/) through [Spring Boot](https://spring.io/projects/spring-boot) and the usual configuration parameters apply, e.g., to run on port 8081:

```shell
java -jar exec/target/exec-0.1.0.jar --server.port=8081
```

Note if the `TOKEN_ISSUER` is on the `localhost` you may need to bypass proxy's token issuer check by setting `RUN_MODE=DEV` environment variable if you are accessing the proxy from an Android emulator, which runs on a separate network.

[Try the proxy with test servers in Docker](https://github.com/google/fhir-gateway/wiki/Try-out-FHIR-Information-Gateway).

GCP note: if this is not on a VM with proper service account (e.g., on a localhost), 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).

## As a docker image
The proxy is also available as a docker image:

```shell
$ docker run -p 8081:8080 -e TOKEN_ISSUER=[token_issuer_url] \
-e PROXY_TO=[fhir_server_url] -e ACCESS_CHECKER=list \
us-docker.pkg.dev/fhir-proxy-build/stable/fhir-gateway:latest
```

Note if the TOKEN_ISSUER is on the localhost you may need to bypass proxy's token issuer check by setting RUN_MODE=DEV environment variable if you are accessing the proxy from an Android emulator, which runs on a separate network.

Try the proxy with test servers in Docker, see the [Getting Started with Docker tutorial](getting_started_docker.md)

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).

## Using the Info Gateway
Once the proxy is running, we first need to fetch an access token from the `TOKEN_ISSUER`; you need the test `username` and `password` plus the
`client_id`:

```shell
$ curl -X POST -d 'client_id=CLIENT_ID' -d 'username=testuser' \
-d 'password=testpass' -d 'grant_type=password' \
"http://localhost:9080/auth/realms/test/protocol/openid-connect/token"
```

We need the `access_token` of the returned JSON to be able to convince the proxy to authorize our FHIR requests (there is also a `refresh_token` in the above response). Assuming this is stored in the `ACCESS_TOKEN` environment variable, we can access the FHIR store:

```shell
$ curl -X GET -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json; charset=utf-8" \
'http://localhost:8081/Patient/f16b5191-af47-4c5a-b9ca-71e0a4365824'
```

```shell
$ curl -X PUT -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json; charset=utf-8" \
'http://localhost:8081/Patient/f16b5191-af47-4c5a-b9ca-71e0a4365824' \
-d @Patient_f16b5191-af47-4c5a-b9ca-71e0a4365824_modified.json
```

Of course, whether a query is accepted or denied, depends on the access-checker used and the `ACCESS_TOKEN` claims.

For example:

* For `ACCESS_CHECKER=list` there should be a `patient_list` claim which is the ID of a `List` FHIR resource with all the patients that this user has access to.
* For `ACCESS_CHECKER=patient`, there should be a `patient_id` claim with a valid Patient resource ID.
Binary file added doc/docs/images/Info_Gateway_Overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/docs/images/Info_Gateway_Use_Cases.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions doc/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# FHIR Info Gateway
The Info Gateway is a reverse proxy which controls client access to FHIR resources on a server by checking requests for authorization to a FHIR URL or search query.

It makes it easier for developers to enforce organizational role based access control (RBAC) policies when working with FHIR data.

* The Info Gateway enables authorization (AT) and access-control (ACL) between a client application and a FHIR server when used along with any OpenID Connect compliant Identity Provider (IdP) and Authorization server (AuthZ).
* It currently supports Keycloak as the IDP+AuthZ provider and has been tested with HAPI FHIR and Google Cloud Healthcare API FHIR store as the FHIR server.

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

## Key Features
Key features of the Info Gateway features include:

* A stand-alone service that can work with any FHIR compliant servers (e.g., a HAPI FHIR server, GCP FHIR store, etc.)
* A pluggable architecture for defining an access-checkers to allow for implementation configurability
* Query filtering to block/allow specific queries such as for disabling joins

## Common use cases
The Info Gateway is designed to solve for a generic problem, that is, access control for **any client**.

Common use cases include:

1. Web based dashboard used by program admins

2. For a mobile app used by commnunity based frontline health workers possibly with offline support

3. For a personal health record app used by patients or care-givers

4. To enable SMART-on-FHIR for patient or system level scopes

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

31 changes: 31 additions & 0 deletions doc/docs/release_process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Semantic versioning

Versioning across all Open Health Stack components is based on the major.minor.patch scheme and respects Semantic Versioning.

Respecting Semantic Versioning is important for multiple reasons:

* It guarantees simple minor version upgrades, as long as you only use the public APIs
* A new major version is an opportunity to thoroughly document breaking changes
* A new major/minor version is an opportunity to communicate new features through a blog post

## Major versions
The major version number is incremented on every breaking change.

Whenever a new major version is released, we publish:

* a blog post with feature highlights, major bug fixes, breaking changes, and upgrade instructions.
* an exhaustive changelog entry via the release notes

## Minor versions
The minor version number is incremented on every significant retro-compatible change.

Whenever a new minor version is released, we publish:

* an exhaustive changelog entry via the release notes

## Patch versions
The patch version number is incremented on bugfixes releases.

Whenever a new patch version is released, we publish:

* an exhaustive changelog entry
Loading
Loading