Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
108 changes: 107 additions & 1 deletion flipt-client-java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ The `FliptClient.builder()` method returns a `FliptClient.Builder` object that a
- `authentication`: The authentication strategy to use when communicating with the upstream Flipt instance. If not provided, the client will default to no authentication. See the [Authentication](#authentication) section for more information.
- `reference`: The [reference](https://docs.flipt.io/guides/user/using-references) to use when fetching flag state. If not provided, reference will not be used.
- `fetchMode`: The fetch mode to use when fetching flag state. If not provided, the client will default to polling.
- `errorStrategy`: The error strategy to use when fetching flag state. If not provide, the client will be default to fail. See the [Error Strategies](#error-strategies) section for more information.
- `errorStrategy`: The error strategy to use when fetching flag state. If not provided, the client will default to fail. See the [Error Strategies](#error-strategies) section for more information.
- `snapshot`: The initial snapshot to use when instantiating the client. See the [Snapshotting](#snapshotting) section for more information.
- `tlsConfig`: The TLS configuration to use when connecting to the upstream Flipt instance. See the [TLS Configuration](#tls-configuration) section for more information.

### Authentication

Expand All @@ -150,6 +151,111 @@ The `FliptClient` supports the following authentication strategies:
- [Client Token Authentication](https://docs.flipt.io/authentication/using-tokens)
- [JWT Authentication](https://docs.flipt.io/authentication/using-jwts)

### TLS Configuration

The `FliptClient` supports configuring TLS settings for secure connections to Flipt servers. This is useful when:

- Connecting to Flipt servers with self-signed certificates
- Using custom Certificate Authorities (CAs)
- Implementing mutual TLS authentication
- Testing with insecure connections (development only)

#### Basic TLS with Custom CA Certificate

```java
// Using a CA certificate file
TlsConfig tlsConfig = TlsConfig.withCaCertFile("/path/to/ca.pem");

FliptClient client = FliptClient.builder()
.url("https://flipt.example.com")
.tlsConfig(tlsConfig)
.build();
```

```java
// Using CA certificate data directly
String caCertData = Files.readString(Paths.get("/path/to/ca.pem"));
TlsConfig tlsConfig = TlsConfig.withCaCertData(caCertData);

FliptClient client = FliptClient.builder()
.url("https://flipt.example.com")
.tlsConfig(tlsConfig)
.build();
```

#### Mutual TLS Authentication

```java
// Using certificate and key files
TlsConfig tlsConfig = TlsConfig.withMutualTls(
"/path/to/client.pem",
"/path/to/client.key"
);

FliptClient client = FliptClient.builder()
.url("https://flipt.example.com")
.tlsConfig(tlsConfig)
.build();
```

```java
// Using certificate and key data directly
String clientCertData = Files.readString(Paths.get("/path/to/client.pem"));
String clientKeyData = Files.readString(Paths.get("/path/to/client.key"));

TlsConfig tlsConfig = TlsConfig.withMutualTlsData(clientCertData, clientKeyData);

FliptClient client = FliptClient.builder()
.url("https://flipt.example.com")
.tlsConfig(tlsConfig)
.build();
```

#### Advanced TLS Configuration

```java
// Full TLS configuration with all options
TlsConfig tlsConfig = TlsConfig.builder()
.caCertFile(Optional.of("/path/to/ca.pem"))
.clientCertFile(Optional.of("/path/to/client.pem"))
.clientKeyFile(Optional.of("/path/to/client.key"))
.insecureSkipVerify(Optional.of(false))
.build();

FliptClient client = FliptClient.builder()
.url("https://flipt.example.com")
.tlsConfig(tlsConfig)
.build();
```

#### Development Mode (Insecure)

**⚠️ WARNING: Only use this in development environments!**

```java
// Skip certificate verification (NOT for production)
TlsConfig tlsConfig = TlsConfig.insecure();

FliptClient client = FliptClient.builder()
.url("https://localhost:8443")
.tlsConfig(tlsConfig)
.build();
```

#### TLS Configuration Options

The `TlsConfig` class supports the following options:

- `caCertFile`: Path to custom CA certificate file (PEM format)
- `caCertData`: Raw CA certificate content (PEM format) - takes precedence over `caCertFile`
- `insecureSkipVerify`: Skip certificate verification (development only)
- `clientCertFile`: Client certificate file for mutual TLS (PEM format)
- `clientKeyFile`: Client private key file for mutual TLS (PEM format)
- `clientCertData`: Raw client certificate content (PEM format) - takes precedence over `clientCertFile`
- `clientKeyData`: Raw client private key content (PEM format) - takes precedence over `clientKeyFile`

> **Note**: When both file paths and data are provided, the data fields take precedence. For example, if both `caCertFile` and `caCertData` are set, `caCertData` will be used.

### Error Strategies

The client `errorStrategy` method supports the following error strategies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
* var client = FliptClient.builder()
* .url("http://localhost:8080")
* .build();
*
* // With TLS configuration
* var tlsClient = FliptClient.builder()
* .url("https://flipt.example.com")
* .tlsConfig(TlsConfig.withCaCertFile("/path/to/ca.pem"))
* .build();
* }</pre>
*
* @since 1.0.0
Expand All @@ -44,6 +50,7 @@ public class FliptClient implements AutoCloseable {
private FetchMode fetchMode;
private ErrorStrategy errorStrategy;
private String snapshot;
private TlsConfig tlsConfig;

private final Pointer engine;
private final ObjectMapper objectMapper;
Expand Down Expand Up @@ -79,17 +86,19 @@ private FliptClient(
Duration updateInterval,
FetchMode fetchMode,
ErrorStrategy errorStrategy,
String snapshot) {
String snapshot,
TlsConfig tlsConfig) {
this.environment = environment != null ? environment : "default";
this.namespace = namespace != null ? namespace : "default";
this.url = url != null ? url : "http://localhost:8080";
this.authentication = authentication;
this.reference = reference;
this.requestTimeout = requestTimeout != null ? requestTimeout : Duration.ZERO;
this.updateInterval = updateInterval != null ? updateInterval : Duration.ZERO;
this.updateInterval = updateInterval != null ? updateInterval : Duration.ofSeconds(120);
this.fetchMode = fetchMode != null ? fetchMode : FetchMode.POLLING;
this.errorStrategy = errorStrategy != null ? errorStrategy : ErrorStrategy.FAIL;
this.snapshot = snapshot;
this.tlsConfig = tlsConfig;

this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new Jdk8Module());
Expand All @@ -105,7 +114,8 @@ private FliptClient(
Optional.ofNullable(this.reference),
Optional.ofNullable(this.fetchMode),
Optional.ofNullable(this.errorStrategy),
Optional.ofNullable(this.snapshot));
Optional.ofNullable(this.snapshot),
Optional.ofNullable(this.tlsConfig));

String clientOptionsSerialized;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ClientOptions {
private final Optional<FetchMode> fetchMode;
private final Optional<ErrorStrategy> errorStrategy;
private final Optional<String> snapshot;
private final Optional<TlsConfig> tlsConfig;

public ClientOptions(
Optional<String> environment,
Expand All @@ -28,7 +29,8 @@ public ClientOptions(
Optional<String> reference,
Optional<FetchMode> fetchMode,
Optional<ErrorStrategy> errorStrategy,
Optional<String> snapshot) {
Optional<String> snapshot,
Optional<TlsConfig> tlsConfig) {
this.environment = environment;
this.namespace = namespace;
this.url = url;
Expand All @@ -50,6 +52,7 @@ public ClientOptions(
this.fetchMode = fetchMode;
this.errorStrategy = errorStrategy;
this.snapshot = snapshot;
this.tlsConfig = tlsConfig;
}

@JsonProperty("environment")
Expand Down Expand Up @@ -101,4 +104,9 @@ public Optional<ErrorStrategy> getErrorStrategy() {
public Optional<String> getSnapshot() {
return snapshot;
}

@JsonProperty("tls_config")
public Optional<TlsConfig> getTlsConfig() {
return tlsConfig;
}
}
Loading
Loading