30 Commits

Author SHA1 Message Date
594b80f62b Typo fix 2017-03-19 12:13:52 +01:00
4bd614a633 Dependencies updated, Release 0.5.0 2017-03-18 14:39:49 +01:00
0f6bccff02 PNG logo 2017-03-18 14:35:00 +01:00
fca6e496d8 SecretResponse.getValue() deprecated 2017-03-18 14:28:48 +01:00
0f5540913a Logo and ReadMe updates 2017-03-18 14:28:48 +01:00
8129017ad0 #7 Convenience methods for SQL credentials 2017-03-18 14:19:40 +01:00
c0ad451134 Test against vault 0.7.0 2017-03-18 13:49:37 +01:00
5f3e285a8a Added "local" attribute for AuthMethod response (0.7.0 compatibility) 2017-03-18 13:48:47 +01:00
107244cb81 Minor fixed and test coverage 2017-02-10 11:16:31 +01:00
e877d377c0 Dependencies updated 2017-02-10 09:58:09 +01:00
a565411b22 UnitTest against 0.6.5 2017-02-10 09:54:23 +01:00
6f13af5c91 More usage examples 2017-01-09 12:48:49 +01:00
ce2de2df81 TokenBuilder with policies as vararg 2017-01-09 12:42:12 +01:00
d7e4e7e5be Writing of complex data 2017-01-09 12:41:49 +01:00
2f312d3937 Read/write/list arbitrary keys 2017-01-08 12:45:07 +01:00
2f5b6d1523 Travis 2017-01-07 21:09:29 +01:00
69874bdceb ReadMe updated 2017-01-07 19:18:37 +01:00
8ab9c23605 Copyright updated 2017-01-07 19:18:37 +01:00
324bff7e58 Additional information in POM 2016-12-30 10:16:12 +01:00
b036b73e11 Typos 2016-12-27 17:49:51 +01:00
17145e53be Minor JavaDoc corrections 2016-12-24 12:43:58 +01:00
e988833eb9 Preparations for 0.4.1 release 2016-12-24 12:24:32 +01:00
ea3b6d50cb Fix #6 Factory Null-tolerant for trusted certificate 2016-12-21 20:30:28 +01:00
3f7f88e14a Tested against 0.6.3 2016-12-14 09:08:05 +01:00
3396693120 Test stacktraces for revealing any secret information 2016-12-04 10:38:30 +01:00
ca51fed145 Unimplemented initialization method removed 2016-12-04 10:18:31 +01:00
9c216dd805 ReadMe updated 2016-12-04 10:12:35 +01:00
b98b7ab95c Dependencies updated 2016-12-04 09:52:04 +01:00
ecf398c9d0 Removed unnecessary boolean results from API 2016-11-13 18:05:36 +01:00
a80805a044 typo fix 2016-11-06 16:48:48 +01:00
47 changed files with 711 additions and 157 deletions

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
branches:
only:
- master
language: java
jdk:
- oraclejdk8
env:
- PATH=$PATH:.
before_script:
- wget https://releases.hashicorp.com/vault/0.7.0/vault_0.7.0_linux_amd64.zip
- unzip vault_0.7.0_linux_amd64.zip
- rm vault_0.7.0_linux_amd64.zip

View File

