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

[SIP2-200]. Enhance HTTP Endpoint Security with TLS and FIPS-140-2 Compliant Cryptography #160

Closed
wants to merge 11 commits into from
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,61 @@ $ java -jar edge-sip2-fat.jar -conf '{"port":1234,"okapiUrl":"https://folio-snap
|`path`|string|File system path to JKS key store|
|`password`|string|The password for the JKS key store|

## Security Configuration

Configuration information is specified in two forms:
1. System Properties - General configuration
2. Properties File - Configuration specific to the desired secure store

### System Properties

| Property | Default | Description |
|---------------------------|---------------------|---------------------------------------------------------------------------|
| `port` | `8081` | Server port to listen on |
| `okapi_url` | *required* | Where to find Okapi (URL) |
| `secure_store` | `Ephemeral` | Type of secure store to use. Valid: `Ephemeral`, `AwsSsm`, `Vault` |
| `secure_store_props` | `NA` | Path to a properties file specifying secure store configuration |
| `token_cache_ttl_ms` | `3600000` | How long to cache JWTs, in milliseconds (ms) |
| `null_token_cache_ttl_ms` | `30000` | How long to cache login failure (null JWTs), in milliseconds (ms) |
| `token_cache_capacity` | `100` | Max token cache size |
| `log_level` | `INFO` | Log4j Log Level |
| `request_timeout_ms` | `30000` | Request Timeout |
| `api_key_sources` | `PARAM,HEADER,PATH` | Defines the sources (order of precendence) of the API key. |

### System Properties for TLS configuration for Http server
To configure Transport Layer Security (TLS) for the HTTP server in an edge module, the following configuration parameters should be used.
Parameters marked as Required are required only in case when ssl_enabled is set to true.

| Property | Default | Description |
|-----------------------------------|-------------------|---------------------------------------------------------------------------------------------|
| `http-server.ssl_enabled` | `false` | Set whether SSL/TLS is enabled for Vertx Http Server |
| `http-server.keystore_type` | `NA` | (Required). Set the type of the keystore. Common types include `JKS`, `PKCS12`, and `BCFKS` |
| `http-server.keystore_provider` | `NA` | Set the provider name of the key store |
| `http-server.keystore_path` | `NA` | (Required). Set the location of the keystore file in the local file system |
| `http-server.keystore_password` | `NA` | (Required). Set the password for the keystore |
| `http-server.key_alias` | `NA` | Set the alias of the key within the keystore. |
| `http-server.key_alias_password` | `NA` | Optional param that points to a password of `key_alias` if it protected |

### System Properties for TLS configuration for Web Client
To configure Transport Layer Security (TLS) for Web clients in the edge module, you can use the following configuration parameters.
Truststore parameters for configuring Web clients are optional even when ssl_enabled = true.
If truststore parameters need to be populated, truststore_type, truststore_path and truststore_password are required.

| Property | Default | Description |
|-----------------------------------|-------------------|----------------------------------------------------------------------------------|
| `web-client.ssl_enabled` | `false` | Set whether SSL/TLS is enabled for Vertx Http Server |
| `web-client.truststore_type` | `NA` | Set the type of the keystore. Common types include `JKS`, `PKCS12`, and `BCFKS` |
| `web-client.truststore_provider` | `NA` | Set the provider name of the key store |
| `web-client.truststore_path` | `NA` | Set the location of the keystore file in the local file system |
| `web-client.truststore_password` | `NA` | Set the password for the keystore |
| `web-client.key_alias` | `NA` | Set the alias of the key within the keystore. |
| `web-client.key_alias_password` | `NA` | Optional param that points to a password of `key_alias` if it protected |


## Additional information

There will be a single instance of okapi client per OkapiClientFactory and per tenant, which means that this client should never be closed or else there will be runtime errors. To enforce this behaviour, method close() has been removed from OkapiClient class.

