From 53a459eda15d5624828ab0c098341f531dab0f6f Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Mon, 17 Oct 2016 16:28:34 +0200 Subject: [PATCH] Token metamodel implemented --- .../jvault/connector/HTTPVaultConnector.java | 7 + .../jvault/connector/VaultConnector.java | 10 + .../jvault/connector/model/Token.java | 117 +++++++++ .../jvault/connector/model/TokenBuilder.java | 247 ++++++++++++++++++ .../connector/model/TokenBuilderTest.java | 160 ++++++++++++ 5 files changed, 541 insertions(+) create mode 100644 src/main/java/de/stklcode/jvault/connector/model/Token.java create mode 100644 src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java create mode 100644 src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 33d2302..471a8cc 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import de.stklcode.jvault.connector.exception.*; import de.stklcode.jvault.connector.model.AuthBackend; +import de.stklcode.jvault.connector.model.Token; import de.stklcode.jvault.connector.model.response.*; import de.stklcode.jvault.connector.model.response.embedded.AuthMethod; import org.apache.http.HttpResponse; @@ -338,6 +339,12 @@ public class HTTPVaultConnector implements VaultConnector { return null; } + @Override + public TokenResponse createToken(final Token token) throws VaultConnectorException { + /* TODO */ + return null; + } + /** * Execute HTTP request using POST method. diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java index 4ededc7..48f59ec 100644 --- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java @@ -18,6 +18,7 @@ package de.stklcode.jvault.connector; import de.stklcode.jvault.connector.exception.VaultConnectorException; import de.stklcode.jvault.connector.model.AuthBackend; +import de.stklcode.jvault.connector.model.Token; import de.stklcode.jvault.connector.model.response.*; import java.util.List; @@ -208,4 +209,13 @@ public interface VaultConnector { * @return Renewed lease */ VaultResponse renew(final String leaseID, final Integer seconds); + + /** + * Create a new token. + * + * @param token the token + * @return the result response + * @throws VaultConnectorException on error + */ + TokenResponse createToken(final Token token) throws VaultConnectorException; } diff --git a/src/main/java/de/stklcode/jvault/connector/model/Token.java b/src/main/java/de/stklcode/jvault/connector/model/Token.java new file mode 100644 index 0000000..ee641ec --- /dev/null +++ b/src/main/java/de/stklcode/jvault/connector/model/Token.java @@ -0,0 +1,117 @@ +/* + * Copyright 2016 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; +import java.util.Map; + +/** + * Vault Token metamodel. + * + * @author Stefan Kalscheuer + * @since 0.4.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Token { + @JsonProperty("id") + @JsonInclude(JsonInclude.Include.NON_NULL) + private String id; + + @JsonProperty("display_name") + @JsonInclude(JsonInclude.Include.NON_NULL) + private String displayName; + + @JsonProperty("no_parent") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean noParent; + + @JsonProperty("no_default_policy") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean noDefaultPolicy; + + @JsonProperty("ttl") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Integer ttl; + + @JsonProperty("num_uses") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Integer numUses; + + @JsonProperty("policies") + @JsonInclude(JsonInclude.Include.NON_NULL) + private List policies; + + @JsonProperty("meta") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Map meta; + + @JsonProperty("renewable") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean renewable; + + public Token(String id, String displayName, Boolean noParent, Boolean noDefaultPolicy, Integer ttl, Integer numUses, List policies, Map meta, Boolean renewable) { + this.id = id; + this.displayName = displayName; + this.ttl = ttl; + this.numUses = numUses; + this.noParent = noParent; + this.noDefaultPolicy = noDefaultPolicy; + this.policies = policies; + this.meta = meta; + this.renewable = renewable; + } + + public String getId() { + return id; + } + + public String getDisplayName() { + return displayName; + } + + public Boolean getNoParent() { + return noParent; + } + + public Boolean getNoDefaultPolicy() { + return noDefaultPolicy; + } + + public Integer getTtl() { + return ttl; + } + + public Integer getNumUses() { + return numUses; + } + + public List getPolicies() { + return policies; + } + + public Map getMeta() { + return meta; + } + + public Boolean isRenewable() { + return renewable; + } +} diff --git a/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java new file mode 100644 index 0000000..4dce766 --- /dev/null +++ b/src/main/java/de/stklcode/jvault/connector/model/TokenBuilder.java @@ -0,0 +1,247 @@ +/* + * Copyright 2016 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.JsonProperty; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A builder for vault tokens. + * + * @author Stefan Kalscheuer + * @since 0.4.0 + */ +public class TokenBuilder { + private String id; + private String displayName; + private Boolean noParent; + private Boolean noDefaultPolicy; + private Integer ttl; + private Integer numUses; + private List policies; + private Map meta; + private Boolean renewable; + + /** + * Add token ID (optional) + * + * @param id the ID + * @return self + */ + public TokenBuilder withId(final String id) { + this.id = id; + return this; + } + + /** + * Add display name + * + * @param displayName the display name + * @return self + */ + public TokenBuilder withDisplayName(final String displayName) { + this.displayName = displayName; + return this; + } + + /** + * Set desired time to live. + * @param ttl the ttl + * @return self + */ + public TokenBuilder withTtl(final Integer ttl) { + this.ttl = ttl; + return this; + } + + /** + * Set desired number of uses. + * @param numUses the number of uses + * @return self + */ + public TokenBuilder 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 TokenBuilder withNoParent(final boolean noParent) { + this.noParent = noParent; + return this; + } + + /** + * Create token without parent. + * Convenience method for withNoParent() + * + * @return self + */ + public TokenBuilder asOrphan() { + return withNoParent(true); + } + + /** + * Create token with parent. + * Convenience method for withNoParent() + * + * @return self + */ + public TokenBuilder 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 TokenBuilder withNoDefaultPolicy(final boolean noDefaultPolicy) { + this.noDefaultPolicy = noDefaultPolicy; + return this; + } + + /** + * Attach default policy to token. + * Convenience method for withNoDefaultPolicy() + * + * @return self + */ + public TokenBuilder withDefaultPolicy() { + return withNoDefaultPolicy(false); + } + + /** + * Do not attach default policy to token. + * Convenience method for withNoDefaultPolicy() + * + * @return self + */ + public TokenBuilder withoutDefaultPolicy() { + return withNoDefaultPolicy(true); + } + + /** + * Add given policies + * + * @param policies the policies + * @return self + */ + public TokenBuilder withPolicies(final List 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 TokenBuilder 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 TokenBuilder withMeta(final Map 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 TokenBuilder 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 TokenBuilder withRenewable(final Boolean renewable) { + this.renewable = renewable; + return this; + } + + /** + * Set token to be renewable. + * Convenience method for withRenewable() + * + * @return self + */ + public TokenBuilder renewable() { + return withRenewable(true); + } + + /** + * Set token to be not renewable. + * Convenience method for withRenewable() + * + * @return self + */ + public TokenBuilder notRenewable() { + return withRenewable(false); + } + + /** + * Build the token based on given parameters. + * + * @return the token + */ + public Token build() { + return new Token(id, + displayName, + noParent, + noDefaultPolicy, + ttl, + numUses, + policies, + meta, + renewable); + } +} diff --git a/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java new file mode 100644 index 0000000..6329a27 --- /dev/null +++ b/src/test/java/de/stklcode/jvault/connector/model/TokenBuilderTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2016 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.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * JUnit Test for Token Builder. + * + * @author Stefan Kalscheuer + * @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 NUM_USES = 4; + private static final List POLICIES = new ArrayList<>(); + private static final String POLICY = "policy"; + private static final String POLICY_2 = "policy"; + private static final Map META = new HashMap<>(); + private static final String META_KEY = "key"; + private static final String META_VALUE = "value"; + 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}"; + + @BeforeClass + public static void init() { + POLICIES.add(POLICY); + META.put(META_KEY, META_VALUE); + } + + /** + * Build token without any parameters. + */ + @Test + public void buildDefaultTest() throws JsonProcessingException { + Token token = new TokenBuilder().build(); + assertThat(token.getId(), 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 all parameters set. + */ + @Test + public void buildFullTest() throws JsonProcessingException { + Token token = new TokenBuilder() + .withId(ID) + .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.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)); + } + + /** + * Test convenience methods + */ + @Test + public void convenienceMethodsTest() { + /* Parent */ + Token token = new TokenBuilder().asOrphan().build(); + assertThat(token.getNoParent(), is(true)); + token = new TokenBuilder().withParent().build(); + assertThat(token.getNoParent(), is(false)); + + /* Default policy */ + token = new TokenBuilder().withDefaultPolicy().build(); + assertThat(token.getNoDefaultPolicy(), is(false)); + token = new TokenBuilder().withoutDefaultPolicy().build(); + assertThat(token.getNoDefaultPolicy(), is(true)); + + /* Renewability */ + token = new TokenBuilder().renewable().build(); + assertThat(token.isRenewable(), is(true)); + token = new TokenBuilder().notRenewable().build(); + assertThat(token.isRenewable(), is(false)); + + /* Add single policy */ + token = new TokenBuilder().withPolicy(POLICY_2).build(); + assertThat(token.getPolicies(), hasSize(1)); + assertThat(token.getPolicies(), contains(POLICY_2)); + token = new TokenBuilder() + .withPolicies(POLICIES) + .withPolicy(POLICY_2) + .build(); + assertThat(token.getPolicies(), hasSize(2)); + assertThat(token.getPolicies(), contains(POLICY, POLICY_2)); + + /* Add single metadata */ + token = new TokenBuilder().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 = new TokenBuilder() + .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)); + } +}