@ -1,3 +1,14 @@
## 0.5.0 [2017-03-18]
* [feature] Convenience methods for DB credentials (#7)
* [fix] Minor bugfix in TokenBuilder
* [deprecation] `SecretResponse.getValue()` deprecated
* [test] Tested against Vault 0.7.0
## 0.4.1 [2016-12-24]
* [fix] Factory Null-tolerant for trusted certificate (#6)
* [test] StackTraces tested for secret leaks
* [test] Tested against Vault 0.6.4
## 0.4.0 [2016-11-06]
* [feature] Option to provide a trusted CA certificate (#2)
* [feature] Deletion, revocation and renewal of secrets (#3)

117
README.md
View File

@ -1,61 +1,124 @@
Java Vault Connector
=========
# Java Vault Connector
[![Build Status](https://travis-ci.org/stklcode/jvaultconnector.svg?branch=master)](https://travis-ci.org/stklcode/jvaultconnector)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/stklcode/jvaultconnector/blob/master/LICENSE.txt)
[![Maven Central](https://img.shields.io/maven-central/v/de.stklcode.jvault/connector.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.jvault%22%20AND%20a%3A%22connector%22)
![Logo](https://raw.githubusercontent.com/stklcode/jvaultconnector/master/assets/logo.png)
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
**Current available features:**
## Features:
* HTTP(S) backend connector
* Authorization methods:
* Ability to provide or enforce custom CA certificate
* Authorization methods
* Token
* Username/Password
* AppID (register and authenticate)
* AppID (register and authenticate) [_deprecated_]
* AppRole (register and authenticate)
* Tokens
* Creation and lookup of tokens
* TokenBuilder for speaking creation of complex configuraitons
* Secrets
* Read secrets
* Write secrets
* List secrets
* Delete secrets
* Renew/revoke leases
* Raw secret content or JSON decoding
* Connector Factory with builder pattern
* Tested against Vault 0.6.2
* Tested against Vault 0.7.0
**Usage Example**
```java
// Instanciate using builder pattern style factory
VaultConnector vault = VaultConnectorFactory.httpFactory()
.wiithHost("127.0.0.1")
.withPort(8200)
.withTLS()
.build();
//authenticate with token
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
// retrieve secret
String secret = vault.readSecret("some/secret/key").getValue();
```
**Maven Artifact**
## Maven Artifact
```
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.4.0</version>
<version>0.5.0</version>
</dependency>
```
**Links**
## Usage Examples
### Initialization
```java
// Instantiate using builder pattern style factory (TLS enabled by default)
VaultConnector vault = VaultConnectorFactory.httpFactory()
.withHost("127.0.0.1")
.withPort(8200)
.withTLS()
.build();
// Instantiate with custom SSL context
VaultConnector vault = VaultConnectorFactory.httpFactory()
.withHost("example.com")
.withPort(8200)
.withTrustedCA(Paths.get("/path/to/CA.pem"))
.build();
```
### Authentication
```java
// Authenticate with token
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
// Authenticate with username and password
vault.authUserPass("username", "p4ssw0rd");
// Authenticate with AppID (secret - 2nd argument - is optional)
vault.authAppId("01234567-89ab-cdef-0123-456789abcdef", "fedcba98-7654-3210-fedc-ba9876543210");
```
### Secret read & write
```java
// Retrieve secret (prefix "secret/" assumed, use read() to read arbitrary paths)
String secret = vault.readSecret("some/secret/key").getValue();
// Complex secret
Map<String, Object> secretData = vault.readSecret("another/secret/key").getData();
// Write simple secret
vault.writeSecret("new/secret/key", "secret value");
// Write complex data to arbitraty path
Map<String, Object> map = [...]
vault.write("any/path/to/write", map);
// Delete secret
vault.delete("any/path/to/write");
```
### Token and role creation
```java
// Create token using TokenBuilder
Token token = new TokenBuilder().withId("token id")
.withDisplayName("new test token")
.withPolicies("pol1", "pol2")
.build();
vault.createToken(token);
// Create AppRole credentials
vault.createAppRole("testrole", policyList);
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
```
## Links
[Project Page](http://jvault.stklcode.de)
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
**Planned features:**
## Planned features
* Creation and modification of policies
* Implement more authentication methods
**License**
## License
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

12
assets/logo.svg Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128">
<path d="M4,12 l60,104 l60,-104 z" stroke="none" fill="#000000" />
<circle cx="78" cy="24" r="6" stroke="none" fill="#00a9c7" />
<circle cx="78" cy="38" r="6" stroke="none" fill="#00a9c7" />
<circle cx="78" cy="52" r="6" stroke="none" fill="#00a9c7" />
<circle cx="78" cy="66" r="6" stroke="none" fill="#00a9c7" />
<circle cx="72" cy="78" r="6" stroke="none" fill="#00a9c7" />
<circle cx="58" cy="78" r="6" stroke="none" fill="#00a9c7" />
<circle cx="52" cy="66" r="6" stroke="none" fill="#00a9c7" />
</svg>

After

Width:  |  Height:  |  Size: 759 B

29
pom.xml
View File

@ -2,11 +2,23 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>jVaultConnector</name>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.4.0</version>
<version>0.5.0</version>
<packaging>jar</packaging>
<name>jVaultConnector</name>
<description>Connector artifact for Hashicorp's Vault secret management</description>
<url>https://jvault.stklcode.de</url>
<licenses>
<license>
<name>Apache License 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -17,7 +29,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
@ -25,28 +37,27 @@
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
<version>4.4.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.4</version>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.4</version>
<version>2.8.7</version>
</dependency>
<dependency>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -49,7 +49,6 @@ public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_SEAL_STATUS = "sys/seal-status";
private static final String PATH_SEAL = "sys/seal";
private static final String PATH_UNSEAL = "sys/unseal";
private static final String PATH_INIT = "sys/init";
private static final String PATH_RENEW = "sys/renew";
private static final String PATH_AUTH = "sys/auth";
private static final String PATH_TOKEN = "auth/token";
@ -59,7 +58,6 @@ public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
private static final String PATH_AUTH_APPID = "auth/app-id/";
private static final String PATH_AUTH_APPROLE = "auth/approle/";
private static final String PATH_SECRET = "secret";
private static final String PATH_REVOKE = "sys/revoke/";
private final ObjectMapper jsonMapper;
@ -136,7 +134,8 @@ public class HTTPVaultConnector implements VaultConnector {
/**
* Create connector using full URL and trusted certificate.
*
* @param baseURL The URL
* @param baseURL The URL
* @param sslContext Custom SSL Context
*/
public HTTPVaultConnector(String baseURL, SSLContext sslContext) {
this.baseURL = baseURL;
@ -196,12 +195,6 @@ public class HTTPVaultConnector implements VaultConnector {
return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis());
}
@Override
public boolean init() {
/* TODO: implement init() */
return true;
}
@Override
public List<AuthBackend> getAuthBackends() throws VaultConnectorException {
try {
@ -240,6 +233,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated
public AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
final Map<String, String> payload = new HashMap<>();
payload.put("app_id", appID);
@ -281,6 +275,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated
public boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
@ -296,6 +291,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated
public boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
@ -466,12 +462,12 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public SecretResponse readSecret(final String key) throws VaultConnectorException {
public SecretResponse read(final String key) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
/* Request HTTP response and parse Secret */
try {
String response = requestGet(PATH_SECRET + "/" + key, new HashMap<>());
String response = requestGet(key, new HashMap<>());
return jsonMapper.readValue(response, SecretResponse.class);
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response", e);
@ -482,12 +478,12 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public List<String> listSecrets(final String path) throws VaultConnectorException {
public List<String> list(final String path) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
try {
String response = requestGet(PATH_SECRET + "/" + path + "/?list=true", new HashMap<>());
String response = requestGet(path + "/?list=true", new HashMap<>());
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
return secrets.getKeys();
} catch (IOException e) {
@ -498,36 +494,32 @@ public class HTTPVaultConnector implements VaultConnector {
}
}
@Override
public boolean writeSecret(final String key, final String value) throws VaultConnectorException {
public void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
if (key == null || key.isEmpty())
throw new InvalidRequestException("Secret path must not be empty.");
Map<String, String> param = new HashMap<>();
param.put("value", value);
return requestPost(PATH_SECRET + "/" + key, param).equals("");
if (!requestPost(key, data).equals(""))
throw new InvalidResponseException("Received response where none was expected.");
}
@Override
public boolean deleteSecret(String key) throws VaultConnectorException {
public void delete(String key) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
/* Request HTTP response and expect empty result */
String response = requestDelete(PATH_SECRET + "/" + key);
String response = requestDelete(key);
/* Response should be code 204 without content */
if (!response.equals(""))
throw new InvalidResponseException("Received response where non was expected.");
return true;
throw new InvalidResponseException("Received response where none was expected.");
}
@Override
public boolean revoke(String leaseID) throws VaultConnectorException {
public void revoke(String leaseID) throws VaultConnectorException {
if (!isAuthorized())
throw new AuthorizationRequiredException();
@ -536,9 +528,7 @@ public class HTTPVaultConnector implements VaultConnector {
/* Response should be code 204 without content */
if (!response.equals(""))
throw new InvalidResponseException("Received response where non was expected.");
return true;
throw new InvalidResponseException("Received response where none was expected.");
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,12 @@
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.AuthorizationRequiredException;
import de.stklcode.jvault.connector.exception.InvalidRequestException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.*;
import de.stklcode.jvault.connector.model.response.*;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/**
* Vault Connector interface.
@ -32,12 +31,7 @@ import java.util.List;
* @since 0.1
*/
public interface VaultConnector {
/**
* Verify that vault connection is initialized.
*
* @return TRUE if correctly initialized
*/
boolean init();
String PATH_SECRET = "secret";
/**
* Reset authorization information.
@ -365,56 +359,136 @@ public interface VaultConnector {
boolean isAuthorized();
/**
* Retrieve secret form Vault.
* Retrieve any nodes content from Vault.
*
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
SecretResponse read(final String key) throws VaultConnectorException;
/**
* Retrieve secret from Vault.
* Prefix "secret/" is automatically added to key.
*
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
*/
SecretResponse readSecret(final String key) throws VaultConnectorException;
default SecretResponse readSecret(final String key) throws VaultConnectorException {
return read(PATH_SECRET + "/" + key);
}
/**
* List available nodes from Vault.
*
* @param path Root path to search
* @return List of secret keys
* @throws VaultConnectorException on error
* @since 0.5.0
*/
List<String> list(final String path) throws VaultConnectorException;
/**
* List available secrets from Vault.
* Prefix "secret/" is automatically added to path.
*
* @param path Root path to search
* @return List of secret keys
* @throws VaultConnectorException on error
*/
List<String> listSecrets(final String path) throws VaultConnectorException;
default List<String> listSecrets(final String path) throws VaultConnectorException {
return list(PATH_SECRET + "/" + path);
}
/**
* Write secret to Vault.
* Write simple value to Vault.
*
* @param key Secret path
* @param value Secret value
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default void write(final String key, final String value) throws VaultConnectorException {
Map<String, Object> param = new HashMap<>();
param.put("value", value);
write(key, param);
}
/**
* Write value to Vault.
*
* @param key Secret path
* @param data Secret content. Value must be be JSON serializable.
* @throws VaultConnectorException on error
* @since 0.5.0
*/
void write(final String key, final Map<String, Object> data) throws VaultConnectorException;
/**
* Write secret to Vault.
* Prefix "secret/" is automatically added to path.
*
* @param key Secret path
* @param value Secret value
* @return TRUE on success
* @throws VaultConnectorException on error
*/
boolean writeSecret(final String key, final String value) throws VaultConnectorException;
default void writeSecret(final String key, final String value) throws VaultConnectorException {
Map<String, Object> param = new HashMap<>();
param.put("value", value);
writeSecret(key, param);
}
/**
* Write secret to Vault.
* Prefix "secret/" is automatically added to path.
*
* @param key Secret path
* @param data Secret content. Value must be be JSON serializable.
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default void writeSecret(final String key, final Map<String, Object> data) throws VaultConnectorException {
if (key == null || key.isEmpty())
throw new InvalidRequestException("Secret path must not be empty.");
write(PATH_SECRET + "/" + key, data);
}
/**
* Delete key from Vault.
*
* @param key Secret path
* @throws VaultConnectorException on error
* @since 0.5.0
*/
void delete(final String key) throws VaultConnectorException;
/**
* Delete secret from Vault.
* Prefix "secret/" is automatically added to path.
*
* @param key Secret path
* @return TRUE on succevss
* @throws VaultConnectorException on error
*/
boolean deleteSecret(final String key) throws VaultConnectorException;
default void deleteSecret(final String key) throws VaultConnectorException {
delete(PATH_SECRET + "/" + key);
}
/**
* Revoke given lease immediately.
*
* @param leaseID the lease ID
* @return TRUE on success
* @throws VaultConnectorException on error
*/
boolean revoke(final String leaseID) throws VaultConnectorException;
void revoke(final String leaseID) throws VaultConnectorException;
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @param leaseID the lase ID
* @return Renewed lease
* @throws VaultConnectorException on error
*/
default SecretResponse renew(final String leaseID) throws VaultConnectorException {
return renew(leaseID, null);
@ -426,6 +500,7 @@ public interface VaultConnector {
* @param leaseID the lase ID
* @param increment number of seconds to extend lease time
* @return Renewed lease
* @throws VaultConnectorException on error
*/
SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException;
@ -466,4 +541,65 @@ public interface VaultConnector {
* @throws VaultConnectorException on error
*/
TokenResponse lookupToken(final String token) throws VaultConnectorException;
/**
* Read credentials for MySQL backend at default mount point
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readMySqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mysql");
}
/**
* Read credentials for PostgreSQL backend at default mount point
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readPostgreSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "postgresql");
}
/**
* Read credentials for MSSQL backend at default mount point
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readMsSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mssql");
}
/**
* Read credentials for MSSQL backend at default mount point
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readMongoDbCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mongodb");
}
/**
* Read credentials for SQL backends.
*
* @param role the role name
* @param mount mount point of the SQL backend
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readDbCredentials(final String role, final String mount) throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -128,10 +128,13 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
*
* @param cert path to certificate file
* @return self
* @throws VaultConnectorException on error
* @since 0.4.0
*/
public HTTPVaultConnectorFactory withTrustedCA(Path cert) throws VaultConnectorException {
return withSslContext(createSslContext(cert));
if (cert != null)
return withSslContext(createSslContext(cert));
return this;
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,10 +18,7 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* A builder for vault tokens.
@ -144,6 +141,17 @@ public class TokenBuilder {
return withNoDefaultPolicy(true);
}
/**
* Add given policies
*
* @param policies the policies
* @return self
* @since 0.5.0
*/
public TokenBuilder withPolicies(final String... policies) {
return withPolicies(Arrays.asList(policies));
}
/**
* Add given policies
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -0,0 +1,48 @@
/*
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.io.IOException;
import java.util.Map;
/**
* Vault response from credentials lookup. Simple wrapper for data objects containing username and password fields.
*
* @author Stefan Kalscheuer
* @since 0.5.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class CredentialsResponse extends SecretResponse {
public String getUsername() {
if (get("username") != null)
return get("username").toString();
return null;
}
public String getPassword() {
if (get("username") != null)
return get("username").toString();
return null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -64,7 +64,9 @@ public class SecretResponse extends VaultDataResponse {
* Method for backwards compatibility in case of simple secrets.
*
* @return the value
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
*/
@Deprecated
public String getValue() {
if (data.get("value") == null)
return null;
@ -79,7 +81,9 @@ public class SecretResponse extends VaultDataResponse {
* @return Parsed object
* @throws InvalidResponseException on parsing error
* @since 0.3
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
*/
@Deprecated
public <T> T getValue(Class<T> type) throws InvalidResponseException {
return get("value", type);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
@ -28,6 +29,7 @@ import java.util.Map;
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthMethod {
private AuthBackend type;
private String rawType;
@ -38,6 +40,9 @@ public class AuthMethod {
@JsonProperty("config")
private Map<String, String> config;
@JsonProperty("local")
private boolean local;
@JsonSetter("type")
public void setType(String type) {
this.rawType = type;
@ -59,4 +64,8 @@ public class AuthMethod {
public Map<String, String> getConfig() {
return config;
}
public boolean isLocal() {
return local;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,10 +30,7 @@ import org.junit.*;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestName;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.*;
import java.net.ServerSocket;
import java.nio.file.Paths;
import java.util.Arrays;
@ -46,7 +43,8 @@ import static org.junit.Assert.*;
import static org.junit.Assume.*;
/**
* JUnit Test for HTTP Vault connector.
* JUnit test for HTTP Vault connector.
* This test requires Vault binary in executable Path as it instantiates a real Vault server on given test data.
*
* @author Stefan Kalscheuer
* @since 0.1
@ -143,10 +141,13 @@ public class HTTPVaultConnectorTest {
@Test
public void authTokenTest() {
TokenResponse res;
final String invalidToken = "52135869df23a5e64c5d33a9785af5edb456b8a4a235d1fe135e6fba1c35edf6";
try {
connector.authToken("52135869df23a5e64c5d33a9785af5edb456b8a4a235d1fe135e6fba1c35edf6");
connector.authToken(invalidToken);
fail("Logged in with invalid token");
} catch (VaultConnectorException ignored) {
} catch (VaultConnectorException e) {
/* Assert that the exception does not reveal the token */
assertThat(stackTrace(e), not(stringContainsInOrder(invalidToken)));
}
try {
@ -164,10 +165,15 @@ public class HTTPVaultConnectorTest {
@Test
public void authUserPassTest() {
AuthResponse res = null;
final String invalidUser = "foo";
final String invalidPass = "bar";
try {
connector.authUserPass("foo", "bar");
connector.authUserPass(invalidUser, invalidPass);
fail("Logged in with invalid credentials");
} catch (VaultConnectorException ignored) {
} catch (VaultConnectorException e) {
/* Assert that the exception does not reveal credentials */
assertThat(stackTrace(e), not(stringContainsInOrder(invalidUser)));
assertThat(stackTrace(e), not(stringContainsInOrder(invalidPass)));
}
try {
@ -183,6 +189,7 @@ public class HTTPVaultConnectorTest {
* App-ID authentication roundtrip.
*/
@Test
@SuppressWarnings("deprecation")
public void authAppIdTest() {
authRoot();
assumeTrue(connector.isAuthorized());
@ -231,19 +238,27 @@ public class HTTPVaultConnectorTest {
}
/* Authenticate with valid secret ID against unknown role */
final String invalidRole = "foo";
try {
AuthResponse res = connector.authAppRole("foo", APPROLE_SECRET);
connector.authAppRole(invalidRole, APPROLE_SECRET);
fail("Successfully logged in with unknown role");
} catch (VaultConnectorException e) {
assertThat(e, is(instanceOf(InvalidResponseException.class)));
/* Assert that the exception does not reveal role ID or secret */
assertThat(stackTrace(e), not(stringContainsInOrder(invalidRole)));
assertThat(stackTrace(e), not(stringContainsInOrder(APPROLE_SECRET)));
}
/* Authenticate without wrong secret ID */
final String invalidSecret = "foo";
try {
AuthResponse res = connector.authAppRole(APPROLE_ROLE, "foo");
fail("Successfully logged in without secret ID");
} catch (VaultConnectorException e) {
assertThat(e, is(instanceOf(InvalidResponseException.class)));
/* Assert that the exception does not reveal role ID or secret */
assertThat(stackTrace(e), not(stringContainsInOrder(APPROLE_ROLE)));
assertThat(stackTrace(e), not(stringContainsInOrder(invalidSecret)));
}
/* Authenticate without secret ID */
@ -252,6 +267,8 @@ public class HTTPVaultConnectorTest {
fail("Successfully logged in without secret ID");
} catch (VaultConnectorException e) {
assertThat(e, is(instanceOf(InvalidResponseException.class)));
/* Assert that the exception does not reveal role ID */
assertThat(stackTrace(e), not(stringContainsInOrder(APPROLE_ROLE)));
}
/* Authenticate with secret ID on role with CIDR whitelist */
@ -437,11 +454,17 @@ public class HTTPVaultConnectorTest {
/* Try to read path user has no permission to read */
SecretResponse res = null;
final String invalidPath = "invalid/path";
try {
res = connector.readSecret("invalid/path");
res = connector.readSecret(invalidPath);
fail("Invalid secret path successfully read.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(PermissionDeniedException.class));
/* Assert that the exception does not reveal secret or credentials */
assertThat(stackTrace(e), not(stringContainsInOrder(invalidPath)));
assertThat(stackTrace(e), not(stringContainsInOrder(USER_VALID)));
assertThat(stackTrace(e), not(stringContainsInOrder(PASS_VALID)));
assertThat(stackTrace(e), not(matchesPattern("[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}")));
}
/* Try to read accessible path with known value */
@ -523,29 +546,28 @@ public class HTTPVaultConnectorTest {
/* Try to write to null path */
try {
boolean res = connector.writeSecret(null, "someValue");
connector.writeSecret(null, "someValue");
fail("Secret written to null path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(InvalidRequestException.class));
}
/* Try to write to invalid path */
try {
boolean res = connector.writeSecret("", "someValue");
connector.writeSecret("", "someValue");
fail("Secret written to invalid path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(InvalidRequestException.class));
}
/* Try to write to a path the user has no access for */
try {
boolean res = connector.writeSecret("invalid/path", "someValue");
connector.writeSecret("invalid/path", "someValue");
fail("Secret written to inaccessible path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(PermissionDeniedException.class));
}
/* Perform a valid write/read roundtrip to valid path. Also check UTF8-encoding. */
try {
boolean res = connector.writeSecret(SECRET_PATH + "/temp", "Abc123äöü,!");
assertThat("Secret could not be written to valid path.", res, is(true));
connector.writeSecret(SECRET_PATH + "/temp", "Abc123äöü,!");
} catch (VaultConnectorException e) {
fail("Secret written to inaccessible path.");
}
@ -567,8 +589,7 @@ public class HTTPVaultConnectorTest {
/* Write a test secret to vault */
try {
boolean res = connector.writeSecret(SECRET_PATH + "/toDelete", "secret content");
assumeThat("Secret could not be written path.", res, is(true));
connector.writeSecret(SECRET_PATH + "/toDelete", "secret content");
} catch (VaultConnectorException e) {
fail("Secret written to inaccessible path.");
}
@ -582,8 +603,7 @@ public class HTTPVaultConnectorTest {
/* Delete secret */
try {
boolean deleted = connector.deleteSecret(SECRET_PATH + "/toDelete");
assertThat("Revocation of secret faiked.", deleted, is(true));
connector.deleteSecret(SECRET_PATH + "/toDelete");
} catch (VaultConnectorException e) {
fail("Revocation threw unexpected exception.");
}
@ -608,8 +628,7 @@ public class HTTPVaultConnectorTest {
/* Write a test secret to vault */
try {
boolean res = connector.writeSecret(SECRET_PATH + "/toRevoke", "secret content");
assumeThat("Secret could not be written path.", res, is(true));
connector.writeSecret(SECRET_PATH + "/toRevoke", "secret content");
} catch (VaultConnectorException e) {
fail("Secret written to inaccessible path.");
}
@ -623,8 +642,7 @@ public class HTTPVaultConnectorTest {
/* Revoke secret */
try {
boolean revoked = connector.revoke(SECRET_PATH + "/toRevoke");
assertThat("Revocation of secret faiked.", revoked, is(true));
connector.revoke(SECRET_PATH + "/toRevoke");
} catch (VaultConnectorException e) {
fail("Revocation threw unexpected exception.");
}
@ -752,7 +770,7 @@ public class HTTPVaultConnectorTest {
/* Write configuration file */
BufferedWriter bw = null;
File configFile = null;
File configFile;
try {
configFile = tmpDir.newFile("vault.conf");
bw = new BufferedWriter(new FileWriter(configFile));
@ -831,4 +849,16 @@ public class HTTPVaultConnectorTest {
}
throw new IllegalStateException("Unable to find a free TCP port.");
}
/**
* Retrieve StackTrace from throwable as string
*
* @param th the throwable
* @return the stack trace
*/
private static String stackTrace(final Throwable th) {
StringWriter sw = new StringWriter();
th.printStackTrace(new PrintWriter(sw, true));
return sw.getBuffer().toString();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -0,0 +1,215 @@
/*
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.junit.MatcherAssume.assumeThat;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* JUnit Test for AppRoleSecret model.
*
* @author Stefan Kalscheuer
* @since 0.5.0
*/
public class AppRoleSecretTest {
private static final String TEST_ID = "abc123";
private static final Map<String, Object> TEST_META = new HashMap<>();
private static final List<String> TEST_CIDR = Arrays.asList("203.0.113.0/24", "198.51.100.0/24");
static {
TEST_META.put("foo", "bar");
TEST_META.put("number", 1337);
}
/**
* Test constructors.
*/
@Test
public void constructorTest() {
/* Empty constructor */
AppRoleSecret secret = new AppRoleSecret();
assertThat(secret.getId(), is(nullValue()));
assertThat(secret.getAccessor(), is(nullValue()));
assertThat(secret.getMetadata(), is(nullValue()));
assertThat(secret.getCidrList(), is(nullValue()));
assertThat(secret.getCidrListString(), is(emptyString()));
assertThat(secret.getCreationTime(), is(nullValue()));
assertThat(secret.getExpirationTime(), is(nullValue()));
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
assertThat(secret.getNumUses(), is(nullValue()));
assertThat(secret.getTtl(), is(nullValue()));
/* Constructor with ID */
secret = new AppRoleSecret(TEST_ID);
assertThat(secret.getId(), is(TEST_ID));
assertThat(secret.getAccessor(), is(nullValue()));
assertThat(secret.getMetadata(), is(nullValue()));
assertThat(secret.getCidrList(), is(nullValue()));
assertThat(secret.getCidrListString(), is(emptyString()));
assertThat(secret.getCreationTime(), is(nullValue()));
assertThat(secret.getExpirationTime(), is(nullValue()));
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
assertThat(secret.getNumUses(), is(nullValue()));
assertThat(secret.getTtl(), is(nullValue()));
/* Constructor with Metadata and CIDR bindings */
secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
assertThat(secret.getId(), is(TEST_ID));
assertThat(secret.getAccessor(), is(nullValue()));
assertThat(secret.getMetadata(), is(TEST_META));
assertThat(secret.getCidrList(), is(TEST_CIDR));
assertThat(secret.getCidrListString(), is(String.join(",", TEST_CIDR)));
assertThat(secret.getCreationTime(), is(nullValue()));
assertThat(secret.getExpirationTime(), is(nullValue()));
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
assertThat(secret.getNumUses(), is(nullValue()));
assertThat(secret.getTtl(), is(nullValue()));
}
/**
* Test setter.
*/
@Test
public void setterTest() {
AppRoleSecret secret = new AppRoleSecret(TEST_ID);
assertThat(secret.getCidrList(), is(nullValue()));
assertThat(secret.getCidrListString(), is(emptyString()));
secret.setCidrList(TEST_CIDR);
assertThat(secret.getCidrList(), is(TEST_CIDR));
assertThat(secret.getCidrListString(), is(String.join(",", TEST_CIDR)));
secret.setCidrList(null);
assertThat(secret.getCidrList(), is(nullValue()));
assertThat(secret.getCidrListString(), is(emptyString()));
}
/**
* Test JSON (de)serialization.
*/
@Test
public void jsonTest() throws NoSuchFieldException, IllegalAccessException {
ObjectMapper mapper = new ObjectMapper();
/* A simple roundtrip first. All set fields should be present afterwards. */
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
String secretJson = "";
try {
secretJson = mapper.writeValueAsString(secret);
} catch (JsonProcessingException e) {
e.printStackTrace();
fail("Serialization failed");
}
/* CIDR list is comma-separated when used as input, but List otherwise, hence convert string to list */
secretJson = commaSeparatedToList(secretJson);
AppRoleSecret secret2;
try {
secret2 = mapper.readValue(secretJson, AppRoleSecret.class);
assertThat(secret.getId(), is(secret2.getId()));
assertThat(secret.getMetadata(), is(secret2.getMetadata()));
assertThat(secret.getCidrList(), is(secret2.getCidrList()));
} catch (IOException e) {
e.printStackTrace();
fail("Deserialization failed");
}
/* Test fields, that should not be written to JSON */
setPrivateField(secret, "accessor", "TEST_ACCESSOR");
assumeThat(secret.getAccessor(), is("TEST_ACCESSOR"));
setPrivateField(secret, "creationTime", "TEST_CREATION");
assumeThat(secret.getCreationTime(), is("TEST_CREATION"));
setPrivateField(secret, "expirationTime", "TEST_EXPIRATION");
assumeThat(secret.getExpirationTime(), is("TEST_EXPIRATION"));
setPrivateField(secret, "lastUpdatedTime", "TEST_UPDATETIME");
assumeThat(secret.getLastUpdatedTime(), is("TEST_UPDATETIME"));
setPrivateField(secret, "numUses", 678);
assumeThat(secret.getNumUses(), is(678));
setPrivateField(secret, "ttl", 12345);
assumeThat(secret.getTtl(), is(12345));
try {
secretJson = mapper.writeValueAsString(secret);
} catch (JsonProcessingException e) {
e.printStackTrace();
fail("Serialization failed");
}
try {
secret2 = mapper.readValue(commaSeparatedToList(secretJson), AppRoleSecret.class);
assertThat(secret.getId(), is(secret2.getId()));
assertThat(secret.getMetadata(), is(secret2.getMetadata()));
assertThat(secret.getCidrList(), is(secret2.getCidrList()));
assertThat(secret2.getAccessor(), is(nullValue()));
assertThat(secret2.getCreationTime(), is(nullValue()));
assertThat(secret2.getExpirationTime(), is(nullValue()));
assertThat(secret2.getLastUpdatedTime(), is(nullValue()));
assertThat(secret2.getNumUses(), is(nullValue()));
assertThat(secret2.getTtl(), is(nullValue()));
} catch (IOException e) {
e.printStackTrace();
fail("Deserialization failed");
}
/* Those fields should be deserialized from JSON though */
secretJson = "{\"secret_id\":\"abc123\",\"metadata\":{\"number\":1337,\"foo\":\"bar\"}," +
"\"cidr_list\":[\"203.0.113.0/24\",\"198.51.100.0/24\"],\"secret_id_accessor\":\"TEST_ACCESSOR\"," +
"\"creation_time\":\"TEST_CREATION\",\"expiration_time\":\"TEST_EXPIRATION\"," +
"\"last_updated_time\":\"TEST_LASTUPDATE\",\"secret_id_num_uses\":678,\"secret_id_ttl\":12345}";
try {
secret2 = mapper.readValue(secretJson, AppRoleSecret.class);
assertThat(secret2.getAccessor(), is("TEST_ACCESSOR"));
assertThat(secret2.getCreationTime(), is("TEST_CREATION"));
assertThat(secret2.getExpirationTime(), is("TEST_EXPIRATION"));
assertThat(secret2.getLastUpdatedTime(), is("TEST_LASTUPDATE"));
assertThat(secret2.getNumUses(), is(678));
assertThat(secret2.getTtl(), is(12345));
} catch (IOException e) {
e.printStackTrace();
fail("Deserialization failed");
}
}
private static void setPrivateField(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(object, value);
field.setAccessible(accessible);
}
private static String commaSeparatedToList(String json) {
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":\\[$1\\]")
.replaceAll("(\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+)", "\"$1\"");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -45,7 +45,8 @@ public class TokenBuilderTest {
private static final Integer NUM_USES = 4;
private static final List<String> POLICIES = new ArrayList<>();
private static final String POLICY = "policy";
private static final String POLICY_2 = "policy";
private static final String POLICY_2 = "policy2";
private static final String POLICY_3 = "policy3";
private static final Map<String, String> META = new HashMap<>();
private static final String META_KEY = "key";
private static final String META_VALUE = "value";
@ -138,11 +139,11 @@ public class TokenBuilderTest {
assertThat(token.getPolicies(), hasSize(1));
assertThat(token.getPolicies(), contains(POLICY_2));
token = new TokenBuilder()
.withPolicies(POLICIES)
.withPolicy(POLICY_2)
.withPolicies(POLICY, POLICY_2)
.withPolicy(POLICY_3)
.build();
assertThat(token.getPolicies(), hasSize(2));
assertThat(token.getPolicies(), contains(POLICY, POLICY_2));
assertThat(token.getPolicies(), hasSize(3));
assertThat(token.getPolicies(), contains(POLICY, POLICY_2, POLICY_3));
/* Add single metadata */
token = new TokenBuilder().withMeta(META_KEY_2, META_VALUE_2).build();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 Stefan Kalscheuer
* Copyright 2016-2017 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.