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

Adds support for token based authentication #23

Merged
merged 6 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
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
47 changes: 36 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,49 @@ 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` are set:
micahlee marked this conversation as resolved.
Show resolved Hide resolved
```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
String authTokenString = new String(Files.readAllBytes(Paths.get('path/to/conjur/authentication/token.json')));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this should be encapsulated inside the library and not given by the developer. So the developer will only state that he/she is using a token from a file. The file should be given in the CONJUR_AUTHN_TOKEN_FILE environment variable or in the Conjur class constructor (instead of getting a token).
Once this is encapsulated, we need to also add a wait mechanism, in case the application is trying to use the token file before it got created by the sidecar. See similar mechanism here: https://github.com/cyberark/conjur-api-go/blob/b75a31bafc95e06780b81df18ba5dba8dd0dc32f/conjurapi/authn/token_file_authenticator.go#L23

Token token = Token.fromJson(authTokenString);
Conjur conjur = new Conjur(token);
```

### Variable Operations

Expand All @@ -119,14 +148,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
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/AuthnK8sClient.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 AuthnK8sClient implements AuthnProvider {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class should be called AuthnFileClient.
Even though reading a token from a file is currently used in K8s, it could easily be used in other flows as well and therefore I think that a generic name is better. We did the same in the other APIs, such as in Go: https://github.com/cyberark/conjur-api-go/blob/b75a31bafc95e06780b81df18ba5dba8dd0dc32f/conjurapi/authn/token_file_authenticator.go

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @rafis3, that we should get this to line up with our Go API client. I think we can do this iteratively though, lining it up with the TokenAuthenticator [1], rather than the TokenFileAuthenticator. I would suggest we rename this to AuthnTokenProvider. We can then add a ticket to add a AuthnTokenProvider that includes the file watch support.

[1] https://github.com/cyberark/conjur-api-go/blob/b75a31bafc95e06780b81df18ba5dba8dd0dc32f/conjurapi/authn/token_authenticator.go

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add that I think the should be updated to include the environment variable, but I would suggest we use CONJUR_AUTHN_TOKEN rather than the file path for this PR.


private Token token;

public AuthnK8sClient(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 K8S auth token
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that according to the official standard, you can either say K8s, k8s or Kubernetes but never K8S.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should reference K8s at all, this is just a normal Conjur access token at this point, correct?

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 AuthnK8sClient(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