Skip to content

Commit 1aaa159

Browse files
Merge pull request #76 from cyberark/74-contrib-sslcontext-vvidovic-master
74 [contrib] Enable use of custom SSLContext
2 parents d6d1b47 + f5f80cd commit 1aaa159

File tree

6 files changed

+175
-27
lines changed

6 files changed

+175
-27
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
variables that have spaces were not encoded correctly
1111
([https://github.com/cyberark/conjur-api-java#78](https://github.com/cyberark/conjur-api-java/issues/78))
1212

13+
### Added
14+
- Implemented [#74](https://github.com/cyberark/conjur-api-java/issues/74)
15+
- Updated code to enable adding custom javax.net.ssl.SSLContext to Conjur which
16+
enables us to set up a trust between application and Conjur server from Java
17+
code
18+
- README has been updated with example SSLContext setup and it's use in Conjur
19+
class constructors
20+
1321
## [2.2.1] - 2020-05-08
1422
### Fixed
1523
- README has been updated to reflect the correct/expected usage of this SDK ([#70](https://github.com/cyberark/conjur-api-java/issues/70),

README.md

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,45 @@ values (like the API key) in source-controlled property files!
187187

188188
## Set Up Trust Between App and Conjur
189189

190-
By default, the Conjur appliance generates and uses self-signed SSL certificates (Java-specific
191-
certificates known as cacerts). Without trusting them, your Java app will not be able to connect
192-
to the Conjur server over APIs and so you will need to configure your app to trust them. You can
193-
accomplish this by loading the Conjur certificate into Java's CA keystore that holds the list of
194-
all the allowed certificates for https connections.
190+
By default, the Conjur appliance generates and uses self-signed SSL certificates. Without
191+
trusting them, your Java app will not be able to connect to the Conjur server over APIs
192+
and so you will need to configure your app to trust them. You can accomplish this by using
193+
the [Client-level `SSLContext`](#client--level-trust) when creating the client or with a
194+
[JVM-level trust](#jvm--level-trust) by loading the Conjur certificate into Java's CA
195+
keystore that holds the list of all the allowed certificates for https connections.
196+
197+
### Client-level trust
198+
199+
We can set up a trust between the client application and a Conjur server using
200+
Java `javax.net.ssl.SSLContext`. This can be done from Java code during
201+
Conjur class initialization.
202+
203+
Usable in Kubernetes/OpenShift environment to setup TLS trust with Conjur
204+
server dynamically from the Kubernetes secret and/or configmap data.
205+
206+
```java
207+
final String conjurTlsCaPath = "/var/conjur-config/tls-ca.pem";
208+
209+
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
210+
final FileInputStream certIs = new FileInputStream(conjurTlsCaPath);
211+
final Certificate cert = cf.generateCertificate(certIs);
212+
213+
final KeyStore ks = KeyStore.getInstance("JKS");
214+
ks.load(null);
215+
ks.setCertificateEntry("conjurTlsCaPath", cert);
216+
217+
final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
218+
tmf.init(ks);
219+
220+
SSLContext conjurSSLContext = SSLContext.getInstance("TLS");
221+
conjurSSLContext.init(null, tmf.getTrustManagers(), null);
222+
```
223+
224+
### JVM-level trust
225+
226+
For a JVM-level trust between Conjur and the API client, you need to load the Conjur
227+
certificate into Java's CA keystore that holds the list of all the allowed certificates
228+
for https connections.
195229

196230
First, we need to get a copy of this certificate, which you can get using `openssl`. Run the
197231
following step from a terminal with OpenSSL that has access to Conjur:
@@ -287,6 +321,8 @@ import net.conjur.api.Conjur;
287321

288322
// Configured using environment variables
289323
Conjur conjur = new Conjur();
324+
// or using custom SSLContext setup as conjurSSLContext variable
325+
Conjur conjur = new Conjur(conjurSSLContext);
290326
```
291327

292328
### System Properties
@@ -303,6 +339,8 @@ import net.conjur.api.Conjur;
303339

304340
// Configured using system properties
305341
Conjur conjur = new Conjur();
342+
// or using custom SSLContext setup as conjurSSLContext variable
343+
Conjur conjur = new Conjur(conjurSSLContext);
306344
```
307345

308346
### System Properties with Maven
@@ -320,6 +358,8 @@ import net.conjur.api.Conjur;
320358

321359
// Configured using system properties
322360
Conjur conjur = new Conjur();
361+
// or using custom SSLContext setup as conjurSSLContext variable
362+
Conjur conjur = new Conjur(conjurSSLContext);
323363
```
324364

325365
### Username and Password
@@ -337,6 +377,8 @@ import net.conjur.api.Conjur;
337377
Conjur conjur = new Conjur('host/host-id', 'password-or-api-key');
338378
// or
339379
Conjur conjur = new Conjur('username', 'password-or-api-key');
380+
// or using custom SSLContext setup as conjurSSLContext variable
381+
Conjur conjur = new Conjur('username', 'password-or-api-key', conjurSSLContext);
340382
```
341383

342384
### Credentials
@@ -354,6 +396,8 @@ import net.conjur.api.Credentials;
354396
// regarding how 'password-or-api-key' is processed.
355397
Credentials credentials = new Credentials('username', 'password-or-api-key');
356398
Conjur conjur = new Conjur(credentials);
399+
// or using custom SSLContext setup as conjurSSLContext variable
400+
Conjur conjur = new Conjur(credentials, conjurSSLContext);
357401
```
358402

359403
### Authorization Token
@@ -371,6 +415,8 @@ import net.conjur.api.Token;
371415

372416
Token token = Token.fromFile(Paths.get('path/to/conjur/authentication/token.json'));
373417
Conjur conjur = new Conjur(token);
418+
// or using custom SSLContext setup as conjurSSLContext variable
419+
Conjur conjur = new Conjur(token, conjurSSLContext);
374420
```
375421

376422
Alternatively, use the `CONJUR_AUTHN_TOKEN_FILE` environment variable:
@@ -387,6 +433,8 @@ import net.conjur.api.Token;
387433

388434
Token token = Token.fromEnv();
389435
Conjur conjur = new Conjur(token);
436+
// or using custom SSLContext setup as conjurSSLContext variable
437+
Conjur conjur = new Conjur(token, conjurSSLContext);
390438
```
391439

392440
## Client APIs
@@ -400,10 +448,15 @@ a secret from Conjur, so we provide some sample code for this use case below.
400448
The client can be instantiated with any of these methods:
401449
```java
402450
Conjur client = Conjur();
451+
Conjur client = Conjur(SSLContext sslContext);
403452
Conjur client = Conjur(String username, String password);
453+
Conjur client = Conjur(String username, String password, SSLContext sslContext);
404454
Conjur client = Conjur(String username, String password, String authnUrl);
455+
Conjur client = Conjur(String username, String password, String authnUrl, SSLContext sslContext);
405456
Conjur client = Conjur(Credentials credentials);
457+
Conjur client = Conjur(Credentials credentials, SSLContext sslContext);
406458
Conjur client = Conjur(Token token);
459+
Conjur client = Conjur(Token token, SSLContext sslContext);
407460
```
408461

409462
_Note:_ **As mentioned before, if you use the default `CONJUR_AUTHN_URL` value or your

src/main/java/net/conjur/api/Conjur.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package net.conjur.api;
22

3+
import javax.net.ssl.SSLContext;
4+
35
/**
46
* Entry point for the Conjur API client.
57
*/
@@ -14,6 +16,14 @@ public Conjur(){
1416
this(Credentials.fromSystemProperties());
1517
}
1618

19+
/**
20+
* Create a Conjur instance that uses credentials from the system properties
21+
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
22+
*/
23+
public Conjur(SSLContext sslContext){
24+
this(Credentials.fromSystemProperties(), sslContext);
25+
}
26+
1727
/**
1828
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
1929
* @param username username for the Conjur identity to authenticate as
@@ -23,6 +33,16 @@ public Conjur(String username, String password) {
2333
this(new Credentials(username, password));
2434
}
2535

36+
/**
37+
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
38+
* @param username username for the Conjur identity to authenticate as
39+
* @param password password or api key for the Conjur identity to authenticate as
40+
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
41+
*/
42+
public Conjur(String username, String password, SSLContext sslContext) {
43+
this(new Credentials(username, password), sslContext);
44+
}
45+
2646
/**
2747
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
2848
* @param username username for the Conjur identity to authenticate as
@@ -33,21 +53,49 @@ public Conjur(String username, String password, String authnUrl) {
3353
this(new Credentials(username, password, authnUrl));
3454
}
3555

56+
/**
57+
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
58+
* @param username username for the Conjur identity to authenticate as
59+
* @param password password or api key for the Conjur identity to authenticate as
60+
* @param authnUrl the conjur authentication url
61+
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
62+
*/
63+
public Conjur(String username, String password, String authnUrl, SSLContext sslContext) {
64+
this(new Credentials(username, password, authnUrl), sslContext);
65+
}
66+
3667
/**
3768
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
3869
* @param credentials the conjur identity to authenticate as
3970
*/
4071
public Conjur(Credentials credentials) {
41-
variables = new Variables(credentials);
72+
this(credentials, null);
4273
}
4374

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

4584
/**
4685
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
4786
* @param token the conjur authorization token to use
4887
*/
4988
public Conjur(Token token) {
50-
variables = new Variables(token);
89+
this(token, null);
90+
}
91+
92+
/**
93+
* Create a Conjur instance that uses a ResourceClient & an AuthnClient constructed with the given credentials
94+
* @param token the conjur authorization token to use
95+
* @param sslContext the {@link SSLContext} to use for connections to Conjur server
96+
*/
97+
public Conjur(Token token, SSLContext sslContext) {
98+
variables = new Variables(token, sslContext);
5199
}
52100

53101
/**

src/main/java/net/conjur/api/Variables.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
package net.conjur.api;
22

3+
import javax.net.ssl.SSLContext;
4+
35
import net.conjur.api.clients.ResourceClient;
46

57
public class Variables {
68

79
private ResourceClient resourceClient;
810

911
public Variables(Credentials credentials) {
10-
resourceClient = new ResourceClient(credentials, Endpoints.fromCredentials(credentials));
12+
this(credentials, null);
13+
}
14+
15+
public Variables(Credentials credentials, SSLContext sslContext) {
16+
resourceClient =
17+
new ResourceClient(credentials, Endpoints.fromCredentials(credentials), sslContext);
1118
}
1219

1320
public Variables(Token token) {
14-
resourceClient = new ResourceClient(token, Endpoints.fromSystemProperties());
21+
this(token, null);
22+
}
23+
24+
public Variables(Token token, SSLContext sslContext) {
25+
resourceClient = new ResourceClient(token, Endpoints.fromSystemProperties(), sslContext);
1526
}
1627

1728
public String retrieveSecret(String variableId) {

src/main/java/net/conjur/api/clients/AuthnClient.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
package net.conjur.api.clients;
22

3-
import net.conjur.api.AuthnProvider;
4-
import net.conjur.api.Credentials;
5-
import net.conjur.api.Endpoints;
6-
import net.conjur.api.Token;
7-
import net.conjur.util.rs.HttpBasicAuthFilter;
3+
import static net.conjur.util.EncodeUriComponent.encodeUriComponent;
84

5+
import javax.net.ssl.SSLContext;
96
import javax.ws.rs.WebApplicationException;
107
import javax.ws.rs.client.Client;
118
import javax.ws.rs.client.ClientBuilder;
129
import javax.ws.rs.client.Entity;
1310
import javax.ws.rs.client.WebTarget;
1411
import javax.ws.rs.core.Response;
1512

16-
import static net.conjur.util.EncodeUriComponent.encodeUriComponent;
13+
import net.conjur.api.AuthnProvider;
14+
import net.conjur.api.Credentials;
15+
import net.conjur.api.Endpoints;
16+
import net.conjur.api.Token;
17+
import net.conjur.util.rs.HttpBasicAuthFilter;
1718

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

3435
public AuthnClient(final Credentials credentials, final Endpoints endpoints) {
36+
this(credentials, endpoints, null);
37+
}
38+
39+
public AuthnClient(final Credentials credentials,
40+
final Endpoints endpoints,
41+
final SSLContext sslContext) {
3542
this.endpoints = endpoints;
3643

37-
init(credentials.getUsername(), credentials.getPassword());
44+
init(credentials.getUsername(), credentials.getPassword(), sslContext);
3845

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

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

5361
// implementation of AuthnProvider method
62+
@Override
5463
public Token authenticate(boolean useCachedToken) {
5564
return authenticate();
5665
}
@@ -66,9 +75,10 @@ public String login(){
6675
return res.readEntity(String.class);
6776
}
6877

69-
private void init(final String username, final String password){
78+
private void init(final String username, final String password, final SSLContext sslContext) {
7079
final ClientBuilder builder = ClientBuilder.newBuilder()
71-
.register(new HttpBasicAuthFilter(username, password));
80+
.register(new HttpBasicAuthFilter(username, password))
81+
.sslContext(sslContext);
7282

7383
Client client = builder.build();
7484
WebTarget root = client.target(endpoints.getAuthnUri());

0 commit comments

Comments
 (0)