Support full pull mode in AppRole authentication through AuthenticationSteps.

We now support full pull mode (pull/wrapped) for roleId and secretId leveraging the newly introduced zipWith operator.

Closes gh-259.
This commit is contained in:
Mark Paluch
2018-08-01 10:21:12 +02:00
parent 109973079b
commit a79898c2b9
3 changed files with 72 additions and 70 deletions

View File

@@ -102,88 +102,74 @@ public class AppRoleAuthentication implements ClientAuthentication,
RoleId roleId = options.getRoleId();
SecretId secretId = options.getSecretId();
if ((roleId instanceof Wrapped || roleId instanceof Pull)
&& (secretId instanceof Wrapped || secretId instanceof Pull)) {
throw new IllegalArgumentException(
"RoleId and SecretId are both configured to obtain their values from initial Vault request. AuthenticationSteps supports currently only fetching of a single element.");
}
return getAuthenticationSteps(options, roleId, secretId).login(
"auth/{mount}/login", options.getPath());
}
private static Node<?> getAuthenticationSteps(AppRoleAuthenticationOptions options,
private static Node<Map<String, String>> getAuthenticationSteps(
AppRoleAuthenticationOptions options,
RoleId roleId, SecretId secretId) {
if (roleId instanceof Pull || roleId instanceof Wrapped) {
Node<String> roleIdSteps = getRoleIdSteps(options, roleId);
Node<String> secretIdSteps = getSecretIdSteps(options, secretId);
Node<VaultResponse> steps;
return roleIdSteps.zipWith(secretIdSteps).map(
it -> getAppRoleLoginBody(it.getLeft(), it.getRight()));
}
if (roleId instanceof Pull) {
HttpHeaders headers = createHttpHeaders(((Pull) roleId).getInitialToken());
steps = AuthenticationSteps.fromHttpRequest(get(
"auth/{mount}/role/{role}/role-id", options.getPath(),
options.getAppRole()).with(headers).as(VaultResponse.class));
}
else {
steps = unwrapResponse(((Wrapped) roleId).getInitialToken());
}
return steps.map(
vaultResponse -> (String) vaultResponse.getRequiredData().get(
"role_id")).map(
roleIdToken -> {
return getAppRoleLoginBody(
roleIdToken,
secretId instanceof Provided ? ((Provided) secretId)
.getValue() : null);
});
}
if (secretId instanceof Pull || secretId instanceof Wrapped) {
Node<VaultResponse> steps;
if (secretId instanceof Pull) {
HttpHeaders headers = createHttpHeaders(((Pull) secretId)
.getInitialToken());
steps = AuthenticationSteps.fromHttpRequest(post(
"auth/{mount}/role/{role}/secret-id", options.getPath(),
options.getAppRole()).with(headers).as(VaultResponse.class));
}
else {
steps = unwrapResponse(((Wrapped) secretId).getInitialToken());
}
return steps.map(
vaultResponse -> (String) vaultResponse.getRequiredData().get(
"secret_id")).map(
secretIdToken -> {
return getAppRoleLoginBody(
roleId instanceof Provided ? ((Provided) roleId)
.getValue() : null, secretIdToken);
});
}
private static Node<String> getRoleIdSteps(AppRoleAuthenticationOptions options,
RoleId roleId) {
if (roleId instanceof Provided) {
return AuthenticationSteps.fromSupplier(() -> {
return getAppRoleLoginBody(((Provided) roleId).getValue(),
secretId instanceof Provided ? ((Provided) secretId).getValue()
: null);
});
return AuthenticationSteps.fromSupplier(((Provided) roleId)::getValue);
}
throw new IllegalArgumentException(String.format(
"Provided RoleId/SecretId setup not supported. RoleId: %s, SecretId: %s",
roleId, secretId));
if (roleId instanceof Pull) {
HttpHeaders headers = createHttpHeaders(((Pull) roleId).getInitialToken());
return AuthenticationSteps.fromHttpRequest(
get("auth/{mount}/role/{role}/role-id", options.getPath(),
options.getAppRole()).with(headers).as(VaultResponse.class))
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get(
"role_id"));
}
if (roleId instanceof Wrapped) {
return unwrapResponse(((Wrapped) roleId).getInitialToken()).map(
vaultResponse -> (String) vaultResponse.getRequiredData().get(
"role_id"));
}
throw new IllegalArgumentException("Unknown RoleId configuration: " + roleId);
}
private static Node<String> getSecretIdSteps(AppRoleAuthenticationOptions options,
SecretId secretId) {
if (secretId instanceof Provided) {
return AuthenticationSteps.fromSupplier(((Provided) secretId)::getValue);
}
if (secretId instanceof Pull) {
HttpHeaders headers = createHttpHeaders(((Pull) secretId).getInitialToken());
return AuthenticationSteps.fromHttpRequest(
post("auth/{mount}/role/{role}/secret-id", options.getPath(),
options.getAppRole()).with(headers).as(VaultResponse.class))
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get(
"secret_id"));
}
if (secretId instanceof Wrapped) {
return unwrapResponse(((Wrapped) secretId).getInitialToken()).map(
vaultResponse -> (String) vaultResponse.getRequiredData().get(
"secret_id"));
}
throw new IllegalArgumentException("Unknown SecretId configuration: " + secretId);
}
private static Node<VaultResponse> unwrapResponse(VaultToken token) {

View File

@@ -29,6 +29,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.Value;
import lombok.experimental.FieldDefaults;
@@ -575,6 +576,8 @@ public class AuthenticationSteps {
* @param <R>
* @since 2.1
*/
@EqualsAndHashCode
@ToString
public static class Pair<L, R> {
private final L left;

View File

@@ -74,6 +74,19 @@ public class AppRoleAuthenticationStepsIntegrationTests extends
assertThat(executor.login()).isNotNull();
}
@Test
public void shouldAuthenticateWithFullPullMode() {
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
.appRole("with-secret-id").initialToken(Settings.token()).build();
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(
AppRoleAuthentication.createAuthenticationSteps(options), prepare()
.getRestTemplate());
assertThat(executor.login()).isNotNull();
}
@Test
public void authenticationStepsShouldAuthenticateWithPullSecretId() {