From 21d544c2c7ebc38824f2fbd631ddeb94bfd0657a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 20 Nov 2019 09:43:11 +0100
Subject: [PATCH 01/21] Test against Vault 1.3.0

---
 .drone.yml                                             | 10 +++++-----
 .travis.yml                                            |  2 +-
 README.md                                              |  2 +-
 .../jvault/connector/HTTPVaultConnectorTest.java       |  2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 9683b56..8e3a979 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,12 +5,12 @@ steps:
   - name: test-online
     image: maven:3-jdk-11
     environment:
-      VAULT_VERSION: 1.2.3
+      VAULT_VERSION: 1.3.0
     commands:
-      - curl -o vault_1.2.3_linux_amd64.zip https://releases.hashicorp.com/vault/1.2.3/vault_1.2.3_linux_amd64.zip
-      - curl -s https://releases.hashicorp.com/vault/1.2.3/vault_1.2.3_SHA256SUMS | grep linux_amd64 | sha256sum -c
-      - unzip vault_1.2.3_linux_amd64.zip
-      - rm vault_1.2.3_linux_amd64.zip
+      - curl -o vault_1.3.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_linux_amd64.zip
+      - curl -s https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
+      - unzip vault_1.3.0_linux_amd64.zip
+      - rm vault_1.3.0_linux_amd64.zip
       - mv vault /bin/
       - mvn clean test
     when:
diff --git a/.travis.yml b/.travis.yml
index 3ad4d83..5f46483 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ addons:
     token:
       secure: "sM9OfX5jW764pn9cb2LSXArnXucKMws+eGeg5NnZxHRcGYt4hpBKLSregBSsBNzUoWVj0zNzPCpnh+UQvgxQzUerOqwEdjTBpy3SNPaxSn7UpoSg+Wz3aUmL9ugmx01b51/wMG4UCHEwTZt2tpgTPVtw8K6uSO78e0dSICCBHDnRcdQwOjMEQHIJJ/qHVRwuy/MzLCAP3W1JPZlsphZg9QsFyhB4hW97dE90joZezfocQIv2xI/r6k+BLz0pY6MxYCul0RiDumaiaej0CPvEJI/uSu//BAQjUdHw+mQgnKUYIbrn2ONOviwNfwdr94JyoZEN2B6zASUmNLjPf4AbIojDeyS+CrpQpm17EVm/Qk/Ds+Xra4PPPIcsZhiWzV0KoDUz9xLfXuRJ526VT5tDPiaeI7oETf0+8l+JIS1b399FyqHi7smzjpvC6GuKflQrbuHK4MuKzDh7WTHiqokGG4SS0wOQIaaHB3dfdwwQzPh6IM24e8CETxh3DjMeqUTU4DWmv5po55jZ934TtxVQvVN78bTG9O0zS9u+JmRY04OZ+OaXuFam6MfMUFQi0EPZzdGul/oWSibGUu3bNfVEBp60CnJwYNM/dKG6U7pJthLHvSwiQFOdKzHZ+l1jZJ4gPaXaIGqpwqVGr28ntqA/El1rytPixr2driE6bYMt5jw="
 env:
-  - PATH=$PATH:. VAULT_VERSION=1.2.3
+  - PATH=$PATH:. VAULT_VERSION=1.3.0
 before_script:
   - |
     if [ "$TRAVIS_BRANCH" = "master" ]; then
diff --git a/README.md b/README.md
index 78262d0..d5f157f 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
     * SQL secret handling
     * KV v1 and v2 support
 * Connector Factory with builder pattern
