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

Unit Tests, Artifact Publishing & Updated Documentation #33

Merged
merged 30 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
41b5f5e
Added unit test for `Application` class
dmccoystephenson Jun 26, 2024
402669d
Added unit tests for base URI & endpoint path trimming
dmccoystephenson Jun 26, 2024
f27691a
Added unit test for signing using HSM
dmccoystephenson Jul 1, 2024
faac2e0
Implemented unit tests for `Message` class
dmccoystephenson Jul 11, 2024
f22b456
Removed unimplemented `signWithHsm()` method from SignatureController…
dmccoystephenson Jul 11, 2024
d5b15c9
Added unit tests for the case where 'base uri' and 'endpoint sign pat…
dmccoystephenson Jul 11, 2024
56371b9
Removed unused variable, renamed variable & modified accessors in Sig…
dmccoystephenson Jul 11, 2024
63b8665
Moved away from deprecated `StringUtils.isEmpty()` method in Signatur…
dmccoystephenson Jul 11, 2024
3ef2239
Created RestTemplateFactory class to make REST calls testable in Sign…
dmccoystephenson Jul 12, 2024
0616ce2
Created more helpers & added unit test for successfully forwarding me…
dmccoystephenson Jul 12, 2024
c92f155
Added unit test for error case during forwarding message to external …
dmccoystephenson Jul 12, 2024
1f9ba91
Added success/failure unit tests for sign() method
dmccoystephenson Jul 12, 2024
ee81b1a
Corrected 'certficates' typo to 'certificates'
dmccoystephenson Jul 12, 2024
9b822bb
Added dev container & test script for convenience
dmccoystephenson Jul 12, 2024
e69a7ee
Revised README
dmccoystephenson Jul 26, 2024
29d8c5a
testing github artifact publishing
Michael7371 Jul 29, 2024
93e91fb
updating trigger to only be on tag creation
Michael7371 Jul 29, 2024
e81af57
Added a test for the HttpClientFactory class
dmccoystephenson Jul 30, 2024
856ee47
Added test for HttpEntityStringifier class
dmccoystephenson Jul 30, 2024
9b62b05
Added tests for KeyStoreReader class
dmccoystephenson Jul 30, 2024
49afc12
Added a test for SSLContextFactory class
dmccoystephenson Jul 30, 2024
43dc010
Added test-scripts README
dmccoystephenson Jul 30, 2024
7d99026
Merge pull request #10 from CDOT-CV/testing/add-unit-tests
payneBrandon Aug 2, 2024
fc2a06c
Merge branch 'dev' into docs/review-documentation-for-accuracy
payneBrandon Aug 2, 2024
439831e
Merge pull request #12 from CDOT-CV/github-actions-artifact-publishing
payneBrandon Aug 14, 2024
79b8e80
Fixed typo in `Mutual TLS Authentication` section of README
dmccoystephenson Sep 3, 2024
f3e6afa
Merge pull request #11 from CDOT-CV/docs/review-documentation-for-acc…
dmccoystephenson Sep 6, 2024
626fc77
Changed version to 1.5.0-SNAPSHOT
dmccoystephenson Sep 6, 2024
d268434
Added release notes for version 1.5.0
dmccoystephenson Sep 6, 2024
7314e2d
Merge pull request #13 from CDOT-CV/q3-release/version-change-and-rel…
drewjj Sep 9, 2024
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
27 changes: 27 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
"name": "Java",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/java:1-21-bullseye",

"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "true",
"installGradle": "false"
}
}

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "java -version",

// Configure tool-specific properties.
// "customizations": {},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
31 changes: 31 additions & 0 deletions .github/workflows/artifact-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Publish Java Package
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will be the approx. artifact size and where we are using this ? As our ODE GitHub org is on free plan we have artifact storage limit of 500mb.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project's JAR file is about 57 MB in size. It is not currently being used, but it is for potential future use. It may be possible to reduce the size of the JAR file in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmccoystephenson seems like for Maven packages and other packages like npm, docker, etc storage limit will be not applied for public repo's. so I think we should be good to use artifacts. However for any private repo's this limits will apply. We have a backlog item for supporting GitHub artifacts setup in future release. Thanks!


on:
push:
tags:
- 'jpo-security-svcs-*'

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'adopt'

