ATTN: This server is now deprecated. Please see the ca.uhn.fhir.jpa.starter.authorization in the CPCDS Server RI github
This project is the authorization server for the CPCDS Reference Server. It supports authorization using OAuth 2.0 in the stand alone SMART app launch sequence.
This server is deployed at http://ec2-18-221-69-59.us-east-2.compute.amazonaws.com:8080/
Note: This is a reference implementation and is intended only to test the CPCDS Server and the CPCDS Client implementations. This authorization server purposefully enables data to be publicly accessible to assist in debugging. Caution should be taken if attempting to use this implementation in a production enviornment. All data sent to the server should be fictional. For more details see "Security" at the bottom of this page.
The quickest way to get the server up and running is by pulling the built image from docker hub.
docker pull blangley/cpcds-auth-server
docker run -p 8180:8180 blangley/cpcds-auth-server
This will deploy the authorization server to http://localhost:8180.
The server will automatically include the following Users and Clients when it starts up.
ID | Username | Password | Description |
---|---|---|---|
1 | user1 | password1 | Account for Patient/1 from Synthea generated data |
689 | user689 | password689 | Account for Patient/689 from Synthea generated data |
Patient1 | patient1 | password1 | Account for Patient/Patient1 from IG Examples |
PatientEx1 | patientex1 | passwordex1 | Account for Patient/PatientEx1 from IG Examples |
admin | admin | 123456789 | Admin account which can access all resources on the server |
ID | RedirectURI | Secret |
---|---|---|
b0c46635-c0b4-448c-a8b9-9bd282d2e05a | http://localhost:4000/login | bUYbEj5wpazS8Xv1jyruFKpuXa24OGn9MHuZ3ygKexaI5mhKUIzVEBvbv2uggVf1cW6kYD3cgTbCIGK3kjiMcmJq3OG9bn85Fh2x7JKYgy7Jwagdzs0qufgkhPGDvEoVpImpA4clIhfwn58qoTrfHx86ooWLWJeQh4s0StEMqoxLqboywr8u11qmMHd1xwBLehGXUbqpEBlkelBHDWaiCjkhwZeRe4nVu4o8wSAbPQIECQcTjqYBUrBjHlMx5vXU |
6cfecf41-e364-44ab-a06f-77f8b0c56c2b | https://cpcds-client-ri.herokuapp.com/login | XHNdbHQlOrWXQ8eeXHvZal1EDjI3n2ISlqhtP30Zc89Ad2NuzreoorWQ5P8dPrxtk267SJ23mbxlMzjriAGgkaTnm6Y9f1cOas4Z6xhWXxG43bkIKHhawMR6gGDXAuEWc8wXUHteZIi4YCX6E1qAvGdsXS1KBhkUf1CLcGmauhbCMd73CjMugT527mpLnIebuTp4LYDiJag0usCE6B6fYuTWV21AbvydLnLsMsk83T7aobE4p9R0upL2Ph3OFTE1 |
To start the server simply build and run using docker. The container will automatically build and deploy using a tomcat server.
git clone https://github.com/carin-alliance/cpcds-auth-server.git
cd cpcds-auth-server
docker build -t cpcds-auth-server .
docker run -p 8180:8180 cpcds-auth-server
This will build and deploy the authorization server to http://localhost:8180.
Clone the repo and build the server:
git clone https://github.com/carin-alliance/cpcds-auth-server.git
cd cpcds-auth-server
./gradlew installBootDist
./gradlew bootRun
This will build and deploy the authorization server to http://localhost:8180.
Note: This has only been tested using Java 11.
This server is hosted on AWS at http://ec2-18-221-169-54.us-east-2.compute.amazonaws.com:8180/. Follow these steps to update it.
- Build the new docker image
docker build -t blangley/cpcds-auth-server .
- Push the image to dockerhub
docker push blangley/cpcds-auth-server
- SSH into the AWS sandbox
ssh -i {pem file} ubuntu@ec2-18-221-169-54.us-east-2.compute.amazonaws.com
- Pull the new image
sudo docker pull blangley/cpcds-auth-server
. - Kill the old image
sudo docker kill {container id}
. To find the container id runsudo docker ps
. - Start the new image
sudo docker run -d -p 8180:8180 blangley/cpcds-auth-server
.
The authorization sequence relies on a valid client and user being registered with the system. In the image of this server on docker hub a few users and clients are already loaded. A web interface is provided at /register/user
and /register/client
to register a new user and client respectively. These two interfaces use the underlying POST requests described in the next section to complete the registration process.
Before the authorization sequence can begin the user must register with the system. The endpoint for this is /register/user
and the JSON body parameters are:
Parameter | Value |
---|---|
username |
User created unique identifier for the system |
password |
User created password to authenticate |
id |
The id of the patient associated with this user |
Example:
POST HTTP/1.1
http://localhost:8180/register/user
Content-Type: application/json
{
"username": "user1",
"password": "password1",
"patientId": "1"
}
The response to the POST is 201 CREATED on success.
A web interface is available to register a new user.
Before the authorization sequence can begin the client must be registered with the system. The endpoint for this is /register/client
and the query parameters are:
Parameter | Value |
---|---|
redirect_uri |
The redirect URI the client will use |
Example:
POST HTTP/1.1
http://localhost:8180/register/client?redirect_uri=http://localhost:4000/login
The response to the post is 201 CREATED on success with the json body:
{
"id": "a12c5a8a-0288-4502-9190-5ddf79145938",
"secret": "N3MXICwdkqIbbkhociXxtZJ8HGu4EpHKT7X7IA6M08P1m3px7aIfBDnfdStUfjArJGqQIoWtH4my5XtkZJso9SHSuOlkhcnIqfB8zj6PqVoXbqjt6svPaCtmDR0qiCZq0g8FfqAikI5DbUkKY2LomIwLjx3Qhe7nzuOZgeap4rDU959tHqYpaD11Yvgjk2SfRXZpdkcEURMhsLVvX7AXgsbylaVyy52iwsF8nSNfjtMXenDQhj1Jxr0WlZHisQNQ",
"redirect": "http://localhost:4000/login"
}
A web interface is available to register a new client.
The first step is to obtain an authorization code from the auth server. The endpoint for this is /authorization
and the query parameters are:
Parameter | Value |
---|---|
response_type |
code |
client_id |
The client id |
redirect_uri |
The URI to redirect to with the code |
scope |
The SMART on FHIR Access Scope |
state |
Unique ID generated by the client for this interaction |
aud |
The base URL for the CPCDS FHIR server (http://localhost:8080/cpcds-server/fhir ) |
Example:
GET http://localhost:8180/authorization?response_type=code&
client_id=user689&redirect_uri=http://localhost:3000/index&
scope=patient/*.read&state=12345abc&aud=http://localhost:8180
The response to the GET request is a redirection to the provided redirect_uri
with the following query parameters:
Parameter | On | Value |
---|---|---|
code |
Success | The authorization code for the client |
state |
Success | Echo of state parameter in the request |
error |
Failure | Error code defined in RFC 6749 |
Example:
HTTP/1.1 302 Found
Location: http://localhost:3000/index?code=abc123&state=12345abc
Note: The authorization code is only valid for 2 minutes.
After obtaining an authorization code it is exchanged for an access token. To obtain an access token (which is valid for 1 hour) use the /token
endpoint with the following query parameters:
Parameter | Value |
---|---|
grant_type |
authorization_code |
code |
The authorization code returned by the /authorization endpoint |
redirect_uri |
The same redirect_uri from the /authorization request |
The client must also include a basic Authorization header with the value base64Encode(client_id:client_secret)
and use Content-Type
of application/x-www-form-urlencoded
.
Example:
POST HTTP/1.1
Authorization: Basic MTpwYXNzd29yZA==
Content-Type: application/x-www-form-urlencoded
http://localhost:8180/token?grant_type=authorization_code&
code=abc123&redirect_uri=http://localhost:3000/index
The response to the POST is a JSON object with the following values:
Key | Value |
---|---|
access_token |
The access token for the protected resource |
token_type |
bearer |
expires_in |
The seconds until expiration (3600 ) |
The access_token
is valid for 1 hour and can be used to query protected resources from the CPCDS Server. For more details on how to use the CPCDS Server view the README.
The public keys used for verifying the signatures are found at this endpoint. For this RI the RSA keys do not rotate and are created at server initialization in App.java
.
Example:
GET http://localhost:8180/.well-known/jwks.json
Retuns:
{
"keys": [
{
"kty": "RSA",
"e": "2542507730329925502019959402417157606871382892503593304032212496853538284138894186312740754437083011799807189636117018396940516735918014461610794552420857",
"use": "sig",
"kid": "NjVBRjY5MDlCMUIwNzU4RTA2QzZFMDQ4QzQ2MDAyQjVDNjk1RTM2Qg",
"alg": "RS256",
"n": "5690166698804597197330905768480486858877596610886363234480576904931540875874759967271069328480055496837733730620168171327423013607454238318286896004712153"
}
]
}
To enable debugging while using this reference implementation three debug endpoints are enabled. These endpoints publicly expose data which is useful for development but should be kept private for a real instance.
Returns a readonly webpage user interface for the Users table in the database. Columns are USERNAME, PATIENT_ID, PASSWORD, REFRESH_TOKEN, and TIMESTAMP.
Returns a readonly webpage user interface for the registered Clients table in the database. Columns are ID, SECRET, REDIRECT_URI, and TIMESTAMP.
Returns the contents of the log file for the server.
JWT tokens are used throughout this process to digitally sign the Authorization Code and the Access Token. All JWT tokens in this reference implementation utilize the HS256 algorithm. The structure of the payload for the two types of tokens are shown below:
{
"aud": "http://localhost:8180", // Audience is the this auth server
"iss": "http://localhost:8180", // Issued by this auth server URL
"redirect_uri": "http://localhost:4000/client", // redirect_uri param from request
"exp": 1583853744, // Time of expiration (120s after iat)
"iat": 1583853624, // Issued at time
"username": "user689", // The login username for this client
"client_id": "0oa41ji88gUjAKHiE4x6" // The client requesting the authorization
}
{
"aud": "http://localhost:8080/cpcds-server/fhir", // Audience is the protected CPCDS server
"iss": "http://localhost:8180", // Issued by this auth server URL
"exp": 1583856862, // Time of expiration (3600s after iat)
"iat": 1583853262, // Issued at time
"patient_id": "1", // Patient ID for this user
"client_id": "0oa41ji88gUjAKHiE4x6", // The client requesting the authorization
"jti": "7f9971da-ea43-4554-b9f7-3157a796175d" // Unique identifier for this token
}
The auth server must know the EHR Server endpoint to validate the audience. This can be configured in App.java
by changing the value of ehrServer
. The default value is the same base url as this auth server with :8080/cpcds-server/fhir
as the endpoint.
Since this code base serves as the reference implementation for the Carin BB IG there are multiple places where potential security vulnerabilities were intentionally made to allow testing developers to debug their code. With these vulnerabilities in place, testing and debugging connections is substantially easier. If this code is to be used for a production enviornment care must be taken to ensure all vulnerabilities are fixed. Below is a list of some of the identified issues. It is your responsibility to make sure all vulnerabilities, including those not listed below, are fixed in a production enviornment.
- Logger statements print secrets - in places such as
User.java
andClient.java
the logger displays the hashed password and client secret. Caution should be used any time a secret value is logged. Care should be taken to protect the log files from malicious users. - Debug endpoint - the debug endpoint provides public access to the Users and Client table which provides hashed passwords and client secrets. This endpoint also provides public access to the log file. The debug endpoint should be removed for a production enviornment.
- Managing keys - the RSA keys used to sign and validate the JWT tokens are hard coded in
App.java
. Your implementation must change these keys and ensure they are stored in a secure location. Consider having rotating keys.
This may not be an exhaustive list. The developers of this reference implementations are not responsible for any vulnerabilities in the code base. All use of this repository comes with the understanding this reference implementation is used for testing connections only.