Allow AWS-EC2 nonce configuration.

We now allow nonce configuration via Nonce.generated()/Nonce.provided() and use with AwsEc2AuthenticationOptions.

Closes gh-89.
This commit is contained in:
Mark Paluch
2017-05-11 16:34:25 +02:00
parent 278f0f80d2
commit 86867badcc
4 changed files with 116 additions and 12 deletions

View File

@@ -100,6 +100,13 @@
<version>1.16.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.7.16</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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<String, String> getEc2Login() {
return Collections.singletonMap("pkcs7", "value");
}
};
AwsEc2Authentication authentication = new AwsEc2Authentication(
authenticationOptions, restTemplate, restTemplate);
VaultToken login = authentication.login();