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

Enable to set custom SSLContext #75

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added
- Implemented [#74](https://github.com/cyberark/conjur-api-java/issues/74)
- Updated code to enable adding custom javax.net.ssl.SSLContext to Conjur which
enables us to set up a trust between application and Conjur server from Java
code
- README has been updated with example SSLContext setup and it's use in Conjur
class constructors

## [2.2.1] - 2020-05-08
### Fixed
- README has been updated to reflect the correct/expected usage of this SDK ([#70](https://github.com/cyberark/conjur-api-java/issues/70),
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,32 @@ conjur-default, May 6, 2020, trustedCertEntry,
There you have it! Now you are all configured to start leveraging the Conjur Java API in
your Java program.

### Programmatic Set Up Trust Between App and Conjur using SSLContext

We can set up a trust between the client application and a Conjur server using
Java javax.net.ssl.SSLContext. This can be done from Java code during
Conjur class initialization.

Usable in Kubernetes/OpenShift environment to setup TLS trust with Conjur
server dynamically from the Kubernetes secret and/or configmap data.

```java
final String conjurTlsCaPath = "/var/conjur-config/tls-ca.pem";

final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final FileInputStream certIs = new FileInputStream(conjurTlsCaPath);
final Certificate cert = cf.generateCertificate(certIs);

final KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null);
ks.setCertificateEntry("conjurTlsCaPath", cert);
final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);

SSLContext conjurSslContext = SSLContext.getInstance("TLS");
conjurSslContext.init(null, tmf.getTrustManagers(), null);
```

## Authorization Examples

As mentioned in the [Configuration](#configuration) section, you can provide varying ways
Expand Down Expand Up @@ -287,6 +313,8 @@ import net.conjur.api.Conjur;

// Configured using environment variables
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(conjurSslContext);
```

### System Properties
Expand All @@ -303,6 +331,8 @@ import net.conjur.api.Conjur;

// Configured using system properties
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(conjurSslContext);
```

### System Properties with Maven
Expand All @@ -320,6 +350,8 @@ import net.conjur.api.Conjur;

// Configured using system properties
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(conjurSslContext);
```

### Username and Password
Expand All @@ -337,6 +369,8 @@ import net.conjur.api.Conjur;
Conjur conjur = new Conjur('host/host-id', 'password-or-api-key');
// or
Conjur conjur = new Conjur('username', 'password-or-api-key');
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur('username', 'password-or-api-key', conjurSslContext);
```

### Credentials
Expand All @@ -354,6 +388,8 @@ import net.conjur.api.Credentials;
// regarding how 'password-or-api-key' is processed.
Credentials credentials = new Credentials('username', 'password-or-api-key');
Conjur conjur = new Conjur(credentials);
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(credentials, conjurSslContext);
```

### Authorization Token
Expand All @@ -371,6 +407,8 @@ import net.conjur.api.Token;

Token token = Token.fromFile(Paths.get('path/to/conjur/authentication/token.json'));
Conjur conjur = new Conjur(token);
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(token, conjurSslContext);
```

Alternatively, use the `CONJUR_AUTHN_TOKEN_FILE` environment variable:
Expand All @@ -387,6 +425,8 @@ import net.conjur.api.Token;

Token token = Token.fromEnv();
Conjur conjur = new Conjur(token);
// or using custom SSLContext setup as conjurSslContext variable
Conjur conjur = new Conjur(token, conjurSslContext);
```

## Client APIs
Expand All @@ -400,10 +440,15 @@ a secret from Conjur, so we provide some sample code for this use case below.
The client can be instantiated with any of these methods:
```java
Conjur client = Conjur();
Conjur client = Conjur(SSLContext sslContext);
Conjur client = Conjur(String username, String password);
Conjur client = Conjur(String username, String password, SSLContext sslContext);
Conjur client = Conjur(String username, String password, String authnUrl);
Conjur client = Conjur(String username, String password, String authnUrl, SSLContext sslContext);
Conjur client = Conjur(Credentials credentials);
Conjur client = Conjur(Credentials credentials, SSLContext sslContext);
Conjur client = Conjur(Token token);
Conjur client = Conjur(Token token, SSLContext sslContext);
```

_Note:_ **As mentioned before, if you use the default `CONJUR_AUTHN_URL` value or your
Expand Down
52 changes: 50 additions & 2 deletions src/main/java/net/conjur/api/Conjur.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.conjur.api;

import javax.net.ssl.SSLContext;

/**
* Entry point for the Conjur API client.
*/
Expand All @@ -14,6 +16,14 @@ public Conjur(){
this(Credentials.fromSystemProperties());
}

/**
* Create a Conjur instance that uses credentials from the system properties
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
*/
public Conjur(SSLContext sslContext){
this(Credentials.fromSystemProperties(), sslContext);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param username username for the Conjur identity to authenticate as
Expand All @@ -23,6 +33,16 @@ public Conjur(String username, String password) {
this(new Credentials(username, password));
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param username username for the Conjur identity to authenticate as
* @param password password or api key for the Conjur identity to authenticate as
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
*/
public Conjur(String username, String password, SSLContext sslContext) {
this(new Credentials(username, password), sslContext);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param username username for the Conjur identity to authenticate as
Expand All @@ -33,21 +53,49 @@ public Conjur(String username, String password, String authnUrl) {
this(new Credentials(username, password, authnUrl));
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param username username for the Conjur identity to authenticate as
* @param password password or api key for the Conjur identity to authenticate as
* @param authnUrl the conjur authentication url
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
*/
public Conjur(String username, String password, String authnUrl, SSLContext sslContext) {
this(new Credentials(username, password, authnUrl), sslContext);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param credentials the conjur identity to authenticate as
*/
public Conjur(Credentials credentials) {
variables = new Variables(credentials);
this(credentials, null);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param credentials the conjur identity to authenticate as
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
*/
public Conjur(Credentials credentials, SSLContext sslContext) {
variables = new Variables(credentials, sslContext);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param token the conjur authorization token to use
*/
public Conjur(Token token) {
variables = new Variables(token);
this(token, null);
}

/**
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
* @param token the conjur authorization token to use
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
*/
public Conjur(Token token, SSLContext sslContext) {
variables = new Variables(token, sslContext);
}

/**
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/net/conjur/api/Variables.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package net.conjur.api;

import javax.net.ssl.SSLContext;

import net.conjur.api.clients.ResourceClient;

public class Variables {

private ResourceClient resourceClient;

public Variables(Credentials credentials) {
resourceClient = new ResourceClient(credentials, Endpoints.fromCredentials(credentials));
this(credentials, null);
}

public Variables(Credentials credentials, SSLContext sslContext) {
resourceClient =
new ResourceClient(credentials, Endpoints.fromCredentials(credentials), sslContext);
}

public Variables(Token token) {
resourceClient = new ResourceClient(token, Endpoints.fromSystemProperties());
this(token, null);
}

public Variables(Token token, SSLContext sslContext) {
resourceClient = new ResourceClient(token, Endpoints.fromSystemProperties(), sslContext);
}

public String retrieveSecret(String variableId) {
Expand Down
30 changes: 20 additions & 10 deletions src/main/java/net/conjur/api/clients/AuthnClient.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package net.conjur.api.clients;

import net.conjur.api.AuthnProvider;
import net.conjur.api.Credentials;
import net.conjur.api.Endpoints;
import net.conjur.api.Token;
import net.conjur.util.rs.HttpBasicAuthFilter;
import static net.conjur.util.EncodeUriComponent.encodeUriComponent;

import javax.net.ssl.SSLContext;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

import static net.conjur.util.EncodeUriComponent.encodeUriComponent;
import net.conjur.api.AuthnProvider;
import net.conjur.api.Credentials;
import net.conjur.api.Endpoints;
import net.conjur.api.Token;
import net.conjur.util.rs.HttpBasicAuthFilter;

/**
* Conjur authentication service client.
*
*
* This client provides methods to get API tokens from the conjur authentication service,
* which can then be used to make authenticated calls to other conjur services.
*
Expand All @@ -32,9 +33,15 @@ public class AuthnClient implements AuthnProvider {
private String apiKey;

public AuthnClient(final Credentials credentials, final Endpoints endpoints) {
this(credentials, endpoints, null);
}

public AuthnClient(final Credentials credentials,
final Endpoints endpoints,
final SSLContext sslContext) {
this.endpoints = endpoints;

init(credentials.getUsername(), credentials.getPassword());
init(credentials.getUsername(), credentials.getPassword(), sslContext);

// replacing the password with an API key
this.apiKey = credentials.getPassword();
Expand All @@ -43,6 +50,7 @@ public AuthnClient(final Credentials credentials, final Endpoints endpoints) {
}
}

@Override
public Token authenticate() {
Response res = authenticate.request("application/json").post(Entity.text(apiKey), Response.class);
validateResponse(res);
Expand All @@ -51,6 +59,7 @@ public Token authenticate() {
}

// implementation of AuthnProvider method
@Override
public Token authenticate(boolean useCachedToken) {
return authenticate();
}
Expand All @@ -66,9 +75,10 @@ public String login(){
return res.readEntity(String.class);
}

private void init(final String username, final String password){
private void init(final String username, final String password, final SSLContext sslContext) {
final ClientBuilder builder = ClientBuilder.newBuilder()
.register(new HttpBasicAuthFilter(username, password));
.register(new HttpBasicAuthFilter(username, password))
.sslContext(sslContext);

Client client = builder.build();
WebTarget root = client.target(endpoints.getAuthnUri());
Expand Down
Loading