Skip to content

Commit

Permalink
add markdown formatter to pom.xml (#7)
Browse files Browse the repository at this point in the history
* add markdown formatter

Co-authored-by: Omar Ismail <[email protected]>
  • Loading branch information
omarismail94 and omarismail94 authored Jun 15, 2022
1 parent c2d588e commit 522934c
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 103 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ again.

## Code reviews

All submissions by non-project members, require review. We
use GitHub pull requests for this purpose. Consult
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.

Expand Down
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

FROM adoptopenjdk/maven-openjdk11

RUN apt-get update && apt-get install -y nodejs npm
RUN npm cache clean -f && npm install -g n && n stable

WORKDIR /app

ENV PROXY_PORT=8080
Expand Down
117 changes: 69 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,47 @@ etc.) and controls access to FHIR resources.

The authorization and access-control have three components; one of them is this
access proxy. The other two are an Identity Provider (IDP) and an Authorization
server (AuthZ). The responsibility of this pair is to authenticate
the user and issue access tokens (in JWT format and using authorization flow of
OAuth 2.0). 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.
server (AuthZ). The responsibility of this pair is to authenticate the user and
issue access tokens (in JWT format and using authorization flow of OAuth 2.0).
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.

![Modules involved in FHIR authorization/access-control](resources/fhir_access_proxy.png)