- name: Remove snapshot from version
run: mvn versions:set -DremoveSnapshot

- name: Build with Maven
run: mvn -B package --file pom.xml

- name: Publish to GitHub Packages
run: mvn --batch-mode -Dgithub_organization=${{ github.repository_owner }} deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
137 changes: 71 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,29 @@

# jpo-security-svcs
This module exposes a RESTful API for performing cryptographic functions. The following paths identify the functions:
|Verb|path|Content Type|Functionality|Request Body Format|Response Body Format|
|--|--|--|--|--|--|
|POST|/sign|application/json|signs data provided in the body of the request|{"message":"Base64 encoded unsigned data"}|{"result": "Base64 Encoded Signed Data"}
This module exposes a RESTful API for performing cryptographic signing of messages.

Cryptographic signing is carried out against a remote instance, which requires mutual TLS authentication to secure the communications. This requires using private and public keys to secure the communications between this instance and the remote signing instance.

## Table of Contents
- [Release notes](#release-notes)
- [Usage](#usage)
- [Installation](#installation)
- [Configuration](#configuration)
- [Mutual TLS Authentication](#mutual-tls-authentication)
- [Debugging](#debugging)
- [Testing](#testing)

Note that the cryptographic functions may be carried out against an on-prem instance, or against a remote instance. A local instance is a simplified case and does not require mutual TLS authentication. For the remote signing use case, MTLS will be used to secure the communications. This requires some additional work on the part of configuration, and uses private and public keys to secure the communications between this instance and the remote signing instance.
## Mutual TLS Authentication
For enhanced security, MTLS is used to communicate with a remote signing system. This requires properly configured certificates from the remote system to property perform - work with your remote signing authority to obtain necessary certificates.
## Release Notes
The current version and release history of the Jpo-security-svcs: [Jpo-security-svcs Release Notes](<docs/Release_notes.md>)

### Certificate Conversion
Certificates can be in several different formats, including the widely used PEM format. Because this is a Java application, the signing certificates must be in the Java Keystore format to be used. The following commands using [OpenSSL](https://www.openssl.org/) and the Java keytool will convert a PEM file to a Java Keystore file.

1. Convert the PEM file to a PKCS12 file:
```
openssl pkcs12 -export -in <cert.pem> -inkey <key.pem> -out <certificate.p12> -name <alias>
```
2. Convert the PKCS12 file to a Java Keystore file:
```
keytool -importkeystore -srckeystore <certificate.p12> -srcstoretype pkcs12 -destkeystore <cert.jks>
```

### Certificate Authority Issues
If your remote signing authority is using their own certificates as a CA, you may need to import those certificates into your Java truststore to allow the handshake to go through. Note that when running the dockerized application, these CA certificates are to be one certificate per file (chain certificates are not supported).

## Install

`mvn clean install`


## Debug
If running in VS Code, a launch.json has been included to allow for ease of debugging. A .env file can be created using the sample.env file as a starting point. Once this settings file is in place, simply click the green arrow in the debug tab to run the application. At this point all breakpoints will function as expected.

## Run

### Java JAR:

`java -jar target/jpo-security-svcs-0.0.1-SNAPSHOT.jar`

### Docker:

`docker build .`

(Take note of image reported by docker build)

`docker run -p 8090:8090 <image>`

### Docker Compose
A docker-compose.yml file has been included as an example for running the application under Docker Compose. Additionally a sample.env has been included to show which values are expected.

The docker-compose.yml file is configured for using certificates, and mounts a volume to the container pointing to the local `./src/main/resources/creds` directory. This directory (or another you chose to point to) should contain your own JKS used to sign messages for MTLS. It should also contain a subdirectory, "caCerts", containing any CA certificates (one per file) from the remote system that need to be installed in the Java truststore on boot.

To use, copy the sample.env file to a new '.env' file and replace with your settings. Then, simply run the following command:
```
docker-compose up --build -d
```
This will spin up a new container and run it listening on port 8090. To stop the container, run the following command:
```
docker-compose down
```

## Test
## Usage
### RESTful API
The following table depicts the RESTful API exposed by the jpo-security-svcs module:
| Verb | path | Content Type | Functionality | Request Body Format | Response Body Format |
| ---- | ---- | ------------ | ------------- | -------------------- | --------------------- |
| POST | /sign|application/json|signs data provided in the body of the request | {"message":"Base64 encoded unsigned data"} | {"result": "Base64 Encoded Signed Data"}

### Example
Send a POST request to `localhost:8090/sign` with a body of the form:

```
Expand All @@ -81,16 +40,62 @@ Expected output:
}
```

## Configuration
## Installation
### Docker
1. Install Docker
1. Set up a directory to contain your own JKS file.
1. Set up a subdirectory in the above directory called "caCerts" to contain any CA certificates (one per file) from the remote system that need to be installed in the Java truststore on boot.
1. Copy the sample.env file to a new '.env' file and populate with your settings. See [Configuration](#configuration) for more information.
1. Build & run the application using `docker compose up --build -d`
1. To spin down the container, run `docker compose down`

### Manual
1. Install Maven
1. Install Java
1. Configure the properties file as needed (see [Configuration](#configuration))
1. Package the application using `mvn clean install`
1. Run the application using `java -jar target/jpo-security-svcs-0.0.1-SNAPSHOT.jar`

## Configuration
In `./src/main/resources/application.properties` you'll find the following properties which can be defined whether on the command line or by environment variable. To define the property on the command line, insert `--` to the front of the Property name, for example, `--server.port=8091`:

| Property | Meaning | Default Value | Environment Variable Substitute |
| -----------|------------|-----------------|-----------|
| server.port | The port number to which this service will be listening.| 8090 |SERVER_PORT|
| sec.useHsm | Whether to use an HSM or not. | false | SEC_USE_HSM |
| sec.cryptoServiceBaseUri | Cryptographic service endpoint URI excluding path. For example, `http://<ip>:<port>` OR `http://server.dns.name` including the port number, if any. | - |SEC_CRYPTO_SERVICE_BASE_URI|
| sec.cryptoServiceEndpointSignPath | The REST endpoint path of the external service. | /tmc/signtim |SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH|
| sec.useCertficates | Whether to use certificates or not. | true | SEC_USE_CERTIFICATES |
| -------- | ------- | ------------- | ------------------------------- |
| server.port | The port number to which this service will be listening. | 8090 | SERVER_PORT |
| sec.cryptoServiceBaseUri | Cryptographic service endpoint URI excluding path. For example, `http://<ip>:<port>` OR `http://server.dns.name` including the port number, if any. | - | SEC_CRYPTO_SERVICE_BASE_URI|
| sec.cryptoServiceEndpointSignPath | The REST endpoint path of the external service. | /tmc/signtim |SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH |
| sec.useCertificates | Whether to use certificates or not. | true | SEC_USE_CERTIFICATES |
| sec.keyStorePath | The path to the keystore file. | /home/cert.jks | SEC_KEY_STORE_PATH |
| sec.keyStorePassword | The password for the keystore file. | password | SEC_KEY_STORE_PASSWORD |

## Mutual TLS Authentication
For enhanced security, MTLS is used to communicate with a remote signing system. This requires properly configured certificates from the remote system to properly perform - work with your remote signing authority to obtain necessary certificates.

### Certificate Conversion
Certificates can be in several different formats, including the widely used PEM format. Because this is a Java application, the signing certificates must be in the Java Keystore format to be used. The following commands using [OpenSSL](https://www.openssl.org/) and the Java keytool will convert a PEM file to a Java Keystore file.

1. Convert the PEM file to a PKCS12 file:
```
openssl pkcs12 -export -in <cert.pem> -inkey <key.pem> -out <certificate.p12> -name <alias>
```
2. Convert the PKCS12 file to a Java Keystore file:
```
keytool -importkeystore -srckeystore <certificate.p12> -srcstoretype pkcs12 -destkeystore <cert.jks>
```

### Certificate Authority Issues
If your remote signing authority is using their own certificates as a CA, you may need to import those certificates into your Java truststore to allow the handshake to go through. Note that when running the dockerized application, these CA certificates are to be one certificate per file (chain certificates are not supported).

## Debugging
If running in VS Code, a launch.json has been included to allow for ease of debugging. A .env file can be created using the sample.env file as a starting point. Once this settings file is in place, simply click the green arrow in the debug tab to run the application. At this point all breakpoints will function as expected.

## Testing
### Unit Tests
To run the unit tests, reopen the project in the provided dev container and run the following command:
`mvn test`

### hit_endpoint.sh Script
A script has been provided to test the endpoint. To use this script, run the following command:
`./hit_endpoint.sh <data to sign>`

This script will send a POST request to the endpoint with the provided data to sign. The output will be the signed data returned from the endpoint. See [Usage](#usage) for more information on the expected input and output.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
environment:
SEC_CRYPTO_SERVICE_BASE_URI: ${SEC_CRYPTO_SERVICE_BASE_URI}
SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH: ${SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH}
SEC_USE_CERTFICATES: ${SEC_USE_CERTFICATES}
SEC_USE_CERTIFICATES: ${SEC_USE_CERTIFICATES}
#SEC_KEY_STORE_PATH: ${SEC_KEY_STORE_PATH}
SEC_KEY_STORE_PASSWORD: ${SEC_KEY_STORE_PASSWORD}
volumes:
Expand Down
11 changes: 11 additions & 0 deletions docs/Release_notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Jpo-security-svcs Release Notes
----------------------------

Version 1.5.0, released September 2024
----------------------------------------
### **Summary**
The changes for the jpo-security-svcs v1.5.0 release include unit tests, documentation updates, and a GitHub action to publish java artifacts to GitHub's hosted Maven Central.

Enhancements in this release:
- CDOT PR 10: Added unit tests to the project
- CDOT PR 11: Revised documentation for accuracy
- CDOT PR 12: Added GitHub action to publish java artifacts to GitHub's hosted Maven Central


Version 1.4.0, released February 2024
----------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/dockerhub.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ services:
environment:
SEC_CRYPTO_SERVICE_BASE_URI: ${SEC_CRYPTO_SERVICE_BASE_URI}
SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH: ${SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH}
SEC_USE_CERTFICATES: ${SEC_USE_CERTFICATES}
SEC_USE_CERTIFICATES: ${SEC_USE_CERTIFICATES}
SEC_KEY_STORE_PASSWORD: ${SEC_KEY_STORE_PASSWORD}
volumes:
- ./creds:/usr/local/share/ca-certificates
Expand Down
37 changes: 33 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>usdot.jpo.ode</groupId>
<artifactId>jpo-security-svcs</artifactId>
<version>1.4.0-SNAPSHOT</version>
<version>1.5.0-SNAPSHOT</version>

<packaging>jar</packaging>
<name>jpo-security-svcs</name>
Expand All @@ -23,11 +23,12 @@
<sonar.organization>usdot-jpo-ode-1</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<!-- JaCoCo Properties -->
<jacoco.version>0.8.8</jacoco.version>
<jacoco.version>0.8.11</jacoco.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<sonar.language>java</sonar.language>
<github_organization>usdot-jpo-ode</github_organization>
</properties>


Expand Down Expand Up @@ -95,7 +96,29 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<argLine>
-javaagent:${user.home}/.m2/repository/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar</argLine>
<!-- <testFailureIgnore>true</testFailureIgnore> -->
<enableProcessChecker>all</enableProcessChecker>
<shutdown>exit</shutdown>
<systemPropertyVariables>
<loader.path>${loader.path}</loader.path>
<buildDirectory>${project.build.directory}</buildDirectory>
</systemPropertyVariables>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit4</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
Expand All @@ -118,5 +141,11 @@
</plugin>
</plugins>
</build>

<distributionManagement>
<repository>
<id>github</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/${github_organization}/jpo-security-svcs</url>
</repository>
</distributionManagement>
</project>
4 changes: 2 additions & 2 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ SEC_CRYPTO_SERVICE_BASE_URI=
#The REST endpoint path of the external service if `sec.useHsm=false`
SEC_CRYPTO_SERVICE_ENDPOINT_SIGN_PATH=/tmc/signtim

SEC_USE_CERTFICATES=true
#The following properties are valid only if sec.useCertficates=true
SEC_USE_CERTIFICATES=true
#The following properties are valid only if sec.useCertificates=true
SEC_KEY_STORE_PATH=/home/cert.jks
SEC_KEY_STORE_PASSWORD=password
Loading
Loading