Programmatic Java access to the Conjur API (for both Conjur Open Source and Enterprise versions). This Java SDK allows developers to build new apps in Java that communicate with Conjur by invoking our Conjur API to perform operations on stored data (add, retrieve, etc).
- Prerequisites
- Setup
- Configuration
- Set Up Trust Between App and Conjur
- Authorization Examples
- Client APIs
- JAX-RS Implementations
- Troubleshooting
- Contributing
- License
It is assumed that Conjur (OSS or Enterprise) and the Conjur CLI have already been installed in the environment and running in the background. If you haven't done so, follow these instructions for installation of the OSS and these for installation of Enterprise.
Once Conjur and the Conjur CLI are running in the background, you are ready to start setting up your Java app to work with our Conjur Java API!
Are you using this project with Conjur Open Source? Then we strongly recommend choosing the version of this project to use from the latest Conjur OSS suite release. Conjur maintainers perform additional testing on the suite release versions to ensure compatibility. When possible, upgrade your Conjur version to match the latest suite release; when using integrations, choose the latest suite release that matches your Conjur version. For any questions, please contact us on Discourse.
The Conjur Java API can be imported manually through building the source code locally, or by using a dependency configuration to import from Maven Central. Please refer to the following instructions for your specific use case.
You can grab the library's dependencies from the source by using Maven or locally by generating a JAR file and adding it to the project manually.
To do so from the source using Maven, following the setup steps below:
- Create new Maven project using an IDE of your choice
- If you are using Maven to manage your project's dependencies, include the following
Conjur API dependency snippet in your
pom.xml
under<project>
/<dependencies>
:
<dependency>
<groupId>com.cyberark.conjur.api</groupId>
<artifactId>conjur-api</artifactId>
<version>3.0.5</version>
</dependency>
NOTE: Depending on what version of the Java compiler you have, you may need to update
the version. At this time, the {version}
that we are targeting compatibility with is
Java 8:
<properties>
<maven.compiler.source>{version}</maven.compiler.source>
<maven.compiler.target>{version}</maven.compiler.target>
</properties>
- Run
mvn install -DskipTests
in this repo's directory to install Conjur API into your local maven repository.
If generating a JAR is preferred, you can build the library locally and add the dependency to the project manually by following the setup steps below:
- Clone the Conjur Java API repo locally:
git clone {repo}
- Go into the cloned repository with
cd conjur-api-java
- Run
mvn package -DskipTests
to generate a JAR file. The output.jar
files will be located in thetarget
directory of the repo
NOTE: The above command runs 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 finish the configuration. For more information on how to run the tests, take a look at
our Contributing guide.
4a. For Intellij, Follow the steps outlined here
to add the SDK JAR files into the new app's project.
4b. For Eclipse you Right click project > Build Path > Configure Build Path > Library > Add External JARs
.
4c. If you are working with the Maven CLI, you can manually install the .jar
into your Maven.
repository by running the following (replacing $VERSION
with the appropriate version
of the API):
sh-session $ mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file \ -Dfile=/path/to/api/repo/target/conjur-api-$VERSION.jar
or
sh-session $ mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file \ -Dfile=/path/to/api/repo/target/conjur-api-$VERSION-with-dependencies.jar
or
sh-session $ mvn install:install-file -Dfile=/path/to/api/repo/target/conjur-api-$VERSION-with-dependencies.jar \ -DgroupId=com.cyberark.conjur.api \ -DartifactId=conjur-api \ -Dversion=$VERSION \ -Dpackaging=jar
To make use of tagged releases published to Maven, verify that you have the dependency
added to your pom.xml
- Add the following snippet to
pom.xml
<dependency>
<groupId>com.cyberark.conjur.api</groupId>
<artifactId>conjur-java-api</artifactId>
<version>x.x.x</version>
</dependency>
To make use of SNAPSHOTS, which are deployed following a nightly build, there are several steps required for configuring your project.
Note: Snapshots contain the latest changes to
conjur-java-api
, but it is recommended to use the current stable release unless there is a significant update required by your project
- Add the following to your
settings.xml
<profiles>
<profile>
<id>allow-snapshots</id>
<activation><activeByDefault>true</activeByDefault></activation>
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
Alternatively, add the following to your list of repositories in pom.xml
<repository>
<id>oss.sonatype.org-snapshot</id>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
- In your
pom.xml
, verify that yourconjur-java-api
dependency includesSNAPSHOT
in the version tag.
<dependency>
<groupId>com.cyberark.conjur.api</groupId>
<artifactId>conjur-java-api</artifactId>
<version>x.x.x-SNAPSHOT</version>
</dependency>
Please refer to the instructions available on Maven Central and select a version for specific instructions on including the Conjur Java API in your project through Gradle, Kotlin, and more!
Once the setup steps have been successfully run, we will now define the variables needed to make the connection between the new app and Conjur. You can do this by setting environment variables, system properties, or some combination of both.
NOTE: System properties will override enviroment values when both are defined for a variable.
In Conjur (both Open Source and Enterprise), 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 need to be included in the app's runtime environment in order use the Conjur API if no other configuration is done (e.g. over system properties or CLI parameters):
CONJUR_APPLIANCE_URL
- The URL of the Conjur instance you are connecting to. When connecting to Conjur Enterprise configured for high availability, this should be the URL of the master load balancer (if performing read and write operations) or the URL of a follower load balancer (if performing read-only operations).CONJUR_ACCOUNT
- Conjur account that you are connecting to. This value is set during Conjur deployment.CONJUR_AUTHN_LOGIN
- User/host identityCONJUR_AUTHN_API_KEY
- User/host API key (or password; see notes onCONJUR_AUTHN_URL
)CONJUR_AUTHN_URL
- (optional) Alternate authentication endpoint. By default the client uses the standard<applianceUrl>/authn
for generic username and API key login flow.
Note: If you use the default CONJUR_AUTHN_URL
value or your CONJUR_AUTHN_URL
ends with /authn
,
the CONJUR_AUTHN_API_KEY
is treated as a password otherwise CONJUR_AUTHN_API_KEY
is treated as
an API key.
For example, you can specify the environment variables like so:
export CONJUR_APPLIANCE_URL=https://conjur.myorg.com/api
export CONJUR_ACCOUNT=myorg
export CONJUR_AUTHN_LOGIN=host/myhost.example.com
export CONJUR_AUTHN_API_KEY=sb0ncv1yj9c4w2e9pb1a2s
or you could provide these at runtime to your jar:
$ CONJUR_APPLIANCE_URL=https://conjur.myorg.com/api \
CONJUR_ACCOUNT=myorg \
CONJUR_AUTHN_LOGIN=host/myhost.example.com \
CONJUR_AUTHN_API_KEY=sb0ncv1yj9c4w2e9pb1a2s \
java -jar myConjurClient.jar
If you are using a host-based user like this example shows, you will need to add the host
to Conjur with the proper privileges in policy in order to know the appropriate
CONJUR_AUTHN_LOGIN
and CONJUR_AUTHN_API_KEY
values.
This API can also be configured using Java system properties You can specify any portion (or all) of the configuration values this way. The advantage of this approach is that the values can be changed dynamically as needed. For example, this snippet would let your client be able to use the API methods using properties defined from the CLI:
java -jar myConjurClient.jar \
-DCONJUR_APPLIANCE_URL=https://conjur.myorg.com/api \
-DCONJUR_ACCOUNT=myorg \
-DCONJUR_AUTHN_LOGIN=host/myhost.example.com \
-DCONJUR_AUTHN_API_KEY=sb0ncv1yj9c4w2e9pb1a2s
If you are using Maven, you can also specify these proprerties on the CLI:
mvn exec:java \
-DCONJUR_APPLIANCE_URL=https://conjur.myorg.com/api \
-DCONJUR_ACCOUNT=myorg \
-DCONJUR_AUTHN_LOGIN=host/myhost.example.com \
-DCONJUR_AUTHN_API_KEY=sb0ncv1yj9c4w2e9pb1a2s \
-Dexec.mainClass="com.myorg.client.App"
NOTE: When using properties to configure Conjur APIs, be careful not to persist sensitive values (like the API key) in source-controlled property files!
By default, the Conjur appliance generates and uses self-signed SSL certificates. Without
trusting them, your Java app will not be able to connect to the Conjur server over APIs
and so you will need to configure your app to trust them. You can accomplish this by using
the Client-level SSLContext
when creating the client or with a
JVM-level trust by loading the Conjur certificate into Java's CA
keystore that holds the list of all the allowed certificates for https connections.
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.
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);
For a JVM-level trust between Conjur and the API client, you need to load the Conjur certificate into Java's CA keystore that holds the list of all the allowed certificates for https connections.
First, we need to get a copy of this certificate, which you can get using openssl
. Run the
following step from a terminal with OpenSSL that has access to Conjur:
$ openssl s_client -showcerts -servername myconjurserver.com \
-connect myconjusrserver.com:443 < /dev/null 2> /dev/null \
| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > conjur.pem
$ # Check that the certificate was properly retrieved. If you do not see this kind of output
$ # ensure that you are providing OpenSSL the correct server information
$ cat conjur.pem
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
This will save the certificate chain to a file called 'conjur.pem'. Since Java doesn't work
natively with the pem
certificate encoding format, you'll need to convert it to the der
format:
$ openssl x509 -outform der -in conjur.pem -out conjur-default.der
Next, you'll need to locate the path to the JRE from the process environment running the Java
app. In the case of Java 8 on most standard Linux distributions it's
/usr/lib/jvm/java-8-openjdk-amd64/jre
. We will export this path to $JRE_HOME
for convenience.
If the file $JRE_HOME/lib/security/cacerts
doesn't exist (you might need to be root to see it),
double check that the JRE_HOME
path is correct. Once you've found it, you can add the
appliance's cert to Java's certificate authority keystore like this:
$ sudo -E keytool -importcert \
-alias conjur-default \
-keystore "$JRE_HOME/lib/security/cacerts" \
-storepass changeit \
-file ./conjur-default.der
Owner: CN=myconjurserver.com
Issuer: CN=myconjurserver.com, OU=Conjur CA, O=myorg
Serial number: 9e930ced498d74b4faf98e6d4f9d90ebdebebd57
Valid from: Mon Mar 30 16:51:15 CDT 2020 until: Thu Mar 28 16:51:15 CDT 2030
Certificate fingerprints:
SHA1: 7A:A3:78:22:50:03:52:C2:B5:3E:1D:98:48:26:82:71:18:FB:2E:26
SHA256: ED:77:BA:4A:81:EB:6C:26:E9:82:AC:75:51:99:9A:2F:76:D5:3C:A2:B4:8D:5D:87:EB:A6:01:49:FC:2F:28:FF
...
Trust this certificate? [no]: yes
Certificate was added to keystore
$ # Make sure you do not see `keytool error: java.io.FileNotFoundException` error. If you do,
$ # your addition of the cert did not work.
Note: On macOS, your default Java may not be able to run this tool so you may need to install
an alternate JDK like openjdk
. You can find more info about this here
and here.
Verify the addition of the SSL key:
$ sudo -E keytool -list \
-storepass changeit \
-keystore $JAVA_HOME/lib/security/cacerts | grep conjur
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.
As mentioned in the Configuration section, you can provide varying ways
for your app to authenticate against a Conjur server. Generally environment variables are
most common but this isn't the only way. In addition to explicitly setting these environment
variables, you can do so by providing properties, using the Credentials
object, or by providing an Authorization Token. Once you have chosen from one of the
patterns below that works for you, you can now create a Conjur
class instance values to
access Conjur services and make RESTful API calls.
Note: As mentioned before, if you use the default CONJUR_AUTHN_URL
value or your
CONJUR_AUTHN_URL
ends with /authn
, the CONJUR_AUTHN_API_KEY
is treated as a password
otherwise CONJUR_AUTHN_API_KEY
is treated as an API key.
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur endpoint URL>
export CONJUR_AUTHN_LOGIN=<user/host identity>
export CONJUR_AUTHN_API_KEY=<user/host API key or password - see notes about `CONJUR_AUTHN_URL`>
import com.cyberark.conjur.api.Conjur;
// Configured using environment variables
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSSLContext variable
Conjur conjur = new Conjur(conjurSSLContext);
$ java -jar myConjurClient.jar \
-DCONJUR_ACCOUNT=<account specified during Conjur setup> \
-DCONJUR_APPLIANCE_URL=<Conjur endpoint URL> \
-DCONJUR_AUTHN_LOGIN=<user/host identity> \
-DCONJUR_AUTHN_API_KEY=<user/host API key - see notes about `CONJUR_AUTHN_URL`>
import com.cyberark.conjur.api.Conjur;
// Configured using system properties
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSSLContext variable
Conjur conjur = new Conjur(conjurSSLContext);
$ mvn exec:java \
-DCONJUR_ACCOUNT=<account specified during Conjur setup> \
-DCONJUR_APPLIANCE_URL=<Conjur endpoint URL> \
-DCONJUR_AUTHN_LOGIN=<user/host identity> \
-DCONJUR_AUTHN_API_KEY=<user/host API key - see notes about `CONJUR_AUTHN_URL`> \
-Dexec.mainClass="com.myorg.client.App"
import com.cyberark.conjur.api.Conjur;
// Configured using system properties
Conjur conjur = new Conjur();
// or using custom SSLContext setup as conjurSSLContext variable
Conjur conjur = new Conjur(conjurSSLContext);
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur endpoint URL>
import com.cyberark.conjur.api.Conjur;
// Authenticate using provided username/hostname and password/API key. See notes about
// `CONJUR_AUTHN_URL` regarding how 'password-or-api-key' is processed.
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);
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur endpoint URL>
import com.cyberark.conjur.api.Conjur;
import com.cyberark.conjur.api.Credentials;
// Authenticate using a Credentials object. See notes about `CONJUR_AUTHN_URL`
// 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);
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur endpoint URL>
# Optional path for non-standard authenticators (e.g. `$CONJUR_APPLIANCE_URL/authn-k8s/myauthenticator`)
# export CONJUR_AUTHN_URL="<authenticator authn url>"
import com.cyberark.conjur.api.Conjur;
import com.cyberark.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:
export CONJUR_ACCOUNT=<account specified during Conjur setup>
export CONJUR_APPLIANCE_URL=<Conjur endpoint URL>
# Optional path for non-standard authenticators (e.g. `$CONJUR_APPLIANCE_URL/authn-k8s/myauthenticator`)
# export CONJUR_AUTHN_URL="<authenticator authn url>"
export CONJUR_AUTHN_TOKEN_FILE="path/to/conjur/authentication/token.json"
import com.cyberark.conjur.api.Conjur;
import com.cyberark.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);
To use the client, you will first create an instance of the client and then call methods to send requests to the Conjur API. The most common use case is adding and retrieving 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:
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
CONJUR_AUTHN_URL
ends with /authn
, the password
parameter is treated as a "password"
otherwise CONJUR_AUTHN_API_KEY
is treated as an "API key".
Sets a variable to a specific value based on its ID.
Example:
import com.cyberark.conjur.api.Conjur;
Conjur conjur = new Conjur();
conjur.variables().addSecret(VARIABLE_ID, VARIABLE_VALUE);
NOTE: For a variable to be set, it first needs to be created by a policy in Conjur otherwise this operation will fail. To do so, you will need a policy that resembles the one supplied in the Configuration section above.
Retireves a variable based on its ID.
Example:
import com.cyberark.conjur.api.Conjur;
Conjur conjur = new Conjur();
String secret = conjur.variables().retrieveSecret("<VARIABLE_ID>");
The Conjur API client uses the JAX-RS standard to make requests to the Conjur web services.
In the future we plan to remove this dependency, but for the time being you may need to
change the JAX-RS implementation to conform to your environment and application dependencies.
Conjur API uses Apache CXF by default but for example, in a JBoss server environment, you
should use the RESTlet implementation. You can replace that dependency in pom.xml
to use an
alternative implementation.
This is caused by Maven's (or your dependency resolution tooling) inability to find Conjur APIs. Please ensure that you have followed the setup section to properly install this as a dependency.
This is due to the lack of dependencies required for this API. You can add this to your pom.xml
to work around this:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
If you don't properly install the Conjur certificate into the Java keystore, you may encounter the folowing errors:
org.apache.cxf.interceptor.Fault: Could not send Message.
jakarta.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException: SSLHandshakeException
javax.net.ssl.SSLHandshakeException: SSLHandshakeException
javax.net.ssl.SSLHandshakeException: PKIX path building failed
sun.security.validator.ValidatorException: PKIX path building failed
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
If you encounter these errors, please ensure that you have followed this section
on how to install Conjur's SSL cetificate into your Java keystore correctly. You should also
ensure that the SSL certificate was added to the correct cacerts
file if you have multiple
JDKs/JREs installed.
For instructions on how to contribute, please see our Contributing guide.
This repository is licensed under Apache License 2.0 - see LICENSE
for more details.