## Permissions
All permission associated with edge-sip2
```
Expand Down
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>

<dependency>
<groupId>org.folio</groupId>
<artifactId>edge-common</artifactId>
<version>4.7.0-SNAPSHOT</version>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>io.vertx</groupId>
Expand Down
30 changes: 23 additions & 7 deletions src/main/java/org/folio/edge/sip2/MainVerticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@
import io.vertx.core.net.NetSocket;
import io.vertx.core.parsetools.RecordParser;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import java.nio.charset.Charset;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.folio.edge.core.Constants;
import org.folio.edge.sip2.cache.TokenCacheFactory;
import org.folio.edge.sip2.domain.PreviousMessage;
import org.folio.edge.sip2.handlers.CheckinHandler;
Expand Down Expand Up @@ -68,6 +71,7 @@ public class MainVerticle extends AbstractVerticle {
private static final int HEALTH_CHECK_PORT = 8081;
private static final String HEALTH_CHECK_PATH = "/admin/health";
private static final String IPADDRESS = "ipAddress";
private static final String SYS_PORT = "port";
private Map<Command, ISip2RequestHandler> handlers;
private NetServer server;
private final Logger log = LogManager.getLogger();
Expand Down Expand Up @@ -106,23 +110,26 @@ public void start(Promise<Void> startFuture) {
TokenCacheFactory.initialize(config()
.getInteger(SYS_TOKEN_CACHE_CAPACITY, DEFAULT_TOKEN_CACHE_CAPACITY));


// We need to reduce the complexity of this method...
setupHanlders();

//set Config object's defaults
int port = config().getInteger("port"); // move port to netServerOptions
NetServerOptions options = new NetServerOptions(
config().getJsonObject("netServerOptions", new JsonObject()))
.setPort(port);
final int port = config().getInteger(SYS_PORT);
log.info("Using port: {}", port);
NetServerOptions options = new NetServerOptions(config()
.getJsonObject("netServerOptions", new JsonObject()));
options.setPort(port);

server = vertx.createNetServer(options);
// move port to httpServerOptions
// initialize response compression

log.info("Deployed verticle at port {}", port);

final Metrics metrics = Metrics.getMetrics(port);
metricsMap.putIfAbsent(port, metrics);

server = vertx.createNetServer(options);

server.connectHandler(socket -> {

String clientAddress = socket.remoteAddress().host();
Expand Down Expand Up @@ -320,7 +327,9 @@ private void resendPreviousMessage(SessionData sessionData,
private void setupHanlders() {
if (handlers == null) {
String okapiUrl = config().getString("okapiUrl");
final WebClient webClient = WebClient.create(vertx);
Integer timeout = config().getInteger(Constants.SYS_REQUEST_TIMEOUT_MS);
WebClientOptions webClientOptions = initDefaultWebClientOptions(timeout);
final WebClient webClient = WebClient.create(vertx, webClientOptions);
final Injector injector = Guice.createInjector(
new FolioResourceProviderModule(okapiUrl, webClient),
new ApplicationModule());
Expand All @@ -342,6 +351,13 @@ private void setupHanlders() {
}
}

private WebClientOptions initDefaultWebClientOptions(int timeout) {
return new WebClientOptions()
.setSsl(true)
.setIdleTimeoutUnit(TimeUnit.MILLISECONDS).setIdleTimeout(timeout)
.setConnectTimeout(timeout);
}

private void callAdminHealthCheckService() {
HttpServer httpServer = vertx.createHttpServer();

Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/folio/edge/sip2/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*
*/
public final class Utils {

private Utils() {
super();
}
Expand Down
Binary file added src/test/resources/sample_keystore.jks
Binary file not shown.
30 changes: 18 additions & 12 deletions src/test/resources/test-sip2.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
"port": 6443,
"okapiUrl": "http://example.com",
"tenantConfigRetrieverOptions": {
"scanPeriod": 1000,
"stores": [
{
"type": "file",
"format": "json",
"config": {
"path": "sip2-tenants.conf"
},
"optional": false
}
]
}
"scanPeriod": 1000,
"stores": [
{
"type": "file",
"format": "json",
"config": {
"path": "sip2-tenants.conf"
},
"optional": false
}
]
},
"response_compression": false,
"http-server.ssl_enabled": true,
"http-server.keystore_type": "JKS",
"http-server.keystore_path": "sample_keystore.jks",
"http-server.keystore_password": "password",
"request_timeout_ms": 5000
}