Skip to content

Commit

Permalink
Hurl scripts refactor (#1522)
Browse files Browse the repository at this point in the history
* Simplified load-etor-org-settings script to only run in local env

* Using preferred gradlew commands instead of prime ones. Also added env variable for RS_HOME

* Moved common functions to /scripts/utils.sh and importing scripts using absolute path

* Extract env variables to a shared .env file, updated docs, renamed some of the envars. Also working of having absolute paths so the scripts could run from anywhere

* Fixed .env loading and some cleanup

* Renamed reset.sh => setup.sh

* Consolidated RS setup scripts into one

* Moved rs/setup.sh to setup-rs.sh and removed rs/ folder

* Updated RS setup instructions in readme to:
- Use new setup-rs.sh script
- Add alternate ways to build and run RS
- Fixed RS docs URL
- Clean up and simplify

* Moved files to reorganize and simplify file structure

* Updated paths

* Reverted moving hurl files

* Moved and renamed function scripts

* Moved and renamed more scripts + added to readme

* Moved function to common.sh

* Removed unused hurl/readme.md

* Fixed .env file reference

* Added to readme and added user message to find instructions

* Added context to instruction

* Added setup script for env vars

* Changed relative path to hurl files for absolute paths

* Fixed typos and cleanup

* Removed setup script not working as intended

* Readme update

* Fixed issues after running shellcheck

* Removed dead code and renamed readme section

* Reverted adding double quotes as it introduces a bug

* Added missing export of env vars that are required to create vault credentials

* Fixed typo

* Renamed client => sender, cleanup

* Refactored to extract common code + fix bug

* Updated readme + cleanup

* Refactored to extract more common code and changed to use global variables for consistency and fto simplify

* Refactored scripts to include epic.sh

* Refactored to simplify + cleanup

* Cleanup

* Renamed epic => ucsd

* Renamed epic => ucsd
  • Loading branch information
basiliskus authored Nov 21, 2024
1 parent bc34bac commit 421ae5b
Show file tree
Hide file tree
Showing 19 changed files with 219 additions and 262 deletions.
2 changes: 1 addition & 1 deletion scripts/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TI_LCL_API_URL="http://host.docker.internal:8080"
TI_STG_API_URL="https://cdcti-stg-api.azurewebsites.net:443"
TI_PRD_API_URL="https://cdcti-prd-api.azurewebsites.net:443"

# Client keys
# Sender keys
TI_LOCAL_PRIVATE_KEY_PATH="${CDCTI_HOME}/mock_credentials/organization-trusted-intermediary-private-key-local.pem"
TI_LOCAL_PUBLIC_KEY_PATH="${CDCTI_HOME}/mock_credentials/organization-trusted-intermediary-public-key-local.pem"
RS_LOCAL_PRIVATE_KEY_PATH="${CDCTI_HOME}/mock_credentials/organization-report-stream-private-key-local.pem"
Expand Down
46 changes: 24 additions & 22 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ Usage: ./submit.sh -f <message_file.hl7> [-e <environment>]
Options:
-f <FILE> Message file path (Required)
-e <ENVIRONMENT> Environment: local|staging|production (Default: local)
-x <RS_CLIENT_PRIVATE_KEY> Path to the client private key for authentication with RS API (Required for non-local environments)
-z <TI_CLIENT_PRIVATE_KEY> Path to the client private key for authentication with TI API (Optional for all environments)
-x <RS_SENDER_PRIVATE_KEY> Path to the sender private key for authentication with RS API (Required for non-local environments)
-z <TI_SENDER_PRIVATE_KEY> Path to the sender private key for authentication with TI API (Optional for all environments)
-h Display this help and exit
```

Expand All @@ -62,14 +62,14 @@ ENDPOINT_NAME:
The name of the endpoint to call (required)
Options:
-f <REL_PATH> Path to the hl7/fhir file to submit (Required for waters API)
-r <ROOT_PATH> Root path to the hl7/fhir files (Default: /Users/bbogado/Code/Flexion/CDC-TI/trusted-intermediary/examples/)
-t <CONTENT_TYPE> Content type for the message (Default: application/hl7-v2)
-e <ENVIRONMENT> Environment: local|staging|production (Default: local)
-c <CLIENT_ID> Client ID (Default: flexion)
-s <CLIENT_SENDER> Client sender (Default: simulated-sender)
-k <KEY_PATH> Path to the client private key (Required for non-local environments)
-i <SUBMISSION_ID> Submission ID for history API (Required for history API)
-e <ENVIRONMENT> Environment: local|staging (Default: local)
-f <REL_PATH> Path to the message file to submit (Required for submission endpoints)
-r <ROOT_PATH> Root path to the message files (Default: /Users/bbogado/Code/Flexion/CDC-TI/trusted-intermediary/examples/)
-t <CONTENT_TYPE> Content type for the message file (Default: application/hl7-v2)
-k <KEY_PATH> Path to the sender private key (Required for non-local environments)
-s <SENDER> Sender ID used for authentication (Default: flexion.simulated-sender)
-u <URL> URL root for the API endpoint (Default: auto-detected)
-i <SUBMISSION_ID> Submission ID (Required for query endpoints)
-v Verbose mode
-h Display this help and exit
```
Expand All @@ -91,7 +91,7 @@ Sending a result to local environment
Sending an order to staging

```
./rs.sh waters -f Test/Orders/003_AL_ORM_O01_NBS_Fully_Populated_0_initial_message.hl7 -e staging -k /path/to/client/staging/private/key
./rs.sh waters -f Test/Orders/003_AL_ORM_O01_NBS_Fully_Populated_0_initial_message.hl7 -e staging -k /path/to/sender/staging/private/key
```

Checking the history in local environment for a submission id
Expand All @@ -103,7 +103,7 @@ Checking the history in local environment for a submission id
Checking the history in staging for a submission id

```
./rs.sh history -i 100 -e staging -k /path/to/client/staging/private/key
./rs.sh history -i 100 -e staging -k /path/to/sender/staging/private/key
```

### ti.sh
Expand All @@ -124,12 +124,14 @@ ENDPOINT_NAME:
The name of the endpoint to call (required)
Options:
-f <REL_PATH> Path to the hl7/fhir file to submit (Required for orders and results APIs)
-r <ROOT_PATH> Root path to the hl7/fhir files (Default: /Users/bbogado/Code/Flexion/CDC-TI/trusted-intermediary/examples/)
-e <ENVIRONMENT> Environment: local|staging (Default: local)
-c <CLIENT> Client ID to create JWT with (Default: report-stream)
-k <KEY_PATH> Path to the client private key (Required for non-local environments)
-i <SUBMISSION_ID> Submission ID for metadata API (Required for orders, results and metadata API)
-f <REL_PATH> Path to the message file to submit (Required for submission endpoints)
-r <ROOT_PATH> Root path to the message files (Default: /Users/bbogado/Code/Flexion/CDC-TI/trusted-intermediary/examples/)
-t <CONTENT_TYPE> Content type for the message file (Default: application/fhir+ndjson)
-k <KEY_PATH> Path to the sender private key (Required for non-local environments)
-s <SENDER> Sender ID used for authentication (Default: report-stream)
-u <URL> URL root for the API endpoint (Default: auto-detected)
-i <SUBMISSION_ID> Submission ID (Required for query endpoints)
-v Verbose mode
-h Display this help and exit
```
Expand All @@ -143,7 +145,7 @@ Submit an order to local environment:

Submit an order to staging:
```
./ti.sh orders -f Test/Orders/003_AL_ORM_O01_NBS_Fully_Populated_0_initial_message.hl7 -e staging -k /path/to/client/staging/private/key
./ti.sh orders -f Test/Orders/003_AL_ORM_O01_NBS_Fully_Populated_0_initial_message.hl7 -e staging -k /path/to/sender/staging/private/key
```

Expand Down Expand Up @@ -172,22 +174,22 @@ Get Health info from local environment:
./ti.sh health
```

### epic.sh
### ucsd.sh

Submit requests to Epic API endpoints
Submit requests to UCSD API endpoints

#### Requirements

- hurl

#### Before running the script

- Add the `client` id to `epic.sh`
- Add the `sender` id to `ucsd.sh`
- Update the `secret` variable path

#### Usage

`./epic.sh results`
`./ucsd.sh results -k /path/to/ucsd-ucsd-private-key.pem -s sender_name`

### setup/update-examples-snapshots.sh

Expand Down
20 changes: 0 additions & 20 deletions scripts/epic.sh

This file was deleted.

4 changes: 2 additions & 2 deletions scripts/hurl/rs/delivery.hurl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $client -i $client -s $client -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $sender -i $sender -s $sender -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
POST {{url}}/api/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client-id}}.*.report
scope: {{sender-org}}.*.report
client_assertion: {{jwt}}
client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
grant_type: client_credentials
Expand Down
4 changes: 2 additions & 2 deletions scripts/hurl/rs/history.hurl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $client -i $client -s $client -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $sender -i $sender -s $sender -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
POST {{url}}/api/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client-id}}.*.report
scope: {{sender-org}}.*.report
client_assertion: {{jwt}}
client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
grant_type: client_credentials
Expand Down
4 changes: 2 additions & 2 deletions scripts/hurl/rs/token.hurl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $client -i $client -s $client -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $sender -i $sender -s $sender -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
POST {{url}}/api/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client-id}}.*.report
scope: {{sender-org}}.*.report
client_assertion: {{jwt}}
client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
grant_type: client_credentials
6 changes: 3 additions & 3 deletions scripts/hurl/rs/waters.hurl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $client -i $client -s $client -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
# curl --header 'Content-Type: application/x-www-form-urlencoded' --data 'scope=flexion.*.report' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $sender -i $sender -s $sender -a $host --no-iat -S @/path/to/ucsd-epic-private-key.pem) --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'http://localhost:7071/api/token'
POST {{url}}/api/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client-id}}.*.report
scope: {{sender-org}}.*.report
client_assertion: {{jwt}}
client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
grant_type: client_credentials
Expand All @@ -15,6 +15,6 @@ token: jsonpath "$['access_token']"
# curl --header 'Content-Type: application/hl7-v2' --header 'Client: flexion.simulated-sender' --header 'Authorization: Bearer $token' --data-binary '@/path/to/message.hl7' 'http://localhost:7071/api/waters'
POST {{url}}/api/waters
Content-Type: {{content-type}}
Client: {{client-id}}.{{client-sender}}
Client: {{sender-org}}.{{sender-name}}
Authorization: Bearer {{token}}
file,{{fpath}};
2 changes: 1 addition & 1 deletion scripts/hurl/ti/auth.hurl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
POST {{url}}/v1/auth/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client}}
scope: {{sender}}
client_assertion: {{jwt}}
2 changes: 1 addition & 1 deletion scripts/hurl/ti/metadata.hurl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
POST {{url}}/v1/auth/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client}}
scope: {{sender}}
client_assertion: {{jwt}}

