Skip to content

Commit

Permalink
Merge pull request #23 from cyberark/authn-kubernetes
Browse files Browse the repository at this point in the history
Adds support for token based authentication
  • Loading branch information
micahlee authored Jan 2, 2019
2 parents e20fe96 + 9d081f3 commit 530db48
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 18 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

## [2.1.0] - 2018-08-24
### Added
- Adds support for token based authentication to support Kubernetes Authenticator

## [2.0.0](https://github.com/cyberark/conjur-api-java/releases/tag/v2.0.0) - 2018-07-12
### Added
- License updated to Apache v2 - [PR #8](https://github.com/cyberark/conjur-api-java/pull/8)
Expand All @@ -21,7 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [1.3.0] - 2015-04-16
### Changed
- Change variable behavior to reflect the fact that you may not have 'read' permission on
- Change variable behavior to reflect the fact that you may not have 'read' permission on
a variable that you can 'execute' or 'update'.
- Allow SSL hostname verification to be disabled in order to facilitate development and debugging.

Expand Down
55 changes: 44 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ If you are using Maven to manage your project's dependencies, you can run `mvn i
<dependency>
<groupId>net.conjur.api</groupId>
<artifactId>conjur-api</artifactId>
<version>2.0.0</version>
<version>2.1.0</version>
</dependency>
```

If you aren't using Maven, you can add the `jar` in the normal way. This `jar` can be found in
the `target` directory created when you ran `mvn package`.

Note that we ran `mvn package` without running the integration tests, since these require access to a Conjur instance. You can run the
Note that we ran `mvn package` without running the integration tests, since these require access to a Conjur instance. You can run the
integration tests with `mvn package` once you finished with the configuration.

### Configuration

The simplest way to configure the Conjur API is by using environment variables, which is often a bit more convenient.
Environment variables are mapped to configuration variables by prepending `CONJUR_` to the all-caps name of the
The simplest way to configure the Conjur API is by using environment variables, which is often a bit more convenient.
Environment variables are mapped to configuration variables by prepending `CONJUR_` to the all-caps name of the
configuration variable. For example, `appliance_url` is `CONJUR_APPLIANCE_URL`, `account` is `CONJUR_ACCOUNT` etc.

The following environment variables are mandatory for running the API: CONJUR_ACCOUNT, CONJUR_AUTHN_LOGIN, CONJUR_AUTHN_API_KEY & CONJUR_APPLIANCE_URL.
Expand Down Expand Up @@ -96,20 +96,57 @@ to your keystore like this:
keytool -import -alias conjur-youraccount -keystore "$JRE_HOME/lib/security/cacerts" -file ./conjur-youraccount.der
```

## Basic Usage
## Examples

### Creating a Conjur Instance
### Authorization Patterns
All authorization options require the environment variables `CONJUR_ACCOUNT` and `CONJUR_APPLIANCE_URL` to be set:
```sh
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur HTTPS endpoint>
```

A `Conjur` instance provides access to the individual Conjur services. To create one, you'll need the environment
variables as described above. You will typically create a Conjur instance from these values in the following way:

#### Environment Variables
```sh
# Additionally set the following environment variables:
export CONJUR_AUTHN_LOGIN=<user/host identity>
export CONJUR_AUTHN_API_KEY=<user/host API key>
```
```java
// Using environment variables
Conjur conjur = new Conjur();
```

#### Username and Password
```java
// Authenticate using provided username/hostname and password/API key
Conjur conjur = new Conjur('host/host-id', 'api-key');
Conjur conjur = new Conjur('username', 'password');
```

where the Conjur object is logged in to the account & ready for use.
#### Credentials
```java
// Authenticate using a Credentials object
Credentials credentials = new Credentials('username', 'password');
Conjur conjur = new Conjur(credentials);
```

#### Authorization Token
```java
Token token = Token.fromFile(Paths.get('path/to/conjur/authentication/token.json'));
Conjur conjur = new Conjur(token);
```

Alternatively, to use the `CONJUR_AUTHN_TOKEN_FILE` environment variable:
```bash
export CONJUR_AUTHN_TOKEN_FILE="path/to/conjur/authentication/token.json"
```
```java
Token token = Token.fromEnv();
Conjur conjur = new Conjur(token);
```

### Variable Operations

Expand All @@ -119,14 +156,10 @@ A variable can have one or more (up to 20) secrets associated with it, and order
You will typically add secrets to variables & retrieve secrets from variables in the following way:

```java
Conjur conjur = new Conjur();
conjur.variables().addSecret(VARIABLE_KEY, VARIABLE_VALUE);
String retrievedSecret = conjur.variables().retrieveSecret(VARIABLE_KEY);
```


## JAX-RS Implementations

The Conjur API client uses the JAX-RS standard to make requests to the Conjur web services. In the future we plan to
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>net.conjur.api</groupId>
<artifactId>conjur-api</artifactId>
<version>2.0.0</version>
<version>2.1.0</version>

<name>Conjur</name>
<description>Client for the Conjur API</description>
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/net/conjur/api/Conjur.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ public Conjur(Credentials credentials) {
variables = new Variables(credentials);
}


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

/**
* Get a Variables instance configured with the same parameters as this instance.
* @return the variables instance
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/net/conjur/api/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
import org.joda.time.format.DateTimeFormatter;

import java.nio.charset.StandardCharsets;
import java.nio.charset.Charset;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Represents a Conjur API authentication token.
Expand All @@ -17,6 +23,7 @@ public class Token {
private static final DateTimeFormatter DATE_TIME_FORMATTER =
// tokens use dates like 2013-10-01 18:48:32 UTC
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ");
private static final String TOKEN_FILE_ENV_VARIABLE = "CONJUR_AUTHN_TOKEN_FILE";

// Hold our fields in here to facilitate json serialization/deserialization
private static class Fields {
Expand Down Expand Up @@ -123,6 +130,29 @@ public static Token fromJson(String json){
return new Token(json);
}

public static Token fromFile(Path filepath, Charset encoding)
throws IOException {
byte[] encodedJson = Files.readAllBytes(filepath);
String json = new String(encodedJson, encoding);
return fromJson(json);
}

public static Token fromFile(Path filepath)
throws IOException {
return fromFile(filepath, StandardCharsets.UTF_8);
}

public static Token fromEnv(Charset encoding)
throws IOException {
String tokenFilePath = System.getenv(TOKEN_FILE_ENV_VARIABLE);
return fromFile(Paths.get(tokenFilePath), encoding);
}

public static Token fromEnv()
throws IOException {
return fromEnv(StandardCharsets.UTF_8);
}

private String fromBase64(String base64){
return new String(Base64.decodeBase64(base64), StandardCharsets.UTF_8);
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/conjur/api/Variables.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public Variables(Credentials credentials) {
credentials.getUsername(), credentials.getPassword(), Endpoints.fromSystemProperties());
}

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

public String retrieveSecret(String variableId) {
return resourceClient.retrieveSecret(variableId);
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/net/conjur/api/clients/AuthnTokenClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.conjur.api.clients;
import net.conjur.api.AuthnProvider;
import net.conjur.api.Token;

public class AuthnTokenClient implements AuthnProvider {

private Token token;

public AuthnTokenClient(Token token) {
this.token = token;
}

public Token authenticate() {
return token;
}

public Token authenticate(boolean useCachedToken) {
return this.authenticate();
}

}
26 changes: 21 additions & 5 deletions src/main/java/net/conjur/api/clients/ResourceClient.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package net.conjur.api.clients;

import net.conjur.api.Endpoints;
import net.conjur.api.ResourceProvider;
import net.conjur.util.EncodeUriComponent;
import net.conjur.util.rs.TokenAuthFilter;

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 net.conjur.api.Endpoints;
import net.conjur.api.ResourceProvider;
import net.conjur.api.Token;
import net.conjur.util.EncodeUriComponent;
import net.conjur.util.rs.TokenAuthFilter;

/**
* Conjur service client.
*/
Expand All @@ -26,6 +27,13 @@ public ResourceClient(final String username, final String password, final Endpoi
init(username, password);
}

// Build ResourceClient using a Conjur auth token
public ResourceClient(final Token token, final Endpoints endpoints) {
this.endpoints = endpoints;

init(token);
}

public String retrieveSecret(String variableId) {
Response response = secrets.path(variableId).request().get(Response.class);
validateResponse(response);
Expand All @@ -51,6 +59,14 @@ private void init(String username, String password){
secrets = client.target(getEndpoints().getSecretsUri());
}

private void init(Token token){
final ClientBuilder builder = ClientBuilder.newBuilder()
.register(new TokenAuthFilter(new AuthnTokenClient(token)));

Client client = builder.build();

secrets = client.target(getEndpoints().getSecretsUri());
}
// TODO orenbm: Remove when we have a response filter to handle this
private void validateResponse(Response response) {
int status = response.getStatus();
Expand Down

0 comments on commit 530db48

Please sign in to comment.