diff --git a/spring-vault-core/pom.xml b/spring-vault-core/pom.xml
index 00bac19c..a47ceb9e 100644
--- a/spring-vault-core/pom.xml
+++ b/spring-vault-core/pom.xml
@@ -100,6 +100,13 @@
1.16.10
true
+
+
+ org.slf4j
+ slf4j-jcl
+ 1.7.16
+ test
+
diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2Authentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2Authentication.java
index d6316189..d79ab504 100644
--- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2Authentication.java
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2Authentication.java
@@ -17,7 +17,6 @@ package org.springframework.vault.authentication;
import java.util.HashMap;
import java.util.Map;
-import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
@@ -159,6 +158,6 @@ public class AwsEc2Authentication implements ClientAuthentication {
}
protected char[] createNonce() {
- return UUID.randomUUID().toString().toCharArray();
+ return options.getNonce().getValue();
}
}
diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2AuthenticationOptions.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2AuthenticationOptions.java
index 5e6462c5..f26abf1e 100644
--- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2AuthenticationOptions.java
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/AwsEc2AuthenticationOptions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.vault.authentication;
import java.net.URI;
+import java.util.Arrays;
+import java.util.UUID;
import org.springframework.util.Assert;
@@ -59,15 +61,23 @@ public class AwsEc2AuthenticationOptions {
*/
private final String role;
+ /**
+ * Authentication nonce.
+ */
+ private final Nonce nonce;
+
private AwsEc2AuthenticationOptions() {
- this(DEFAULT_AWS_AUTHENTICATION_PATH, DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI, "");
+ this(DEFAULT_AWS_AUTHENTICATION_PATH, DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI, "",
+ Nonce.generated());
}
- private AwsEc2AuthenticationOptions(String path, URI identityDocumentUri, String role) {
+ private AwsEc2AuthenticationOptions(String path, URI identityDocumentUri,
+ String role, Nonce nonce) {
this.path = path;
this.identityDocumentUri = identityDocumentUri;
this.role = role;
+ this.nonce = nonce;
}
/**
@@ -98,6 +108,13 @@ public class AwsEc2AuthenticationOptions {
return role;
}
+ /**
+ * @return the configured {@link Nonce}.
+ */
+ public Nonce getNonce() {
+ return nonce;
+ }
+
/**
* Builder for {@link AwsEc2AuthenticationOptionsBuilder}.
*/
@@ -106,6 +123,7 @@ public class AwsEc2AuthenticationOptions {
private String path = DEFAULT_AWS_AUTHENTICATION_PATH;
private URI identityDocumentUri = DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI;
private String role;
+ private Nonce nonce = Nonce.generated();
AwsEc2AuthenticationOptionsBuilder() {
}
@@ -152,6 +170,22 @@ public class AwsEc2AuthenticationOptions {
return this;
}
+ /**
+ * Configure a {@link Nonce} for login requests. Defaults to
+ * {@link Nonce#generated()}.
+ *
+ * @param nonce must not be {@literal null}.
+ * @return {@code this} {@link AwsEc2AuthenticationOptionsBuilder}.
+ * @since 1.1
+ */
+ public AwsEc2AuthenticationOptionsBuilder nonce(Nonce nonce) {
+
+ Assert.notNull(nonce, "Nonce must not be null");
+
+ this.nonce = nonce;
+ return this;
+ }
+
/**
* Build a new {@link AwsEc2AuthenticationOptions} instance.
*
@@ -161,7 +195,63 @@ public class AwsEc2AuthenticationOptions {
Assert.notNull(identityDocumentUri, "IdentityDocumentUri must not be null");
- return new AwsEc2AuthenticationOptions(path, identityDocumentUri, role);
+ return new AwsEc2AuthenticationOptions(path, identityDocumentUri, role, nonce);
+ }
+ }
+
+ /**
+ * Value object for an authentication nonce.
+ *
+ * @since 1.1
+ */
+ public static class Nonce {
+
+ private final char[] value;
+
+ protected Nonce(char[] value) {
+ this.value = value;
+ }
+
+ /**
+ * Create a new generated {@link Nonce} using {@link UUID}.
+ *
+ * @return a new generated {@link Nonce} using {@link UUID}.
+ */
+ public static Nonce generated() {
+ return new Generated();
+ }
+
+ /**
+ * Create a wrapped {@link Nonce} given a {@code nonce} value.
+ *
+ * @return a wrapped {@link Nonce} given for the {@code nonce} value.
+ */
+ public static Nonce provided(char[] nonce) {
+
+ Assert.notNull(nonce, "Nonce must not be null");
+
+ return new Provided(Arrays.copyOf(nonce, nonce.length));
+ }
+
+ /**
+ * @return the nonce value.
+ */
+ public char[] getValue() {
+ return value;
+ }
+
+ static class Generated extends Nonce {
+
+ Generated() {
+ super(UUID.randomUUID().toString().toCharArray());
+ }
+ }
+
+ static class Provided extends Nonce {
+
+ Provided(char[] nonce) {
+ super(nonce);
+ }
}
}
}
diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/AwsEc2AuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/AwsEc2AuthenticationUnitTests.java
index 8e619348..3d5da10c 100644
--- a/spring-vault-core/src/test/java/org/springframework/vault/authentication/AwsEc2AuthenticationUnitTests.java
+++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/AwsEc2AuthenticationUnitTests.java
@@ -25,6 +25,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.vault.VaultException;
+import org.springframework.vault.authentication.AwsEc2AuthenticationOptions.Nonce;
import org.springframework.vault.client.VaultClients;
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
import org.springframework.vault.support.VaultToken;
@@ -94,9 +95,20 @@ public class AwsEc2AuthenticationUnitTests {
@Test
public void shouldLogin() throws Exception {
+ Nonce nonce = Nonce.provided("foo".toCharArray());
+
+ AwsEc2AuthenticationOptions authenticationOptions = AwsEc2AuthenticationOptions
+ .builder().nonce(nonce).build();
+
+ mockRest.expect(
+ requestTo("http://169.254.169.254/latest/dynamic/instance-identity/pkcs7")) //
+ .andExpect(method(HttpMethod.GET)) //
+ .andRespond(withSuccess().body("value"));
+
mockRest.expect(requestTo("/auth/aws-ec2/login"))
.andExpect(method(HttpMethod.POST))
.andExpect(jsonPath("$.pkcs7").value("value"))
+ .andExpect(jsonPath("$.nonce").value("foo"))
.andRespond(
withSuccess()
.contentType(MediaType.APPLICATION_JSON)
@@ -104,12 +116,8 @@ public class AwsEc2AuthenticationUnitTests {
+ "\"auth\":{\"client_token\":\"my-token\", \"lease_duration\":20}"
+ "}"));
- AwsEc2Authentication authentication = new AwsEc2Authentication(restTemplate) {
- @Override
- protected Map getEc2Login() {
- return Collections.singletonMap("pkcs7", "value");
- }
- };
+ AwsEc2Authentication authentication = new AwsEc2Authentication(
+ authenticationOptions, restTemplate, restTemplate);
VaultToken login = authentication.login();