HTTP 200
Expand Down
2 changes: 1 addition & 1 deletion scripts/hurl/ti/orders.hurl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
POST {{url}}/v1/auth/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client}}
scope: {{sender}}
client_assertion: {{jwt}}

HTTP 200
Expand Down
2 changes: 1 addition & 1 deletion scripts/hurl/ti/results.hurl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
POST {{url}}/v1/auth/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
scope: {{client}}
scope: {{sender}}
client_assertion: {{jwt}}

HTTP 200
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# curl -H 'Content-Type: application/x-www-form-urlencoded' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $client -i $client -s $client -a https://epicproxy-np.et0502.epichosted.com/FhirProxy/oauth2/token --no-iat -S @/path/to/ucsd-epic-private-key.pem)' --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'https://epicproxy-np.et0502.epichosted.com/FhirProxy/oauth2/token'
POST https://epicproxy-np.et0502.epichosted.com/FhirProxy/oauth2/token
# curl -H 'Content-Type: application/x-www-form-urlencoded' --data 'client_assertion=$(jwt encode --exp=+5min --jti $(uuidgen) --alg RS256 -k $sender -i $sender -s $sender -a https://epicproxy-np.et0502.epichosted.com/FhirProxy/oauth2/token --no-iat -S @/path/to/ucsd-epic-private-key.pem)' --data 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' --data 'grant_type=client_credentials' 'https://epicproxy-np.et0502.epichosted.com/FhirProxy/oauth2/token'
POST {{url}}/FhirProxy/oauth2/token
Content-Type: application/x-www-form-urlencoded
[FormParams]
client_assertion: {{jwt}}
Expand All @@ -12,7 +12,7 @@ HTTP 200
token: jsonpath "$['access_token']"

