Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ public interface VaultTokenOperations {
*/
VaultTokenResponse create(VaultTokenRequest request) throws VaultException;

/**
* Create a new token for the given {@code role}.
* @param role must not be {@literal null}.
* @return a {@link VaultTokenResponse}
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
* /auth/token/create/:role</a>
*/
VaultTokenResponse create(String role) throws VaultException;

/**
* Create a new token for the given {@code role} and {@link VaultTokenRequest}.
* @param role must not be {@literal null}.
* @param request must not be {@literal null}.
* @return a {@link VaultTokenResponse}
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
* /auth/token/create/:role</a>
*/
VaultTokenResponse create(String role, VaultTokenRequest request) throws VaultException;

/**
* Create a new orphan token.
* @return a {@link VaultTokenResponse}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.vault.VaultException;
import org.springframework.vault.client.VaultResponses;
import org.springframework.vault.support.VaultResponseSupport;
import org.springframework.vault.support.VaultToken;
Expand Down Expand Up @@ -62,6 +63,21 @@ public VaultTokenResponse create(VaultTokenRequest request) {
return writeAndReturn("auth/token/create", request, VaultTokenResponse.class);
}

@Override
public VaultTokenResponse create(String role) throws VaultException {

return create(role, VaultTokenRequest.builder().build());
}

@Override
public VaultTokenResponse create(String role, VaultTokenRequest request) throws VaultException {

Assert.notNull(role, "role must not be null");
Assert.notNull(request, "VaultTokenRequest must not be null");

return writeAndReturn("auth/token/create/%s".formatted(role), request, VaultTokenResponse.class);
}

@Override
public VaultTokenResponse createOrphan() {
return createOrphan(VaultTokenRequest.builder().build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.stream.StreamSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Expand Down Expand Up @@ -63,9 +64,12 @@ public class VaultTokenRequest {
@JsonProperty("num_uses")
private final int numUses;

@JsonProperty("entity_alias")
private final String entityAlias;

VaultTokenRequest(@Nullable String id, List<String> policies, Map<String, String> meta, boolean noParent,
boolean noDefaultPolicy, boolean renewable, @Nullable String ttl, @Nullable String explicitMaxTtl,
String displayName, int numUses) {
String displayName, int numUses, String entityAlias) {

this.id = id;
this.policies = policies;
Expand All @@ -77,6 +81,7 @@ public class VaultTokenRequest {
this.explicitMaxTtl = explicitMaxTtl;
this.displayName = displayName;
this.numUses = numUses;
this.entityAlias = entityAlias;
}

/**
Expand Down Expand Up @@ -160,6 +165,15 @@ public int getNumUses() {
return this.numUses;
}

/**
* @return then name of the entity alias to associate with during token creation. Only
* works in combination with role_name argument and used entity alias must be listed
* in allowed_entity_aliases
*/
public String getEntityAlias() {
return this.entityAlias;
}

/**
* Builder to build a {@link VaultTokenRequest}.
*/
Expand Down Expand Up @@ -188,6 +202,8 @@ public static class VaultTokenRequestBuilder {

private int numUses;

private String entityAlias;

VaultTokenRequestBuilder() {
}

Expand Down Expand Up @@ -398,45 +414,45 @@ public VaultTokenRequestBuilder displayName(String displayName) {
return this;
}

/**
* Configure the entity alias for the token.
* @param entityAlias must not be empty or {@literal null}.
* @return {@code this} {@link VaultTokenRequestBuilder}.
*/
public VaultTokenRequestBuilder entityAlias(String entityAlias) {

Assert.hasText(entityAlias, "Entity alias must not be empty");

this.entityAlias = entityAlias;
return this;
}

/**
* Build a new {@link VaultTokenRequest} instance.
* @return a new {@link VaultCertificateRequest}.
*/
/**
* Build a new {@link VaultTokenRequest} instance.
* @return a new {@link VaultCertificateRequest}.
*/
public VaultTokenRequest build() {

List<String> policies;
switch (this.policies.size()) {
case 0:
policies = Collections.emptyList();
break;
case 1:
policies = Collections.singletonList(this.policies.get(0));
break;
default:
policies = Collections.unmodifiableList(new ArrayList<>(this.policies));

}
Map<String, String> meta;
switch (this.meta.size()) {
case 0:
meta = Collections.emptyMap();
break;
default:
meta = Collections.unmodifiableMap(new LinkedHashMap<>(this.meta));
}
List<String> policies = switch (this.policies.size()) {
case 0 -> List.of();
case 1 -> List.of(this.policies.get(0));
default -> List.copyOf(this.policies);
};
Map<String, String> meta = switch (this.meta.size()) {
case 0 -> Map.of();
default -> Collections.unmodifiableMap(new LinkedHashMap<>(this.meta));
};

return new VaultTokenRequest(this.id, policies, meta, this.noParent, this.noDefaultPolicy, this.renewable,
this.ttl, this.explicitMaxTtl, this.displayName, this.numUses);
this.ttl, this.explicitMaxTtl, this.displayName, this.numUses, this.entityAlias);
}

private static <E> List<E> toList(Iterable<E> iter) {

List<E> list = new ArrayList<>();
for (E item : iter) {
list.add(item);
}

return list;
return StreamSupport.stream(iter.spliterator(), false).toList();
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;

import org.junit.jupiter.api.BeforeEach;
Expand All @@ -38,7 +39,9 @@
import org.springframework.vault.util.IntegrationTestSupport;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* Integration tests for {@link VaultTokenTemplate} through {@link VaultTokenOperations}.
Expand Down Expand Up @@ -85,6 +88,34 @@ void createTokenShouldCreateACustomizedToken() {
assertThat(tokenResponse.getAuth()).containsEntry("client_token", tokenRequest.getId());
}

@Test
void createTokenWithRoleShouldCreateAToken() {

prepare().getVaultOperations()
.doWithSession(template -> template.postForEntity("auth/token/roles/my-role", Map.of(), String.class));

VaultTokenResponse tokenResponse = this.tokenOperations.create("my-role");
assertThat(tokenResponse.getAuth()).containsKey("client_token");
}

@Test
void noTokenWhenRoleDoesNotExists() {

assertThatThrownBy(() -> this.tokenOperations.create("unknown-role")).isInstanceOf(VaultException.class);
}

@Test
void createTokenWithEntityAliasShouldCreateAToken() {

prepare().getVaultOperations()
.doWithSession(template -> template.postForEntity("auth/token/roles/my-role",
Map.of("allowed_entity_aliases", "my-entity-alias"), String.class));

VaultTokenResponse tokenResponse = this.tokenOperations.create("my-role",
VaultTokenRequest.builder().entityAlias("my-entity-alias").build());
assertThat(tokenResponse.getAuth()).containsKey("client_token");
}

@Test
void createOrphanTokenShouldCreateAToken() {

Expand Down