-* Tested against Vault 1.2.3
+* Tested against Vault 1.3.0
 
 
 ## Maven Artifact
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 1215bb9..b9701db 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -52,7 +52,7 @@ import static org.junit.jupiter.api.Assumptions.*;
  */
 @Tag("online")
 public class HTTPVaultConnectorTest {
-    private static String VAULT_VERSION = "1.2.3";  // the vault version this test is supposed to run against
+    private static String VAULT_VERSION = "1.3.0";  // the vault version this test is supposed to run against
     private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
     private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
     private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";

From 4788fa7272b9c8a519c5c8074f11a7692c00f996 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 25 Mar 2020 10:21:10 +0100
Subject: [PATCH 02/21] Test against Vault 1.4.0-rc1

---
 .drone.yml                                             | 10 +++++-----
 .travis.yml                                            |  2 +-
 README.md                                              |  2 +-
 .../jvault/connector/HTTPVaultConnectorTest.java       |  2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 8e3a979..e51b747 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,12 +5,12 @@ steps:
   - name: test-online
     image: maven:3-jdk-11
     environment:
-      VAULT_VERSION: 1.3.0
+      VAULT_VERSION: 1.4.0-rc1
     commands:
-      - curl -o vault_1.3.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_linux_amd64.zip
-      - curl -s https://releases.hashicorp.com/vault/1.3.0/vault_1.3.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
-      - unzip vault_1.3.0_linux_amd64.zip
-      - rm vault_1.3.0_linux_amd64.zip
+      - curl -o vault_1.4.0-rc1_linux_amd64.zip https://releases.hashicorp.com/vault/1.4.0-rc1/vault_1.4.0-rc1_linux_amd64.zip
+      - curl -s https://releases.hashicorp.com/vault/1.4.0-rc1/vault_1.4.0-rc1_SHA256SUMS | grep linux_amd64 | sha256sum -c
+      - unzip vault_1.4.0-rc1_linux_amd64.zip
+      - rm vault_1.4.0-rc1_linux_amd64.zip
       - mv vault /bin/
       - mvn clean test
     when:
diff --git a/.travis.yml b/.travis.yml
index 5f46483..449dfeb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ addons:
     token:
       secure: "sM9OfX5jW764pn9cb2LSXArnXucKMws+eGeg5NnZxHRcGYt4hpBKLSregBSsBNzUoWVj0zNzPCpnh+UQvgxQzUerOqwEdjTBpy3SNPaxSn7UpoSg+Wz3aUmL9ugmx01b51/wMG4UCHEwTZt2tpgTPVtw8K6uSO78e0dSICCBHDnRcdQwOjMEQHIJJ/qHVRwuy/MzLCAP3W1JPZlsphZg9QsFyhB4hW97dE90joZezfocQIv2xI/r6k+BLz0pY6MxYCul0RiDumaiaej0CPvEJI/uSu//BAQjUdHw+mQgnKUYIbrn2ONOviwNfwdr94JyoZEN2B6zASUmNLjPf4AbIojDeyS+CrpQpm17EVm/Qk/Ds+Xra4PPPIcsZhiWzV0KoDUz9xLfXuRJ526VT5tDPiaeI7oETf0+8l+JIS1b399FyqHi7smzjpvC6GuKflQrbuHK4MuKzDh7WTHiqokGG4SS0wOQIaaHB3dfdwwQzPh6IM24e8CETxh3DjMeqUTU4DWmv5po55jZ934TtxVQvVN78bTG9O0zS9u+JmRY04OZ+OaXuFam6MfMUFQi0EPZzdGul/oWSibGUu3bNfVEBp60CnJwYNM/dKG6U7pJthLHvSwiQFOdKzHZ+l1jZJ4gPaXaIGqpwqVGr28ntqA/El1rytPixr2driE6bYMt5jw="
 env:
-  - PATH=$PATH:. VAULT_VERSION=1.3.0
+  - PATH=$PATH:. VAULT_VERSION=1.4.0-rc1
 before_script:
   - |
     if [ "$TRAVIS_BRANCH" = "master" ]; then
diff --git a/README.md b/README.md
index d5f157f..33c0473 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
     * SQL secret handling
     * KV v1 and v2 support
 * Connector Factory with builder pattern
-* Tested against Vault 1.3.0
+* Tested against Vault 1.3.4
 
 
 ## Maven Artifact
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index b9701db..d6728ab 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -52,7 +52,7 @@ import static org.junit.jupiter.api.Assumptions.*;
  */
 @Tag("online")
 public class HTTPVaultConnectorTest {
-    private static String VAULT_VERSION = "1.3.0";  // the vault version this test is supposed to run against
+    private static String VAULT_VERSION = "1.4.0-rc1";  // the vault version this test is supposed to run against
     private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
     private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
     private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";

From 071eeda423d9de788e1b57e5a139cdf23f46948d Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 29 Mar 2020 12:56:06 +0200
Subject: [PATCH 03/21] correclty map token meta in lookup response (fix #34)

---
 CHANGELOG.md                                              | 6 ++++++
 pom.xml                                                   | 2 +-
 .../connector/model/response/embedded/TokenData.java      | 6 ++++--
 .../connector/model/response/TokenResponseTest.java       | 8 +++++++-
 4 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63a451d..38bdee9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.9.0 (unreleased)
+
+### Fixes
+* Correctly parse Map field for token metadata (#34)
+
+
 ## 0.8.2 (2019-10-20)
 
 ### Fixes
diff --git a/pom.xml b/pom.xml
index 43474f6..0c13a31 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
     <groupId>de.stklcode.jvault</groupId>
     <artifactId>jvault-connector</artifactId>
-    <version>0.8.2</version>
+    <version>0.9.0-SNAPSHOT</version>
 
     <packaging>jar</packaging>
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
index fb503c7..1652a05 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
@@ -19,6 +19,8 @@ package de.stklcode.jvault.connector.model.response.embedded;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import java.util.Map;
+
 /**
  * Embedded token information inside Vault response.
  *
@@ -43,7 +45,7 @@ public final class TokenData {
     private String id;
 
     @JsonProperty("meta")
-    private String meta;
+    private Map<String, Object> meta;
 
     @JsonProperty("num_uses")
     private Integer numUses;
@@ -133,7 +135,7 @@ public final class TokenData {
     /**
      * @return Metadata
      */
-    public String getMeta() {
+    public Map<String, Object> getMeta() {
         return meta;
     }
 }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
index 272de50..3d068af 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
@@ -39,6 +39,8 @@ public class TokenResponseTest {
     private static final Integer TOKEN_CREATION_TIME = 1457533232;
     private static final Integer TOKEN_TTL = 2764800;
     private static final String TOKEN_DISPLAY_NAME = "token";
+    private static final String TOKEN_META_KEY = "foo";
+    private static final String TOKEN_META_VALUE = "bar";
     private static final Integer TOKEN_NUM_USES = 0;
     private static final Boolean TOKEN_ORPHAN = false;
     private static final String TOKEN_PATH = "auth/token/create";
@@ -56,7 +58,9 @@ public class TokenResponseTest {
             "    \"creation_time\": " + TOKEN_CREATION_TIME + ",\n" +
             "    \"creation_ttl\": " + TOKEN_TTL + ",\n" +
             "    \"display_name\": \"" + TOKEN_DISPLAY_NAME + "\",\n" +
-            "    \"meta\": null,\n" +
+            "    \"meta\": {\n" +
+            "      \"" + TOKEN_META_KEY + "\": \"" + TOKEN_META_VALUE + "\"\n" +
+            "    },\n" +
             "    \"num_uses\": " + TOKEN_NUM_USES + ",\n" +
             "    \"orphan\": " + TOKEN_ORPHAN + ",\n" +
             "    \"path\": \"" + TOKEN_PATH + "\",\n" +
@@ -113,6 +117,8 @@ public class TokenResponseTest {
             assertThat("Incorrect token number of uses", data.getNumUses(), is(TOKEN_NUM_USES));
             assertThat("Incorrect token orphan flag", data.isOrphan(), is(TOKEN_ORPHAN));
             assertThat("Incorrect token path", data.getPath(), is(TOKEN_PATH));
+            assertThat("Incorrect auth metadata size", data.getMeta().entrySet(), hasSize(1));
+            assertThat("Incorrect auth metadata", data.getMeta().get(TOKEN_META_KEY), is(TOKEN_META_VALUE));
             assertThat("Incorrect response renewable flag", res.isRenewable(), is(RES_RENEWABLE));
             assertThat("Incorrect response TTL", data.getTtl(), is(RES_TTL));
             assertThat("Incorrect response lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));

From d564ba93656a228d2b1344f2059d4f5e100aa33f Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 29 Mar 2020 13:00:49 +0200
Subject: [PATCH 04/21] update dependencies and plugins for JDK 14 build
 environments

---
 CHANGELOG.md |  3 +++
 pom.xml      | 16 ++++++++--------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38bdee9..bc5f108 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@
 ### Fixes
 * Correctly parse Map field for token metadata (#34)
 
+### Improvements
+* Minor dependency updates
+
 
 ## 0.8.2 (2019-10-20)
 
diff --git a/pom.xml b/pom.xml
index 0c13a31..fee8ef0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-jar-plugin</artifactId>
-                    <version>3.1.2</version>
+                    <version>3.2.0</version>
                     <configuration>
                         <archive>
                             <manifestEntries>
@@ -101,18 +101,18 @@
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.5.10</version>
+            <version>4.5.12</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
-            <version>2.10.0</version>
+            <version>2.10.3</version>
         </dependency>
 
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
-            <version>5.5.2</version>
+            <version>5.6.1</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -124,7 +124,7 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>3.1.0</version>
+            <version>3.3.3</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
@@ -140,20 +140,20 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-inline</artifactId>
-            <version>3.1.0</version>
+            <version>3.3.3</version>
             <scope>test</scope>
         </dependency>
         <!-- Updated transient dependency from mockito-core for JDK 13 compatibility -->
         <dependency>
             <groupId>net.bytebuddy</groupId>
             <artifactId>byte-buddy</artifactId>
-            <version>1.9.16</version>
+            <version>1.10.8</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>net.bytebuddy</groupId>
             <artifactId>byte-buddy-agent</artifactId>
-            <version>1.9.16</version>
+            <version>1.10.8</version>
             <scope>test</scope>
         </dependency>
         <dependency>

From 83a05fcd40a70f5de6327b7b52ab62a43d24db71 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 29 Mar 2020 13:58:32 +0200
Subject: [PATCH 05/21] correctly map token policies on lookup (close #35)

Remove superfluous "role" flag and add "policies" list instead.
---
 CHANGELOG.md                                     |  1 +
 .../model/response/embedded/TokenData.java       | 16 +++++++++-------
 .../jvault/connector/HTTPVaultConnectorTest.java |  5 ++++-
 .../model/response/TokenResponseTest.java        |  6 ++++--
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc5f108..6a4cd7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ### Fixes
 * Correctly parse Map field for token metadata (#34)
+* Correctly map token policies on lookup (#35)
 
 ### Improvements
 * Minor dependency updates
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
index 1652a05..1e5f202 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
@@ -19,13 +19,14 @@ package de.stklcode.jvault.connector.model.response.embedded;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import java.util.List;
 import java.util.Map;
 
 /**
  * Embedded token information inside Vault response.
  *
- * @author  Stefan Kalscheuer
- * @since   0.1
+ * @author Stefan Kalscheuer
+ * @since 0.1
  */
 @JsonIgnoreProperties(ignoreUnknown = true)
 public final class TokenData {
@@ -56,8 +57,8 @@ public final class TokenData {
     @JsonProperty("path")
     private String path;
 
-    @JsonProperty("role")
-    private String role;
+    @JsonProperty("policies")
+    private List<String> policies;
 
     @JsonProperty("ttl")
     private Integer ttl;
@@ -119,10 +120,11 @@ public final class TokenData {
     }
 
     /**
-     * @return Token role
+     * @return Token policies
+     * @since 0.9
      */
-    public String getRole() {
-        return role;
+    public List<String> getPolicies() {
+        return policies;
     }
 
     /**
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index d6728ab..752118a 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -41,7 +41,8 @@ import static org.hamcrest.Matchers.*;
 import static org.hamcrest.core.Is.is;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.Assumptions.*;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 /**
  * JUnit test for HTTP Vault connector.
@@ -1128,6 +1129,8 @@ public class HTTPVaultConnectorTest {
             try {
                 TokenResponse res = connector.lookupToken("my-token");
                 assertThat("Unexpected token ID", res.getData().getId(), is(token.getId()));
+                assertThat("Unexpected number of policies", res.getData().getPolicies(), hasSize(1));
+                assertThat("Unexpected policy", res.getData().getPolicies(), contains("root"));
             } catch (VaultConnectorException e) {
                 fail("Token creation failed.");
             }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
index 3d068af..bd853a4 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
@@ -117,8 +117,10 @@ public class TokenResponseTest {
             assertThat("Incorrect token number of uses", data.getNumUses(), is(TOKEN_NUM_USES));
             assertThat("Incorrect token orphan flag", data.isOrphan(), is(TOKEN_ORPHAN));
             assertThat("Incorrect token path", data.getPath(), is(TOKEN_PATH));
-            assertThat("Incorrect auth metadata size", data.getMeta().entrySet(), hasSize(1));
-            assertThat("Incorrect auth metadata", data.getMeta().get(TOKEN_META_KEY), is(TOKEN_META_VALUE));
+            assertThat("Incorrect token metadata size", data.getMeta().entrySet(), hasSize(1));
+            assertThat("Incorrect token metadata", data.getMeta().get(TOKEN_META_KEY), is(TOKEN_META_VALUE));
+            assertThat("Incorrect number of token policies", data.getPolicies(), hasSize(2));
+            assertThat("Incorrect token policies", data.getPolicies(), contains(TOKEN_POLICY_1, TOKEN_POLICY_2));
             assertThat("Incorrect response renewable flag", res.isRenewable(), is(RES_RENEWABLE));
             assertThat("Incorrect response TTL", data.getTtl(), is(RES_TTL));
             assertThat("Incorrect response lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));

From df696e9f17fa71d51b5492b5cbf6a5c187ff367c Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 16 Oct 2019 18:06:55 +0200
Subject: [PATCH 06/21] add token type to model and builder classes

---
 .../jvault/connector/model/Token.java         | 62 +++++++++++++++++++
 .../jvault/connector/model/TokenBuilder.java  | 14 +++++
 .../model/response/embedded/TokenData.java    | 11 ++++
 .../connector/HTTPVaultConnectorTest.java     |  3 +
 .../connector/model/TokenBuilderTest.java     |  5 +-
 5 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index c6e2633..a87e0b1 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -45,6 +45,10 @@ public final class Token {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private String id;
 
+    @JsonProperty("type")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String type;
+
     @JsonProperty("display_name")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private String displayName;
@@ -77,6 +81,33 @@ public final class Token {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Boolean renewable;
 
+    /**
+     * Construct complete {@link Token} object with default type.
+     *
+     * @param id              Token ID (optional)
+     * @param displayName     Token display name (optional)
+     * @param noParent        Token has no parent (optional)
+     * @param noDefaultPolicy Do not add default policy (optional)
+     * @param ttl             Token TTL in seconds (optional)
+     * @param numUses         Number of uses (optional)
+     * @param policies        List of policies (optional)
+     * @param meta            Metadata (optional)
+     * @param renewable       Is the token renewable (optional)
+     * @deprecated As of 0.9, use {@link #Token(String, String, String, Boolean, Boolean, Integer, Integer, List, Map, Boolean)} instead.
+     */
+    @Deprecated
+    public Token(final String id,
+                 final String displayName,
+                 final Boolean noParent,
+                 final Boolean noDefaultPolicy,
+                 final Integer ttl,
+                 final Integer numUses,
+                 final List<String> policies,
+                 final Map<String, String> meta,
+                 final Boolean renewable) {
+        this(id, Type.DEFAULT.value(), displayName, noParent, noDefaultPolicy, ttl, numUses, policies, meta, renewable);
+    }
+
     /**
      * Construct complete {@link Token} object.
      *
@@ -91,6 +122,7 @@ public final class Token {
      * @param renewable       Is the token renewable (optional)
      */
     public Token(final String id,
+                 final String type,
                  final String displayName,
                  final Boolean noParent,
                  final Boolean noDefaultPolicy,
@@ -100,6 +132,7 @@ public final class Token {
                  final Map<String, String> meta,
                  final Boolean renewable) {
         this.id = id;
+        this.type = type;
         this.displayName = displayName;
         this.ttl = ttl;
         this.numUses = numUses;
@@ -117,6 +150,14 @@ public final class Token {
         return id;
     }
 
+    /**
+     * @return Token type
+     * @since 0.9
+     */
+    public String getType() {
+        return type;
+    }
+
     /**
      * @return Token display name
      */
@@ -172,4 +213,25 @@ public final class Token {
     public Boolean isRenewable() {
         return renewable;
     }
+
+    /**
+     * Constants for token types.
+     */
+    public enum Type {
+        DEFAULT("default"),
+        BATCH("batch"),
+        SERVICE("service"),
+        DEFAULT_SERVICE("default-service"),
+        DEFAULT_BATCH("default-batch");
+
+        private final String value;
+
+        Type(String value) {
+            this.value = value;
+        }
+
+        public String value() {
+            return value;
+        }
+    }
 }
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
index 8fed8dd..ba17bb1 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
@@ -26,6 +26,7 @@ import java.util.*;
  */
 public final class TokenBuilder {
     private String id;
+    private Token.Type type;
     private String displayName;
     private Boolean noParent;
     private Boolean noDefaultPolicy;
@@ -46,6 +47,18 @@ public final class TokenBuilder {
         return this;
     }
 
+    /**
+     * Specify token type.
+     *
+     * @param type the type
+     * @return self
+     * @since 0.9
+     */
+    public TokenBuilder withType(final Token.Type type) {
+        this.type = type;
+        return this;
+    }
+
     /**
      * Add display name.
      *
@@ -247,6 +260,7 @@ public final class TokenBuilder {
      */
     public Token build() {
         return new Token(id,
+                type != null ? type.value() : null,
                 displayName,
                 noParent,
                 noDefaultPolicy,
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
index 1e5f202..b45c3c4 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
@@ -45,6 +45,9 @@ public final class TokenData {
     @JsonProperty("id")
     private String id;
 
+    @JsonProperty("type")
+    private String type;
+
     @JsonProperty("meta")
     private Map<String, Object> meta;
 
@@ -98,6 +101,14 @@ public final class TokenData {
         return id;
     }
 
+    /**
+     * @return Token type
+     * @since 0.9
+     */
+    public String getType() {
+        return type;
+    }
+
     /**
      * @return Number of uses
      */
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 752118a..dd2a394 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -1039,6 +1039,7 @@ public class HTTPVaultConnectorTest {
             /* Create token */
             Token token = Token.builder()
                     .withId("test-id")
+                    .withType(Token.Type.SERVICE)
                     .withDisplayName("test name")
                     .build();
 
@@ -1116,6 +1117,7 @@ public class HTTPVaultConnectorTest {
             /* Create token with attributes */
             Token token = Token.builder()
                     .withId("my-token")
+                    .withType(Token.Type.SERVICE)
                     .build();
             try {
                 connector.createToken(token);
@@ -1131,6 +1133,7 @@ public class HTTPVaultConnectorTest {
                 assertThat("Unexpected token ID", res.getData().getId(), is(token.getId()));
                 assertThat("Unexpected number of policies", res.getData().getPolicies(), hasSize(1));
                 assertThat("Unexpected policy", res.getData().getPolicies(), contains("root"));
+                assertThat("Unexpected token type", res.getData().getType(), is(token.getType()));
             } catch (VaultConnectorException e) {
                 fail("Token creation failed.");
             }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
index 30ca1d4..e236dbb 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
@@ -53,7 +53,7 @@ public class TokenBuilderTest {
     private static final String META_KEY_2 = "key2";
     private static final String META_VALUE_2 = "value2";
     private static final Boolean RENEWABLE = true;
-    private static final String JSON_FULL = "{\"id\":\"test-id\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true}";
+    private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true}";
 
     @BeforeAll
     public static void init() {
@@ -68,6 +68,7 @@ public class TokenBuilderTest {
     public void buildDefaultTest() throws JsonProcessingException {
         Token token = new TokenBuilder().build();
         assertThat(token.getId(), is(nullValue()));
+        assertThat(token.getType(), is(nullValue()));
         assertThat(token.getDisplayName(), is(nullValue()));
         assertThat(token.getNoParent(), is(nullValue()));
         assertThat(token.getNoDefaultPolicy(), is(nullValue()));
@@ -88,6 +89,7 @@ public class TokenBuilderTest {
     public void buildFullTest() throws JsonProcessingException {
         Token token = new TokenBuilder()
                 .withId(ID)
+                .withType(Token.Type.SERVICE)
                 .withDisplayName(DISPLAY_NAME)
                 .withNoParent(NO_PARENT)
                 .withNoDefaultPolicy(NO_DEFAULT_POLICY)
@@ -98,6 +100,7 @@ public class TokenBuilderTest {
                 .withRenewable(RENEWABLE)
                 .build();
         assertThat(token.getId(), is(ID));
+        assertThat(token.getType(), is(Token.Type.SERVICE.value()));
         assertThat(token.getDisplayName(), is(DISPLAY_NAME));
         assertThat(token.getNoParent(), is(NO_PARENT));
         assertThat(token.getNoDefaultPolicy(), is(NO_DEFAULT_POLICY));

From a4a0e13904195e207bd382a38c9bd1a52d824ea7 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 29 Mar 2020 11:53:02 +0200
Subject: [PATCH 07/21] add missing fields to auth response

* token_policies
* entity_id
* token_type
* orphan
---
 CHANGELOG.md                                  |  4 ++
 .../model/response/embedded/AuthData.java     | 50 +++++++++++++++++--
 .../connector/HTTPVaultConnectorTest.java     | 28 ++++++++++-
 .../model/response/AuthResponseTest.java      | 22 +++++++-
 4 files changed, 97 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a4cd7e..be674ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,11 @@
 * Correctly parse Map field for token metadata (#34)
 * Correctly map token policies on lookup (#35)
 
+### Features
+* Support for token types (#26)
+
 ### Improvements
+* Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
 * Minor dependency updates
 
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
index bf2d12f..ac5fc5c 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
@@ -39,6 +39,9 @@ public final class AuthData {
     @JsonProperty("policies")
     private List<String> policies;
 
+    @JsonProperty("token_policies")
+    private List<String> tokenPolicies;
+
     @JsonProperty("metadata")
     private Map<String, Object> metadata;
 
@@ -48,6 +51,15 @@ public final class AuthData {
     @JsonProperty("renewable")
     private boolean renewable;
 
+    @JsonProperty("entity_id")
+    private String entityId;
+
+    @JsonProperty("token_type")
+    private String tokenType;
+
+    @JsonProperty("orphan")
+    private boolean orphan;
+
     /**
      * @return Client token
      */
@@ -56,10 +68,11 @@ public final class AuthData {
     }
 
     /**
-     * @return Token accessor
+     * @return Token type
+     * @since 0.9
      */
-    public String getAccessor() {
-        return accessor;
+    public String getTokenType() {
+        return tokenType;
     }
 
     /**
@@ -69,6 +82,14 @@ public final class AuthData {
         return policies;
     }
 
+    /**
+     * @return List of policies associated with the ooken
+     * @since 0.9
+     */
+    public List<String> getTokenPolicies() {
+        return tokenPolicies;
+    }
+
     /**
      * @return Metadata
      */
@@ -89,4 +110,27 @@ public final class AuthData {
     public boolean isRenewable() {
         return renewable;
     }
+
+    /**
+     * @return Entity ID
+     * @since 0.9
+     */
+    public String getEntityId() {
+        return entityId;
+    }
+
+    /**
+     * @return Token accessor
+     */
+    public String getAccessor() {
+        return accessor;
+    }
+
+    /**
+     * @return Token is orphan
+     * @since 0.9
+     */
+    public boolean isOrphan() {
+        return orphan;
+    }
 }
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index dd2a394..ca8f6a5 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -1050,8 +1050,12 @@ public class HTTPVaultConnectorTest {
                 assertThat("Invalid token ID returned.", res.getAuth().getClientToken(), is("test-id"));
                 assertThat("Invalid number of policies returned.", res.getAuth().getPolicies(), hasSize(1));
                 assertThat("Root policy not inherited.", res.getAuth().getPolicies(), contains("root"));
+                assertThat("Invalid number of token policies returned.", res.getAuth().getTokenPolicies(), hasSize(1));
+                assertThat("Root policy not inherited for token.", res.getAuth().getTokenPolicies(), contains("root"));
+                assertThat("Unexpected token type.", res.getAuth().getTokenType(), is(Token.Type.SERVICE.value()));
                 assertThat("Metadata unexpected.", res.getAuth().getMetadata(), is(nullValue()));
                 assertThat("Root token should not be renewable", res.getAuth().isRenewable(), is(false));
+                assertThat("Root token should not be orphan", res.getAuth().isOrphan(), is(false));
 
                 // Starting with Vault 1.0 a warning "cusotm ID uses weaker SHA1..." is given.
                 if (VAULT_VERSION.startsWith("1.")) {
@@ -1075,12 +1079,12 @@ public class HTTPVaultConnectorTest {
                 AuthResponse res = connector.createToken(token);
                 assertThat("Invalid token ID returned.", res.getAuth().getClientToken(), is("test-id2"));
                 assertThat("Invalid number of policies returned.", res.getAuth().getPolicies(), hasSize(1));
-                assertThat("Root policy not inherited.", res.getAuth().getPolicies(), contains("testpolicy"));
+                assertThat("Custom policy not set.", res.getAuth().getPolicies(), contains("testpolicy"));
                 assertThat("Metadata not given.", res.getAuth().getMetadata(), is(notNullValue()));
                 assertThat("Metadata not correct.", res.getAuth().getMetadata().get("foo"), is("bar"));
                 assertThat("Token should be renewable", res.getAuth().isRenewable(), is(true));
             } catch (VaultConnectorException e) {
-                fail("Secret written to inaccessible path.");
+                fail("Token createion failed: " + e.getMessage());
             }
 
             /* Overwrite token should fail as of Vault 0.8.0 */
@@ -1102,6 +1106,26 @@ public class HTTPVaultConnectorTest {
                 /* Assert that the exception does not reveal token ID */
                 assertThat(stackTrace(e), not(stringContainsInOrder(token.getId())));
             }
+
+            /* Create token with batch type */
+            token = Token.builder()
+                    .withDisplayName("test name 3")
+                    .withPolicy("batchpolicy")
+                    .withoutDefaultPolicy()
+                    .withType(Token.Type.BATCH)
+                    .build();
+            try {
+                AuthResponse res = connector.createToken(token);
+                assertThat("Unexpected token prefix", res.getAuth().getClientToken(), startsWith("b."));
+                assertThat("Invalid number of policies returned.", res.getAuth().getPolicies(), hasSize(1));
+                assertThat("Custom policy policy not set.", res.getAuth().getPolicies(), contains("batchpolicy"));
+                assertThat("Token should not be renewable", res.getAuth().isRenewable(), is(false));
+                assertThat("Token should not be orphan", res.getAuth().isOrphan(), is(false));
+                assertThat("Specified token Type not set", res.getAuth().getTokenType(), is(Token.Type.BATCH.value()));
+
+            } catch (VaultConnectorException e) {
+                fail("Token createion failed: " + e.getMessage());
+            }
         }
 
         /**
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
index a0f1e62..f2e942b 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
@@ -44,6 +44,9 @@ public class AuthResponseTest {
     private static final String AUTH_META_VALUE = "armon";
     private static final Integer AUTH_LEASE_DURATION = 3600;
     private static final Boolean AUTH_RENEWABLE = true;
+    private static final String AUTH_ENTITY_ID = "";
+    private static final String AUTH_TOKEN_TYPE = "service";
+    private static final Boolean AUTH_ORPHAN = false;
 
     private static final String RES_JSON = "{\n" +
             "  \"auth\": {\n" +
@@ -53,11 +56,18 @@ public class AuthResponseTest {
             "      \"" + AUTH_POLICY_1 + "\", \n" +
             "      \"" + AUTH_POLICY_2 + "\"\n" +
             "    ],\n" +
+            "    \"token_policies\": [\n" +
+            "      \"" + AUTH_POLICY_2 + "\",\n" +
+            "      \"" + AUTH_POLICY_1 + "\" \n" +
+            "    ],\n" +
             "    \"metadata\": {\n" +
             "      \"" + AUTH_META_KEY + "\": \"" + AUTH_META_VALUE + "\"\n" +
             "    },\n" +
             "    \"lease_duration\": " + AUTH_LEASE_DURATION + ",\n" +
-            "    \"renewable\": " + AUTH_RENEWABLE + "\n" +
+            "    \"renewable\": " + AUTH_RENEWABLE + ",\n" +
+            "    \"entity_id\": \"" + AUTH_ENTITY_ID + "\",\n" +
+            "    \"token_type\": \"" + AUTH_TOKEN_TYPE + "\",\n" +
+            "    \"orphan\": " + AUTH_ORPHAN + "\n" +
             "  }\n" +
             "}";
 
@@ -104,8 +114,16 @@ public class AuthResponseTest {
             assertThat("Incorrect auth client token", data.getClientToken(), is(AUTH_CLIENT_TOKEN));
             assertThat("Incorrect auth lease duration", data.getLeaseDuration(), is(AUTH_LEASE_DURATION));
             assertThat("Incorrect auth renewable flag", data.isRenewable(), is(AUTH_RENEWABLE));
+            assertThat("Incorrect auth orphan flag", data.isOrphan(), is(AUTH_ORPHAN));
+            assertThat("Incorrect auth token type", data.getTokenType(), is(AUTH_TOKEN_TYPE));
+            assertThat("Incorrect auth entity id", data.getEntityId(), is(AUTH_ENTITY_ID));
             assertThat("Incorrect number of policies", data.getPolicies(), hasSize(2));
-            assertThat("Incorrect auth policies", data.getPolicies(), containsInAnyOrder(AUTH_POLICY_1, AUTH_POLICY_2));
+            assertThat("Incorrect auth policies", data.getPolicies(), containsInRelativeOrder(AUTH_POLICY_1, AUTH_POLICY_2));
+            assertThat("Incorrect number of token policies", data.getTokenPolicies(), hasSize(2));
+            assertThat("Incorrect token policies", data.getTokenPolicies(), containsInRelativeOrder(AUTH_POLICY_2, AUTH_POLICY_1));
+            assertThat("Incorrect auth metadata size", data.getMetadata().entrySet(), hasSize(1));
+            assertThat("Incorrect auth metadata", data.getMetadata().get(AUTH_META_KEY), is(AUTH_META_VALUE));
+
         } catch (IOException e) {
             fail("AuthResponse deserialization failed: " + e.getMessage());
         }

From 8f10bbfed705e2970f92019bf599995f9c9dedcf Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 29 Mar 2020 12:34:19 +0200
Subject: [PATCH 08/21] add missing fields to token data

* entity_id
* expire_time
* explicit_max_ttl
* issue_time
* renewable
* type
---
 CHANGELOG.md                                  |  1 +
 .../model/response/embedded/TokenData.java    | 84 ++++++++++++++++++-
 .../connector/HTTPVaultConnectorTest.java     |  1 +
 .../model/response/TokenResponseTest.java     | 40 +++++++--
 4 files changed, 117 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index be674ab..a107dea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 
 ### Improvements
 * Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
+* Added `entity_id`, `expire_time`, `explicit_max_ttl`, `issue_time`, `renewable` and `type` flags to token data
 * Minor dependency updates
 
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
index b45c3c4..e68aab4 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
@@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response.embedded;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Map;
 
@@ -42,11 +43,20 @@ public final class TokenData {
     @JsonProperty("display_name")
     private String name;
 
+    @JsonProperty("entity_id")
+    private String entityId;
+
+    @JsonProperty("expire_time")
+    private String expireTime;
+
+    @JsonProperty("explicit_max_ttl")
+    private Integer explicitMaxTtl;
+
     @JsonProperty("id")
     private String id;
 
-    @JsonProperty("type")
-    private String type;
+    @JsonProperty("issue_time")
+    private String issueTime;
 
     @JsonProperty("meta")
     private Map<String, Object> meta;
@@ -63,9 +73,15 @@ public final class TokenData {
     @JsonProperty("policies")
     private List<String> policies;
 
+    @JsonProperty("renewable")
+    private boolean renewable;
+
     @JsonProperty("ttl")
     private Integer ttl;
 
+    @JsonProperty("type")
+    private String type;
+
     /**
      * @return Token accessor
      */
@@ -94,6 +110,42 @@ public final class TokenData {
         return name;
     }
 
+    /**
+     * @return Entity ID
+     * @since 0.9
+     */
+    public String getEntityId() {
+        return entityId;
+    }
+
+    /**
+     * @return Expire time as raw string value
+     * @since 0.9
+     */
+    public String getExpireTimeString() {
+        return expireTime;
+    }
+
+    /**
+     * @return Expire time (parsed)
+     * @since 0.9
+     */
+    public ZonedDateTime getExpireTime() {
+        if (expireTime == null) {
+            return null;
+        } else {
+            return ZonedDateTime.parse(expireTime);
+        }
+    }
+
+    /**
+     * @return Explicit maximum TTL
+     * @since 0.9
+     */
+    public Integer getExplicitMaxTtl() {
+        return explicitMaxTtl;
+    }
+
     /**
      * @return Token ID
      */
@@ -101,6 +153,26 @@ public final class TokenData {
         return id;
     }
 
+    /**
+     * @return Issue time as raw string value
+     * @since 0.9
+     */
+    public String getIssueTimeString() {
+        return issueTime;
+    }
+
+    /**
+     * @return Expire time (parsed)
+     * @since 0.9
+     */
+    public ZonedDateTime getIssueTime() {
+        if (issueTime == null) {
+            return null;
+        } else {
+            return ZonedDateTime.parse(issueTime);
+        }
+    }
+
     /**
      * @return Token type
      * @since 0.9
@@ -138,6 +210,14 @@ public final class TokenData {
         return policies;
     }
 
+    /**
+     * @return Token is renewable
+     * @since 0.9
+     */
+    public boolean isRenewable() {
+        return renewable;
+    }
+
     /**
      * @return Token TTL (in seconds)
      */
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index ca8f6a5..3e6d497 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -1158,6 +1158,7 @@ public class HTTPVaultConnectorTest {
                 assertThat("Unexpected number of policies", res.getData().getPolicies(), hasSize(1));
                 assertThat("Unexpected policy", res.getData().getPolicies(), contains("root"));
                 assertThat("Unexpected token type", res.getData().getType(), is(token.getType()));
+                assertThat("Issue time expected to be filled", res.getData().getIssueTime(), is(notNullValue()));
             } catch (VaultConnectorException e) {
                 fail("Token creation failed.");
             }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
index bd853a4..a083aa6 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
@@ -22,6 +22,7 @@ import de.stklcode.jvault.connector.model.response.embedded.TokenData;
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
+import java.time.ZonedDateTime;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -38,26 +39,40 @@ import static org.junit.jupiter.api.Assertions.fail;
 public class TokenResponseTest {
     private static final Integer TOKEN_CREATION_TIME = 1457533232;
     private static final Integer TOKEN_TTL = 2764800;
+    private static final Integer TOKEN_EXPLICIT_MAX_TTL = 0;
     private static final String TOKEN_DISPLAY_NAME = "token";
     private static final String TOKEN_META_KEY = "foo";
     private static final String TOKEN_META_VALUE = "bar";
     private static final Integer TOKEN_NUM_USES = 0;
     private static final Boolean TOKEN_ORPHAN = false;
+    private static final Boolean TOKEN_RENEWABLE = true;
     private static final String TOKEN_PATH = "auth/token/create";
     private static final String TOKEN_POLICY_1 = "default";
     private static final String TOKEN_POLICY_2 = "web";
     private static final Boolean RES_RENEWABLE = false;
     private static final Integer RES_TTL = 2591976;
     private static final Integer RES_LEASE_DURATION = 0;
+    private static final String TOKEN_ACCESSOR = "VKvzT2fKHFsZFUus9LyoXCvu";
+    private static final String TOKEN_ENTITY_ID = "7d2e3179-f69b-450c-7179-ac8ee8bd8ca9";
+    private static final String TOKEN_EXPIRE_TIME = "2018-05-19T11:35:54.466476215-04:00";
+    private static final String TOKEN_ID = "my-token";
+    private static final String TOKEN_ISSUE_TIME = "2018-04-17T11:35:54.466476078-04:00";
+    private static final String TOKEN_TYPE = "service";
 
     private static final String RES_JSON = "{\n" +
             "  \"lease_id\": \"\",\n" +
             "  \"renewable\": " + RES_RENEWABLE + ",\n" +
             "  \"lease_duration\": " + RES_LEASE_DURATION + ",\n" +
             "  \"data\": {\n" +
+            "    \"accessor\": \"" + TOKEN_ACCESSOR + "\",\n" +
             "    \"creation_time\": " + TOKEN_CREATION_TIME + ",\n" +
             "    \"creation_ttl\": " + TOKEN_TTL + ",\n" +
             "    \"display_name\": \"" + TOKEN_DISPLAY_NAME + "\",\n" +
+            "    \"entity_id\": \"" + TOKEN_ENTITY_ID + "\",\n" +
+            "    \"expire_time\": \"" + TOKEN_EXPIRE_TIME + "\",\n" +
+            "    \"explicit_max_ttl\": \"" + TOKEN_EXPLICIT_MAX_TTL + "\",\n" +
+            "    \"id\": \"" + TOKEN_ID + "\",\n" +
+            "    \"issue_time\": \"" + TOKEN_ISSUE_TIME + "\",\n" +
             "    \"meta\": {\n" +
             "      \"" + TOKEN_META_KEY + "\": \"" + TOKEN_META_VALUE + "\"\n" +
             "    },\n" +
@@ -68,7 +83,9 @@ public class TokenResponseTest {
             "      \"" + TOKEN_POLICY_1 + "\", \n" +
             "      \"" + TOKEN_POLICY_2 + "\"\n" +
             "    ],\n" +
-            "    \"ttl\": " + RES_TTL + "\n" +
+            "    \"renewable\": " + TOKEN_RENEWABLE + ",\n" +
+            "    \"ttl\": " + RES_TTL + ",\n" +
+            "    \"type\": \"" + TOKEN_TYPE + "\"\n" +
             "  },\n" +
             "  \"warnings\": null,\n" +
             "  \"auth\": null\n" +
@@ -107,23 +124,32 @@ public class TokenResponseTest {
             TokenResponse res = new ObjectMapper().readValue(RES_JSON, TokenResponse.class);
             assertThat("Parsed response is NULL", res, is(notNullValue()));
             assertThat("Incorrect lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));
-            assertThat("Incorrect renewable status", res.isRenewable(), is(RES_RENEWABLE));
+            assertThat("Incorrect response renewable flag", res.isRenewable(), is(RES_RENEWABLE));
+            assertThat("Incorrect response lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));
             // Extract token data.
             TokenData data = res.getData();
             assertThat("Token data is NULL", data, is(notNullValue()));
+            assertThat("Incorrect token accessor", data.getAccessor(), is(TOKEN_ACCESSOR));
             assertThat("Incorrect token creation time", data.getCreationTime(), is(TOKEN_CREATION_TIME));
             assertThat("Incorrect token creation TTL", data.getCreationTtl(), is(TOKEN_TTL));
             assertThat("Incorrect token display name", data.getName(), is(TOKEN_DISPLAY_NAME));
+            assertThat("Incorrect token entity ID", data.getEntityId(), is(TOKEN_ENTITY_ID));
+            assertThat("Incorrect token expire time", data.getExpireTimeString(), is(TOKEN_EXPIRE_TIME));
+            assertThat("Incorrect parsed token expire time", data.getExpireTime(), is(ZonedDateTime.parse(TOKEN_EXPIRE_TIME)));
+            assertThat("Incorrect token explicit max TTL", data.getExplicitMaxTtl(), is(TOKEN_EXPLICIT_MAX_TTL));
+            assertThat("Incorrect token ID", data.getId(), is(TOKEN_ID));
+            assertThat("Incorrect token issue time", data.getIssueTimeString(), is(TOKEN_ISSUE_TIME));
+            assertThat("Incorrect parsed token issue time", data.getIssueTime(), is(ZonedDateTime.parse(TOKEN_ISSUE_TIME)));
+            assertThat("Incorrect token metadata size", data.getMeta().entrySet(), hasSize(1));
+            assertThat("Incorrect token metadata", data.getMeta().get(TOKEN_META_KEY), is(TOKEN_META_VALUE));
             assertThat("Incorrect token number of uses", data.getNumUses(), is(TOKEN_NUM_USES));
             assertThat("Incorrect token orphan flag", data.isOrphan(), is(TOKEN_ORPHAN));
             assertThat("Incorrect token path", data.getPath(), is(TOKEN_PATH));
-            assertThat("Incorrect token metadata size", data.getMeta().entrySet(), hasSize(1));
-            assertThat("Incorrect token metadata", data.getMeta().get(TOKEN_META_KEY), is(TOKEN_META_VALUE));
             assertThat("Incorrect number of token policies", data.getPolicies(), hasSize(2));
             assertThat("Incorrect token policies", data.getPolicies(), contains(TOKEN_POLICY_1, TOKEN_POLICY_2));
-            assertThat("Incorrect response renewable flag", res.isRenewable(), is(RES_RENEWABLE));
-            assertThat("Incorrect response TTL", data.getTtl(), is(RES_TTL));
-            assertThat("Incorrect response lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));
+            assertThat("Incorrect token renewable flag", data.isRenewable(), is(TOKEN_RENEWABLE));
+            assertThat("Incorrect token TTL", data.getTtl(), is(RES_TTL));
+            assertThat("Incorrect token type", data.getType(), is(TOKEN_TYPE));
         } catch (IOException e) {
             fail("TokenResponse deserialization failed: " + e.getMessage());
         }

From f54ba38cf558ae0f193608de52fa5423749f7d80 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Mon, 6 Apr 2020 17:58:11 +0200
Subject: [PATCH 09/21] implement TokenRole metamodel and corresponding builder

---
 .../jvault/connector/model/TokenRole.java     | 231 +++++++++++++++
 .../connector/model/TokenRoleBuilder.java     | 280 ++++++++++++++++++
 .../connector/model/TokenRoleBuilderTest.java | 180 +++++++++++
 3 files changed, 691 insertions(+)
 create mode 100644 src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
 create mode 100644 src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
 create mode 100644 src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java

diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
new file mode 100644
index 0000000..160cda0
--- /dev/null
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2016-2020 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.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+/**
+ * Vault Token Role metamodel.
+ *
+ * @author Stefan Kalscheuer
+ * @since 0.9
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public final class TokenRole {
+    /**
+     * Get {@link TokenRoleBuilder} instance.
+     *
+     * @return Token Role Builder.
+     * @since 0.9
+     */
+    public static TokenRoleBuilder builder() {
+        return new TokenRoleBuilder();
+    }
+
+    @JsonProperty("name")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String name;
+
+    @JsonProperty("allowed_policies")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private List<String> allowedPolicies;
+
+    @JsonProperty("disallowed_policies")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private List<String> disallowedPolicies;
+
+    @JsonProperty("orphan")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean orphan;
+
+    @JsonProperty("renewable")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean renewable;
+
+    @JsonProperty("path_suffix")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String pathSuffix;
+
+    @JsonProperty("allowed_entity_aliases")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private List<String> allowedEntityAliases;
+
+    @JsonProperty("token_bound_cidrs")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private List<String> tokenBoundCidrs;
+
+    @JsonProperty("token_explicit_max_ttl")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenExplicitMaxTtl;
+
+    @JsonProperty("token_no_default_policy")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean tokenNoDefaultPolicy;
+
+    @JsonProperty("token_num_uses")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenNumUses;
+
+    @JsonProperty("token_period")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenPeriod;
+
+    @JsonProperty("token_type")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String tokenType;
+
+
+    /**
+     * Construct complete {@link TokenRole} object.
+     *
+     * @param name                 Token Role name (redundant for creation).
+     * @param allowedPolicies      Allowed policies (optional)
+     * @param disallowedPolicies   Disallowed policies (optional)
+     * @param orphan               Role is orphan? (optional)
+     * @param renewable            Role is renewable? (optional)
+     * @param pathSuffix           Paht suffix (optional)
+     * @param allowedEntityAliases Allowed entity aliases (optional)
+     * @param tokenBoundCidrs      Token bound CIDR blocks (optional)
+     * @param tokenExplicitMaxTtl  Token explicit maximum TTL (optional)
+     * @param tokenNoDefaultPolicy Token wihtout default policy? (optional)
+     * @param tokenNumUses         Token number of uses (optional)
+     * @param tokenPeriod          Token period (optional)
+     * @param tokenType            Token type (optional)
+     */
+    public TokenRole(final String name,
+                     final List<String> allowedPolicies,
+                     final List<String> disallowedPolicies,
+                     final Boolean orphan,
+                     final Boolean renewable,
+                     final String pathSuffix,
+                     final List<String> allowedEntityAliases,
+                     final List<String> tokenBoundCidrs,
+                     final Integer tokenExplicitMaxTtl,
+                     final Boolean tokenNoDefaultPolicy,
+                     final Integer tokenNumUses,
+                     final Integer tokenPeriod,
+                     final String tokenType) {
+        this.name = name;
+        this.allowedPolicies = allowedPolicies;
+        this.disallowedPolicies = disallowedPolicies;
+        this.orphan = orphan;
+        this.renewable = renewable;
+        this.pathSuffix = pathSuffix;
+        this.allowedEntityAliases = allowedEntityAliases;
+        this.tokenBoundCidrs = tokenBoundCidrs;
+        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+        this.tokenNumUses = tokenNumUses;
+        this.tokenPeriod = tokenPeriod;
+        this.tokenType = tokenType;
+    }
+
+    /**
+     * @return Token Role name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return List of allowed policies
+     */
+    public List<String> getAllowedPolicies() {
+        return allowedPolicies;
+    }
+
+    /**
+     * @return List of disallowed policies
+     */
+    public List<String> getDisallowedPolicies() {
+        return disallowedPolicies;
+    }
+
+    /**
+     * @return Is Roken Role orphan?
+     */
+    public Boolean getOrphan() {
+        return orphan;
+    }
+
+    /**
+     * @return Is Roken Role renewable?
+     */
+    public Boolean getRenewable() {
+        return renewable;
+    }
+
+    /**
+     * @return Path suffix
+     */
+    public String getPathSuffix() {
+        return pathSuffix;
+    }
+
+    /**
+     * @return List of allowed entity aliases
+     */
+    public List<String> getAllowedEntityAliases() {
+        return allowedEntityAliases;
+    }
+
+    /**
+     * @return Token bound CIDR blocks
+     */
+    public List<String> getTokenBoundCidrs() {
+        return tokenBoundCidrs;
+    }
+
+    /**
+     * @return Token explicit maximum TTL
+     */
+    public Integer getTokenExplicitMaxTtl() {
+        return tokenExplicitMaxTtl;
+    }
+
+    /**
+     * @return Token without default policy?
+     */
+    public Boolean getTokenNoDefaultPolicy() {
+        return tokenNoDefaultPolicy;
+    }
+
+    /**
+     * @return Token number of uses
+     */
+    public Integer getTokenNumUses() {
+        return tokenNumUses;
+    }
+
+    /**
+     * @return Token period
+     */
+    public Integer getTokenPeriod() {
+        return tokenPeriod;
+    }
+
+    /**
+     * @return Token type
+     */
+    public String getTokenType() {
+        return tokenType;
+    }
+}
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
new file mode 100644
index 0000000..2a79a1c
--- /dev/null
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2016-2020 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 java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A builder for vault token roles.
+ *
+ * @author Stefan Kalscheuer
+ * @since 0.9
+ */
+public final class TokenRoleBuilder {
+    private List<String> allowedPolicies;
+    private List<String> disallowedPolicies;
+    private Boolean orphan;
+    private Boolean renewable;
+    private String pathSuffix;
+    private List<String> allowedEntityAliases;
+    private List<String> tokenBoundCidrs;
+    private Integer tokenExplicitMaxTtl;
+    private Boolean tokenNoDefaultPolicy;
+    private Integer tokenNumUses;
+    private Integer tokenPeriod;
+    private Token.Type tokenType;
+
+    /**
+     * Add an allowed policy.
+     *
+     * @param allowedPolicy allowed policy to add
+     * @return self
+     */
+    public TokenRoleBuilder withAllowedPolicy(final String allowedPolicy) {
+        if (allowedPolicy != null) {
+            if (this.allowedPolicies == null) {
+                this.allowedPolicies = new ArrayList<>();
+            }
+            this.allowedPolicies.add(allowedPolicy);
+        }
+        return this;
+    }
+
+    /**
+     * Add allowed policies.
+     *
+     * @param allowedPolicies list of allowed policies
+     * @return self
+     */
+    public TokenRoleBuilder withAllowedPolicies(final List<String> allowedPolicies) {
+        if (allowedPolicies != null) {
+            if (this.allowedPolicies == null) {
+                this.allowedPolicies = new ArrayList<>();
+            }
+            this.allowedPolicies.addAll(allowedPolicies);
+        }
+        return this;
+    }
+
+    /**
+     * Add a disallowed policy.
+     *
+     * @param disallowedPolicy disallowed policy to add
+     * @return self
+     */
+    public TokenRoleBuilder withDisallowedPolicy(final String disallowedPolicy) {
+        if (disallowedPolicy != null) {
+            if (this.disallowedPolicies == null) {
+                this.disallowedPolicies = new ArrayList<>();
+            }
+            this.disallowedPolicies.add(disallowedPolicy);
+        }
+        return this;
+    }
+
+    /**
+     * Add disallowed policies.
+     *
+     * @param disallowedPolicies list of disallowed policies
+     * @return self
+     */
+    public TokenRoleBuilder withDisallowedPolicies(final List<String> disallowedPolicies) {
+        if (disallowedPolicies != null) {
+            if (this.disallowedPolicies == null) {
+                this.disallowedPolicies = new ArrayList<>();
+            }
+            this.disallowedPolicies.addAll(disallowedPolicies);
+        }
+        return this;
+    }
+
+    /**
+     * Set TRUE if the token role should be created orphan.
+     *
+     * @param orphan if TRUE, token role is created as orphan
+     * @return self
+     */
+    public TokenRoleBuilder orphan(final Boolean orphan) {
+        this.orphan = orphan;
+        return this;
+    }
+
+    /**
+     * Set TRUE if the token role should be created renewable.
+     *
+     * @param renewable if TRUE, token role is created renewable
+     * @return self
+     */
+    public TokenRoleBuilder renewable(final Boolean renewable) {
+        this.renewable = renewable;
+        return this;
+    }
+
+    /**
+     * Set token role path suffix.
+     *
+     * @param pathSuffix path suffix to use
+     * @return self
+     */
+    public TokenRoleBuilder withPathSuffix(final String pathSuffix) {
+        this.pathSuffix = pathSuffix;
+        return this;
+    }
+
+    /**
+     * Add an allowed entity alias.
+     *
+     * @param allowedEntityAlias allowed entity alias to add
+     * @return self
+     */
+    public TokenRoleBuilder withAllowedEntityAlias(final String allowedEntityAlias) {
+        if (allowedEntityAlias != null) {
+            if (this.allowedEntityAliases == null) {
+                this.allowedEntityAliases = new ArrayList<>();
+            }
+            this.allowedEntityAliases.add(allowedEntityAlias);
+        }
+        return this;
+    }
+
+    /**
+     * Add allowed entity aliases.
+     *
+     * @param allowedEntityAliases list of allowed entity aliases to add
+     * @return self
+     */
+    public TokenRoleBuilder withAllowedEntityAliases(final List<String> allowedEntityAliases) {
+        if (allowedEntityAliases != null) {
+            if (this.allowedEntityAliases == null) {
+                this.allowedEntityAliases = new ArrayList<>();
+            }
+            this.allowedEntityAliases.addAll(allowedEntityAliases);
+        }
+        return this;
+    }
+
+    /**
+     * Add a single bound CIDR.
+     *
+     * @param tokenBoundCidr bound CIDR to add
+     * @return self
+     */
+    public TokenRoleBuilder withTokenBoundCidr(final String tokenBoundCidr) {
+        if (tokenBoundCidr != null) {
+            if (this.tokenBoundCidrs == null) {
+                this.tokenBoundCidrs = new ArrayList<>();
+            }
+            this.tokenBoundCidrs.add(tokenBoundCidr);
+        }
+        return this;
+    }
+
+    /**
+     * Add a list of bound CIDRs.
+     *
+     * @param tokenBoundCidrs list of bound CIDRs to add
+     * @return self
+     */
+    public TokenRoleBuilder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
+        if (tokenBoundCidrs != null) {
+            if (this.tokenBoundCidrs == null) {
+                this.tokenBoundCidrs = new ArrayList<>();
+            }
+            this.tokenBoundCidrs.addAll(tokenBoundCidrs);
+        }
+        return this;
+    }
+
+    /**
+     * Set explicit max. TTL for token.
+     *
+     * @param tokenExplicitMaxTtl explicit maximum TTL
+     * @return self
+     */
+    public TokenRoleBuilder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
+        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+        return this;
+    }
+
+    /**
+     * Set TRUE if the token role should be created renewable.
+     *
+     * @param tokenNoDefaultPolicy if TRUE, token is created without default policy.
+     * @return self
+     */
+    public TokenRoleBuilder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
+        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+        return this;
+    }
+
+    /**
+     * Set number of uses for tokens.
+     *
+     * @param tokenNumUses number of uses for associated tokens.
+     * @return self
+     */
+    public TokenRoleBuilder withTokenNumUses(final Integer tokenNumUses) {
+        this.tokenNumUses = tokenNumUses;
+        return this;
+    }
+
+    /**
+     * Set token period.
+     *
+     * @param tokenPeriod token period
+     * @return self
+     */
+    public TokenRoleBuilder withTokenPeriod(final Integer tokenPeriod) {
+        this.tokenPeriod = tokenPeriod;
+        return this;
+    }
+
+    /**
+     * Set token type.
+     *
+     * @param tokenType token type
+     * @return self
+     */
+    public TokenRoleBuilder withTokenType(final Token.Type tokenType) {
+        this.tokenType = tokenType;
+        return this;
+    }
+
+    /**
+     * Build the token based on given parameters.
+     *
+     * @return the token
+     */
+    public TokenRole build() {
+        return new TokenRole(
+                null,
+                allowedPolicies,
+                disallowedPolicies,
+                orphan,
+                renewable,
+                pathSuffix,
+                allowedEntityAliases,
+                tokenBoundCidrs,
+                tokenExplicitMaxTtl,
+                tokenNoDefaultPolicy,
+                tokenNumUses,
+                tokenPeriod,
+                tokenType != null ? tokenType.value() : null
+        );
+    }
+}
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
new file mode 100644
index 0000000..483a024
--- /dev/null
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2016-2020 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.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+/**
+ * Unit Test for {@link TokenRoleBuilder}
+ *
+ * @author Stefan Kalscheuer
+ * @since 0.9
+ */
+public class TokenRoleBuilderTest {
+    private static final String ALLOWED_POLICY_1 = "apol-1";
+    private static final String ALLOWED_POLICY_2 = "apol-2";
+    private static final String ALLOWED_POLICY_3 = "apol-3";
+    private static final List<String> ALLOWED_POLICIES = Arrays.asList(ALLOWED_POLICY_1, ALLOWED_POLICY_2);
+    private static final String DISALLOWED_POLICY_1 = "dpol-1";
+    private static final String DISALLOWED_POLICY_2 = "dpol-2";
+    private static final String DISALLOWED_POLICY_3 = "dpol-3";
+    private static final List<String> DISALLOWED_POLICIES = Arrays.asList(DISALLOWED_POLICY_2, DISALLOWED_POLICY_3);
+    private static final Boolean ORPHAN = false;
+    private static final Boolean RENEWABLE = true;
+    private static final String PATH_SUFFIX = "ps";
+    private static final String ALLOWED_ENTITY_ALIAS_1 = "alias-1";
+    private static final String ALLOWED_ENTITY_ALIAS_2 = "alias-2";
+    private static final String ALLOWED_ENTITY_ALIAS_3 = "alias-3";
+    private static final List<String> ALLOWED_ENTITY_ALIASES = Arrays.asList(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_3);
+    private static final String TOKEN_BOUND_CIDR_1 = "192.0.2.0/24";
+    private static final String TOKEN_BOUND_CIDR_2 = "198.51.100.0/24";
+    private static final String TOKEN_BOUND_CIDR_3 = "203.0.113.0/24";
+    private static final List<String> TOKEN_BOUND_CIDRS = Arrays.asList(TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_1);
+    private static final Integer TOKEN_EXPLICIT_MAX_TTL = 1234;
+    private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
+    private static final Integer TOKEN_NUM_USES = 5;
+    private static final Integer TOKEN_PERIOD = 2345;
+    private static final Token.Type TOKEN_TYPE = Token.Type.SERVICE;
+
+    private static final String JSON_FULL = "{" +
+            "\"allowed_policies\":[\"" + ALLOWED_POLICY_1 + "\",\"" + ALLOWED_POLICY_2 + "\",\"" + ALLOWED_POLICY_3 + "\"]," +
+            "\"disallowed_policies\":[\"" + DISALLOWED_POLICY_1 + "\",\"" + DISALLOWED_POLICY_2 + "\",\"" + DISALLOWED_POLICY_3 + "\"]," +
+            "\"orphan\":" + ORPHAN + "," +
+            "\"renewable\":" + RENEWABLE + "," +
+            "\"path_suffix\":\"" + PATH_SUFFIX + "\"," +
+            "\"allowed_entity_aliases\":[\"" + ALLOWED_ENTITY_ALIAS_1 + "\",\"" + ALLOWED_ENTITY_ALIAS_3 + "\",\"" + ALLOWED_ENTITY_ALIAS_2 + "\"]," +
+            "\"token_bound_cidrs\":[\"" + TOKEN_BOUND_CIDR_3 + "\",\"" + TOKEN_BOUND_CIDR_2 + "\",\"" + TOKEN_BOUND_CIDR_1 + "\"]," +
+            "\"token_explicit_max_ttl\":" + TOKEN_EXPLICIT_MAX_TTL + "," +
+            "\"token_no_default_policy\":" + TOKEN_NO_DEFAULT_POLICY + "," +
+            "\"token_num_uses\":" + TOKEN_NUM_USES + "," +
+            "\"token_period\":" + TOKEN_PERIOD + "," +
+            "\"token_type\":\"" + TOKEN_TYPE.value() + "\"}";
+
+    /**
+     * Build token without any parameters.
+     */
+    @Test
+    public void buildDefaultTest() throws JsonProcessingException {
+        TokenRole role = new TokenRoleBuilder().build();
+        assertThat(role.getAllowedPolicies(), is(nullValue()));
+        assertThat(role.getDisallowedPolicies(), is(nullValue()));
+        assertThat(role.getOrphan(), is(nullValue()));
+        assertThat(role.getRenewable(), is(nullValue()));
+        assertThat(role.getAllowedEntityAliases(), is(nullValue()));
+        assertThat(role.getTokenBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenExplicitMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenNoDefaultPolicy(), is(nullValue()));
+        assertThat(role.getTokenNumUses(), is(nullValue()));
+        assertThat(role.getTokenPeriod(), is(nullValue()));
+        assertThat(role.getTokenType(), is(nullValue()));
+
+        /* optional fields should be ignored, so JSON string should be empty */
+        assertThat(new ObjectMapper().writeValueAsString(role), is("{}"));
+    }
+
+    /**
+     * Build token without all parameters NULL.
+     */
+    @Test
+    public void buildNullTest() throws JsonProcessingException {
+        TokenRole role = TokenRole.builder()
+                .withAllowedPolicies(null)
+                .withAllowedPolicy(null)
+                .withDisallowedPolicy(null)
+                .withDisallowedPolicies(null)
+                .orphan(null)
+                .renewable(null)
+                .withPathSuffix(null)
+                .withAllowedEntityAliases(null)
+                .withAllowedEntityAlias(null)
+                .withTokenBoundCidr(null)
+                .withTokenBoundCidrs(null)
+                .withTokenExplicitMaxTtl(null)
+                .withTokenNoDefaultPolicy(null)
+                .withTokenNumUses(null)
+                .withTokenPeriod(null)
+                .withTokenType(null)
+                .build();
+
+        assertThat(role.getAllowedPolicies(), is(nullValue()));
+        assertThat(role.getDisallowedPolicies(), is(nullValue()));
+        assertThat(role.getOrphan(), is(nullValue()));
+        assertThat(role.getRenewable(), is(nullValue()));
+        assertThat(role.getAllowedEntityAliases(), is(nullValue()));
+        assertThat(role.getTokenBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenExplicitMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenNoDefaultPolicy(), is(nullValue()));
+        assertThat(role.getTokenNumUses(), is(nullValue()));
+        assertThat(role.getTokenPeriod(), is(nullValue()));
+        assertThat(role.getTokenType(), is(nullValue()));
+
+        /* optional fields should be ignored, so JSON string should be empty */
+        assertThat(new ObjectMapper().writeValueAsString(role), is("{}"));
+    }
+
+    /**
+     * Build token without all parameters set.
+     */
+    @Test
+    public void buildFullTest() throws JsonProcessingException {
+        TokenRole role = TokenRole.builder()
+                .withAllowedPolicies(ALLOWED_POLICIES)
+                .withAllowedPolicy(ALLOWED_POLICY_3)
+                .withDisallowedPolicy(DISALLOWED_POLICY_1)
+                .withDisallowedPolicies(DISALLOWED_POLICIES)
+                .orphan(ORPHAN)
+                .renewable(RENEWABLE)
+                .withPathSuffix(PATH_SUFFIX)
+                .withAllowedEntityAliases(ALLOWED_ENTITY_ALIASES)
+                .withAllowedEntityAlias(ALLOWED_ENTITY_ALIAS_2)
+                .withTokenBoundCidr(TOKEN_BOUND_CIDR_3)
+                .withTokenBoundCidrs(TOKEN_BOUND_CIDRS)
+                .withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
+                .withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
+                .withTokenNumUses(TOKEN_NUM_USES)
+                .withTokenPeriod(TOKEN_PERIOD)
+                .withTokenType(TOKEN_TYPE)
+                .build();
+        assertThat(role.getName(), is(nullValue()));
+        assertThat(role.getAllowedPolicies(), hasSize(ALLOWED_POLICIES.size() + 1));
+        assertThat(role.getAllowedPolicies(), containsInAnyOrder(ALLOWED_POLICY_1, ALLOWED_POLICY_2, ALLOWED_POLICY_3));
+        assertThat(role.getDisallowedPolicies(), hasSize(DISALLOWED_POLICIES.size() + 1));
+        assertThat(role.getDisallowedPolicies(), containsInAnyOrder(DISALLOWED_POLICY_1, DISALLOWED_POLICY_2, DISALLOWED_POLICY_3));
+        assertThat(role.getOrphan(), is(ORPHAN));
+        assertThat(role.getRenewable(), is(RENEWABLE));
+        assertThat(role.getPathSuffix(), is(PATH_SUFFIX));
+        assertThat(role.getAllowedEntityAliases(), hasSize(ALLOWED_ENTITY_ALIASES.size() + 1));
+        assertThat(role.getAllowedEntityAliases(), containsInAnyOrder(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_2, ALLOWED_ENTITY_ALIAS_3));
+        assertThat(role.getTokenBoundCidrs(), hasSize(TOKEN_BOUND_CIDRS.size() + 1));
+        assertThat(role.getTokenBoundCidrs(), containsInAnyOrder(TOKEN_BOUND_CIDR_1, TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_3));
+        assertThat(role.getTokenNoDefaultPolicy(), is(TOKEN_NO_DEFAULT_POLICY));
+        assertThat(role.getTokenNumUses(), is(TOKEN_NUM_USES));
+        assertThat(role.getTokenPeriod(), is(TOKEN_PERIOD));
+        assertThat(role.getTokenType(), is(TOKEN_TYPE.value()));
+
+        /* Verify that all parameters are included in JSON string */
+        assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_FULL));
+    }
+}

From c0708bd288727a1234fb379c74c1c43c9c059620 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Mon, 6 Apr 2020 18:36:42 +0200
Subject: [PATCH 10/21] implement methods for token role handling (#27)

Create, update, read, delete and list token roles is now possible.
---
 CHANGELOG.md                                  |  1 +
 .../jvault/connector/HTTPVaultConnector.java  | 53 +++++++++--
 .../jvault/connector/VaultConnector.java      | 70 ++++++++++++---
 .../jvault/connector/model/TokenRole.java     |  5 ++
 .../connector/model/TokenRoleBuilder.java     | 14 ++-
 .../model/response/TokenRoleResponse.java     | 60 +++++++++++++
 .../connector/HTTPVaultConnectorTest.java     | 90 ++++++++++++++++++-
 .../connector/model/TokenRoleBuilderTest.java |  6 +-
 8 files changed, 280 insertions(+), 19 deletions(-)
 create mode 100644 src/main/java/de/stklcode/jvault/connector/model/response/TokenRoleResponse.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a107dea..2d5f545 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
 
 ### Features
 * Support for token types (#26)
+* Support for token role handling (#27)
 
 ### Improvements
 * Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
index 2494b12..980e876 100644
--- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
@@ -20,10 +20,7 @@ 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.internal.RequestHelper;
-import de.stklcode.jvault.connector.model.AppRole;
-import de.stklcode.jvault.connector.model.AppRoleSecret;
-import de.stklcode.jvault.connector.model.AuthBackend;
-import de.stklcode.jvault.connector.model.Token;
+import de.stklcode.jvault.connector.model.*;
 import de.stklcode.jvault.connector.model.response.*;
 import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
 
@@ -49,6 +46,7 @@ public class HTTPVaultConnector implements VaultConnector {
     private static final String PATH_TOKEN = "auth/token";
     private static final String PATH_LOOKUP = "/lookup";
     private static final String PATH_CREATE = "/create";
+    private static final String PATH_ROLES = "/roles";
     private static final String PATH_CREATE_ORPHAN = "/create-orphan";
     private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
     private static final String PATH_AUTH_APPID = "auth/app-id/";
@@ -530,7 +528,7 @@ public class HTTPVaultConnector implements VaultConnector {
         if (cas != null) {
             options.put("cas", cas);
         }
-        
+
         Map<String, Object> payload = new HashMap<>();
         payload.put("data", data);
         payload.put("options", options);
@@ -701,6 +699,51 @@ public class HTTPVaultConnector implements VaultConnector {
         return request.get(PATH_TOKEN + PATH_LOOKUP, param, token, TokenResponse.class);
     }
 
+    @Override
+    public boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException {
+        requireAuth();
+
+        if (name == null) {
+            throw new InvalidRequestException("Role name must be provided.");
+        } else if (role == null) {
+            throw new InvalidRequestException("Role must be provided.");
+        }
+
+        // Issue request and expect code 204 with empty response.
+        request.postWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, role, token);
+
+        return true;
+    }
+
+    @Override
+    public TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException {
+        requireAuth();
+
+        // Request HTTP response and parse response.
+        return request.get(PATH_TOKEN + PATH_ROLES + "/" + name, new HashMap<>(), token, TokenRoleResponse.class);
+    }
+
+    @Override
+    public List<String> listTokenRoles() throws VaultConnectorException {
+        requireAuth();
+
+        return list(PATH_TOKEN + PATH_ROLES);
+    }
+
+    @Override
+    public boolean deleteTokenRole(final String name) throws VaultConnectorException {
+        requireAuth();
+
+        if (name == null) {
+            throw new InvalidRequestException("Role name must be provided.");
+        }
+
+        // Issue request and expect code 204 with empty response.
+        request.deleteWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, token);
+
+        return true;
+    }
+
     /**
      * Check for required authorization.
      *
diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
index 83b9187..de7579d 100644
--- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
@@ -233,7 +233,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Delete AppRole role from Vault.
      *
      * @param roleName The role anme
-     * @return {@code true} on succevss
+     * @return {@code true} on success
      * @throws VaultConnectorException on error
      */
     boolean deleteAppRole(final String roleName) throws VaultConnectorException;
@@ -446,7 +446,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Prefix {@code secret/} is automatically added to path.
      * Only available for KV v2 secrets.
      *
-     * @param key Secret identifier.
+     * @param key  Secret identifier.
      * @param data Secret content. Value must be be JSON serializable.
      * @return Metadata for the created/updated secret.
      * @throws VaultConnectorException on error
@@ -463,8 +463,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Only available for KV v2 secrets.
      *
      * @param mount Secret store mountpoint (without leading or trailing slash).
-     * @param key Secret identifier
-     * @param data Secret content. Value must be be JSON serializable.
+     * @param key   Secret identifier
+     * @param data  Secret content. Value must be be JSON serializable.
      * @return Metadata for the created/updated secret.
      * @throws VaultConnectorException on error
      * @since 0.8
@@ -480,9 +480,9 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Only available for KV v2 secrets.
      *
      * @param mount Secret store mountpoint (without leading or trailing slash).
-     * @param key Secret identifier
-     * @param data Secret content. Value must be be JSON serializable.
-     * @param cas  Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
+     * @param key   Secret identifier
+     * @param data  Secret content. Value must be be JSON serializable.
+     * @param cas   Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
      * @return Metadata for the created/updated secret.
      * @throws VaultConnectorException on error
      * @since 0.8
@@ -540,7 +540,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code secret/metadata/<key>} is read here.
      * Only available for KV v2 secrets.
      *
-     * @param key Secret identifier
+     * @param key         Secret identifier
      * @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
      * @param casRequired Specify if Check-And-Set is required for this secret.
      * @throws VaultConnectorException on error
@@ -737,8 +737,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Prefix {@code secret/} is automatically added to path.
      * Only available for KV v2 stores.
      *
-     * @param mount    Secret store mountpoint (without leading or trailing slash).
-     * @param key Secret path.
+     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param key   Secret path.
      * @throws VaultConnectorException on error
      * @since 0.8
      */
@@ -888,7 +888,57 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      */
     TokenResponse lookupToken(final String token) throws VaultConnectorException;
 
+    /**
+     * Create a new or update an existing token role.
+     *
+     * @param role the role entity (name must be set)
+     * @return {@code true} on success
+     * @throws VaultConnectorException on error
+     * @since 0.9
+     */
+    default boolean createOrUpdateTokenRole(final TokenRole role) throws VaultConnectorException {
+        return createOrUpdateTokenRole(role.getName(), role);
+    }
 
+    /**
+     * Create a new or update an existing token role.
+     *
+     * @param name the role name (overrides name possibly set in role entity)
+     * @param role the role entity
+     * @return {@code true} on success
+     * @throws VaultConnectorException on error
+     * @since 0.9
+     */
+    boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException;
+
+    /**
+     * Lookup token information.
+     *
+     * @param name the role name
+     * @return the result response
+     * @throws VaultConnectorException on error
+     * @since 0.9
+     */
+    TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException;
+
+    /**
+     * List available token roles from Vault.
+     *
+     * @return List of token roles
+     * @throws VaultConnectorException on error
+     * @since 0.9
+     */
+    List<String> listTokenRoles() throws VaultConnectorException;
+
+    /**
+     * Delete a token role.
+     *
+     * @param name the role name to delete
+     * @return {@code true} on success
+     * @throws VaultConnectorException on error
+     * @since 0.9
+     */
+    boolean deleteTokenRole(final String name) throws VaultConnectorException;
 
     /**
      * Read credentials for MySQL backend at default mount point.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
index 160cda0..a980408 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
@@ -92,6 +92,11 @@ public final class TokenRole {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private String tokenType;
 
+    /**
+     * Construct empty {@link TokenRole} object.
+     */
+    public TokenRole() {
+    }
 
     /**
      * Construct complete {@link TokenRole} object.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
index 2a79a1c..0c5a4b8 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
@@ -26,6 +26,7 @@ import java.util.List;
  * @since 0.9
  */
 public final class TokenRoleBuilder {
+    private String name;
     private List<String> allowedPolicies;
     private List<String> disallowedPolicies;
     private Boolean orphan;
@@ -39,6 +40,17 @@ public final class TokenRoleBuilder {
     private Integer tokenPeriod;
     private Token.Type tokenType;
 
+    /**
+     * Add token role name.
+     *
+     * @param name role name
+     * @return self
+     */
+    public TokenRoleBuilder forName(final String name) {
+        this.name = name;
+        return this;
+    }
+
     /**
      * Add an allowed policy.
      *
@@ -262,7 +274,7 @@ public final class TokenRoleBuilder {
      */
     public TokenRole build() {
         return new TokenRole(
-                null,
+                name,
                 allowedPolicies,
                 disallowedPolicies,
                 orphan,
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/TokenRoleResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/TokenRoleResponse.java
new file mode 100644
index 0000000..68c11cd
--- /dev/null
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/TokenRoleResponse.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016-2020 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.databind.ObjectMapper;
+import de.stklcode.jvault.connector.exception.InvalidResponseException;
+import de.stklcode.jvault.connector.model.TokenRole;
+import de.stklcode.jvault.connector.model.response.embedded.TokenData;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Vault response from token role lookup providing Token information in {@link TokenData} field.
+ *
+ * @author Stefan Kalscheuer
+ * @since 0.9
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public final class TokenRoleResponse extends VaultDataResponse {
+    private TokenRole data;
+
+    /**
+     * Set data. Parses response data map to {@link TokenRole}.
+     *
+     * @param data Raw response data
+     * @throws InvalidResponseException on parsing errors
+     */
+    @Override
+    public void setData(final Map<String, Object> data) throws InvalidResponseException {
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            this.data = mapper.readValue(mapper.writeValueAsString(data), TokenRole.class);
+        } catch (IOException e) {
+            throw new InvalidResponseException("Failed deserializing response", e);
+        }
+    }
+
+    /**
+     * @return TokenRole data
+     */
+    public TokenRole getData() {
+        return data;
+    }
+}
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 3e6d497..892b5f2 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -22,6 +22,7 @@ import de.stklcode.jvault.connector.exception.*;
 import de.stklcode.jvault.connector.model.AppRole;
 import de.stklcode.jvault.connector.model.AuthBackend;
 import de.stklcode.jvault.connector.model.Token;
+import de.stklcode.jvault.connector.model.TokenRole;
 import de.stklcode.jvault.connector.model.response.*;
 import de.stklcode.jvault.connector.test.Credentials;
 import de.stklcode.jvault.connector.test.VaultConfiguration;
@@ -39,8 +40,7 @@ import static org.apache.commons.io.FileUtils.copyDirectory;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 import static org.hamcrest.core.Is.is;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
@@ -1163,6 +1163,92 @@ public class HTTPVaultConnectorTest {
                 fail("Token creation failed.");
             }
         }
+
+        /**
+         * Test token role handling.
+         */
+        @Test
+        @Order(40)
+        @DisplayName("Token roles")
+        public void tokenRolesTest() {
+            authRoot();
+            assumeTrue(connector.isAuthorized());
+
+            // Create token role.
+            final String roleName = "test-role";
+            final TokenRole role = TokenRole.builder().build();
+
+            try {
+                assertThat(connector.createOrUpdateTokenRole(roleName, role), is(true));
+            } catch (VaultConnectorException e) {
+                fail("Token role creation failed.");
+            }
+
+            // Read the role.
+            TokenRoleResponse res = null;
+            try {
+                res = connector.readTokenRole(roleName);
+            } catch (VaultConnectorException e) {
+                fail("Reading token role failed.");
+            }
+
+            assertThat("Token role response must not be null", res, is(notNullValue()));
+            assertThat("Token role must not be null", res.getData(), is(notNullValue()));
+            assertThat("Token role name not as expected", res.getData().getName(), is(roleName));
+            assertThat("Token role expected to be renewable by default", res.getData().getRenewable(), is(true));
+            assertThat("Token role not expected to be orphan by default", res.getData().getOrphan(), is(false));
+            assertThat("Unexpected default token type", res.getData().getTokenType(), is(Token.Type.DEFAULT_SERVICE.value()));
+
+            // Update the role, i.e. change some attributes.
+            final TokenRole role2 = TokenRole.builder()
+                    .forName(roleName)
+                    .withPathSuffix("suffix")
+                    .orphan(true)
+                    .renewable(false)
+                    .withTokenNumUses(42)
+                    .build();
+
+            try {
+                assertThat(connector.createOrUpdateTokenRole(role2), is(true));
+            } catch (VaultConnectorException e) {
+                fail("Token role update failed.");
+            }
+
+            try {
+                res = connector.readTokenRole(roleName);
+            } catch (VaultConnectorException e) {
+                fail("Reading token role failed.");
+            }
+
+            assertThat("Token role response must not be null", res, is(notNullValue()));
+            assertThat("Token role must not be null", res.getData(), is(notNullValue()));
+            assertThat("Token role name not as expected", res.getData().getName(), is(roleName));
+            assertThat("Token role not expected to be renewable  after update", res.getData().getRenewable(), is(false));
+            assertThat("Token role expected to be orphan  after update", res.getData().getOrphan(), is(true));
+            assertThat("Unexpected number of token uses after update", res.getData().getTokenNumUses(), is(42));
+
+            // List roles.
+            List<String> listRes = null;
+            try {
+                listRes = connector.listTokenRoles();
+            } catch (VaultConnectorException e) {
+                fail("Listing token roles failed.");
+            }
+
+            assertThat("Token role list must not be null", listRes, is(notNullValue()));
+            assertThat("Unexpected number of token roles", listRes, hasSize(1));
+            assertThat("Unexpected token role in list", listRes, contains(roleName));
+
+            // Delete the role.
+            try {
+                assertThat(connector.deleteTokenRole(roleName), is(true));
+            } catch (VaultConnectorException e) {
+                fail("Token role deletion failed.");
+            }
+
+            assertThrows(InvalidResponseException.class, () -> connector.readTokenRole(roleName), "Reading inexistent token role should fail");
+            assertThrows(InvalidResponseException.class, () -> connector.listTokenRoles(), "Listing inexistent token roles should fail");
+        }
     }
 
     @Nested
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
index 483a024..f738fbc 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
@@ -33,6 +33,7 @@ import static org.hamcrest.Matchers.*;
  * @since 0.9
  */
 public class TokenRoleBuilderTest {
+    private static final String NAME = "test-role";
     private static final String ALLOWED_POLICY_1 = "apol-1";
     private static final String ALLOWED_POLICY_2 = "apol-2";
     private static final String ALLOWED_POLICY_3 = "apol-3";
@@ -59,6 +60,7 @@ public class TokenRoleBuilderTest {
     private static final Token.Type TOKEN_TYPE = Token.Type.SERVICE;
 
     private static final String JSON_FULL = "{" +
+            "\"name\":\"" + NAME + "\"," +
             "\"allowed_policies\":[\"" + ALLOWED_POLICY_1 + "\",\"" + ALLOWED_POLICY_2 + "\",\"" + ALLOWED_POLICY_3 + "\"]," +
             "\"disallowed_policies\":[\"" + DISALLOWED_POLICY_1 + "\",\"" + DISALLOWED_POLICY_2 + "\",\"" + DISALLOWED_POLICY_3 + "\"]," +
             "\"orphan\":" + ORPHAN + "," +
@@ -100,6 +102,7 @@ public class TokenRoleBuilderTest {
     @Test
     public void buildNullTest() throws JsonProcessingException {
         TokenRole role = TokenRole.builder()
+                .forName(null)
                 .withAllowedPolicies(null)
                 .withAllowedPolicy(null)
                 .withDisallowedPolicy(null)
@@ -140,6 +143,7 @@ public class TokenRoleBuilderTest {
     @Test
     public void buildFullTest() throws JsonProcessingException {
         TokenRole role = TokenRole.builder()
+                .forName(NAME)
                 .withAllowedPolicies(ALLOWED_POLICIES)
                 .withAllowedPolicy(ALLOWED_POLICY_3)
                 .withDisallowedPolicy(DISALLOWED_POLICY_1)
@@ -157,7 +161,7 @@ public class TokenRoleBuilderTest {
                 .withTokenPeriod(TOKEN_PERIOD)
                 .withTokenType(TOKEN_TYPE)
                 .build();
-        assertThat(role.getName(), is(nullValue()));
+        assertThat(role.getName(), is(NAME));
         assertThat(role.getAllowedPolicies(), hasSize(ALLOWED_POLICIES.size() + 1));
         assertThat(role.getAllowedPolicies(), containsInAnyOrder(ALLOWED_POLICY_1, ALLOWED_POLICY_2, ALLOWED_POLICY_3));
         assertThat(role.getDisallowedPolicies(), hasSize(DISALLOWED_POLICIES.size() + 1));

From edb9194153697cbb9dbfe9f589ed18ad352a55f8 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 8 Apr 2020 14:23:48 +0200
Subject: [PATCH 11/21] Update copyright notice to 2020

Better late than never, at least before the next release... [skip ci]
---
 .../java/de/stklcode/jvault/connector/HTTPVaultConnector.java   | 2 +-
 src/main/java/de/stklcode/jvault/connector/VaultConnector.java  | 2 +-
 .../jvault/connector/builder/HTTPVaultConnectorBuilder.java     | 2 +-
 .../jvault/connector/builder/VaultConnectorBuilder.java         | 2 +-
 .../java/de/stklcode/jvault/connector/builder/package-info.java | 2 +-
 .../connector/exception/AuthorizationRequiredException.java     | 2 +-
 .../jvault/connector/exception/ConnectionException.java         | 2 +-
 .../jvault/connector/exception/InvalidRequestException.java     | 2 +-
 .../jvault/connector/exception/InvalidResponseException.java    | 2 +-
 .../jvault/connector/exception/PermissionDeniedException.java   | 2 +-
 .../de/stklcode/jvault/connector/exception/TlsException.java    | 2 +-
 .../jvault/connector/exception/VaultConnectorException.java     | 2 +-
 .../de/stklcode/jvault/connector/exception/package-info.java    | 2 +-
 .../jvault/connector/factory/HTTPVaultConnectorFactory.java     | 2 +-
 .../jvault/connector/factory/VaultConnectorFactory.java         | 2 +-
 .../java/de/stklcode/jvault/connector/factory/package-info.java | 2 +-
 src/main/java/de/stklcode/jvault/connector/internal/Error.java  | 2 +-
 src/main/java/de/stklcode/jvault/connector/model/AppRole.java   | 2 +-
 .../java/de/stklcode/jvault/connector/model/AppRoleBuilder.java | 2 +-
 .../java/de/stklcode/jvault/connector/model/AppRoleSecret.java  | 2 +-
 .../java/de/stklcode/jvault/connector/model/AuthBackend.java    | 2 +-
 src/main/java/de/stklcode/jvault/connector/model/Token.java     | 2 +-
 .../java/de/stklcode/jvault/connector/model/TokenBuilder.java   | 2 +-
 .../java/de/stklcode/jvault/connector/model/package-info.java   | 2 +-
 .../jvault/connector/model/response/AppRoleResponse.java        | 2 +-
 .../jvault/connector/model/response/AppRoleSecretResponse.java  | 2 +-
 .../jvault/connector/model/response/AuthMethodsResponse.java    | 2 +-
 .../stklcode/jvault/connector/model/response/AuthResponse.java  | 2 +-
 .../jvault/connector/model/response/CredentialsResponse.java    | 2 +-
 .../stklcode/jvault/connector/model/response/ErrorResponse.java | 2 +-
 .../jvault/connector/model/response/HealthResponse.java         | 2 +-
 .../stklcode/jvault/connector/model/response/HelpResponse.java  | 2 +-
 .../jvault/connector/model/response/MetadataResponse.java       | 2 +-
 .../jvault/connector/model/response/RawDataResponse.java        | 2 +-
 .../stklcode/jvault/connector/model/response/SealResponse.java  | 2 +-
 .../jvault/connector/model/response/SecretListResponse.java     | 2 +-
 .../jvault/connector/model/response/SecretResponse.java         | 2 +-
 .../jvault/connector/model/response/SecretVersionResponse.java  | 2 +-
 .../stklcode/jvault/connector/model/response/TokenResponse.java | 2 +-
 .../jvault/connector/model/response/VaultDataResponse.java      | 2 +-
 .../stklcode/jvault/connector/model/response/VaultResponse.java | 2 +-
 .../jvault/connector/model/response/embedded/AuthData.java      | 2 +-
 .../jvault/connector/model/response/embedded/AuthMethod.java    | 2 +-
 .../connector/model/response/embedded/SecretMetadata.java       | 2 +-
 .../jvault/connector/model/response/embedded/TokenData.java     | 2 +-
 .../connector/model/response/embedded/VersionMetadata.java      | 2 +-
 .../jvault/connector/model/response/embedded/package-info.java  | 2 +-
 .../stklcode/jvault/connector/model/response/package-info.java  | 2 +-
 src/main/java/de/stklcode/jvault/connector/package-info.java    | 2 +-
 .../jvault/connector/HTTPVaultConnectorOfflineTest.java         | 2 +-
 .../de/stklcode/jvault/connector/HTTPVaultConnectorTest.java    | 2 +-
 .../jvault/connector/builder/HTTPVaultConnectorBuilderTest.java | 2 +-
 .../jvault/connector/exception/VaultConnectorExceptionTest.java | 2 +-
 .../jvault/connector/factory/HTTPVaultConnectorFactoryTest.java | 2 +-
 .../de/stklcode/jvault/connector/model/AppRoleBuilderTest.java  | 2 +-
 .../de/stklcode/jvault/connector/model/AppRoleSecretTest.java   | 2 +-
 .../de/stklcode/jvault/connector/model/AuthBackendTest.java     | 2 +-
 .../de/stklcode/jvault/connector/model/TokenBuilderTest.java    | 2 +-
 .../jvault/connector/model/response/AppRoleResponseTest.java    | 2 +-
 .../connector/model/response/AuthMethodsResponseTest.java       | 2 +-
 .../jvault/connector/model/response/AuthResponseTest.java       | 2 +-
 .../connector/model/response/CredentialsResponseTest.java       | 2 +-
 .../jvault/connector/model/response/HealthResponseTest.java     | 2 +-
 .../jvault/connector/model/response/MetadataResponseTest.java   | 2 +-
 .../jvault/connector/model/response/SealResponseTest.java       | 2 +-
 .../jvault/connector/model/response/SecretListResponseTest.java | 2 +-
 .../jvault/connector/model/response/SecretResponseTest.java     | 2 +-
 .../connector/model/response/SecretVersionResponseTest.java     | 2 +-
 .../jvault/connector/model/response/TokenResponseTest.java      | 2 +-
 .../java/de/stklcode/jvault/connector/test/Credentials.java     | 2 +-
 .../java/de/stklcode/jvault/connector/test/EnvironmentMock.java | 2 +-
 .../de/stklcode/jvault/connector/test/VaultConfiguration.java   | 2 +-
 72 files changed, 72 insertions(+), 72 deletions(-)

diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
index 2494b12..c5ae9d8 100644
--- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
index 83b9187..ce933f2 100644
--- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java b/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
index 101972f..0174389 100644
--- a/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/builder/VaultConnectorBuilder.java b/src/main/java/de/stklcode/jvault/connector/builder/VaultConnectorBuilder.java
index 1a3fcd3..b6e344d 100644
--- a/src/main/java/de/stklcode/jvault/connector/builder/VaultConnectorBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/builder/VaultConnectorBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/builder/package-info.java b/src/main/java/de/stklcode/jvault/connector/builder/package-info.java
index f2f4c1b..fd7ebac 100644
--- a/src/main/java/de/stklcode/jvault/connector/builder/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/builder/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/AuthorizationRequiredException.java b/src/main/java/de/stklcode/jvault/connector/exception/AuthorizationRequiredException.java
index 2e9a957..c56063d 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/AuthorizationRequiredException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/AuthorizationRequiredException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/ConnectionException.java b/src/main/java/de/stklcode/jvault/connector/exception/ConnectionException.java
index cd2cd98..cb240e6 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/ConnectionException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/ConnectionException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/InvalidRequestException.java b/src/main/java/de/stklcode/jvault/connector/exception/InvalidRequestException.java
index bc5759a..958bbe6 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/InvalidRequestException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/InvalidRequestException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/InvalidResponseException.java b/src/main/java/de/stklcode/jvault/connector/exception/InvalidResponseException.java
index 42f4184..3931f69 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/InvalidResponseException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/InvalidResponseException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/PermissionDeniedException.java b/src/main/java/de/stklcode/jvault/connector/exception/PermissionDeniedException.java
index 9f01658..a953271 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/PermissionDeniedException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/PermissionDeniedException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java b/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java
index 20f465a..e2c3517 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/VaultConnectorException.java b/src/main/java/de/stklcode/jvault/connector/exception/VaultConnectorException.java
index 8e9644c..418abda 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/VaultConnectorException.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/VaultConnectorException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/exception/package-info.java b/src/main/java/de/stklcode/jvault/connector/exception/package-info.java
index 1cdbeeb..3131472 100644
--- a/src/main/java/de/stklcode/jvault/connector/exception/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/exception/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
index 678b35d..8ae3d5b 100644
--- a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
+++ b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java b/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java
index 1147bac..1f3c2be 100644
--- a/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java
+++ b/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/factory/package-info.java b/src/main/java/de/stklcode/jvault/connector/factory/package-info.java
index f6323de..1774531 100644
--- a/src/main/java/de/stklcode/jvault/connector/factory/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/factory/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/internal/Error.java b/src/main/java/de/stklcode/jvault/connector/internal/Error.java
index 55331d7..15c0f94 100644
--- a/src/main/java/de/stklcode/jvault/connector/internal/Error.java
+++ b/src/main/java/de/stklcode/jvault/connector/internal/Error.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
index ce700d3..4ee4546 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
index ae871cc..15a5674 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRoleSecret.java b/src/main/java/de/stklcode/jvault/connector/model/AppRoleSecret.java
index 6952074..8fa51f5 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRoleSecret.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRoleSecret.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AuthBackend.java b/src/main/java/de/stklcode/jvault/connector/model/AuthBackend.java
index d098fa1..6c2d3ea 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AuthBackend.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AuthBackend.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index a87e0b1..7dec7e4 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
index ba17bb1..18ef7fd 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/package-info.java b/src/main/java/de/stklcode/jvault/connector/model/package-info.java
index 6e87e2f..dce8c1b 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleResponse.java
index b58e3f4..f3c19d5 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleSecretResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleSecretResponse.java
index 869cbf7..35eb3b0 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleSecretResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/AppRoleSecretResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java
index da72378..58ebf36 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/AuthResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/AuthResponse.java
index 67080ac..d5b35ca 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/AuthResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/AuthResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/CredentialsResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/CredentialsResponse.java
index ed4b6e4..d524339 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/CredentialsResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/CredentialsResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/ErrorResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/ErrorResponse.java
index 9b91b19..a1a04ef 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/ErrorResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/ErrorResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/HealthResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/HealthResponse.java
index a8aa2d5..940ac5b 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/HealthResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/HealthResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/HelpResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/HelpResponse.java
index 4aa9e75..f2dbfa5 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/HelpResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/HelpResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/MetadataResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/MetadataResponse.java
index fda5f6d..89de0da 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/MetadataResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/MetadataResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/RawDataResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/RawDataResponse.java
index 039a1f0..d959c96 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/RawDataResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/RawDataResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SealResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SealResponse.java
index 052e3db..4ce5e39 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SealResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SealResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SecretListResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SecretListResponse.java
index 5f46dbb..35699a3 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SecretListResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SecretListResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
index f4f3c1d..b670a5b 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SecretResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
index aa7a6db..2a6d0a0 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/TokenResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/TokenResponse.java
index 0cd2fe0..cabea7c 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/TokenResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/TokenResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/VaultDataResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/VaultDataResponse.java
index 073d3ce..d0b5595 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/VaultDataResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/VaultDataResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/VaultResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/VaultResponse.java
index c331205..bc82e40 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/VaultResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/VaultResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
index ac5fc5c..9243eca 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java
index aa4e87d..88b5b59 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java
index 9a9233e..a248d77 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
index e68aab4..5e0f461 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/TokenData.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java
index 4fbbc4a..7f06d54 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/package-info.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/package-info.java
index f2754ad..7d24785 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/package-info.java b/src/main/java/de/stklcode/jvault/connector/model/response/package-info.java
index 3d41006..65ddb0a 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/main/java/de/stklcode/jvault/connector/package-info.java b/src/main/java/de/stklcode/jvault/connector/package-info.java
index 9417eb1..8e67bbd 100644
--- a/src/main/java/de/stklcode/jvault/connector/package-info.java
+++ b/src/main/java/de/stklcode/jvault/connector/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
index b44c2dc..5ba03fb 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 3e6d497..06d0132 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilderTest.java
index 788301e..6a089b9 100644
--- a/src/test/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/exception/VaultConnectorExceptionTest.java b/src/test/java/de/stklcode/jvault/connector/exception/VaultConnectorExceptionTest.java
index d680f7a..6c15b4f 100644
--- a/src/test/java/de/stklcode/jvault/connector/exception/VaultConnectorExceptionTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/exception/VaultConnectorExceptionTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactoryTest.java b/src/test/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactoryTest.java
index de4fb95..4435d2f 100644
--- a/src/test/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactoryTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactoryTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
index 21a586b..8ef0229 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/AppRoleSecretTest.java b/src/test/java/de/stklcode/jvault/connector/model/AppRoleSecretTest.java
index fbabb32..27a4792 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/AppRoleSecretTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/AppRoleSecretTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/AuthBackendTest.java b/src/test/java/de/stklcode/jvault/connector/model/AuthBackendTest.java
index b8fead6..a9b2ebb 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/AuthBackendTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/AuthBackendTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
index e236dbb..6672815 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
index 2d02ba5..dfb91b7 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponseTest.java
index b93eaf2..a94d4f8 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
index f2e942b..933aa6d 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/AuthResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/CredentialsResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/CredentialsResponseTest.java
index 38bea55..331d04a 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/CredentialsResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/CredentialsResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/HealthResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/HealthResponseTest.java
index 1435c5e..f5b90f7 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/HealthResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/HealthResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
index 05a5402..0b2d65e 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/SealResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/SealResponseTest.java
index a57f4f9..e4eddd3 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/SealResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/SealResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/SecretListResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/SecretListResponseTest.java
index 93dacb7..e282aa6 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/SecretListResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/SecretListResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/SecretResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/SecretResponseTest.java
index cc66efe..6998cbb 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/SecretResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/SecretResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
index 99d5a62..5422618 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
index a083aa6..e069500 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/TokenResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/test/Credentials.java b/src/test/java/de/stklcode/jvault/connector/test/Credentials.java
index b2031d7..9efd44d 100644
--- a/src/test/java/de/stklcode/jvault/connector/test/Credentials.java
+++ b/src/test/java/de/stklcode/jvault/connector/test/Credentials.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/test/EnvironmentMock.java b/src/test/java/de/stklcode/jvault/connector/test/EnvironmentMock.java
index 582e056..a8b24ad 100644
--- a/src/test/java/de/stklcode/jvault/connector/test/EnvironmentMock.java
+++ b/src/test/java/de/stklcode/jvault/connector/test/EnvironmentMock.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java b/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java
index 0aaa4d2..d95d0a0 100644
--- a/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java
+++ b/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2019 Stefan Kalscheuer
+ * Copyright 2016-2020 Stefan Kalscheuer
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

From 94d1d2c80be07d53270d5c40ada2ccfd157009da Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 8 Apr 2020 14:25:16 +0200
Subject: [PATCH 12/21] test against Vault 1.4.0

---
 .drone.yml                                             | 10 +++++-----
 .travis.yml                                            |  2 +-
 README.md                                              |  2 +-
 .../jvault/connector/HTTPVaultConnectorTest.java       |  2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index e51b747..71600ea 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,12 +5,12 @@ steps:
   - name: test-online
     image: maven:3-jdk-11
     environment:
-      VAULT_VERSION: 1.4.0-rc1
+      VAULT_VERSION: 1.4.0
     commands:
-      - curl -o vault_1.4.0-rc1_linux_amd64.zip https://releases.hashicorp.com/vault/1.4.0-rc1/vault_1.4.0-rc1_linux_amd64.zip
-      - curl -s https://releases.hashicorp.com/vault/1.4.0-rc1/vault_1.4.0-rc1_SHA256SUMS | grep linux_amd64 | sha256sum -c
-      - unzip vault_1.4.0-rc1_linux_amd64.zip
-      - rm vault_1.4.0-rc1_linux_amd64.zip
+      - curl -o vault_1.4.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_linux_amd64.zip
+      - curl -s https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
+      - unzip vault_1.4.0_linux_amd64.zip
+      - rm vault_1.4.0_linux_amd64.zip
       - mv vault /bin/
       - mvn clean test
     when:
diff --git a/.travis.yml b/.travis.yml
index 449dfeb..74f5d22 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ addons:
     token:
       secure: "sM9OfX5jW764pn9cb2LSXArnXucKMws+eGeg5NnZxHRcGYt4hpBKLSregBSsBNzUoWVj0zNzPCpnh+UQvgxQzUerOqwEdjTBpy3SNPaxSn7UpoSg+Wz3aUmL9ugmx01b51/wMG4UCHEwTZt2tpgTPVtw8K6uSO78e0dSICCBHDnRcdQwOjMEQHIJJ/qHVRwuy/MzLCAP3W1JPZlsphZg9QsFyhB4hW97dE90joZezfocQIv2xI/r6k+BLz0pY6MxYCul0RiDumaiaej0CPvEJI/uSu//BAQjUdHw+mQgnKUYIbrn2ONOviwNfwdr94JyoZEN2B6zASUmNLjPf4AbIojDeyS+CrpQpm17EVm/Qk/Ds+Xra4PPPIcsZhiWzV0KoDUz9xLfXuRJ526VT5tDPiaeI7oETf0+8l+JIS1b399FyqHi7smzjpvC6GuKflQrbuHK4MuKzDh7WTHiqokGG4SS0wOQIaaHB3dfdwwQzPh6IM24e8CETxh3DjMeqUTU4DWmv5po55jZ934TtxVQvVN78bTG9O0zS9u+JmRY04OZ+OaXuFam6MfMUFQi0EPZzdGul/oWSibGUu3bNfVEBp60CnJwYNM/dKG6U7pJthLHvSwiQFOdKzHZ+l1jZJ4gPaXaIGqpwqVGr28ntqA/El1rytPixr2driE6bYMt5jw="
 env:
-  - PATH=$PATH:. VAULT_VERSION=1.4.0-rc1
+  - PATH=$PATH:. VAULT_VERSION=1.4.0
 before_script:
   - |
     if [ "$TRAVIS_BRANCH" = "master" ]; then
diff --git a/README.md b/README.md
index 33c0473..77cc066 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
     * SQL secret handling
     * KV v1 and v2 support
 * Connector Factory with builder pattern
-* Tested against Vault 1.3.4
+* Tested against Vault 1.4.0
 
 
 ## Maven Artifact
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 06d0132..e968343 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -53,7 +53,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
  */
 @Tag("online")
 public class HTTPVaultConnectorTest {
-    private static String VAULT_VERSION = "1.4.0-rc1";  // the vault version this test is supposed to run against
+    private static String VAULT_VERSION = "1.4.0";  // the vault version this test is supposed to run against
     private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
     private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
     private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";

From dcb8d6067a43627df14627ec7b9e295b096fe00e Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Mon, 13 Apr 2020 19:18:33 +0200
Subject: [PATCH 13/21] update AppRole model and builder to current API

Add missing JSON fields and remove unprefixed, already deprecated fields
---
 CHANGELOG.md                                  |   9 +
 .../jvault/connector/VaultConnector.java      |   2 +-
 .../jvault/connector/model/AppRole.java       | 248 ++++++++++++------
 .../connector/model/AppRoleBuilder.java       | 207 ++++++++++++---
 .../connector/HTTPVaultConnectorTest.java     |  22 ++
 .../connector/model/AppRoleBuilderTest.java   |  76 ++++--
 .../model/response/AppRoleResponseTest.java   |  13 +-
 7 files changed, 424 insertions(+), 153 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d5f545..7152a1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,8 +11,17 @@
 ### Improvements
 * Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
 * Added `entity_id`, `expire_time`, `explicit_max_ttl`, `issue_time`, `renewable` and `type` flags to token data
+* Added `enable_local_secret_ids`, `token_bound_cidrs`, `token_explicit_max_ttl`, `token_no_default_policy`, 
+  `token_num_uses`, `token_period` and `token_type` flags to _AppRole_ model
 * Minor dependency updates
 
+### Deprecations
+* `AppRole#getPolicies()` and `#setPolicies()` are deprecated in favor of `#getTokenPolicies()` and `#setTokenPolicies()`
+* `AppRole#getPeriod()` is deprecated in favor of `#getTokenPeriod()`
+
+### Removals
+* Deprecated methods `AppRole#getBoundCidrList()`, `#setBoundCidrList()` and `getBoundCidrListString()` have been removed.
+
 
 ## 0.8.2 (2019-10-20)
 
diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
index e21ec11..0b0adb9 100644
--- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
@@ -226,7 +226,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      */
     default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
             throws VaultConnectorException {
-        return createAppRole(new AppRoleBuilder(roleName).withPolicies(policies).withId(roleID).build());
+        return createAppRole(new AppRoleBuilder(roleName).withTokenPolicies(policies).withId(roleID).build());
     }
 
     /**
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
index 4ee4546..8dbb1a6 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
@@ -50,12 +50,8 @@ public final class AppRole {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Boolean bindSecretId;
 
-    private List<String> boundCidrList;
-
     private List<String> secretIdBoundCidrs;
 
-    private List<String> policies;
-
     @JsonProperty("secret_id_num_uses")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer secretIdNumUses;
@@ -64,6 +60,10 @@ public final class AppRole {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer secretIdTtl;
 
+    @JsonProperty("enable_local_secret_ids")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean enableLocalSecretIds;
+
     @JsonProperty("token_ttl")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer tokenTtl;
@@ -72,9 +72,31 @@ public final class AppRole {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer tokenMaxTtl;
 
-    @JsonProperty("period")
+    private List<String> tokenPolicies;
+
+    @JsonProperty("token_bound_cidrs")
     @JsonInclude(JsonInclude.Include.NON_NULL)
-    private Integer period;
+    private List<String> tokenBoundCidrs;
+
+    @JsonProperty("token_explicit_max_ttl")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenExplicitMaxTtl;
+
+    @JsonProperty("token_no_default_policy")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean tokenNoDefaultPolicy;
+
+    @JsonProperty("token_num_uses")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenNumUses;
+
+    @JsonProperty("token_period")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tokenPeriod;
+
+    @JsonProperty("token_type")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String tokenType;
 
     /**
      * Construct empty {@link AppRole} object.
@@ -83,66 +105,49 @@ public final class AppRole {
 
     }
 
-    /**
-     * Construct complete {@link AppRole} object.
-     *
-     * @param name               Role name (required)
-     * @param id                 Role ID (optional)
-     * @param bindSecretId       Bind secret ID (optional)
-     * @param secretIdBoundCidrs Whitelist of subnets in CIDR notation (optional)
-     * @param policies           List of policies (optional)
-     * @param secretIdNumUses    Maximum number of uses per secret (optional)
-     * @param secretIdTtl        Maximum TTL in seconds for secrets (optional)
-     * @param tokenTtl           Token TTL in seconds (optional)
-     * @param tokenMaxTtl        Maximum token TTL in seconds, including renewals (optional)
-     * @param period             Duration in seconds, if set the token is a periodic token (optional)
-     */
-    public AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> secretIdBoundCidrs,
-                   final List<String> policies, final Integer secretIdNumUses, final Integer secretIdTtl,
-                   final Integer tokenTtl, final Integer tokenMaxTtl, final Integer period) {
-        this.name = name;
-        this.id = id;
-        this.bindSecretId = bindSecretId;
-        this.secretIdBoundCidrs = secretIdBoundCidrs;
-        this.policies = policies;
-        this.secretIdNumUses = secretIdNumUses;
-        this.secretIdTtl = secretIdTtl;
-        this.tokenTtl = tokenTtl;
-        this.tokenMaxTtl = tokenMaxTtl;
-        this.period = period;
-    }
-
     /**
      * Construct complete {@link AppRole} object.
      * <p>
      * This constructor is used for transition from {@code bound_cidr_list} to {@code secret_id_bound_cidrs} only.
      *
-     * @param name               Role name (required)
-     * @param id                 Role ID (optional)
-     * @param bindSecretId       Bind secret ID (optional)
-     * @param boundCidrList      Whitelist of subnets in CIDR notation (optional)
-     * @param secretIdBoundCidrs Whitelist of subnets in CIDR notation (optional)
-     * @param policies           List of policies (optional)
-     * @param secretIdNumUses    Maximum number of uses per secret (optional)
-     * @param secretIdTtl        Maximum TTL in seconds for secrets (optional)
-     * @param tokenTtl           Token TTL in seconds (optional)
-     * @param tokenMaxTtl        Maximum token TTL in seconds, including renewals (optional)
-     * @param period             Duration in seconds, if set the token is a periodic token (optional)
+     * @param name                 Role name (required)
+     * @param id                   Role ID (optional)
+     * @param bindSecretId         Bind secret ID (optional)
+     * @param secretIdBoundCidrs   Whitelist of subnets in CIDR notation (optional)
+     * @param secretIdNumUses      Maximum number of uses per secret (optional)
+     * @param secretIdTtl          Maximum TTL in seconds for secrets (optional)
+     * @param enableLocalSecretIds Enable local secret IDs (optional)
+     * @param tokenTtl             Token TTL in seconds (optional)
+     * @param tokenMaxTtl          Maximum token TTL in seconds, including renewals (optional)
+     * @param tokenPolicies        List of token policies (optional)
+     * @param tokenBoundCidrs      Whitelist of subnets in CIDR notation for associated tokens (optional)
+     * @param tokenExplicitMaxTtl  Explicit maximum TTL for associated tokens (optional)
+     * @param tokenNoDefaultPolicy Enable or disable default policy for associated tokens (optional)
+     * @param tokenNumUses         Number of uses for tokens (optional)
+     * @param tokenPeriod          Duration in seconds, if set the token is a periodic token (optional)
+     * @param tokenType            Token type (optional)
      */
-    AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> boundCidrList,
-            final List<String> secretIdBoundCidrs, final List<String> policies, final Integer secretIdNumUses,
-            final Integer secretIdTtl, final Integer tokenTtl, final Integer tokenMaxTtl, final Integer period) {
+    AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> secretIdBoundCidrs,
+            final Integer secretIdNumUses, final Integer secretIdTtl, final Boolean enableLocalSecretIds,
+            final Integer tokenTtl, final Integer tokenMaxTtl, final List<String> tokenPolicies,
+            final List<String> tokenBoundCidrs, final Integer tokenExplicitMaxTtl, final Boolean tokenNoDefaultPolicy,
+            final Integer tokenNumUses, final Integer tokenPeriod, final String tokenType) {
         this.name = name;
         this.id = id;
         this.bindSecretId = bindSecretId;
-        this.boundCidrList = boundCidrList;
         this.secretIdBoundCidrs = secretIdBoundCidrs;
-        this.policies = policies;
+        this.tokenPolicies = tokenPolicies;
         this.secretIdNumUses = secretIdNumUses;
         this.secretIdTtl = secretIdTtl;
+        this.enableLocalSecretIds = enableLocalSecretIds;
         this.tokenTtl = tokenTtl;
         this.tokenMaxTtl = tokenMaxTtl;
-        this.period = period;
+        this.tokenBoundCidrs = tokenBoundCidrs;
+        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+        this.tokenNumUses = tokenNumUses;
+        this.tokenPeriod = tokenPeriod;
+        this.tokenType = tokenType;
     }
 
     /**
@@ -167,41 +172,38 @@ public final class AppRole {
     }
 
     /**
-     * @return list of bound CIDR subnets
-     * @deprecated Use {@link #getSecretIdBoundCidrs()} instead, as this parameter is deprecated in Vault.
+     * @return list of bound CIDR subnets of assiciated tokens
+     * @since 0.9
      */
-    @Deprecated
-    public List<String> getBoundCidrList() {
-        return boundCidrList;
+    public List<String> getTokenBoundCidrs() {
+        return tokenBoundCidrs;
     }
 
     /**
      * @param boundCidrList list of subnets in CIDR notation to bind role to
-     * @deprecated Use {@link #setSecretIdBoundCidrs(List)} instead, as this parameter is deprecated in Vault.
+     * @since 0.9
      */
-    @Deprecated
-    @JsonSetter("bound_cidr_list")
-    public void setBoundCidrList(final List<String> boundCidrList) {
-        this.boundCidrList = boundCidrList;
+    @JsonSetter("token_bound_cidrs")
+    public void setBoundCidrs(final List<String> boundCidrList) {
+        this.tokenBoundCidrs = boundCidrList;
     }
 
     /**
      * @return list of subnets in CIDR notation as comma-separated {@link String}
-     * @deprecated Use {@link #getSecretIdBoundCidrsString()} instead, as this parameter is deprecated in Vault.
+     * @since 0.9
      */
-    @Deprecated
-    @JsonGetter("bound_cidr_list")
+    @JsonGetter("token_bound_cidrs")
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
-    public String getBoundCidrListString() {
-        if (boundCidrList == null || boundCidrList.isEmpty()) {
+    public String getTokenBoundCidrsString() {
+        if (tokenBoundCidrs == null || tokenBoundCidrs.isEmpty()) {
             return "";
         }
-        return String.join(",", boundCidrList);
+        return String.join(",", tokenBoundCidrs);
     }
 
     /**
      * @return list of bound CIDR subnets
-     * @since 0.8 replaces {@link #getBoundCidrList()}
+     * @since 0.8 replaces {@code getBoundCidrList()}
      */
     public List<String> getSecretIdBoundCidrs() {
         return secretIdBoundCidrs;
@@ -209,7 +211,7 @@ public final class AppRole {
 
     /**
      * @param secretIdBoundCidrs List of subnets in CIDR notation to bind secrets of this role to.
-     * @since 0.8 replaces {@link #setBoundCidrList(List)}
+     * @since 0.8 replaces {@code setBoundCidrList(List)}
      */
     @JsonSetter("secret_id_bound_cidrs")
     public void setSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
@@ -218,7 +220,7 @@ public final class AppRole {
 
     /**
      * @return List of subnets in CIDR notation as comma-separated {@link String}
-     * @since 0.8 replaces {@link #getBoundCidrListString()} ()}
+     * @since 0.8 replaces {@code getBoundCidrListString()} ()}
      */
     @JsonGetter("secret_id_bound_cidrs")
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
@@ -230,30 +232,63 @@ public final class AppRole {
     }
 
     /**
-     * @return list of policies
+     * @return list of token policies
+     * @since 0.9
      */
+    public List<String> getTokenPolicies() {
+        return tokenPolicies;
+    }
+
+    /**
+     * @return list of token policies
+     * @deprecated Use {@link #getTokenPolicies()} instead.
+     */
+    @Deprecated
+    @JsonIgnore
     public List<String> getPolicies() {
-        return policies;
+        return getTokenPolicies();
+    }
+
+    /**
+     * @param tokenPolicies list of token policies
+     * @since 0.9
+     */
+    @JsonSetter("token_policies")
+    public void setTokenPolicies(final List<String> tokenPolicies) {
+        this.tokenPolicies = tokenPolicies;
     }
 
     /**
      * @param policies list of policies
+     * @deprecated Use {@link #setTokenPolicies(List)} instead.
      */
-    @JsonSetter("policies")
+    @Deprecated
+    @JsonIgnore
     public void setPolicies(final List<String> policies) {
-        this.policies = policies;
+        setTokenPolicies(policies);
     }
 
     /**
      * @return list of policies as comma-separated {@link String}
+     * @since 0.9
      */
-    @JsonGetter("policies")
+    @JsonGetter("token_policies")
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
-    public String getPoliciesString() {
-        if (policies == null || policies.isEmpty()) {
+    public String getTokenPoliciesString() {
+        if (tokenPolicies == null || tokenPolicies.isEmpty()) {
             return "";
         }
-        return String.join(",", policies);
+        return String.join(",", tokenPolicies);
+    }
+
+    /**
+     * @return list of policies as comma-separated {@link String}
+     * @deprecated Use {@link #getTokenPoliciesString()} instead.
+     */
+    @Deprecated
+    @JsonIgnore
+    public String getPoliciesString() {
+        return getTokenPoliciesString();
     }
 
     /**
@@ -270,6 +305,14 @@ public final class AppRole {
         return secretIdTtl;
     }
 
+    /**
+     * @return Enable local secret IDs?
+     * @since 0.9
+     */
+    public Boolean getEnableLocalSecretIds() {
+        return enableLocalSecretIds;
+    }
+
     /**
      * @return token TTL in seconds
      */
@@ -285,9 +328,52 @@ public final class AppRole {
     }
 
     /**
-     * @return duration in seconds, if specified
+     * @return explicit maximum token TTL in seconds, including renewals
+     * @since 0.9
      */
+    public Integer getTokenExplicitMaxTtl() {
+        return tokenExplicitMaxTtl;
+    }
+
+    /**
+     * @return enable default policy for token?
+     * @since 0.9
+     */
+    public Boolean getTokenNoDefaultPolicy() {
+        return tokenNoDefaultPolicy;
+    }
+
+    /**
+     * @return number of uses for token
+     * @since 0.9
+     */
+    public Integer getTokenNumUses() {
+        return tokenNumUses;
+    }
+
+    /**
+     * @return duration in seconds, if specified
+     * @since 0.9
+     */
+    public Integer getTokenPeriod() {
+        return tokenPeriod;
+    }
+
+    /**
+     * @return duration in seconds, if specified
+     * @deprecated Use {@link #getTokenPeriod()} instead.
+     */
+    @Deprecated
+    @JsonIgnore
     public Integer getPeriod() {
-        return period;
+        return getTokenPeriod();
+    }
+
+    /**
+     * @return duration in seconds, if specified
+     * @since 0.9
+     */
+    public String getTokenType() {
+        return tokenType;
     }
 }
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
index 15a5674..58859ca 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
@@ -29,14 +29,19 @@ public final class AppRoleBuilder {
     private String name;
     private String id;
     private Boolean bindSecretId;
-    private List<String> boundCidrList;
     private List<String> secretIdBoundCidrs;
-    private List<String> policies;
+    private List<String> tokenPolicies;
     private Integer secretIdNumUses;
     private Integer secretIdTtl;
+    private Boolean enableLocalSecretIds;
     private Integer tokenTtl;
     private Integer tokenMaxTtl;
-    private Integer period;
+    private List<String> tokenBoundCidrs;
+    private Integer tokenExplicitMaxTtl;
+    private Boolean tokenNoDefaultPolicy;
+    private Integer tokenNumUses;
+    private Integer tokenPeriod;
+    private Token.Type tokenType;
 
     /**
      * Construct {@link AppRoleBuilder} with only the role name set.
@@ -89,47 +94,48 @@ public final class AppRoleBuilder {
         return withBindSecretID(false);
     }
 
-    /**
-     * Set bound CIDR blocks.
-     *
-     * @param boundCidrList List of CIDR blocks which can perform login
-     * @return self
-     * @deprecated Use {@link #withSecretIdBoundCidrs(List)} instead, as this parameter is deprecated in Vault.
-     */
-    @Deprecated
-    public AppRoleBuilder withBoundCidrList(final List<String> boundCidrList) {
-        this.boundCidrList = boundCidrList;
-        return this;
-    }
-
     /**
      * Set bound CIDR blocks.
      *
      * @param secretIdBoundCidrs List of CIDR blocks which can perform login
      * @return self
-     * @since 0.8 replaces {@link #withBoundCidrList(List)}
+     * @since 0.8 replaces {@code withBoundCidrList(List)}
      */
     public AppRoleBuilder withSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
-        this.secretIdBoundCidrs = secretIdBoundCidrs;
+        if (this.secretIdBoundCidrs == null) {
+            this.secretIdBoundCidrs = new ArrayList<>();
+        }
+        this.secretIdBoundCidrs.addAll(secretIdBoundCidrs);
         return this;
     }
 
     /**
-     * Add a CIDR block to list of bound blocks.
+     * Add a CIDR block to list of bound blocks for secret.
      *
-     * @param cidrBlock the CIDR block
+     * @param secretBoundCidr the CIDR block
      * @return self
+     * @since 0.9
      */
-    public AppRoleBuilder withCidrBlock(final String cidrBlock) {
-        if (boundCidrList == null) {
-            boundCidrList = new ArrayList<>();
-        }
-        boundCidrList.add(cidrBlock);
-
+    public AppRoleBuilder withSecretBoundCidr(final String secretBoundCidr) {
         if (secretIdBoundCidrs == null) {
             secretIdBoundCidrs = new ArrayList<>();
         }
-        secretIdBoundCidrs.add(cidrBlock);
+        secretIdBoundCidrs.add(secretBoundCidr);
+        return this;
+    }
+
+    /**
+     * Add given policies.
+     *
+     * @param tokenPolicies the token policies
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenPolicies(final List<String> tokenPolicies) {
+        if (this.tokenPolicies == null) {
+            this.tokenPolicies = new ArrayList<>();
+        }
+        this.tokenPolicies.addAll(tokenPolicies);
         return this;
     }
 
@@ -138,12 +144,25 @@ public final class AppRoleBuilder {
      *
      * @param policies the policies
      * @return self
+     * @deprecated Use {@link #withTokenPolicies(List)} instead.
      */
+    @Deprecated
     public AppRoleBuilder withPolicies(final List<String> policies) {
-        if (this.policies == null) {
-            this.policies = new ArrayList<>();
+        return withTokenPolicies(policies);
+    }
+
+    /**
+     * Add a single policy.
+     *
+     * @param tokenPolicy the token policy
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenPolicy(final String tokenPolicy) {
+        if (this.tokenPolicies == null) {
+            this.tokenPolicies = new ArrayList<>();
         }
-        this.policies.addAll(policies);
+        tokenPolicies.add(tokenPolicy);
         return this;
     }
 
@@ -152,13 +171,11 @@ public final class AppRoleBuilder {
      *
      * @param policy the policy
      * @return self
+     * @deprecated Use {@link #withTokenPolicy(String)} instead.
      */
+    @Deprecated
     public AppRoleBuilder withPolicy(final String policy) {
-        if (this.policies == null) {
-            this.policies = new ArrayList<>();
-        }
-        policies.add(policy);
-        return this;
+        return withTokenPolicy(policy);
     }
 
     /**
@@ -183,6 +200,18 @@ public final class AppRoleBuilder {
         return this;
     }
 
+    /**
+     * Enable or disable local secret IDs.
+     *
+     * @param enableLocalSecretIds Enable local secret IDs?
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withEnableLocalSecretIds(final Boolean enableLocalSecretIds) {
+        this.enableLocalSecretIds = enableLocalSecretIds;
+        return this;
+    }
+
     /**
      * Set default token TTL in seconds.
      *
@@ -205,17 +234,106 @@ public final class AppRoleBuilder {
         return this;
     }
 
+    /**
+     * Set bound CIDR blocks for associated tokens.
+     *
+     * @param tokenBoundCidrs List of CIDR blocks which can perform login
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
+        if (this.tokenBoundCidrs == null) {
+            this.tokenBoundCidrs = new ArrayList<>();
+        }
+        this.tokenBoundCidrs.addAll(tokenBoundCidrs);
+        return this;
+    }
+
+    /**
+     * Add a CIDR block to list of bound blocks for token.
+     *
+     * @param tokenBoundCidr the CIDR block
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenBoundCidr(final String tokenBoundCidr) {
+        if (tokenBoundCidrs == null) {
+            tokenBoundCidrs = new ArrayList<>();
+        }
+        tokenBoundCidrs.add(tokenBoundCidr);
+        return this;
+    }
+
+    /**
+     * Set explicit maximum token TTL in seconds.
+     *
+     * @param tokenExplicitMaxTtl the TTL
+     * @return self
+     */
+    public AppRoleBuilder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
+        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+        return this;
+    }
+
+    /**
+     * Enable or disable default policy for generated token.
+     *
+     * @param tokenNoDefaultPolicy Enable default policy for token?
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
+        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+        return this;
+    }
+
+    /**
+     * Set number of uses for generated tokens.
+     *
+     * @param tokenNumUses number of uses for tokens
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenNumUses(final Integer tokenNumUses) {
+        this.tokenNumUses = tokenNumUses;
+        return this;
+    }
+
+    /**
+     * Set renewal period for generated token in seconds.
+     *
+     * @param tokenPeriod period in seconds
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder wit0hTokenPeriod(final Integer tokenPeriod) {
+        this.tokenPeriod = tokenPeriod;
+        return this;
+    }
+
     /**
      * Set renewal period for generated token in seconds.
      *
      * @param period period in seconds
      * @return self
+     * @deprecated Use {@link #wit0hTokenPeriod(Integer)} instead.
      */
+    @Deprecated
     public AppRoleBuilder withPeriod(final Integer period) {
-        this.period = period;
-        return this;
+        return wit0hTokenPeriod(period);
     }
 
+    /**
+     * Set type of generated token.
+     *
+     * @param tokenType token type
+     * @return self
+     * @since 0.9
+     */
+    public AppRoleBuilder withTokenType(final Token.Type tokenType) {
+        this.tokenType = tokenType;
+        return this;
+    }
 
     /**
      * Build the AppRole role based on given parameters.
@@ -223,16 +341,23 @@ public final class AppRoleBuilder {
      * @return the role
      */
     public AppRole build() {
-        return new AppRole(name,
+        return new AppRole(
+                name,
                 id,
                 bindSecretId,
-                boundCidrList,
                 secretIdBoundCidrs,
-                policies,
                 secretIdNumUses,
                 secretIdTtl,
+                enableLocalSecretIds,
                 tokenTtl,
                 tokenMaxTtl,
-                period);
+                tokenPolicies,
+                tokenBoundCidrs,
+                tokenExplicitMaxTtl,
+                tokenNoDefaultPolicy,
+                tokenNumUses,
+                tokenPeriod,
+                tokenType != null ? tokenType.value() : null
+        );
     }
 }
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 7e69f1c..08dbb99 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -881,6 +881,28 @@ public class HTTPVaultConnectorTest {
                 fail("Role ID lookup failed.");
             }
 
+            /* Update role model with custom flags */
+            role = AppRole.builder(roleName)
+                    .wit0hTokenPeriod(321)
+                    .build();
+
+            /* Create role */
+            try {
+                boolean res = connector.createAppRole(role);
+                assertThat("No result given.", res, is(notNullValue()));
+            } catch (VaultConnectorException e) {
+                fail("Role creation failed.");
+            }
+
+            /* Lookup updated role */
+            try {
+                AppRoleResponse res = connector.lookupAppRole(roleName);
+                assertThat("Role lookup returned no role.", res.getRole(), is(notNullValue()));
+                assertThat("Token period not set for role.", res.getRole().getTokenPeriod(), is(321));
+            } catch (VaultConnectorException e) {
+                fail("Role lookup failed.");
+            }
+
             /* Create role by name */
             roleName = "RoleByName";
             try {
diff --git a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
index 8ef0229..690ad2e 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
@@ -34,8 +34,6 @@ import static org.hamcrest.Matchers.*;
  * @since 0.4.0
  */
 public class AppRoleBuilderTest {
-
-
     private static final String NAME = "TestRole";
     private static final String ID = "test-id";
     private static final Boolean BIND_SECRET_ID = true;
@@ -47,12 +45,17 @@ public class AppRoleBuilderTest {
     private static final String POLICY_2 = "policy2";
     private static final Integer SECRET_ID_NUM_USES = 10;
     private static final Integer SECRET_ID_TTL = 7200;
+    private static final Boolean ENABLE_LOCAL_SECRET_IDS = false;
     private static final Integer TOKEN_TTL = 4800;
     private static final Integer TOKEN_MAX_TTL = 9600;
-    private static final Integer PERIOD = 1234;
+    private static final Integer TOKEN_EXPLICIT_MAX_TTL = 14400;
+    private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
+    private static final Integer TOKEN_NUM_USES = 42;
+    private static final Integer TOKEN_PERIOD = 1234;
+    private static final Token.Type TOKEN_TYPE = Token.Type.DEFAULT_SERVICE;
     private static final String JSON_MIN = "{\"role_name\":\"" + NAME + "\"}";
-    private static final String JSON_FULL = String.format("{\"role_name\":\"%s\",\"role_id\":\"%s\",\"bind_secret_id\":%s,\"bound_cidr_list\":\"%s\",\"secret_id_bound_cidrs\":\"%s\",\"policies\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"token_ttl\":%d,\"token_max_ttl\":%d,\"period\":%d}",
-            NAME, ID, BIND_SECRET_ID, CIDR_1, CIDR_1, POLICY, SECRET_ID_NUM_USES, SECRET_ID_TTL, TOKEN_TTL, TOKEN_MAX_TTL, PERIOD);
+    private static final String JSON_FULL = String.format("{\"role_name\":\"%s\",\"role_id\":\"%s\",\"bind_secret_id\":%s,\"secret_id_bound_cidrs\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"enable_local_secret_ids\":%s,\"token_ttl\":%d,\"token_max_ttl\":%d,\"token_policies\":\"%s\",\"token_bound_cidrs\":\"%s\",\"token_explicit_max_ttl\":%d,\"token_no_default_policy\":%s,\"token_num_uses\":%d,\"token_period\":%d,\"token_type\":\"%s\"}",
+            NAME, ID, BIND_SECRET_ID, CIDR_1, SECRET_ID_NUM_USES, SECRET_ID_TTL, ENABLE_LOCAL_SECRET_IDS, TOKEN_TTL, TOKEN_MAX_TTL, POLICY, CIDR_1, TOKEN_EXPLICIT_MAX_TTL, TOKEN_NO_DEFAULT_POLICY, TOKEN_NUM_USES, TOKEN_PERIOD, TOKEN_TYPE.value());
 
     @BeforeAll
     public static void init() {
@@ -68,14 +71,21 @@ public class AppRoleBuilderTest {
         AppRole role = new AppRoleBuilder(NAME).build();
         assertThat(role.getId(), is(nullValue()));
         assertThat(role.getBindSecretId(), is(nullValue()));
-        assertThat(role.getBoundCidrList(), is(nullValue()));
         assertThat(role.getSecretIdBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenPolicies(), is(nullValue()));
         assertThat(role.getPolicies(), is(nullValue()));
         assertThat(role.getSecretIdNumUses(), is(nullValue()));
         assertThat(role.getSecretIdTtl(), is(nullValue()));
+        assertThat(role.getEnableLocalSecretIds(), is(nullValue()));
         assertThat(role.getTokenTtl(), is(nullValue()));
         assertThat(role.getTokenMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenExplicitMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenNoDefaultPolicy(), is(nullValue()));
+        assertThat(role.getTokenNumUses(), is(nullValue()));
+        assertThat(role.getTokenPeriod(), is(nullValue()));
         assertThat(role.getPeriod(), is(nullValue()));
+        assertThat(role.getTokenType(), is(nullValue()));
 
         /* optional fields should be ignored, so JSON string should only contain role_name */
         assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_MIN));
@@ -89,26 +99,38 @@ public class AppRoleBuilderTest {
         AppRole role = new AppRoleBuilder(NAME)
                 .withId(ID)
                 .withBindSecretID(BIND_SECRET_ID)
-                .withBoundCidrList(BOUND_CIDR_LIST)
                 .withSecretIdBoundCidrs(BOUND_CIDR_LIST)
-                .withPolicies(POLICIES)
+                .withTokenPolicies(POLICIES)
                 .withSecretIdNumUses(SECRET_ID_NUM_USES)
                 .withSecretIdTtl(SECRET_ID_TTL)
+                .withEnableLocalSecretIds(ENABLE_LOCAL_SECRET_IDS)
                 .withTokenTtl(TOKEN_TTL)
                 .withTokenMaxTtl(TOKEN_MAX_TTL)
-                .withPeriod(PERIOD)
+                .withTokenBoundCidrs(BOUND_CIDR_LIST)
+                .withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
+                .withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
+                .withTokenNumUses(TOKEN_NUM_USES)
+                .wit0hTokenPeriod(TOKEN_PERIOD)
+                .withTokenType(TOKEN_TYPE)
                 .build();
         assertThat(role.getName(), is(NAME));
         assertThat(role.getId(), is(ID));
         assertThat(role.getBindSecretId(), is(BIND_SECRET_ID));
-        assertThat(role.getBoundCidrList(), is(BOUND_CIDR_LIST));
         assertThat(role.getSecretIdBoundCidrs(), is(BOUND_CIDR_LIST));
-        assertThat(role.getPolicies(), is(POLICIES));
+        assertThat(role.getTokenPolicies(), is(POLICIES));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
         assertThat(role.getSecretIdNumUses(), is(SECRET_ID_NUM_USES));
         assertThat(role.getSecretIdTtl(), is(SECRET_ID_TTL));
+        assertThat(role.getEnableLocalSecretIds(), is(ENABLE_LOCAL_SECRET_IDS));
         assertThat(role.getTokenTtl(), is(TOKEN_TTL));
         assertThat(role.getTokenMaxTtl(), is(TOKEN_MAX_TTL));
-        assertThat(role.getPeriod(), is(PERIOD));
+        assertThat(role.getTokenBoundCidrs(), is(BOUND_CIDR_LIST));
+        assertThat(role.getTokenExplicitMaxTtl(), is(TOKEN_EXPLICIT_MAX_TTL));
+        assertThat(role.getTokenNoDefaultPolicy(), is(TOKEN_NO_DEFAULT_POLICY));
+        assertThat(role.getTokenNumUses(), is(TOKEN_NUM_USES));
+        assertThat(role.getTokenPeriod(), is(TOKEN_PERIOD));
+        assertThat(role.getPeriod(), is(TOKEN_PERIOD));
+        assertThat(role.getTokenType(), is(TOKEN_TYPE.value()));
 
         /* Verify that all parameters are included in JSON string */
         assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_FULL));
@@ -128,29 +150,33 @@ public class AppRoleBuilderTest {
         assertThat(role.getBindSecretId(), is(false));
 
         /* Add single CIDR subnet */
-        role = new AppRoleBuilder(NAME).withCidrBlock(CIDR_2).build();
-        assertThat(role.getBoundCidrList(), hasSize(1));
-        assertThat(role.getBoundCidrList(), contains(CIDR_2));
+        role = new AppRoleBuilder(NAME).withSecretBoundCidr(CIDR_2).withTokenBoundCidr(CIDR_2).build();
         assertThat(role.getSecretIdBoundCidrs(), hasSize(1));
         assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_2));
+        assertThat(role.getTokenBoundCidrs(), hasSize(1));
+        assertThat(role.getTokenBoundCidrs(), contains(CIDR_2));
         role = new AppRoleBuilder(NAME)
                 .withSecretIdBoundCidrs(BOUND_CIDR_LIST)
-                .withCidrBlock(CIDR_2)
+                .withSecretBoundCidr(CIDR_2)
+                .withTokenBoundCidrs(BOUND_CIDR_LIST)
+                .withTokenBoundCidr(CIDR_2)
                 .build();
-        assertThat(role.getBoundCidrList(), hasSize(1));
-        assertThat(role.getBoundCidrList(), contains(CIDR_2));
         assertThat(role.getSecretIdBoundCidrs(), hasSize(2));
         assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_1, CIDR_2));
+        assertThat(role.getTokenBoundCidrs(), hasSize(2));
+        assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_1, CIDR_2));
 
         /* Add single policy */
-        role = new AppRoleBuilder(NAME).withPolicy(POLICY_2).build();
-        assertThat(role.getPolicies(), hasSize(1));
-        assertThat(role.getPolicies(), contains(POLICY_2));
+        role = new AppRoleBuilder(NAME).withTokenPolicy(POLICY_2).build();
+        assertThat(role.getTokenPolicies(), hasSize(1));
+        assertThat(role.getTokenPolicies(), contains(POLICY_2));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
         role = new AppRoleBuilder(NAME)
-                .withPolicies(POLICIES)
-                .withPolicy(POLICY_2)
+                .withTokenPolicies(POLICIES)
+                .withTokenPolicy(POLICY_2)
                 .build();
-        assertThat(role.getPolicies(), hasSize(2));
-        assertThat(role.getPolicies(), contains(POLICY, POLICY_2));
+        assertThat(role.getTokenPolicies(), hasSize(2));
+        assertThat(role.getTokenPolicies(), contains(POLICY, POLICY_2));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
     }
 }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
index dfb91b7..e428f2b 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/AppRoleResponseTest.java
@@ -53,10 +53,10 @@ public class AppRoleResponseTest {
             "    \"token_max_ttl\": " + ROLE_TOKEN_MAX_TTL + ",\n" +
             "    \"secret_id_ttl\": " + ROLE_SECRET_TTL + ",\n" +
             "    \"secret_id_num_uses\": " + ROLE_SECRET_NUM_USES + ",\n" +
-            "    \"policies\": [\n" +
+            "    \"token_policies\": [\n" +
             "      \"" + ROLE_POLICY + "\"\n" +
             "    ],\n" +
-            "    \"period\": " + ROLE_PERIOD + ",\n" +
+            "    \"token_period\": " + ROLE_PERIOD + ",\n" +
             "    \"bind_secret_id\": " + ROLE_BIND_SECRET + ",\n" +
             "    \"bound_cidr_list\": \"\"\n" +
             "  },\n" +
@@ -68,7 +68,7 @@ public class AppRoleResponseTest {
     private static final Map<String, Object> INVALID_DATA = new HashMap<>();
 
     static {
-        INVALID_DATA.put("policies", "fancy-policy");
+        INVALID_DATA.put("token_policies", "fancy-policy");
     }
 
     /**
@@ -104,12 +104,15 @@ public class AppRoleResponseTest {
             assertThat("Incorrect token max TTL", role.getTokenMaxTtl(), is(ROLE_TOKEN_MAX_TTL));
             assertThat("Incorrect secret ID TTL", role.getSecretIdTtl(), is(ROLE_SECRET_TTL));
             assertThat("Incorrect secret ID umber of uses", role.getSecretIdNumUses(), is(ROLE_SECRET_NUM_USES));
+            assertThat("Incorrect number of policies", role.getTokenPolicies(), hasSize(1));
+            assertThat("Incorrect role policies", role.getTokenPolicies(), contains(ROLE_POLICY));
             assertThat("Incorrect number of policies", role.getPolicies(), hasSize(1));
             assertThat("Incorrect role policies", role.getPolicies(), contains(ROLE_POLICY));
+            assertThat("Incorrect role period", role.getTokenPeriod(), is(ROLE_PERIOD));
             assertThat("Incorrect role period", role.getPeriod(), is(ROLE_PERIOD));
             assertThat("Incorrect role bind secret ID flag", role.getBindSecretId(), is(ROLE_BIND_SECRET));
-            assertThat("Incorrect biund CIDR list", role.getBoundCidrList(), is(nullValue()));
-            assertThat("Incorrect biund CIDR list string", role.getBoundCidrListString(), is(emptyString()));
+            assertThat("Incorrect bound CIDR list", role.getTokenBoundCidrs(), is(nullValue()));
+            assertThat("Incorrect bound CIDR list string", role.getTokenBoundCidrsString(), is(emptyString()));
         } catch (IOException e) {
             fail("AuthResponse deserialization failed: " + e.getMessage());
         }

From e0cbe34881f3c8be13146266724236f184f66548 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 15 Apr 2020 16:29:42 +0200
Subject: [PATCH 14/21] minor JavaDoc correction

[skip ci]
---
 src/main/java/de/stklcode/jvault/connector/model/Token.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index 7dec7e4..083464b 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -112,6 +112,7 @@ public final class Token {
      * Construct complete {@link Token} object.
      *
      * @param id              Token ID (optional)
+     * @param type            Token type (optional)
      * @param displayName     Token display name (optional)
      * @param noParent        Token has no parent (optional)
      * @param noDefaultPolicy Do not add default policy (optional)

From fa7036921a00b2bb45b9a119fc303e0399456545 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 15 Apr 2020 17:13:50 +0200
Subject: [PATCH 15/21] move builders into model classes and deprecate
 constructors

Enforces use of builder pattern in future releases. Builder API is
unchanged despite the class itself.
---
 CHANGELOG.md                                  |   2 +
 .../jvault/connector/VaultConnector.java      |   2 +-
 .../jvault/connector/model/AppRole.java       | 373 +++++++++++++++++-
 .../connector/model/AppRoleBuilder.java       |   2 +
 .../jvault/connector/model/Token.java         | 284 ++++++++++++-
 .../jvault/connector/model/TokenBuilder.java  |   2 +
 .../jvault/connector/model/TokenRole.java     | 323 ++++++++++++---
 .../connector/model/TokenRoleBuilder.java     | 292 --------------
 .../connector/model/AppRoleBuilderTest.java   | 117 ++++++
 .../connector/model/TokenBuilderTest.java     | 101 +++++
 .../connector/model/TokenRoleBuilderTest.java |   4 +-
 11 files changed, 1150 insertions(+), 352 deletions(-)
 delete mode 100644 src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7152a1f..f9d280f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@
 ### Deprecations
 * `AppRole#getPolicies()` and `#setPolicies()` are deprecated in favor of `#getTokenPolicies()` and `#setTokenPolicies()`
 * `AppRole#getPeriod()` is deprecated in favor of `#getTokenPeriod()`
+* `AppRoleBuilder` and `TokenBuilder` in favor of `AppRole.Builder` and `Token.Builder`
+* All-arg constructors of `AppRole` and `Token` in favor of `.builder()....build()` introduced in 0.8
 
 ### Removals
 * Deprecated methods `AppRole#getBoundCidrList()`, `#setBoundCidrList()` and `getBoundCidrListString()` have been removed.
diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
index 0b0adb9..c3cfd5d 100644
--- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
@@ -226,7 +226,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      */
     default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
             throws VaultConnectorException {
-        return createAppRole(new AppRoleBuilder(roleName).withTokenPolicies(policies).withId(roleID).build());
+        return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
     }
 
     /**
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
index 8dbb1a6..d65c12b 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
@@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.model;
 
 import com.fasterxml.jackson.annotation.*;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -29,14 +30,14 @@ import java.util.List;
 @JsonIgnoreProperties(ignoreUnknown = true)
 public final class AppRole {
     /**
-     * Get {@link AppRoleBuilder} instance.
+     * Get {@link Builder} instance.
      *
      * @param name Role name.
      * @return AppRole Builder.
      * @since 0.8
      */
-    public static AppRoleBuilder builder(final String name) {
-        return new AppRoleBuilder(name);
+    public static Builder builder(final String name) {
+        return new Builder(name);
     }
 
     @JsonProperty("role_name")
@@ -102,7 +103,6 @@ public final class AppRole {
      * Construct empty {@link AppRole} object.
      */
     public AppRole() {
-
     }
 
     /**
@@ -126,7 +126,9 @@ public final class AppRole {
      * @param tokenNumUses         Number of uses for tokens (optional)
      * @param tokenPeriod          Duration in seconds, if set the token is a periodic token (optional)
      * @param tokenType            Token type (optional)
+     * @deprecated As of 0.9 in favor of {@link #builder(String)}. Will be removed with next major release.
      */
+    @Deprecated
     AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> secretIdBoundCidrs,
             final Integer secretIdNumUses, final Integer secretIdTtl, final Boolean enableLocalSecretIds,
             final Integer tokenTtl, final Integer tokenMaxTtl, final List<String> tokenPolicies,
@@ -150,6 +152,30 @@ public final class AppRole {
         this.tokenType = tokenType;
     }
 
+    /**
+     * Construct {@link AppRole} object from {@link AppRole.Builder}.
+     *
+     * @param builder AppRole builder.
+     */
+    public AppRole(final Builder builder) {
+        this.name = builder.name;
+        this.id = builder.id;
+        this.bindSecretId = builder.bindSecretId;
+        this.secretIdBoundCidrs = builder.secretIdBoundCidrs;
+        this.secretIdNumUses = builder.secretIdNumUses;
+        this.secretIdTtl = builder.secretIdTtl;
+        this.enableLocalSecretIds = builder.enableLocalSecretIds;
+        this.tokenTtl = builder.tokenTtl;
+        this.tokenMaxTtl = builder.tokenMaxTtl;
+        this.tokenPolicies = builder.tokenPolicies;
+        this.tokenBoundCidrs = builder.tokenBoundCidrs;
+        this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
+        this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
+        this.tokenNumUses = builder.tokenNumUses;
+        this.tokenPeriod = builder.tokenPeriod;
+        this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
+    }
+
     /**
      * @return the role name
      */
@@ -376,4 +402,343 @@ public final class AppRole {
     public String getTokenType() {
         return tokenType;
     }
+
+
+    /**
+     * A builder for vault AppRole roles..
+     *
+     * @author Stefan Kalscheuer
+     * @since 0.4.0
+     * @since 0.9 Moved into subclass of {@link AppRole}.
+     */
+    public static final class Builder {
+        private String name;
+        private String id;
+        private Boolean bindSecretId;
+        private List<String> secretIdBoundCidrs;
+        private List<String> tokenPolicies;
+        private Integer secretIdNumUses;
+        private Integer secretIdTtl;
+        private Boolean enableLocalSecretIds;
+        private Integer tokenTtl;
+        private Integer tokenMaxTtl;
+        private List<String> tokenBoundCidrs;
+        private Integer tokenExplicitMaxTtl;
+        private Boolean tokenNoDefaultPolicy;
+        private Integer tokenNumUses;
+        private Integer tokenPeriod;
+        private Token.Type tokenType;
+
+        /**
+         * Construct {@link Builder} with only the role name set.
+         *
+         * @param name Role name
+         */
+        public Builder(final String name) {
+            this.name = name;
+        }
+
+        /**
+         * Add role name.
+         *
+         * @param name Role name
+         * @return self
+         */
+        public Builder withName(final String name) {
+            this.name = name;
+            return this;
+        }
+
+        /**
+         * Add custom role ID. (optional)
+         *
+         * @param id the ID
+         * @return self
+         */
+        public Builder withId(final String id) {
+            this.id = id;
+            return this;
+        }
+
+        /**
+         * Set if role is bound to secret ID.
+         *
+         * @param bindSecretId the display name
+         * @return self
+         */
+        public Builder withBindSecretID(final Boolean bindSecretId) {
+            this.bindSecretId = bindSecretId;
+            return this;
+        }
+
+        /**
+         * Bind role to secret ID.
+         * Convenience method for {@link #withBindSecretID(Boolean)}
+         *
+         * @return self
+         */
+        public Builder withBindSecretID() {
+            return withBindSecretID(true);
+        }
+
+        /**
+         * Do not bind role to secret ID.
+         * Convenience method for {@link #withBindSecretID(Boolean)}
+         *
+         * @return self
+         */
+        public Builder withoutBindSecretID() {
+            return withBindSecretID(false);
+        }
+
+        /**
+         * Set bound CIDR blocks.
+         *
+         * @param secretIdBoundCidrs List of CIDR blocks which can perform login
+         * @return self
+         * @since 0.8 replaces {@code withBoundCidrList(List)}
+         */
+        public Builder withSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
+            if (this.secretIdBoundCidrs == null) {
+                this.secretIdBoundCidrs = new ArrayList<>();
+            }
+            this.secretIdBoundCidrs.addAll(secretIdBoundCidrs);
+            return this;
+        }
+
+        /**
+         * Add a CIDR block to list of bound blocks for secret.
+         *
+         * @param secretBoundCidr the CIDR block
+         * @return self
+         * @since 0.9
+         */
+        public Builder withSecretBoundCidr(final String secretBoundCidr) {
+            if (secretIdBoundCidrs == null) {
+                secretIdBoundCidrs = new ArrayList<>();
+            }
+            secretIdBoundCidrs.add(secretBoundCidr);
+            return this;
+        }
+
+        /**
+         * Add given policies.
+         *
+         * @param tokenPolicies the token policies
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenPolicies(final List<String> tokenPolicies) {
+            if (this.tokenPolicies == null) {
+                this.tokenPolicies = new ArrayList<>();
+            }
+            this.tokenPolicies.addAll(tokenPolicies);
+            return this;
+        }
+
+        /**
+         * Add given policies.
+         *
+         * @param policies the policies
+         * @return self
+         * @deprecated Use {@link #withTokenPolicies(List)} instead.
+         */
+        @Deprecated
+        public Builder withPolicies(final List<String> policies) {
+            return withTokenPolicies(policies);
+        }
+
+        /**
+         * Add a single policy.
+         *
+         * @param tokenPolicy the token policy
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenPolicy(final String tokenPolicy) {
+            if (this.tokenPolicies == null) {
+                this.tokenPolicies = new ArrayList<>();
+            }
+            tokenPolicies.add(tokenPolicy);
+            return this;
+        }
+
+        /**
+         * Add a single policy.
+         *
+         * @param policy the policy
+         * @return self
+         * @deprecated Use {@link #withTokenPolicy(String)} instead.
+         */
+        @Deprecated
+        public Builder withPolicy(final String policy) {
+            return withTokenPolicy(policy);
+        }
+
+        /**
+         * Set number of uses for sectet IDs.
+         *
+         * @param secredIdNumUses the number of uses
+         * @return self
+         */
+        public Builder withSecretIdNumUses(final Integer secredIdNumUses) {
+            this.secretIdNumUses = secredIdNumUses;
+            return this;
+        }
+
+        /**
+         * Set default sectet ID TTL in seconds.
+         *
+         * @param secredIdTtl the TTL
+         * @return self
+         */
+        public Builder withSecretIdTtl(final Integer secredIdTtl) {
+            this.secretIdTtl = secredIdTtl;
+            return this;
+        }
+
+        /**
+         * Enable or disable local secret IDs.
+         *
+         * @param enableLocalSecretIds Enable local secret IDs?
+         * @return self
+         * @since 0.9
+         */
+        public Builder withEnableLocalSecretIds(final Boolean enableLocalSecretIds) {
+            this.enableLocalSecretIds = enableLocalSecretIds;
+            return this;
+        }
+
+        /**
+         * Set default token TTL in seconds.
+         *
+         * @param tokenTtl the TTL
+         * @return self
+         */
+        public Builder withTokenTtl(final Integer tokenTtl) {
+            this.tokenTtl = tokenTtl;
+            return this;
+        }
+
+        /**
+         * Set maximum token TTL in seconds.
+         *
+         * @param tokenMaxTtl the TTL
+         * @return self
+         */
+        public Builder withTokenMaxTtl(final Integer tokenMaxTtl) {
+            this.tokenMaxTtl = tokenMaxTtl;
+            return this;
+        }
+
+        /**
+         * Set bound CIDR blocks for associated tokens.
+         *
+         * @param tokenBoundCidrs List of CIDR blocks which can perform login
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
+            if (this.tokenBoundCidrs == null) {
+                this.tokenBoundCidrs = new ArrayList<>();
+            }
+            this.tokenBoundCidrs.addAll(tokenBoundCidrs);
+            return this;
+        }
+
+        /**
+         * Add a CIDR block to list of bound blocks for token.
+         *
+         * @param tokenBoundCidr the CIDR block
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenBoundCidr(final String tokenBoundCidr) {
+            if (tokenBoundCidrs == null) {
+                tokenBoundCidrs = new ArrayList<>();
+            }
+            tokenBoundCidrs.add(tokenBoundCidr);
+            return this;
+        }
+
+        /**
+         * Set explicit maximum token TTL in seconds.
+         *
+         * @param tokenExplicitMaxTtl the TTL
+         * @return self
+         */
+        public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
+            this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+            return this;
+        }
+
+        /**
+         * Enable or disable default policy for generated token.
+         *
+         * @param tokenNoDefaultPolicy Enable default policy for token?
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
+            this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+            return this;
+        }
+
+        /**
+         * Set number of uses for generated tokens.
+         *
+         * @param tokenNumUses number of uses for tokens
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenNumUses(final Integer tokenNumUses) {
+            this.tokenNumUses = tokenNumUses;
+            return this;
+        }
+
+        /**
+         * Set renewal period for generated token in seconds.
+         *
+         * @param tokenPeriod period in seconds
+         * @return self
+         * @since 0.9
+         */
+        public Builder wit0hTokenPeriod(final Integer tokenPeriod) {
+            this.tokenPeriod = tokenPeriod;
+            return this;
+        }
+
+        /**
+         * Set renewal period for generated token in seconds.
+         *
+         * @param period period in seconds
+         * @return self
+         * @deprecated Use {@link #wit0hTokenPeriod(Integer)} instead.
+         */
+        @Deprecated
+        public Builder withPeriod(final Integer period) {
+            return wit0hTokenPeriod(period);
+        }
+
+        /**
+         * Set type of generated token.
+         *
+         * @param tokenType token type
+         * @return self
+         * @since 0.9
+         */
+        public Builder withTokenType(final Token.Type tokenType) {
+            this.tokenType = tokenType;
+            return this;
+        }
+
+        /**
+         * Build the AppRole role based on given parameters.
+         *
+         * @return the role
+         */
+        public AppRole build() {
+            return new AppRole(this);
+        }
+    }
 }
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
index 58859ca..9fd0e3d 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
@@ -24,7 +24,9 @@ import java.util.List;
  *
  * @author Stefan Kalscheuer
  * @since 0.4.0
+ * @deprecated As of 0.9 in favor of {@link AppRole.Builder}.
  */
+@Deprecated
 public final class AppRoleBuilder {
     private String name;
     private String id;
diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index 083464b..de9995c 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -20,8 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * Vault Token metamodel.
@@ -32,13 +31,13 @@ import java.util.Map;
 @JsonIgnoreProperties(ignoreUnknown = true)
 public final class Token {
     /**
-     * Get {@link TokenBuilder} instance.
+     * Get {@link Builder} instance.
      *
      * @return Token Builder.
      * @since 0.8
      */
-    public static TokenBuilder builder() {
-        return new TokenBuilder();
+    public static Builder builder() {
+        return new Builder();
     }
 
     @JsonProperty("id")
@@ -81,6 +80,12 @@ public final class Token {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Boolean renewable;
 
+    /**
+     * Construct empty {@link Token} object.
+     */
+    public Token() {
+    }
+
     /**
      * Construct complete {@link Token} object with default type.
      *
@@ -93,7 +98,7 @@ public final class Token {
      * @param policies        List of policies (optional)
      * @param meta            Metadata (optional)
      * @param renewable       Is the token renewable (optional)
-     * @deprecated As of 0.9, use {@link #Token(String, String, String, Boolean, Boolean, Integer, Integer, List, Map, Boolean)} instead.
+     * @deprecated As of 0.9 in favor of {@link #builder()}. Will be removed with next major release.
      */
     @Deprecated
     public Token(final String id,
@@ -121,7 +126,9 @@ public final class Token {
      * @param policies        List of policies (optional)
      * @param meta            Metadata (optional)
      * @param renewable       Is the token renewable (optional)
+     * @deprecated As of 0.9 in favor of {@link #builder()}. Will be removed with next major release.
      */
+    @Deprecated
     public Token(final String id,
                  final String type,
                  final String displayName,
@@ -144,6 +151,24 @@ public final class Token {
         this.renewable = renewable;
     }
 
+    /**
+     * Construct {@link Token} object from {@link Builder}.
+     *
+     * @param builder Token builder.
+     */
+    public Token(final Builder builder) {
+        this.id = builder.id;
+        this.type = builder.type != null ? builder.type.value() : null;
+        this.displayName = builder.displayName;
+        this.noParent = builder.noParent;
+        this.noDefaultPolicy = builder.noDefaultPolicy;
+        this.ttl = builder.ttl;
+        this.numUses = builder.numUses;
+        this.policies = builder.policies;
+        this.meta = builder.meta;
+        this.renewable = builder.renewable;
+    }
+
     /**
      * @return Token ID
      */
@@ -235,4 +260,251 @@ public final class Token {
             return value;
         }
     }
+
+
+    /**
+     * A builder for vault tokens.
+     *
+     * @author Stefan Kalscheuer
+     * @since 0.4.0
+     * @since 0.9 Moved into subclass of {@link Token}.
+     */
+    public static final class Builder {
+        private String id;
+        private Type type;
+        private String displayName;
+        private Boolean noParent;
+        private Boolean noDefaultPolicy;
+        private Integer ttl;
+        private Integer numUses;
+        private List<String> policies;
+        private Map<String, String> meta;
+        private Boolean renewable;
+
+        /**
+         * Add token ID. (optional)
+         *
+         * @param id the ID
+         * @return self
+         */
+        public Builder withId(final String id) {
+            this.id = id;
+            return this;
+        }
+
+        /**
+         * Specify token type.
+         *
+         * @param type the type
+         * @return self
+         * @since 0.9
+         */
+        public Builder withType(final Token.Type type) {
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Add display name.
+         *
+         * @param displayName the display name
+         * @return self
+         */
+        public Builder withDisplayName(final String displayName) {
+            this.displayName = displayName;
+            return this;
+        }
+
+        /**
+         * Set desired time to live.
+         *
+         * @param ttl the ttl
+         * @return self
+         */
+        public Builder withTtl(final Integer ttl) {
+            this.ttl = ttl;
+            return this;
+        }
+
+        /**
+         * Set desired number of uses.
+         *
+         * @param numUses the number of uses
+         * @return self
+         */
+        public Builder withNumUses(final Integer numUses) {
+            this.numUses = numUses;
+            return this;
+        }
+
+        /**
+         * Set TRUE if the token should be created without parent.
+         *
+         * @param noParent if TRUE, token is created as orphan
+         * @return self
+         */
+        public Builder withNoParent(final boolean noParent) {
+            this.noParent = noParent;
+            return this;
+        }
+
+        /**
+         * Create token without parent.
+         * Convenience method for withNoParent()
+         *
+         * @return self
+         */
+        public Builder asOrphan() {
+            return withNoParent(true);
+        }
+
+        /**
+         * Create token with parent.
+         * Convenience method for withNoParent()
+         *
+         * @return self
+         */
+        public Builder withParent() {
+            return withNoParent(false);
+        }
+
+        /**
+         * Set TRUE if the default policy should not be part of this token.
+         *
+         * @param noDefaultPolicy if TRUE, default policy is not attached
+         * @return self
+         */
+        public Builder withNoDefaultPolicy(final boolean noDefaultPolicy) {
+            this.noDefaultPolicy = noDefaultPolicy;
+            return this;
+        }
+
+        /**
+         * Attach default policy to token.
+         * Convenience method for withNoDefaultPolicy()
+         *
+         * @return self
+         */
+        public Builder withDefaultPolicy() {
+            return withNoDefaultPolicy(false);
+        }
+
+        /**
+         * Do not attach default policy to token.
+         * Convenience method for withNoDefaultPolicy()
+         *
+         * @return self
+         */
+        public Builder withoutDefaultPolicy() {
+            return withNoDefaultPolicy(true);
+        }
+
+        /**
+         * Add given policies.
+         *
+         * @param policies the policies
+         * @return self
+         * @since 0.5.0
+         */
+        public Builder withPolicies(final String... policies) {
+            return withPolicies(Arrays.asList(policies));
+        }
+
+        /**
+         * Add given policies.
+         *
+         * @param policies the policies
+         * @return self
+         */
+        public Builder withPolicies(final List<String> policies) {
+            if (this.policies == null) {
+                this.policies = new ArrayList<>();
+            }
+            this.policies.addAll(policies);
+            return this;
+        }
+
+        /**
+         * Add a single policy.
+         *
+         * @param policy the policy
+         * @return self
+         */
+        public Builder withPolicy(final String policy) {
+            if (this.policies == null) {
+                this.policies = new ArrayList<>();
+            }
+            policies.add(policy);
+            return this;
+        }
+
+        /**
+         * Add meta data.
+         *
+         * @param meta the metadata
+         * @return self
+         */
+        public Builder withMeta(final Map<String, String> meta) {
+            if (this.meta == null) {
+                this.meta = new HashMap<>();
+            }
+            this.meta.putAll(meta);
+            return this;
+        }
+
+        /**
+         * Add meta data.
+         *
+         * @param key   the key
+         * @param value the value
+         * @return self
+         */
+        public Builder withMeta(final String key, final String value) {
+            if (this.meta == null) {
+                this.meta = new HashMap<>();
+            }
+            this.meta.put(key, value);
+            return this;
+        }
+
+        /**
+         * Set if token is renewable.
+         *
+         * @param renewable TRUE, if renewable
+         * @return self
+         */
+        public Builder withRenewable(final Boolean renewable) {
+            this.renewable = renewable;
+            return this;
+        }
+
+        /**
+         * Set token to be renewable.
+         * Convenience method for withRenewable()
+         *
+         * @return self
+         */
+        public Builder renewable() {
+            return withRenewable(true);
+        }
+
+        /**
+         * Set token to be not renewable.
+         * Convenience method for withRenewable()
+         *
+         * @return self
+         */
+        public Builder notRenewable() {
+            return withRenewable(false);
+        }
+
+        /**
+         * Build the token based on given parameters.
+         *
+         * @return the token
+         */
+        public Token build() {
+            return new Token(this);
+        }
+    }
 }
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
index 18ef7fd..589a2d5 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java
@@ -23,7 +23,9 @@ import java.util.*;
  *
  * @author Stefan Kalscheuer
  * @since 0.4.0
+ * @deprecated As of 0.9 in favor of {@link Token.Builder}.
  */
+@Deprecated
 public final class TokenBuilder {
     private String id;
     private Token.Type type;
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
index a980408..3526f49 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -31,13 +32,12 @@ import java.util.List;
 @JsonIgnoreProperties(ignoreUnknown = true)
 public final class TokenRole {
     /**
-     * Get {@link TokenRoleBuilder} instance.
+     * Get {@link Builder} instance.
      *
      * @return Token Role Builder.
-     * @since 0.9
      */
-    public static TokenRoleBuilder builder() {
-        return new TokenRoleBuilder();
+    public static Builder builder() {
+        return new Builder();
     }
 
     @JsonProperty("name")
@@ -98,49 +98,20 @@ public final class TokenRole {
     public TokenRole() {
     }
 
-    /**
-     * Construct complete {@link TokenRole} object.
-     *
-     * @param name                 Token Role name (redundant for creation).
-     * @param allowedPolicies      Allowed policies (optional)
-     * @param disallowedPolicies   Disallowed policies (optional)
-     * @param orphan               Role is orphan? (optional)
-     * @param renewable            Role is renewable? (optional)
-     * @param pathSuffix           Paht suffix (optional)
-     * @param allowedEntityAliases Allowed entity aliases (optional)
-     * @param tokenBoundCidrs      Token bound CIDR blocks (optional)
-     * @param tokenExplicitMaxTtl  Token explicit maximum TTL (optional)
-     * @param tokenNoDefaultPolicy Token wihtout default policy? (optional)
-     * @param tokenNumUses         Token number of uses (optional)
-     * @param tokenPeriod          Token period (optional)
-     * @param tokenType            Token type (optional)
-     */
-    public TokenRole(final String name,
-                     final List<String> allowedPolicies,
-                     final List<String> disallowedPolicies,
-                     final Boolean orphan,
-                     final Boolean renewable,
-                     final String pathSuffix,
-                     final List<String> allowedEntityAliases,
-                     final List<String> tokenBoundCidrs,
-                     final Integer tokenExplicitMaxTtl,
-                     final Boolean tokenNoDefaultPolicy,
-                     final Integer tokenNumUses,
-                     final Integer tokenPeriod,
-                     final String tokenType) {
-        this.name = name;
-        this.allowedPolicies = allowedPolicies;
-        this.disallowedPolicies = disallowedPolicies;
-        this.orphan = orphan;
-        this.renewable = renewable;
-        this.pathSuffix = pathSuffix;
-        this.allowedEntityAliases = allowedEntityAliases;
-        this.tokenBoundCidrs = tokenBoundCidrs;
-        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
-        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
-        this.tokenNumUses = tokenNumUses;
-        this.tokenPeriod = tokenPeriod;
-        this.tokenType = tokenType;
+    public TokenRole(final Builder builder) {
+        this.name = builder.name;
+        this.allowedPolicies = builder.allowedPolicies;
+        this.disallowedPolicies = builder.disallowedPolicies;
+        this.orphan = builder.orphan;
+        this.renewable = builder.renewable;
+        this.pathSuffix = builder.pathSuffix;
+        this.allowedEntityAliases = builder.allowedEntityAliases;
+        this.tokenBoundCidrs = builder.tokenBoundCidrs;
+        this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
+        this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
+        this.tokenNumUses = builder.tokenNumUses;
+        this.tokenPeriod = builder.tokenPeriod;
+        this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
     }
 
     /**
@@ -233,4 +204,262 @@ public final class TokenRole {
     public String getTokenType() {
         return tokenType;
     }
+
+    /**
+     * A builder for vault token roles.
+     *
+     * @author Stefan Kalscheuer
+     * @since 0.9
+     */
+    public static final class Builder {
+        private String name;
+        private List<String> allowedPolicies;
+        private List<String> disallowedPolicies;
+        private Boolean orphan;
+        private Boolean renewable;
+        private String pathSuffix;
+        private List<String> allowedEntityAliases;
+        private List<String> tokenBoundCidrs;
+        private Integer tokenExplicitMaxTtl;
+        private Boolean tokenNoDefaultPolicy;
+        private Integer tokenNumUses;
+        private Integer tokenPeriod;
+        private Token.Type tokenType;
+
+        /**
+         * Add token role name.
+         *
+         * @param name role name
+         * @return self
+         */
+        public Builder forName(final String name) {
+            this.name = name;
+            return this;
+        }
+
+        /**
+         * Add an allowed policy.
+         *
+         * @param allowedPolicy allowed policy to add
+         * @return self
+         */
+        public Builder withAllowedPolicy(final String allowedPolicy) {
+            if (allowedPolicy != null) {
+                if (this.allowedPolicies == null) {
+                    this.allowedPolicies = new ArrayList<>();
+                }
+                this.allowedPolicies.add(allowedPolicy);
+            }
+            return this;
+        }
+
+        /**
+         * Add allowed policies.
+         *
+         * @param allowedPolicies list of allowed policies
+         * @return self
+         */
+        public Builder withAllowedPolicies(final List<String> allowedPolicies) {
+            if (allowedPolicies != null) {
+                if (this.allowedPolicies == null) {
+                    this.allowedPolicies = new ArrayList<>();
+                }
+                this.allowedPolicies.addAll(allowedPolicies);
+            }
+            return this;
+        }
+
+        /**
+         * Add a disallowed policy.
+         *
+         * @param disallowedPolicy disallowed policy to add
+         * @return self
+         */
+        public Builder withDisallowedPolicy(final String disallowedPolicy) {
+            if (disallowedPolicy != null) {
+                if (this.disallowedPolicies == null) {
+                    this.disallowedPolicies = new ArrayList<>();
+                }
+                this.disallowedPolicies.add(disallowedPolicy);
+            }
+            return this;
+        }
+
+        /**
+         * Add disallowed policies.
+         *
+         * @param disallowedPolicies list of disallowed policies
+         * @return self
+         */
+        public Builder withDisallowedPolicies(final List<String> disallowedPolicies) {
+            if (disallowedPolicies != null) {
+                if (this.disallowedPolicies == null) {
+                    this.disallowedPolicies = new ArrayList<>();
+                }
+                this.disallowedPolicies.addAll(disallowedPolicies);
+            }
+            return this;
+        }
+
+        /**
+         * Set TRUE if the token role should be created orphan.
+         *
+         * @param orphan if TRUE, token role is created as orphan
+         * @return self
+         */
+        public Builder orphan(final Boolean orphan) {
+            this.orphan = orphan;
+            return this;
+        }
+
+        /**
+         * Set TRUE if the token role should be created renewable.
+         *
+         * @param renewable if TRUE, token role is created renewable
+         * @return self
+         */
+        public Builder renewable(final Boolean renewable) {
+            this.renewable = renewable;
+            return this;
+        }
+
+        /**
+         * Set token role path suffix.
+         *
+         * @param pathSuffix path suffix to use
+         * @return self
+         */
+        public Builder withPathSuffix(final String pathSuffix) {
+            this.pathSuffix = pathSuffix;
+            return this;
+        }
+
+        /**
+         * Add an allowed entity alias.
+         *
+         * @param allowedEntityAlias allowed entity alias to add
+         * @return self
+         */
+        public Builder withAllowedEntityAlias(final String allowedEntityAlias) {
+            if (allowedEntityAlias != null) {
+                if (this.allowedEntityAliases == null) {
+                    this.allowedEntityAliases = new ArrayList<>();
+                }
+                this.allowedEntityAliases.add(allowedEntityAlias);
+            }
+            return this;
+        }
+
+        /**
+         * Add allowed entity aliases.
+         *
+         * @param allowedEntityAliases list of allowed entity aliases to add
+         * @return self
+         */
+        public Builder withAllowedEntityAliases(final List<String> allowedEntityAliases) {
+            if (allowedEntityAliases != null) {
+                if (this.allowedEntityAliases == null) {
+                    this.allowedEntityAliases = new ArrayList<>();
+                }
+                this.allowedEntityAliases.addAll(allowedEntityAliases);
+            }
+            return this;
+        }
+
+        /**
+         * Add a single bound CIDR.
+         *
+         * @param tokenBoundCidr bound CIDR to add
+         * @return self
+         */
+        public Builder withTokenBoundCidr(final String tokenBoundCidr) {
+            if (tokenBoundCidr != null) {
+                if (this.tokenBoundCidrs == null) {
+                    this.tokenBoundCidrs = new ArrayList<>();
+                }
+                this.tokenBoundCidrs.add(tokenBoundCidr);
+            }
+            return this;
+        }
+
+        /**
+         * Add a list of bound CIDRs.
+         *
+         * @param tokenBoundCidrs list of bound CIDRs to add
+         * @return self
+         */
+        public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
+            if (tokenBoundCidrs != null) {
+                if (this.tokenBoundCidrs == null) {
+                    this.tokenBoundCidrs = new ArrayList<>();
+                }
+                this.tokenBoundCidrs.addAll(tokenBoundCidrs);
+            }
+            return this;
+        }
+
+        /**
+         * Set explicit max. TTL for token.
+         *
+         * @param tokenExplicitMaxTtl explicit maximum TTL
+         * @return self
+         */
+        public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
+            this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
+            return this;
+        }
+
+        /**
+         * Set TRUE if the token role should be created renewable.
+         *
+         * @param tokenNoDefaultPolicy if TRUE, token is created without default policy.
+         * @return self
+         */
+        public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
+            this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
+            return this;
+        }
+
+        /**
+         * Set number of uses for tokens.
+         *
+         * @param tokenNumUses number of uses for associated tokens.
+         * @return self
+         */
+        public Builder withTokenNumUses(final Integer tokenNumUses) {
+            this.tokenNumUses = tokenNumUses;
+            return this;
+        }
+
+        /**
+         * Set token period.
+         *
+         * @param tokenPeriod token period
+         * @return self
+         */
+        public Builder withTokenPeriod(final Integer tokenPeriod) {
+            this.tokenPeriod = tokenPeriod;
+            return this;
+        }
+
+        /**
+         * Set token type.
+         *
+         * @param tokenType token type
+         * @return self
+         */
+        public Builder withTokenType(final Token.Type tokenType) {
+            this.tokenType = tokenType;
+            return this;
+        }
+
+        /**
+         * Build the token based on given parameters.
+         *
+         * @return the token
+         */
+        public TokenRole build() {
+            return new TokenRole(this);
+        }
+    }
 }
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
deleted file mode 100644
index 0c5a4b8..0000000
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenRoleBuilder.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2016-2020 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 java.util.ArrayList;
-import java.util.List;
-
-/**
- * A builder for vault token roles.
- *
- * @author Stefan Kalscheuer
- * @since 0.9
- */
-public final class TokenRoleBuilder {
-    private String name;
-    private List<String> allowedPolicies;
-    private List<String> disallowedPolicies;
-    private Boolean orphan;
-    private Boolean renewable;
-    private String pathSuffix;
-    private List<String> allowedEntityAliases;
-    private List<String> tokenBoundCidrs;
-    private Integer tokenExplicitMaxTtl;
-    private Boolean tokenNoDefaultPolicy;
-    private Integer tokenNumUses;
-    private Integer tokenPeriod;
-    private Token.Type tokenType;
-
-    /**
-     * Add token role name.
-     *
-     * @param name role name
-     * @return self
-     */
-    public TokenRoleBuilder forName(final String name) {
-        this.name = name;
-        return this;
-    }
-
-    /**
-     * Add an allowed policy.
-     *
-     * @param allowedPolicy allowed policy to add
-     * @return self
-     */
-    public TokenRoleBuilder withAllowedPolicy(final String allowedPolicy) {
-        if (allowedPolicy != null) {
-            if (this.allowedPolicies == null) {
-                this.allowedPolicies = new ArrayList<>();
-            }
-            this.allowedPolicies.add(allowedPolicy);
-        }
-        return this;
-    }
-
-    /**
-     * Add allowed policies.
-     *
-     * @param allowedPolicies list of allowed policies
-     * @return self
-     */
-    public TokenRoleBuilder withAllowedPolicies(final List<String> allowedPolicies) {
-        if (allowedPolicies != null) {
-            if (this.allowedPolicies == null) {
-                this.allowedPolicies = new ArrayList<>();
-            }
-            this.allowedPolicies.addAll(allowedPolicies);
-        }
-        return this;
-    }
-
-    /**
-     * Add a disallowed policy.
-     *
-     * @param disallowedPolicy disallowed policy to add
-     * @return self
-     */
-    public TokenRoleBuilder withDisallowedPolicy(final String disallowedPolicy) {
-        if (disallowedPolicy != null) {
-            if (this.disallowedPolicies == null) {
-                this.disallowedPolicies = new ArrayList<>();
-            }
-            this.disallowedPolicies.add(disallowedPolicy);
-        }
-        return this;
-    }
-
-    /**
-     * Add disallowed policies.
-     *
-     * @param disallowedPolicies list of disallowed policies
-     * @return self
-     */
-    public TokenRoleBuilder withDisallowedPolicies(final List<String> disallowedPolicies) {
-        if (disallowedPolicies != null) {
-            if (this.disallowedPolicies == null) {
-                this.disallowedPolicies = new ArrayList<>();
-            }
-            this.disallowedPolicies.addAll(disallowedPolicies);
-        }
-        return this;
-    }
-
-    /**
-     * Set TRUE if the token role should be created orphan.
-     *
-     * @param orphan if TRUE, token role is created as orphan
-     * @return self
-     */
-    public TokenRoleBuilder orphan(final Boolean orphan) {
-        this.orphan = orphan;
-        return this;
-    }
-
-    /**
-     * Set TRUE if the token role should be created renewable.
-     *
-     * @param renewable if TRUE, token role is created renewable
-     * @return self
-     */
-    public TokenRoleBuilder renewable(final Boolean renewable) {
-        this.renewable = renewable;
-        return this;
-    }
-
-    /**
-     * Set token role path suffix.
-     *
-     * @param pathSuffix path suffix to use
-     * @return self
-     */
-    public TokenRoleBuilder withPathSuffix(final String pathSuffix) {
-        this.pathSuffix = pathSuffix;
-        return this;
-    }
-
-    /**
-     * Add an allowed entity alias.
-     *
-     * @param allowedEntityAlias allowed entity alias to add
-     * @return self
-     */
-    public TokenRoleBuilder withAllowedEntityAlias(final String allowedEntityAlias) {
-        if (allowedEntityAlias != null) {
-            if (this.allowedEntityAliases == null) {
-                this.allowedEntityAliases = new ArrayList<>();
-            }
-            this.allowedEntityAliases.add(allowedEntityAlias);
-        }
-        return this;
-    }
-
-    /**
-     * Add allowed entity aliases.
-     *
-     * @param allowedEntityAliases list of allowed entity aliases to add
-     * @return self
-     */
-    public TokenRoleBuilder withAllowedEntityAliases(final List<String> allowedEntityAliases) {
-        if (allowedEntityAliases != null) {
-            if (this.allowedEntityAliases == null) {
-                this.allowedEntityAliases = new ArrayList<>();
-            }
-            this.allowedEntityAliases.addAll(allowedEntityAliases);
-        }
-        return this;
-    }
-
-    /**
-     * Add a single bound CIDR.
-     *
-     * @param tokenBoundCidr bound CIDR to add
-     * @return self
-     */
-    public TokenRoleBuilder withTokenBoundCidr(final String tokenBoundCidr) {
-        if (tokenBoundCidr != null) {
-            if (this.tokenBoundCidrs == null) {
-                this.tokenBoundCidrs = new ArrayList<>();
-            }
-            this.tokenBoundCidrs.add(tokenBoundCidr);
-        }
-        return this;
-    }
-
-    /**
-     * Add a list of bound CIDRs.
-     *
-     * @param tokenBoundCidrs list of bound CIDRs to add
-     * @return self
-     */
-    public TokenRoleBuilder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
-        if (tokenBoundCidrs != null) {
-            if (this.tokenBoundCidrs == null) {
-                this.tokenBoundCidrs = new ArrayList<>();
-            }
-            this.tokenBoundCidrs.addAll(tokenBoundCidrs);
-        }
-        return this;
-    }
-
-    /**
-     * Set explicit max. TTL for token.
-     *
-     * @param tokenExplicitMaxTtl explicit maximum TTL
-     * @return self
-     */
-    public TokenRoleBuilder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
-        this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
-        return this;
-    }
-
-    /**
-     * Set TRUE if the token role should be created renewable.
-     *
-     * @param tokenNoDefaultPolicy if TRUE, token is created without default policy.
-     * @return self
-     */
-    public TokenRoleBuilder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
-        this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
-        return this;
-    }
-
-    /**
-     * Set number of uses for tokens.
-     *
-     * @param tokenNumUses number of uses for associated tokens.
-     * @return self
-     */
-    public TokenRoleBuilder withTokenNumUses(final Integer tokenNumUses) {
-        this.tokenNumUses = tokenNumUses;
-        return this;
-    }
-
-    /**
-     * Set token period.
-     *
-     * @param tokenPeriod token period
-     * @return self
-     */
-    public TokenRoleBuilder withTokenPeriod(final Integer tokenPeriod) {
-        this.tokenPeriod = tokenPeriod;
-        return this;
-    }
-
-    /**
-     * Set token type.
-     *
-     * @param tokenType token type
-     * @return self
-     */
-    public TokenRoleBuilder withTokenType(final Token.Type tokenType) {
-        this.tokenType = tokenType;
-        return this;
-    }
-
-    /**
-     * Build the token based on given parameters.
-     *
-     * @return the token
-     */
-    public TokenRole build() {
-        return new TokenRole(
-                name,
-                allowedPolicies,
-                disallowedPolicies,
-                orphan,
-                renewable,
-                pathSuffix,
-                allowedEntityAliases,
-                tokenBoundCidrs,
-                tokenExplicitMaxTtl,
-                tokenNoDefaultPolicy,
-                tokenNumUses,
-                tokenPeriod,
-                tokenType != null ? tokenType.value() : null
-        );
-    }
-}
diff --git a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
index 690ad2e..2a98f7f 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/AppRoleBuilderTest.java
@@ -68,6 +68,34 @@ public class AppRoleBuilderTest {
      */
     @Test
     public void buildDefaultTest() throws JsonProcessingException {
+        AppRole role = AppRole.builder(NAME).build();
+        assertThat(role.getId(), is(nullValue()));
+        assertThat(role.getBindSecretId(), is(nullValue()));
+        assertThat(role.getSecretIdBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenPolicies(), is(nullValue()));
+        assertThat(role.getPolicies(), is(nullValue()));
+        assertThat(role.getSecretIdNumUses(), is(nullValue()));
+        assertThat(role.getSecretIdTtl(), is(nullValue()));
+        assertThat(role.getEnableLocalSecretIds(), is(nullValue()));
+        assertThat(role.getTokenTtl(), is(nullValue()));
+        assertThat(role.getTokenMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenBoundCidrs(), is(nullValue()));
+        assertThat(role.getTokenExplicitMaxTtl(), is(nullValue()));
+        assertThat(role.getTokenNoDefaultPolicy(), is(nullValue()));
+        assertThat(role.getTokenNumUses(), is(nullValue()));
+        assertThat(role.getTokenPeriod(), is(nullValue()));
+        assertThat(role.getPeriod(), is(nullValue()));
+        assertThat(role.getTokenType(), is(nullValue()));
+
+        /* optional fields should be ignored, so JSON string should only contain role_name */
+        assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_MIN));
+    }
+
+    /**
+     * Build role with only a name.
+     */
+    @Test
+    public void legacyBuildDefaultTest() throws JsonProcessingException {
         AppRole role = new AppRoleBuilder(NAME).build();
         assertThat(role.getId(), is(nullValue()));
         assertThat(role.getBindSecretId(), is(nullValue()));
@@ -96,6 +124,51 @@ public class AppRoleBuilderTest {
      */
     @Test
     public void buildFullTest() throws JsonProcessingException {
+        AppRole role = AppRole.builder(NAME)
+                .withId(ID)
+                .withBindSecretID(BIND_SECRET_ID)
+                .withSecretIdBoundCidrs(BOUND_CIDR_LIST)
+                .withTokenPolicies(POLICIES)
+                .withSecretIdNumUses(SECRET_ID_NUM_USES)
+                .withSecretIdTtl(SECRET_ID_TTL)
+                .withEnableLocalSecretIds(ENABLE_LOCAL_SECRET_IDS)
+                .withTokenTtl(TOKEN_TTL)
+                .withTokenMaxTtl(TOKEN_MAX_TTL)
+                .withTokenBoundCidrs(BOUND_CIDR_LIST)
+                .withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
+                .withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
+                .withTokenNumUses(TOKEN_NUM_USES)
+                .wit0hTokenPeriod(TOKEN_PERIOD)
+                .withTokenType(TOKEN_TYPE)
+                .build();
+        assertThat(role.getName(), is(NAME));
+        assertThat(role.getId(), is(ID));
+        assertThat(role.getBindSecretId(), is(BIND_SECRET_ID));
+        assertThat(role.getSecretIdBoundCidrs(), is(BOUND_CIDR_LIST));
+        assertThat(role.getTokenPolicies(), is(POLICIES));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
+        assertThat(role.getSecretIdNumUses(), is(SECRET_ID_NUM_USES));
+        assertThat(role.getSecretIdTtl(), is(SECRET_ID_TTL));
+        assertThat(role.getEnableLocalSecretIds(), is(ENABLE_LOCAL_SECRET_IDS));
+        assertThat(role.getTokenTtl(), is(TOKEN_TTL));
+        assertThat(role.getTokenMaxTtl(), is(TOKEN_MAX_TTL));
+        assertThat(role.getTokenBoundCidrs(), is(BOUND_CIDR_LIST));
+        assertThat(role.getTokenExplicitMaxTtl(), is(TOKEN_EXPLICIT_MAX_TTL));
+        assertThat(role.getTokenNoDefaultPolicy(), is(TOKEN_NO_DEFAULT_POLICY));
+        assertThat(role.getTokenNumUses(), is(TOKEN_NUM_USES));
+        assertThat(role.getTokenPeriod(), is(TOKEN_PERIOD));
+        assertThat(role.getPeriod(), is(TOKEN_PERIOD));
+        assertThat(role.getTokenType(), is(TOKEN_TYPE.value()));
+
+        /* Verify that all parameters are included in JSON string */
+        assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_FULL));
+    }
+
+    /**
+     * Build token without all parameters set.
+     */
+    @Test
+    public void legacyBuildFullTest() throws JsonProcessingException {
         AppRole role = new AppRoleBuilder(NAME)
                 .withId(ID)
                 .withBindSecretID(BIND_SECRET_ID)
@@ -141,6 +214,50 @@ public class AppRoleBuilderTest {
      */
     @Test
     public void convenienceMethodsTest() {
+        /* bind_secret_id */
+        AppRole role = AppRole.builder(NAME).build();
+        assertThat(role.getBindSecretId(), is(nullValue()));
+        role = AppRole.builder(NAME).withBindSecretID().build();
+        assertThat(role.getBindSecretId(), is(true));
+        role = AppRole.builder(NAME).withoutBindSecretID().build();
+        assertThat(role.getBindSecretId(), is(false));
+
+        /* Add single CIDR subnet */
+        role = AppRole.builder(NAME).withSecretBoundCidr(CIDR_2).withTokenBoundCidr(CIDR_2).build();
+        assertThat(role.getSecretIdBoundCidrs(), hasSize(1));
+        assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_2));
+        assertThat(role.getTokenBoundCidrs(), hasSize(1));
+        assertThat(role.getTokenBoundCidrs(), contains(CIDR_2));
+        role = AppRole.builder(NAME)
+                .withSecretIdBoundCidrs(BOUND_CIDR_LIST)
+                .withSecretBoundCidr(CIDR_2)
+                .withTokenBoundCidrs(BOUND_CIDR_LIST)
+                .withTokenBoundCidr(CIDR_2)
+                .build();
+        assertThat(role.getSecretIdBoundCidrs(), hasSize(2));
+        assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_1, CIDR_2));
+        assertThat(role.getTokenBoundCidrs(), hasSize(2));
+        assertThat(role.getSecretIdBoundCidrs(), contains(CIDR_1, CIDR_2));
+
+        /* Add single policy */
+        role = AppRole.builder(NAME).withTokenPolicy(POLICY_2).build();
+        assertThat(role.getTokenPolicies(), hasSize(1));
+        assertThat(role.getTokenPolicies(), contains(POLICY_2));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
+        role = AppRole.builder(NAME)
+                .withTokenPolicies(POLICIES)
+                .withTokenPolicy(POLICY_2)
+                .build();
+        assertThat(role.getTokenPolicies(), hasSize(2));
+        assertThat(role.getTokenPolicies(), contains(POLICY, POLICY_2));
+        assertThat(role.getPolicies(), is(role.getTokenPolicies()));
+    }
+
+    /**
+     * Test convenience methods
+     */
+    @Test
+    public void legacyConvenienceMethodsTest() {
         /* bind_secret_id */
         AppRole role = new AppRoleBuilder(NAME).build();
         assertThat(role.getBindSecretId(), is(nullValue()));
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
index 6672815..3f228f6 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
@@ -66,6 +66,27 @@ public class TokenBuilderTest {
      */
     @Test
     public void buildDefaultTest() throws JsonProcessingException {
+        Token token = Token.builder().build();
+        assertThat(token.getId(), is(nullValue()));
+        assertThat(token.getType(), is(nullValue()));
+        assertThat(token.getDisplayName(), is(nullValue()));
+        assertThat(token.getNoParent(), is(nullValue()));
+        assertThat(token.getNoDefaultPolicy(), is(nullValue()));
+        assertThat(token.getTtl(), is(nullValue()));
+        assertThat(token.getNumUses(), is(nullValue()));
+        assertThat(token.getPolicies(), is(nullValue()));
+        assertThat(token.getMeta(), is(nullValue()));
+        assertThat(token.isRenewable(), is(nullValue()));
+
+        /* optional fields should be ignored, so JSON string should be empty */
+        assertThat(new ObjectMapper().writeValueAsString(token), is("{}"));
+    }
+
+    /**
+     * Build token without any parameters.
+     */
+    @Test
+    public void legadcyBuildDefaultTest() throws JsonProcessingException {
         Token token = new TokenBuilder().build();
         assertThat(token.getId(), is(nullValue()));
         assertThat(token.getType(), is(nullValue()));
@@ -87,6 +108,38 @@ public class TokenBuilderTest {
      */
     @Test
     public void buildFullTest() throws JsonProcessingException {
+        Token token = Token.builder()
+                .withId(ID)
+                .withType(Token.Type.SERVICE)
+                .withDisplayName(DISPLAY_NAME)
+                .withNoParent(NO_PARENT)
+                .withNoDefaultPolicy(NO_DEFAULT_POLICY)
+                .withTtl(TTL)
+                .withNumUses(NUM_USES)
+                .withPolicies(POLICIES)
+                .withMeta(META)
+                .withRenewable(RENEWABLE)
+                .build();
+        assertThat(token.getId(), is(ID));
+        assertThat(token.getType(), is(Token.Type.SERVICE.value()));
+        assertThat(token.getDisplayName(), is(DISPLAY_NAME));
+        assertThat(token.getNoParent(), is(NO_PARENT));
+        assertThat(token.getNoDefaultPolicy(), is(NO_DEFAULT_POLICY));
+        assertThat(token.getTtl(), is(TTL));
+        assertThat(token.getNumUses(), is(NUM_USES));
+        assertThat(token.getPolicies(), is(POLICIES));
+        assertThat(token.getMeta(), is(META));
+        assertThat(token.isRenewable(), is(RENEWABLE));
+
+        /* Verify that all parameters are included in JSON string */
+        assertThat(new ObjectMapper().writeValueAsString(token), is(JSON_FULL));
+    }
+
+    /**
+     * Build token without all parameters set.
+     */
+    @Test
+    public void legacyBuildFullTest() throws JsonProcessingException {
         Token token = new TokenBuilder()
                 .withId(ID)
                 .withType(Token.Type.SERVICE)
@@ -119,6 +172,54 @@ public class TokenBuilderTest {
      */
     @Test
     public void convenienceMethodsTest() {
+        /* Parent */
+        Token token = Token.builder().asOrphan().build();
+        assertThat(token.getNoParent(), is(true));
+        token = Token.builder().withParent().build();
+        assertThat(token.getNoParent(), is(false));
+
+        /* Default policy */
+        token = Token.builder().withDefaultPolicy().build();
+        assertThat(token.getNoDefaultPolicy(), is(false));
+        token = Token.builder().withoutDefaultPolicy().build();
+        assertThat(token.getNoDefaultPolicy(), is(true));
+
+        /* Renewability */
+        token = Token.builder().renewable().build();
+        assertThat(token.isRenewable(), is(true));
+        token = Token.builder().notRenewable().build();
+        assertThat(token.isRenewable(), is(false));
+
+        /* Add single policy */
+        token = Token.builder().withPolicy(POLICY_2).build();
+        assertThat(token.getPolicies(), hasSize(1));
+        assertThat(token.getPolicies(), contains(POLICY_2));
+        token = Token.builder()
+                .withPolicies(POLICY, POLICY_2)
+                .withPolicy(POLICY_3)
+                .build();
+        assertThat(token.getPolicies(), hasSize(3));
+        assertThat(token.getPolicies(), contains(POLICY, POLICY_2, POLICY_3));
+
+        /* Add single metadata */
+        token = Token.builder().withMeta(META_KEY_2, META_VALUE_2).build();
+        assertThat(token.getMeta().size(), is(1));
+        assertThat(token.getMeta().keySet(), contains(META_KEY_2));
+        assertThat(token.getMeta().get(META_KEY_2), is(META_VALUE_2));
+        token = Token.builder()
+                .withMeta(META)
+                .withMeta(META_KEY_2, META_VALUE_2)
+                .build();
+        assertThat(token.getMeta().size(), is(2));
+        assertThat(token.getMeta().get(META_KEY), is(META_VALUE));
+        assertThat(token.getMeta().get(META_KEY_2), is(META_VALUE_2));
+    }
+
+    /**
+     * Test convenience methods
+     */
+    @Test
+    public void legacyConvenienceMethodsTest() {
         /* Parent */
         Token token = new TokenBuilder().asOrphan().build();
         assertThat(token.getNoParent(), is(true));
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
index f738fbc..e1b2bc7 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenRoleBuilderTest.java
@@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 
 /**
- * Unit Test for {@link TokenRoleBuilder}
+ * Unit Test for {@link Token.Builder}
  *
  * @author Stefan Kalscheuer
  * @since 0.9
@@ -79,7 +79,7 @@ public class TokenRoleBuilderTest {
      */
     @Test
     public void buildDefaultTest() throws JsonProcessingException {
-        TokenRole role = new TokenRoleBuilder().build();
+        TokenRole role = TokenRole.builder().build();
         assertThat(role.getAllowedPolicies(), is(nullValue()));
         assertThat(role.getDisallowedPolicies(), is(nullValue()));
         assertThat(role.getOrphan(), is(nullValue()));

From be7aa865d81c5116cf5db31fcadc1352a84ddb71 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 22 Apr 2020 19:31:55 +0200
Subject: [PATCH 16/21] rework CI configuration for multi-stage job

---
 .drone.yml  | 35 ++++++++++++++++++++++++-----------
 .travis.yml | 35 ++++++++++++++++++++++++++---------
 2 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 71600ea..0195d77 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -2,25 +2,38 @@ kind: pipeline
 name: default
 
 steps:
-  - name: test-online
+  - name: compile
     image: maven:3-jdk-11
-    environment:
-      VAULT_VERSION: 1.4.0
     commands:
-      - curl -o vault_1.4.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_linux_amd64.zip
-      - curl -s https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
-      - unzip vault_1.4.0_linux_amd64.zip
-      - rm vault_1.4.0_linux_amd64.zip
-      - mv vault /bin/
-      - mvn clean test
+      - mvn clean compile
     when:
       branch:
         - master
-  - name: test-offline
+        - develop
+        - feature/*
+        - fix/*
+        - release/*
+  - name: unit-tests
     image: maven:3-jdk-11
     commands:
-      - mvn clean test -P offline-tests
+      - mvn test -P offline-tests
     when:
       branch:
         - develop
         - feature/*
+        - fix/*
+  - name: unit-integration-tests
+    image: maven:3-jdk-11
+    environment:
+      VAULT_VERSION: 1.4.0
+    commands:
+      - curl -s -o vault_1.4.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_linux_amd64.zip
+      - curl -s https://releases.hashicorp.com/vault/1.4.0/vault_1.4.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
+      - unzip vault_1.4.0_linux_amd64.zip
+      - rm vault_1.4.0_linux_amd64.zip
+      - mv vault /bin/
+      - mvn test
+    when:
+      branch:
+        - master
+        - release/*
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 74f5d22..74536ca 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,12 +7,16 @@ addons:
     organization: "stklcode-github"
     token:
       secure: "sM9OfX5jW764pn9cb2LSXArnXucKMws+eGeg5NnZxHRcGYt4hpBKLSregBSsBNzUoWVj0zNzPCpnh+UQvgxQzUerOqwEdjTBpy3SNPaxSn7UpoSg+Wz3aUmL9ugmx01b51/wMG4UCHEwTZt2tpgTPVtw8K6uSO78e0dSICCBHDnRcdQwOjMEQHIJJ/qHVRwuy/MzLCAP3W1JPZlsphZg9QsFyhB4hW97dE90joZezfocQIv2xI/r6k+BLz0pY6MxYCul0RiDumaiaej0CPvEJI/uSu//BAQjUdHw+mQgnKUYIbrn2ONOviwNfwdr94JyoZEN2B6zASUmNLjPf4AbIojDeyS+CrpQpm17EVm/Qk/Ds+Xra4PPPIcsZhiWzV0KoDUz9xLfXuRJ526VT5tDPiaeI7oETf0+8l+JIS1b399FyqHi7smzjpvC6GuKflQrbuHK4MuKzDh7WTHiqokGG4SS0wOQIaaHB3dfdwwQzPh6IM24e8CETxh3DjMeqUTU4DWmv5po55jZ934TtxVQvVN78bTG9O0zS9u+JmRY04OZ+OaXuFam6MfMUFQi0EPZzdGul/oWSibGUu3bNfVEBp60CnJwYNM/dKG6U7pJthLHvSwiQFOdKzHZ+l1jZJ4gPaXaIGqpwqVGr28ntqA/El1rytPixr2driE6bYMt5jw="
+stages:
+  - Compile
+  - Test
+  - Analysis
 env:
   - PATH=$PATH:. VAULT_VERSION=1.4.0
 before_script:
   - |
-    if [ "$TRAVIS_BRANCH" = "master" ]; then
-      wget https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
+    if [[ "$TRAVIS_BRANCH" =~ ^master|(release\/.+)$ ]]; then
+      wget -q https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
       wget -q -O - https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_SHA256SUMS | grep linux_amd64 | sha256sum -c
       unzip vault_${VAULT_VERSION}_linux_amd64.zip
       rm vault_${VAULT_VERSION}_linux_amd64.zip
@@ -21,13 +25,26 @@ cache:
   directories:
     - '$HOME/.m2/repository'
     - '$HOME/.sonar/cache'
-script:
-  - |
-    if [ "$TRAVIS_BRANCH" = "master" ]; then
-      mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
-    else
-      mvn clean test -P offline-tests
-    fi
+jobs:
+  include:
+    - stage: Compile
+      name: Compile
+      script:
+        - mvn clean compile
+    - stage: Test
+      name: Unit Tests
+      if: NOT branch =~ ^master|(release/.+)$
+      script:
+        - mvn test -P offline-tests
+    - name: Unit and Integration Tests
+      if: branch =~ ^master|(release/.+)$
+      script:
+        - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package
+    - stage: Analysis
+      if: branch = master
+      script:
+        - mvn sonar:sonar
+
 notifications:
   slack:
     secure: "YyE5GePOLkCVTtCy8j507BRmQrtrWhtvmUt4kY0Z2/ptf0LzfuDEJQ4ZbCxO5ri5IDJrrvyPAedjft818+bMzdFfxvi1oviIL+LZNhyev8gfeIBF/U2pvSLGKCRX4g4aZ6NKN3Untjdm8lmiVTltOyZ59JizQVwXzAl3LiOpnJugyBqbhOx4EIqBzwW3gaYAofMqY2LczW5W/M+99HJCst8Mb8H06GstCPEHCizAq7VRaUS68PstlxQMV0Q6bsSYMLFbLWmhuXs96WHqOrT+nNsl07ikr3N8c4HafhFutt2Jyc1+8gXO417+eSvVM0iBpHGwTmfGFfCqx/4Pf62DTJuvh8dR4fLgLDiqEeDrBEcRRDOs9cvXVOO22NN1HuBBJY8VRiFcwNAvuVMXCtnC+1RJRAZB2zubsANiFe+ygk/ywj37cVXY+NpqlBwcSph6jPHo2hD6cIl2rTWn1EnZH519Rh38xTSv6MRzAO9kWNVrAlX+UtvYS8Sk7Owrc0tET9Lc4zj6aI5tsA1wYbN3Jk6EbMhsF6K/XF2npt2qg09pxkj8wmxoUoR6/rGuSv55aSxTdLDmH+en4ahEm3uc4h1lYoVCk0yrZoTAas3zS4WpBCKnl+mweuKNxaejyy0Wv6NR9ZCTaS3yFgibNOjvDpxZxTAPdNBL7hn+k4LwgN4="

From 46461f482a59284a9600bb7924195b739c0908b5 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sat, 25 Apr 2020 12:33:22 +0200
Subject: [PATCH 17/21] add coverage profile to maven project

---
 .travis.yml |  2 +-
 pom.xml     | 46 ++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 74536ca..30922b1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,7 +39,7 @@ jobs:
     - name: Unit and Integration Tests
       if: branch =~ ^master|(release/.+)$
       script:
-        - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package
+        - mvn -P coverage clean package
     - stage: Analysis
       if: branch = master
       script:
diff --git a/pom.xml b/pom.xml
index fee8ef0..16bdb67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -147,13 +147,13 @@
         <dependency>
             <groupId>net.bytebuddy</groupId>
             <artifactId>byte-buddy</artifactId>
-            <version>1.10.8</version>
+            <version>1.10.9</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>net.bytebuddy</groupId>
             <artifactId>byte-buddy-agent</artifactId>
-            <version>1.10.8</version>
+            <version>1.10.9</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -164,6 +164,16 @@
         </dependency>
     </dependencies>
 
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.sonarsource.scanner.maven</groupId>
+                <artifactId>sonar-maven-plugin</artifactId>
+                <version>3.7.0.1746</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
 
     <profiles>
         <profile>
@@ -176,7 +186,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-source-plugin</artifactId>
-                        <version>3.1.0</version>
+                        <version>3.2.1</version>
                         <executions>
                             <execution>
                                 <id>attach-sources</id>
@@ -200,7 +210,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-javadoc-plugin</artifactId>
-                        <version>3.1.1</version>
+                        <version>3.2.0</version>
                         <configuration>
                             <source>1.8</source>
                         </configuration>
@@ -242,6 +252,34 @@
             </build>
         </profile>
 
+        <profile>
+            <id>coverage</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.jacoco</groupId>
+                        <artifactId>jacoco-maven-plugin</artifactId>
+                        <version>0.8.5</version>
+                        <executions>
+                            <execution>
+                                <id>prepare-agent</id>
+                                <goals>
+                                    <goal>prepare-agent</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>report</id>
+                                <phase>prepare-package</phase>
+                                <goals>
+                                    <goal>report</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+
         <profile>
             <id>offline-tests</id>
             <build>

From 9f80a7dadaec43ce58f70ba6fbf76624a121ab1d Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sat, 25 Apr 2020 13:04:39 +0200
Subject: [PATCH 18/21] typo fixes

---
 README.md                                     |  4 +--
 .../jvault/connector/HTTPVaultConnector.java  |  4 +--
 .../jvault/connector/VaultConnector.java      | 28 +++++++++----------
 .../builder/HTTPVaultConnectorBuilder.java    |  6 ++--
 .../factory/HTTPVaultConnectorFactory.java    |  4 +--
 .../jvault/connector/internal/Error.java      |  2 +-
 .../connector/internal/RequestHelper.java     |  6 ++--
 .../jvault/connector/model/AppRole.java       | 14 +++++-----
 .../connector/model/AppRoleBuilder.java       | 16 +++++------
 .../jvault/connector/model/TokenRole.java     |  4 +--
 .../model/response/SecretVersionResponse.java |  2 +-
 .../model/response/embedded/AuthData.java     |  2 +-
 .../HTTPVaultConnectorOfflineTest.java        |  2 +-
 .../connector/HTTPVaultConnectorTest.java     | 18 ++++++------
 .../connector/model/TokenBuilderTest.java     |  2 +-
 .../model/response/MetadataResponseTest.java  |  8 +++---
 .../response/SecretVersionResponseTest.java   |  2 +-
 17 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/README.md b/README.md
index 77cc066..62f8552 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,8 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
     * AppRole (register and authenticate)
     * AppID (register and authenticate) [_deprecated_]
 * Tokens
-    * Creation and lookup of tokens
-    * TokenBuilder for speaking creation of complex configuraitons
+    * Creation and lookup of tokens and token roles
+    * TokenBuilder for speaking creation of complex configurations
 * Secrets
     * Read secrets
     * Write secrets
diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
index ea37094..dbe21b9 100644
--- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java
@@ -31,7 +31,7 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
- * Vault Connector implementatin using Vault's HTTP API.
+ * Vault Connector implementation using Vault's HTTP API.
  *
  * @author Stefan Kalscheuer
  * @since 0.1
@@ -605,7 +605,7 @@ public class HTTPVaultConnector implements VaultConnector {
     /**
      * Common method to bundle secret version operations.
      *
-     * @param mount    Secret store mountpoint (without leading or trailing slash).
+     * @param mount    Secret store mount point (without leading or trailing slash).
      * @param pathPart Path part to query.
      * @param key      Secret key.
      * @param versions Versions to handle.
diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
index c3cfd5d..ce5a1f6 100644
--- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
+++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java
@@ -91,7 +91,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
     HealthResponse getHealth() throws VaultConnectorException;
 
     /**
-     * Get all availale authentication backends.
+     * Get all available authentication backends.
      *
      * @return List of backends
      * @throws VaultConnectorException on error
@@ -232,7 +232,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
     /**
      * Delete AppRole role from Vault.
      *
-     * @param roleName The role anme
+     * @param roleName The role name
      * @return {@code true} on success
      * @throws VaultConnectorException on error
      */
@@ -430,7 +430,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/data/<key>} is read here.
      * Only available for KV v2 secrets.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret identifier
      * @return Secret response
      * @throws VaultConnectorException on error
@@ -462,7 +462,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/data/<key>} is written here.
      * Only available for KV v2 secrets.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret identifier
      * @param data  Secret content. Value must be be JSON serializable.
      * @return Metadata for the created/updated secret.
@@ -479,7 +479,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/data/<key>} is written here.
      * Only available for KV v2 secrets.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret identifier
      * @param data  Secret content. Value must be be JSON serializable.
      * @param cas   Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
@@ -511,10 +511,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/data/<key>} is read here.
      * Only available for KV v2 secrets.
      *
-     * @param mount   Secret store mountpoint (without leading or trailing slash).
+     * @param mount   Secret store mount point (without leading or trailing slash).
      * @param key     Secret identifier
      * @param version Version to read. If {@code null} or zero, the latest version will be returned.
-     * @return Secret responsef
+     * @return Secret response.
      * @throws VaultConnectorException on error
      * @since 0.8
      */
@@ -556,7 +556,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/metadata/<key>} is read here.
      * Only available for KV v2 secrets.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret identifier
      * @return Metadata response
      * @throws VaultConnectorException on error
@@ -570,7 +570,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Path {@code <mount>/metadata/<key>} is written here.
      * Only available for KV v2 secrets.
      *
-     * @param mount       Secret store mountpoint (without leading or trailing slash).
+     * @param mount       Secret store mount point (without leading or trailing slash).
      * @param key         Secret identifier
      * @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
      * @param casRequired Specify if Check-And-Set is required for this secret.
@@ -710,7 +710,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * <br>
      * Only available for KV v2 stores.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret path.
      * @throws VaultConnectorException on error
      * @since 0.8
@@ -737,7 +737,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Prefix {@code secret/} is automatically added to path.
      * Only available for KV v2 stores.
      *
-     * @param mount Secret store mountpoint (without leading or trailing slash).
+     * @param mount Secret store mount point (without leading or trailing slash).
      * @param key   Secret path.
      * @throws VaultConnectorException on error
      * @since 0.8
@@ -763,7 +763,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * <br>
      * Only available for KV v2 stores.
      *
-     * @param mount    Secret store mountpoint (without leading or trailing slash).
+     * @param mount    Secret store mount point (without leading or trailing slash).
      * @param key      Secret path.
      * @param versions Versions of the secret to delete.
      * @throws VaultConnectorException on error
@@ -788,7 +788,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Undelete (restore) secret versions from Vault.
      * Only available for KV v2 stores.
      *
-     * @param mount    Secret store mountpoint (without leading or trailing slash).
+     * @param mount    Secret store mount point (without leading or trailing slash).
      * @param key      Secret path.
      * @param versions Versions of the secret to undelete.
      * @throws VaultConnectorException on error
@@ -813,7 +813,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
      * Destroy secret versions from Vault.
      * Only available for KV v2 stores.
      *
-     * @param mount    Secret store mountpoint (without leading or trailing slash).
+     * @param mount    Secret store mount point (without leading or trailing slash).
      * @param key      Secret path.
      * @param versions Versions of the secret to destroy.
      * @throws VaultConnectorException on error
diff --git a/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java b/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
index 0174389..97e8597 100644
--- a/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/builder/HTTPVaultConnectorBuilder.java
@@ -33,7 +33,7 @@ import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 
 /**
- * Vault Connector Factory implementation for HTTP Vault connectors.
+ * Vault Connector Builder implementation for HTTP Vault connectors.
  *
  * @author Stefan Kalscheuer
  * @since 0.8.0
@@ -162,7 +162,7 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
     }
 
     /**
-     * Add a trusted CA certifiate for HTTPS connections.
+     * Add a trusted CA certificate for HTTPS connections.
      *
      * @param cert path to certificate file
      * @return self
@@ -179,7 +179,7 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
     }
 
     /**
-     * Add a trusted CA certifiate for HTTPS connections.
+     * Add a trusted CA certificate for HTTPS connections.
      *
      * @param cert path to certificate file
      * @return self
diff --git a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
index 8ae3d5b..4389916 100644
--- a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
+++ b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java
@@ -107,7 +107,7 @@ public final class HTTPVaultConnectorFactory extends VaultConnectorFactory {
     }
 
     /**
-     * Add a trusted CA certifiate for HTTPS connections.
+     * Add a trusted CA certificate for HTTPS connections.
      *
      * @param cert path to certificate file
      * @return self
@@ -120,7 +120,7 @@ public final class HTTPVaultConnectorFactory extends VaultConnectorFactory {
     }
 
     /**
-     * Add a trusted CA certifiate for HTTPS connections.
+     * Add a trusted CA certificate for HTTPS connections.
      *
      * @param cert path to certificate file
      * @return self
diff --git a/src/main/java/de/stklcode/jvault/connector/internal/Error.java b/src/main/java/de/stklcode/jvault/connector/internal/Error.java
index 15c0f94..f72ab65 100644
--- a/src/main/java/de/stklcode/jvault/connector/internal/Error.java
+++ b/src/main/java/de/stklcode/jvault/connector/internal/Error.java
@@ -28,7 +28,7 @@ final class Error {
     static final String UNEXPECTED_RESPONSE = "Received response where none was expected";
     static final String URI_FORMAT = "Invalid URI format";
     static final String RESPONSE_CODE = "Invalid response code";
-    static final String INIT_SSL_CONTEXT = "Unable to intialize SSLContext";
+    static final String INIT_SSL_CONTEXT = "Unable to initialize SSLContext";
 
     /**
      * Constructor hidden, this class should not be instantiated.
diff --git a/src/main/java/de/stklcode/jvault/connector/internal/RequestHelper.java b/src/main/java/de/stklcode/jvault/connector/internal/RequestHelper.java
index 560355f..00b5f1b 100644
--- a/src/main/java/de/stklcode/jvault/connector/internal/RequestHelper.java
+++ b/src/main/java/de/stklcode/jvault/connector/internal/RequestHelper.java
@@ -340,7 +340,7 @@ public final class RequestHelper implements Serializable {
                         /* Fail on different error code and/or no retries left */
                         handleError(response);
 
-                        /* Throw exception withoud details, if response entity is empty. */
+                        /* Throw exception without details, if response entity is empty. */
                         throw new InvalidResponseException(Error.RESPONSE_CODE,
                                 response.getStatusLine().getStatusCode());
                     }
@@ -362,7 +362,7 @@ public final class RequestHelper implements Serializable {
      * Create a custom socket factory from trusted CA certificate.
      *
      * @return The factory.
-     * @throws TlsException An error occured during initialization of the SSL context.
+     * @throws TlsException An error occurred during initialization of the SSL context.
      * @since 0.8.0
      */
     private SSLConnectionSocketFactory createSSLSocketFactory() throws TlsException {
@@ -376,7 +376,7 @@ public final class RequestHelper implements Serializable {
             TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
             tmf.init(keyStore);
 
-            // Create context usint this TrustManager.
+            // Create context using this TrustManager.
             SSLContext context = SSLContext.getInstance(tlsVersion);
             context.init(null, tmf.getTrustManagers(), new SecureRandom());
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
index d65c12b..db1b249 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRole.java
@@ -198,7 +198,7 @@ public final class AppRole {
     }
 
     /**
-     * @return list of bound CIDR subnets of assiciated tokens
+     * @return list of bound CIDR subnets of associated tokens
      * @since 0.9
      */
     public List<String> getTokenBoundCidrs() {
@@ -578,22 +578,22 @@ public final class AppRole {
         /**
          * Set number of uses for sectet IDs.
          *
-         * @param secredIdNumUses the number of uses
+         * @param secretIdNumUses the number of uses
          * @return self
          */
-        public Builder withSecretIdNumUses(final Integer secredIdNumUses) {
-            this.secretIdNumUses = secredIdNumUses;
+        public Builder withSecretIdNumUses(final Integer secretIdNumUses) {
+            this.secretIdNumUses = secretIdNumUses;
             return this;
         }
 
         /**
          * Set default sectet ID TTL in seconds.
          *
-         * @param secredIdTtl the TTL
+         * @param secretIdTtl the TTL
          * @return self
          */
-        public Builder withSecretIdTtl(final Integer secredIdTtl) {
-            this.secretIdTtl = secredIdTtl;
+        public Builder withSecretIdTtl(final Integer secretIdTtl) {
+            this.secretIdTtl = secretIdTtl;
             return this;
         }
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
index 9fd0e3d..7267127 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/AppRoleBuilder.java
@@ -181,24 +181,24 @@ public final class AppRoleBuilder {
     }
 
     /**
-     * Set number of uses for sectet IDs.
+     * Set number of uses for secret IDs.
      *
-     * @param secredIdNumUses the number of uses
+     * @param secretIdNumUses the number of uses
      * @return self
      */
-    public AppRoleBuilder withSecretIdNumUses(final Integer secredIdNumUses) {
-        this.secretIdNumUses = secredIdNumUses;
+    public AppRoleBuilder withSecretIdNumUses(final Integer secretIdNumUses) {
+        this.secretIdNumUses = secretIdNumUses;
         return this;
     }
 
     /**
-     * Set default sectet ID TTL in seconds.
+     * Set default secret ID TTL in seconds.
      *
-     * @param secredIdTtl the TTL
+     * @param secretIdTtl the TTL
      * @return self
      */
-    public AppRoleBuilder withSecretIdTtl(final Integer secredIdTtl) {
-        this.secretIdTtl = secredIdTtl;
+    public AppRoleBuilder withSecretIdTtl(final Integer secretIdTtl) {
+        this.secretIdTtl = secretIdTtl;
         return this;
     }
 
diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
index 3526f49..d32d087 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
@@ -136,14 +136,14 @@ public final class TokenRole {
     }
 
     /**
-     * @return Is Roken Role orphan?
+     * @return Is Token Role orphan?
      */
     public Boolean getOrphan() {
         return orphan;
     }
 
     /**
-     * @return Is Roken Role renewable?
+     * @return Is Token Role renewable?
      */
     public Boolean getRenewable() {
         return renewable;
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
index 2a6d0a0..2abd162 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/SecretVersionResponse.java
@@ -25,7 +25,7 @@ import java.io.IOException;
 import java.util.Map;
 
 /**
- * Vault response for a single secret version metatada, i.e. after update (KV v2).
+ * Vault response for a single secret version metadata, i.e. after update (KV v2).
  *
  * @author Stefan Kalscheuer
  * @since 0.8
diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
index 9243eca..d5ed06c 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthData.java
@@ -83,7 +83,7 @@ public final class AuthData {
     }
 
     /**
-     * @return List of policies associated with the ooken
+     * @return List of policies associated with the token
      * @since 0.9
      */
     public List<String> getTokenPolicies() {
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
index 5ba03fb..db06169 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorOfflineTest.java
@@ -151,7 +151,7 @@ public class HTTPVaultConnectorOfflineTest {
     }
 
     /**
-     * Test constductors of the {@link HTTPVaultConnector} class.
+     * Test constructors of the {@link HTTPVaultConnector} class.
      */
     @Test
     public void constructorTest() throws IOException, CertificateException {
diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
index 08dbb99..c808f72 100644
--- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java
@@ -948,8 +948,8 @@ public class HTTPVaultConnectorTest {
             try {
                 AppRoleResponse res = connector.lookupAppRole(roleName);
                 // Note: As of Vault 0.8.3 default policy is not added automatically, so this test should return 1, not 2.
-                assertThat("Role lookuo returned wrong policy count (before Vault 0.8.3 is should be 2)", res.getRole().getPolicies(), hasSize(1));
-                assertThat("Role lookuo returned wrong policies", res.getRole().getPolicies(), hasItem("testpolicy"));
+                assertThat("Role lookup returned wrong policy count (before Vault 0.8.3 is should be 2)", res.getRole().getPolicies(), hasSize(1));
+                assertThat("Role lookup returned wrong policies", res.getRole().getPolicies(), hasItem("testpolicy"));
             } catch (VaultConnectorException e) {
                 fail("Creation of role by name failed.");
             }
@@ -1079,7 +1079,7 @@ public class HTTPVaultConnectorTest {
                 assertThat("Root token should not be renewable", res.getAuth().isRenewable(), is(false));
                 assertThat("Root token should not be orphan", res.getAuth().isOrphan(), is(false));
 
-                // Starting with Vault 1.0 a warning "cusotm ID uses weaker SHA1..." is given.
+                // Starting with Vault 1.0 a warning "custom ID uses weaker SHA1..." is given.
                 if (VAULT_VERSION.startsWith("1.")) {
                     assertThat("Token creation did not return expected warning.", res.getWarnings(), hasSize(1));
                 } else {
@@ -1106,7 +1106,7 @@ public class HTTPVaultConnectorTest {
                 assertThat("Metadata not correct.", res.getAuth().getMetadata().get("foo"), is("bar"));
                 assertThat("Token should be renewable", res.getAuth().isRenewable(), is(true));
             } catch (VaultConnectorException e) {
-                fail("Token createion failed: " + e.getMessage());
+                fail("Token creation failed: " + e.getMessage());
             }
 
             /* Overwrite token should fail as of Vault 0.8.0 */
@@ -1146,12 +1146,12 @@ public class HTTPVaultConnectorTest {
                 assertThat("Specified token Type not set", res.getAuth().getTokenType(), is(Token.Type.BATCH.value()));
 
             } catch (VaultConnectorException e) {
-                fail("Token createion failed: " + e.getMessage());
+                fail("Token creation failed: " + e.getMessage());
             }
         }
 
         /**
-         * Test token lookuo.
+         * Test token lookup.
          */
         @Test
         @Order(30)
@@ -1268,8 +1268,8 @@ public class HTTPVaultConnectorTest {
                 fail("Token role deletion failed.");
             }
 
-            assertThrows(InvalidResponseException.class, () -> connector.readTokenRole(roleName), "Reading inexistent token role should fail");
-            assertThrows(InvalidResponseException.class, () -> connector.listTokenRoles(), "Listing inexistent token roles should fail");
+            assertThrows(InvalidResponseException.class, () -> connector.readTokenRole(roleName), "Reading nonexistent token role should fail");
+            assertThrows(InvalidResponseException.class, () -> connector.listTokenRoles(), "Listing nonexistent token roles should fail");
         }
     }
 
@@ -1405,7 +1405,7 @@ public class HTTPVaultConnectorTest {
             try {
                 connector.seal();
                 assumeTrue(connector.sealStatus().isSealed());
-                connector.resetAuth();  // SHould work unauthenticated
+                connector.resetAuth();  // Should work unauthenticated
             } catch (VaultConnectorException e) {
                 fail("Unexpected exception on sealing: " + e.getMessage());
             }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
index 3f228f6..3fa9513 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
@@ -86,7 +86,7 @@ public class TokenBuilderTest {
      * Build token without any parameters.
      */
     @Test
-    public void legadcyBuildDefaultTest() throws JsonProcessingException {
+    public void legacyBuildDefaultTest() throws JsonProcessingException {
         Token token = new TokenBuilder().build();
         assertThat(token.getId(), is(nullValue()));
         assertThat(token.getType(), is(nullValue()));
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
index 0b2d65e..a37f675 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java
@@ -77,7 +77,7 @@ public class MetadataResponseTest {
         try {
             MetadataResponse res = new ObjectMapper().readValue(META_JSON, MetadataResponse.class);
             assertThat("Parsed response is NULL", res, is(notNullValue()));
-            assertThat("Parsed metadatra is NULL", res.getMetadata(), is(notNullValue()));
+            assertThat("Parsed metadata is NULL", res.getMetadata(), is(notNullValue()));
             assertThat("Incorrect created time", res.getMetadata().getCreatedTimeString(), is(V1_TIME));
             assertThat("Parting created time failed", res.getMetadata().getCreatedTime(), is(notNullValue()));
             assertThat("Incorrect current version", res.getMetadata().getCurrentVersion(), is(CURRENT_VERSION));
@@ -87,14 +87,14 @@ public class MetadataResponseTest {
             assertThat("Parting updated time failed", res.getMetadata().getUpdatedTime(), is(notNullValue()));
             assertThat("Incorrect number of versions", res.getMetadata().getVersions().size(), is(3));
             assertThat("Incorrect version 1 delete time", res.getMetadata().getVersions().get(1).getDeletionTimeString(), is(V2_TIME));
-            assertThat("Parsion version delete time failed", res.getMetadata().getVersions().get(1).getDeletionTime(), is(notNullValue()));
+            assertThat("Parsing version delete time failed", res.getMetadata().getVersions().get(1).getDeletionTime(), is(notNullValue()));
             assertThat("Incorrect version 1 destroyed state", res.getMetadata().getVersions().get(1).isDestroyed(), is(true));
             assertThat("Incorrect version 2 created time", res.getMetadata().getVersions().get(2).getCreatedTimeString(), is(V2_TIME));
-            assertThat("Parsion version created failed", res.getMetadata().getVersions().get(2).getCreatedTime(), is(notNullValue()));
+            assertThat("Parsing version created failed", res.getMetadata().getVersions().get(2).getCreatedTime(), is(notNullValue()));
             assertThat("Incorrect version 3 destroyed state", res.getMetadata().getVersions().get(3).isDestroyed(), is(false));
 
         } catch (IOException e) {
-            fail("MetadataResoponse deserialization failed: " + e.getMessage());
+            fail("MetadataResponse deserialization failed: " + e.getMessage());
         }
     }
 }
diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
index 5422618..ca76d7d 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/response/SecretVersionResponseTest.java
@@ -54,7 +54,7 @@ public class SecretVersionResponseTest {
         try {
             SecretVersionResponse res = new ObjectMapper().readValue(META_JSON, SecretVersionResponse.class);
             assertThat("Parsed response is NULL", res, is(notNullValue()));
-            assertThat("Parsed metadatra is NULL", res.getMetadata(), is(notNullValue()));
+            assertThat("Parsed metadata is NULL", res.getMetadata(), is(notNullValue()));
             assertThat("Incorrect created time", res.getMetadata().getCreatedTimeString(), is(CREATION_TIME));
             assertThat("Incorrect deletion time", res.getMetadata().getDeletionTimeString(), is(DELETION_TIME));
             assertThat("Incorrect destroyed state", res.getMetadata().isDestroyed(), is(false));

From 1d5db0c365559bd4e25a9feb668894c6fce39011 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Sun, 26 Apr 2020 18:04:35 +0200
Subject: [PATCH 19/21] add missing fields to Token model and builder (#41)

* explicit_max_ttl
* period
* entity_alias
---
 CHANGELOG.md                                  |  1 +
 .../jvault/connector/model/Token.java         | 74 +++++++++++++++++++
 .../connector/model/TokenBuilderTest.java     | 17 ++++-
 3 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f9d280f..5be328f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
 ### Improvements
 * Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
 * Added `entity_id`, `expire_time`, `explicit_max_ttl`, `issue_time`, `renewable` and `type` flags to token data
+* Added `explicit_max_ttl`, `period` and `entity_alias` flags to _Token_ model (#41)
 * Added `enable_local_secret_ids`, `token_bound_cidrs`, `token_explicit_max_ttl`, `token_no_default_policy`, 
   `token_num_uses`, `token_period` and `token_type` flags to _AppRole_ model
 * Minor dependency updates
diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index de9995c..e0153c2 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -64,6 +64,10 @@ public final class Token {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer ttl;
 
+    @JsonProperty("explicit_max_ttl")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer explicitMaxTtl;
+
     @JsonProperty("num_uses")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Integer numUses;
@@ -80,6 +84,14 @@ public final class Token {
     @JsonInclude(JsonInclude.Include.NON_NULL)
     private Boolean renewable;
 
+    @JsonProperty("period")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer period;
+
+    @JsonProperty("entity_alias")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String entityAlias;
+
     /**
      * Construct empty {@link Token} object.
      */
@@ -163,10 +175,13 @@ public final class Token {
         this.noParent = builder.noParent;
         this.noDefaultPolicy = builder.noDefaultPolicy;
         this.ttl = builder.ttl;
+        this.explicitMaxTtl = builder.explicitMaxTtl;
         this.numUses = builder.numUses;
         this.policies = builder.policies;
         this.meta = builder.meta;
         this.renewable = builder.renewable;
+        this.period = builder.period;
+        this.entityAlias = builder.entityAlias;
     }
 
     /**
@@ -212,6 +227,14 @@ public final class Token {
         return ttl;
     }
 
+    /**
+     * @return Explicit maximum time-to-live in seconds
+     * @since 0.9
+     */
+    public Integer getExplicitMaxTtl() {
+        return explicitMaxTtl;
+    }
+
     /**
      * @return Number of uses
      */
@@ -240,6 +263,22 @@ public final class Token {
         return renewable;
     }
 
+    /**
+     * @return Token period.
+     * @since 0.9
+     */
+    public Integer getPeriod() {
+        return period;
+    }
+
+    /**
+     * @return Token entity alias.
+     * @since 0.9
+     */
+    public String getEntityAlias() {
+        return entityAlias;
+    }
+
     /**
      * Constants for token types.
      */
@@ -276,10 +315,13 @@ public final class Token {
         private Boolean noParent;
         private Boolean noDefaultPolicy;
         private Integer ttl;
+        private Integer explicitMaxTtl;
         private Integer numUses;
         private List<String> policies;
         private Map<String, String> meta;
         private Boolean renewable;
+        private Integer period;
+        private String entityAlias;
 
         /**
          * Add token ID. (optional)
@@ -326,6 +368,17 @@ public final class Token {
             return this;
         }
 
+        /**
+         * Set desired explicit maximum time to live.
+         *
+         * @param explicitMaxTtl the explicit max. TTL
+         * @return self
+         */
+        public Builder withExplicitMaxTtl(final Integer explicitMaxTtl) {
+            this.explicitMaxTtl = explicitMaxTtl;
+            return this;
+        }
+
         /**
          * Set desired number of uses.
          *
@@ -498,6 +551,27 @@ public final class Token {
             return withRenewable(false);
         }
 
+        /**
+         * Set token period (former lease time).
+         *
+         * @return self
+         */
+        public Builder withPeriod(final Integer period) {
+            this.period = period;
+            return this;
+        }
+
+        /**
+         * Set entity alias for token.
+         * Only works in combination with an associated token role.
+         *
+         * @return self
+         */
+        public Builder withEntityAlias(final String entityAlias) {
+            this.entityAlias = entityAlias;
+            return this;
+        }
+
         /**
          * Build the token based on given parameters.
          *
diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
index 3fa9513..424558d 100644
--- a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
+++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java
@@ -36,12 +36,12 @@ import static org.hamcrest.Matchers.*;
  * @since 0.4.0
  */
 public class TokenBuilderTest {
-
     private static final String ID = "test-id";
     private static final String DISPLAY_NAME = "display-name";
     private static final Boolean NO_PARENT = false;
     private static final Boolean NO_DEFAULT_POLICY = false;
     private static final Integer TTL = 123;
+    private static final Integer EXPLICIT_MAX_TTL = 456;
     private static final Integer NUM_USES = 4;
     private static final List<String> POLICIES = new ArrayList<>();
     private static final String POLICY = "policy";
@@ -53,7 +53,10 @@ public class TokenBuilderTest {
     private static final String META_KEY_2 = "key2";
     private static final String META_VALUE_2 = "value2";
     private static final Boolean RENEWABLE = true;
-    private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true}";
+    private static final Integer PERIOD = 3600;
+    private static final String ENTITY_ALIAS = "alias-value";
+    private static final String LEGACY_JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true}";
+    private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"explicit_max_ttl\":456,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true,\"period\":3600,\"entity_alias\":\"alias-value\"}";
 
     @BeforeAll
     public static void init() {
@@ -73,10 +76,13 @@ public class TokenBuilderTest {
         assertThat(token.getNoParent(), is(nullValue()));
         assertThat(token.getNoDefaultPolicy(), is(nullValue()));
         assertThat(token.getTtl(), is(nullValue()));
+        assertThat(token.getExplicitMaxTtl(), is(nullValue()));
         assertThat(token.getNumUses(), is(nullValue()));
         assertThat(token.getPolicies(), is(nullValue()));
         assertThat(token.getMeta(), is(nullValue()));
         assertThat(token.isRenewable(), is(nullValue()));
+        assertThat(token.getPeriod(), is(nullValue()));
+        assertThat(token.getEntityAlias(), is(nullValue()));
 
         /* optional fields should be ignored, so JSON string should be empty */
         assertThat(new ObjectMapper().writeValueAsString(token), is("{}"));
@@ -115,10 +121,13 @@ public class TokenBuilderTest {
                 .withNoParent(NO_PARENT)
                 .withNoDefaultPolicy(NO_DEFAULT_POLICY)
                 .withTtl(TTL)
+                .withExplicitMaxTtl(EXPLICIT_MAX_TTL)
                 .withNumUses(NUM_USES)
                 .withPolicies(POLICIES)
                 .withMeta(META)
                 .withRenewable(RENEWABLE)
+                .withPeriod(PERIOD)
+                .withEntityAlias(ENTITY_ALIAS)
                 .build();
         assertThat(token.getId(), is(ID));
         assertThat(token.getType(), is(Token.Type.SERVICE.value()));
@@ -126,10 +135,12 @@ public class TokenBuilderTest {
         assertThat(token.getNoParent(), is(NO_PARENT));
         assertThat(token.getNoDefaultPolicy(), is(NO_DEFAULT_POLICY));
         assertThat(token.getTtl(), is(TTL));
+        assertThat(token.getExplicitMaxTtl(), is(EXPLICIT_MAX_TTL));
         assertThat(token.getNumUses(), is(NUM_USES));
         assertThat(token.getPolicies(), is(POLICIES));
         assertThat(token.getMeta(), is(META));
         assertThat(token.isRenewable(), is(RENEWABLE));
+        assertThat(token.getPeriod(), is(PERIOD));
 
         /* Verify that all parameters are included in JSON string */
         assertThat(new ObjectMapper().writeValueAsString(token), is(JSON_FULL));
@@ -164,7 +175,7 @@ public class TokenBuilderTest {
         assertThat(token.isRenewable(), is(RENEWABLE));
 
         /* Verify that all parameters are included in JSON string */
-        assertThat(new ObjectMapper().writeValueAsString(token), is(JSON_FULL));
+        assertThat(new ObjectMapper().writeValueAsString(token), is(LEGACY_JSON_FULL));
     }
 
     /**

From 4fb63f097708b721b2f822821a031121b5c866ff Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 29 Apr 2020 15:24:16 +0200
Subject: [PATCH 20/21] prepare release 0.9.0

---
 CHANGELOG.md | 9 ++++++---
 README.md    | 2 +-
 pom.xml      | 4 ++--
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5be328f..27e36d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,12 @@
-## 0.9.0 (unreleased)
+## 0.9.0 (2020-04-29)
 
 ### Fixes
 * Correctly parse Map field for token metadata (#34)
-* Correctly map token policies on lookup (#35)
+* Correctly map token policies on token lookup (#35)
 
 ### Features
 * Support for token types (#26)
-* Support for token role handling (#27)
+* Support for token role handling (#27) (#37)
 
 ### Improvements
 * Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
@@ -25,6 +25,9 @@
 ### Removals
 * Deprecated methods `AppRole#getBoundCidrList()`, `#setBoundCidrList()` and `getBoundCidrListString()` have been removed.
 
+### Test
+* Tested against Vault 1.4.0
+
 
 ## 0.8.2 (2019-10-20)
 
diff --git a/README.md b/README.md
index 62f8552..99b17e5 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
 <dependency>
     <groupId>de.stklcode.jvault</groupId>
     <artifactId>jvault-connector</artifactId>
-    <version>0.8.2</version>
+    <version>0.9.0</version>
 </dependency>
 ```
 
diff --git a/pom.xml b/pom.xml
index 16bdb67..f9ac031 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
     <groupId>de.stklcode.jvault</groupId>
     <artifactId>jvault-connector</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.9.0</version>
 
     <packaging>jar</packaging>
 
@@ -112,7 +112,7 @@
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
-            <version>5.6.1</version>
+            <version>5.6.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>

From aab76273a5d6a6b4bfdca0910778b2682f57cbbc Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer <stefan@stklcode.de>
Date: Wed, 29 Apr 2020 15:47:20 +0200
Subject: [PATCH 21/21] last minute JavaDoc corrections

---
 src/main/java/de/stklcode/jvault/connector/model/Token.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java
index e0153c2..73bc25f 100644
--- a/src/main/java/de/stklcode/jvault/connector/model/Token.java
+++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java
@@ -554,6 +554,7 @@ public final class Token {
         /**
          * Set token period (former lease time).
          *
+         * @param period Period in seconds.
          * @return self
          */
         public Builder withPeriod(final Integer period) {
@@ -565,6 +566,7 @@ public final class Token {
          * Set entity alias for token.
          * Only works in combination with an associated token role.
          *
+         * @param entityAlias Entity alias.
          * @return self
          */
         public Builder withEntityAlias(final String entityAlias) {