# curl -H 'Content-Type: application/hl7-v2' -H 'Authorization: Bearer $token' --data-binary '@/path/to/oru.hl7' 'https://epicproxy-np.et0502.epichosted.com/CDPH_NBGS_TST/api/epic/2015/EDI/HTTP/HL7v2/910377'
POST https://epicproxy-np.et0502.epichosted.com/CDPH_NBGS_TST/api/epic/2015/EDI/HTTP/HL7v2/910377
Content-Type: application/hl7-v2
POST {{url}}/CDPH_NBGS_TST/api/epic/2015/EDI/HTTP/HL7v2/910377
Content-Type: {{content-type}}
Authorization: Bearer {{token}}
file,{{fpath}};
95 changes: 95 additions & 0 deletions scripts/lib/api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/bash

show_usage() {
local script_name=$1

cat <<EOF
Usage: ./$script_name <ENDPOINT_NAME> [OPTIONS]
ENDPOINT_NAME:
The name of the endpoint to call (required)
Options:
-e <ENVIRONMENT> Environment: local|staging (Default: $ENVIRONMENT)
-f <REL_PATH> Path to the message file to submit (Required for submission endpoints)
-r <ROOT_PATH> Root path to the message files (Default: $ROOT_PATH)
-t <CONTENT_TYPE> Content type for the message file (Default: $CONTENT_TYPE)
-k <KEY_PATH> Path to the sender private key (Required for non-local environments)
-s <SENDER> Sender ID used for authentication (Default: $SENDER)
-u <URL> URL root for the API endpoint (Default: auto-detected)
-i <SUBMISSION_ID> Submission ID (Required for query endpoints)
-v Verbose mode
-h Display this help and exit
EOF
}