The initial design doc for this work is available
[here](https://docs.google.com/document/d/14YnCTzsaTj-WGWIV_VF5QERl5_XV2UriHwtnor0FKoo/edit).

<!--- TODO: create a public version of this doc. --->

# Modules
The proxy consists of a core, which is in the [server](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

The proxy consists of a core, which is in the [server](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](plugins) module. To build both modules, from the root run:

```shell
mvn package
```

This creates an executable server and a plugin jar which can be run together:

```shell
java -Dloader.path="plugins/target/plugins-0.1.0.jar" \
-jar server/target/server-0.1.0-exec.jar --server.port=8081
```

The plugin library can be swapped with any third party access-checker as
described in the [plugins](plugins) directory. If you prefer to combine
everything into a single standalone jar, you can do:

```shell
mvn package -Pstandalone-app
```

and then run:

```shell
java -jar plugins/target/plugins-0.0.1-exec.jar --server.port=8081
```
Expand All @@ -49,83 +58,94 @@ java -jar plugins/target/plugins-0.0.1-exec.jar --server.port=8081
The proxy configuration parameters are currently provided through environment
variables:

- **FHIR store location**: This is set by `PROXY_TO` environment
variable, using the base url of the FHIR store e.g.:
- **FHIR store location**: This is set by `PROXY_TO` environment variable, using
the base url of the FHIR store e.g.:

```shell
export PROXY_TO=https://example.com/fhir
```

- **Access token issuer**: This is set by `TOKEN_ISSUER` variable, 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/keycloak) directory. If you want to use a
SMART-on-FHIR app use this realm instead:
[Keycloak](https://github.com/Alvearie/keycloak-extensions-for-fhir) server.
To see how this server is configured, check the
[docker/keycloak](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
```

- **AccessChecker**: As mentioned above, access-checkers can be provided as
plugins and easily swapped. Each access-checker has a name
(see [plugins](plugins) for details) and `ACCESS_CHECKER` variable should
be set to this name. For example, the two plugins that are provided in this
repository, can be selected by either of:
plugins and easily swapped. Each access-checker has a name (see
[plugins](plugins) for details) and `ACCESS_CHECKER` variable should be set to
this name. For example, the two plugins that are provided in this repository,
can be selected by either of:

```shell
export ACCESS_CHECKER=list
export ACCESS_CHECKER=patient
```

- **AllowedQueriesChecker**: There are URL requests that the server can allow
without going through an access checker. [`AllowedQueriesChecker`](https://github.com/google/fhir-access-proxy/blob/main/server/src/main/java/com/google/fhir/proxy/AllowedQueriesChecker.java)
is a special `AccessChecker` that 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. An example of this is:
[`hapi_page_url_allowed_queries.json`](https://github.com/google/fhir-access-proxy/blob/main/resources/hapi_page_url_allowed_queries.json).
To use the file, set the `ALLOWED_QUERIES_FILE` variable:
```shell
export ALLOWED_QUERIES_FILE="resources/hapi_page_url_allowed_queries.json"
```
without going through an access checker.
[`AllowedQueriesChecker`](https://github.com/google/fhir-access-proxy/blob/main/server/src/main/java/com/google/fhir/proxy/AllowedQueriesChecker.java)
is a special `AccessChecker` that 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. An example of this is:
[`hapi_page_url_allowed_queries.json`](https://github.com/google/fhir-access-proxy/blob/main/resources/hapi_page_url_allowed_queries.json).
To use the file, set the `ALLOWED_QUERIES_FILE` variable:

```shell
export ALLOWED_QUERIES_FILE="resources/hapi_page_url_allowed_queries.json"
```

- The proxy makes no assumptions about what the FHIR server is, but the proxy
should be able to send any FHIR queries to the server. For example, 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
should be able to send any FHIR queries to the server. For example, 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"
```

Once you have set all the above, you can run the proxy server. By default, the
server 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:
[Spring Boot](https://spring.io/projects/spring-boot) and the usual
configuration parameters apply, e.g., to run on port 8081:

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

## Docker

The proxy is also available as a [docker image](Dockerfile):

```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-access-proxy:latest
```

Note if the `TOKEN_ISSUER` is on the `localhost` you need to bypass proxy's
Note if the `TOKEN_ISSUER` is on the `localhost` you need to bypass proxy's
token issuer check by setting `RUN_MODE=DEV` environment variable.

GCP note: if this is not on a VM with proper service account (e.g., on a local
Expand All @@ -146,9 +166,9 @@ $ curl -X POST -d 'client_id=CLIENT_ID' -d 'username=testuser' \
```

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:
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}" \
Expand All @@ -170,6 +190,7 @@ 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.

# Acknowledgement

This proxy is implemented as a
[HAPI FHIR Plain Server](https://hapifhir.io/hapi-fhir/docs/server_plain/introduction.html),
starting from this
Expand Down
8 changes: 4 additions & 4 deletions doc/developers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Setting up IDE to use google-java-format by default

- If your IDE is IntelliJ, follow the
instructions [here](https://github.com/google/google-java-format#intellij-android-studio-and-other-jetbrains-ides)
- If your IDE is IntelliJ, follow the instructions
[here](https://github.com/google/google-java-format#intellij-android-studio-and-other-jetbrains-ides)

- If your IDE is Eclipse, follow the
instructions [here](https://github.com/google/google-java-format#eclipse)
- If your IDE is Eclipse, follow the instructions
[here](https://github.com/google/google-java-format#eclipse)
61 changes: 33 additions & 28 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,59 @@
# Docker Compose YAMLs

This directory contains two Docker Compose YAML files. [hapi-proxy-compose.yaml](./hapi-proxy-compose.yaml)
sets up the FHIR Proxy and a HAPI FHIR Server with synthetic data pre-loaded
(more details below). [keycloak/config-compose.yaml](./keycloak/config-compose.yaml)
sets up a test Keycloak instance that can support both a list based access control
and a single-patient based SMART-on-FHIR app (in two separate realms).
This directory contains two Docker Compose YAML files.
[hapi-proxy-compose.yaml](./hapi-proxy-compose.yaml) sets up the FHIR Proxy and
a HAPI FHIR Server with synthetic data pre-loaded (more details below).
[keycloak/config-compose.yaml](./keycloak/config-compose.yaml) sets up a test
Keycloak instance that can support both a list based access control and a
single-patient based SMART-on-FHIR app (in two separate realms).

## Pre-loaded HAPI Server

The [us-docker.pkg.dev/fhir-proxy-build/stable/hapi-synthea:latest](https://console.cloud.google.com/gcr/images/fhir-sdk/global/synthetic-data)
image is based on the HAPI FHIR [image](https://hub.docker.com/r/hapiproject/hapi) with the
`1K Sample Synthetic Patient Records, FHIR R4` dataset from [Synthea](https://synthea.mitre.org/downloads) stored in the
container itself. To load this dataset into the HAPI FHIR image, do the following:
The
[us-docker.pkg.dev/fhir-proxy-build/stable/hapi-synthea:latest](https://console.cloud.google.com/gcr/images/fhir-sdk/global/synthetic-data)
image is based on the HAPI FHIR
[image](https://hub.docker.com/r/hapiproject/hapi) with the
`1K Sample Synthetic Patient Records, FHIR R4` dataset from
[Synthea](https://synthea.mitre.org/downloads) stored in the container itself.
To load this dataset into the HAPI FHIR image, do the following:

1. Run a local version of the HAPI FHIR server:

```
docker run --rm -d -p 8080:8080 --name hapi_fhir hapiproject/hapi:latest
```

2. Download the `1K Sample Synthetic Patient Records, FHIR R4` dataset:
2. Download the `1K Sample Synthetic Patient Records, FHIR R4` dataset:

```
wget https://synthetichealth.github.io/synthea-sample-data/downloads/synthea_sample_data_fhir_r4_sep2019.zip \
-O fhir.zip
```

3. Unzip the file, a directory named `fhir` should be created containig JSON files:
3. Unzip the file, a directory named `fhir` should be created containig JSON
files:

```
unzip fhir.zip
```

4. Use the Synthetic Data Uploader from the [FHIR Analytics](https://github.com/GoogleCloudPlatform/openmrs-fhir-analytics/tree/master/synthea-hiv)
repo to upload the files into the HAPI FHIR container
```
docker run -it --network=host \
-e SINK_TYPE="HAPI" \
-e FHIR_ENDPOINT=http://localhost:8080/fhir \
-e INPUT_DIR="/workspace/output/fhir" \
-e CORES="--cores 1" \
-v $(pwd)/fhir:/workspace/output/fhir \
us-docker.pkg.dev/cloud-build-fhir/fhir-analytics/synthea-uploader:latest
```
4. Use the Synthetic Data Uploader from the
[FHIR Analytics](https://github.com/GoogleCloudPlatform/openmrs-fhir-analytics/tree/master/synthea-hiv)
repo to upload the files into the HAPI FHIR container
`docker run -it --network=host \ -e SINK_TYPE="HAPI" \ -e FHIR_ENDPOINT=http://localhost:8080/fhir \ -e INPUT_DIR="/workspace/output/fhir" \ -e CORES="--cores 1" \ -v $(pwd)/fhir:/workspace/output/fhir \ us-docker.pkg.dev/cloud-build-fhir/fhir-analytics/synthea-uploader:latest`

5. As the uploader uses `POST` to upload the JSON files, the server will create
the ID used to refer to resources. We would like to upload a patient list example,
but to do so, we need to fetch the IDs from the server. To do so, run:
the ID used to refer to resources. We would like to upload a patient list
example, but to do so, we need to fetch the IDs from the server. To do so,
run:

```
curl http://localhost:8080/fhir/Patient?_elements=fullUrl
```

6. Choose two Patient IDs (the two picked here are 2522 and 2707), then run the
following to upload the list into the server
following to upload the list into the server

```
PATIENT_ID1=2522
PATIENT_ID2=2707
Expand All @@ -75,12 +79,13 @@ following to upload the list into the server
}'
```

6. Commit the Docker container. This saves its state into a new image
7. Commit the Docker container. This saves its state into a new image

```
docker commit hapi_fhir us-docker.pkg.dev/fhir-proxy-build/stable/hapi-synthea:latest
```
```

7. Push the image
8. Push the image
```
docker push us-docker.pkg.dev/fhir-proxy-build/stable/hapi-synthea:latest
```
25 changes: 15 additions & 10 deletions docker/keycloak/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Sample Identity Provider and Authorization Server

This directory contains the docker configuration for a sample
[Keycloak](https://www.keycloak.org/) server that can be used as the Identity
Provider (IDP) and Authorization server (AuthZ) companions of the FHIR proxy.
Expand All @@ -8,23 +9,27 @@ production without addressing security issues, in particular SSL access.

There are three components involved here which are all combined in
[config-compose.yaml](config-compose.yaml):
- The [Alvearie SMART Keycloak](https://github.com/Alvearie/keycloak-extensions-for-fhir).
We could also use the base Keycloak image if the access-checker does not care
about [SMART on FHIR](http://www.hl7.org/fhir/smart-app-launch/) spec (for
example the
[`list` access-checker](../../plugins/src/main/java/com/google/fhir/proxy/plugin/ListAccessChecker.java)).
The [`patient` access-checker](../../plugins/src/main/java/com/google/fhir/proxy/plugin/PatientAccessChecker.java)
is intended for a SMART on FHIR app with patient scopes.

- The
[Alvearie SMART Keycloak](https://github.com/Alvearie/keycloak-extensions-for-fhir).
We could also use the base Keycloak image if the access-checker does not care
about [SMART on FHIR](http://www.hl7.org/fhir/smart-app-launch/) spec (for
example the
[`list` access-checker](../../plugins/src/main/java/com/google/fhir/proxy/plugin/ListAccessChecker.java)).
The
[`patient` access-checker](../../plugins/src/main/java/com/google/fhir/proxy/plugin/PatientAccessChecker.java)
is intended for a SMART on FHIR app with patient scopes.

- The `alvearie/keycloak-config:latest` docker image to configure a SMART
enabled realm. This is useful for the `patient` access-checker.
enabled realm. This is useful for the `patient` access-checker.

- The `us-docker.pkg.dev/fhir-proxy-build/stable/keycloak-config:latest` docker image to configure a realm
for the `list` access-checker.
- The `us-docker.pkg.dev/fhir-proxy-build/stable/keycloak-config:latest` docker
image to configure a realm for the `list` access-checker.

You can change the configuration parameters by changing environment variables
passed to the docker images. By default, the values in [`.env`](.env) is used.
To run all above components:

```shell
docker-compose -f config-compose.yaml up
```
9 changes: 4 additions & 5 deletions kokoro/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Kokoro Infrastructure
----------------------
## Kokoro Infrastructure

The files in this directory serve as plumbing for running tests under
Kokoro, our internal CI. If there are any changes required to these
config files, please file an issue.
The files in this directory serve as plumbing for running tests under Kokoro,
our internal CI. If there are any changes required to these config files, please
file an issue.
Loading

0 comments on commit 522934c

Please sign in to comment.