parse_args() {
local type=$1
shift

[ "$1" = "-h" ] || [ "$1" = "--help" ] && return 1
[ $# -eq 0 ] && fail "Missing required argument <ENDPOINT_NAME>"

HURL_FILE_PATH="$CDCTI_HOME/scripts/hurl/$type/$1.hurl"
shift

while getopts ':e:f:r:t:k:s:u:i:v' opt; do
case "$opt" in
e) ENVIRONMENT="$OPTARG" ;;
f) REL_PATH="$OPTARG" ;;
r) ROOT_PATH="$OPTARG" ;;
t) CONTENT_TYPE="$OPTARG" ;;
k) SENDER_PRIVATE_KEY="$OPTARG" ;;
s) SENDER="$OPTARG" ;;
u) URL="$OPTARG" ;;
i) SUBMISSION_ID="$OPTARG" ;;
v) VERBOSE="--verbose" ;;
?) fail "Invalid option -$OPTARG" ;;
esac
done

parse_sender_string "$SENDER"

if [ -z "$SENDER_PRIVATE_KEY" ] && [ "$ENVIRONMENT" = "local" ] && [ -f "$DEFAULT_SENDER_PRIVATE_KEY_PATH" ] && [ "$SENDER_ORG" = "$DEFAULT_SENDER_PRIVATE_KEY_ORG" ]; then
SENDER_PRIVATE_KEY="$DEFAULT_SENDER_PRIVATE_KEY_PATH"
elif [ -z "$SENDER_PRIVATE_KEY" ] && [ "$ENVIRONMENT" != "local" ]; then
fail "Sender private key (-k) is required for non-local environments"
fi

[ ! -f "$SENDER_PRIVATE_KEY" ] && fail "Sender private key file not found: $SENDER_PRIVATE_KEY"

shift "$((OPTIND - 1))"
REMAINING_ARGS="$*"
}

handle_api_request() {
local api_type=$1
shift

local host jwt_token
[ -z "$URL" ] && URL=$(get_api_url "$ENVIRONMENT" "$api_type")
host=$(extract_host_from_url "$URL")
jwt_token=$(generate_jwt "$SENDER" "$host" "$SENDER_PRIVATE_KEY")

local vars=(
--variable fpath=$REL_PATH
--file-root $ROOT_PATH
--variable url=$URL
--variable jwt=$jwt_token
--variable content-type=$CONTENT_TYPE
)

if [ "$api_type" = "rs" ]; then
vars+=(
--variable sender-org=$SENDER_ORG
--variable sender-name=$SENDER_NAME
)
else
vars+=(--variable sender=$SENDER)
fi

if [ -n "$SUBMISSION_ID" ]; then vars+=(--variable submissionid="$SUBMISSION_ID"); fi
if [ -n "$VERBOSE" ]; then vars+=("$VERBOSE"); fi

hurl "${vars[@]}" "$HURL_FILE_PATH" ${REMAINING_ARGS:+$REMAINING_ARGS}
}
22 changes: 18 additions & 4 deletions scripts/lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,33 @@ extract_host_from_url() {
echo "$url" | sed 's|^.*://\([^/:]*\)[:/].*|\1|'
}

parse_sender_string() {
local sender_string=$1

if [[ "$sender_string" =~ ^([^.]+)\.([^.]+)$ ]]; then
SENDER_ORG="${BASH_REMATCH[1]}"
SENDER_NAME="${BASH_REMATCH[2]}"
return 0
else
SENDER_ORG="$sender_string"
SENDER_NAME=""
return 1
fi
}

generate_jwt() {
# requires: jwt-cli
local client=$1
local sender=$1
local audience=$2
local secret_path=$3

jwt encode \
--exp='+5min' \
--jti "$(uuidgen)" \
--alg RS256 \
-k "$client" \
-i "$client" \
-s "$client" \
-k "$sender" \
-i "$sender" \
-s "$sender" \
-a "$audience" \
--no-iat \
-S "@$secret_path"
Expand Down
Loading

0 comments on commit 421ae5b

Please sign in to comment.