Provide AuthenticationSteps for token authentication with self-lookup.
Closes gh-158.
This commit is contained in:
@@ -131,7 +131,10 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
String.format(
|
||||
"Cannot retrieve VaultToken from authentication chain. Got instead %s",
|
||||
stateObject));
|
||||
});
|
||||
})
|
||||
.onErrorMap(
|
||||
t -> new VaultException(
|
||||
"Cannot retrieve VaultToken from authentication chain", t));
|
||||
}
|
||||
|
||||
private static Object doSupplierStep(SupplierStep<Object> supplierStep) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.vault.authentication;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
@@ -40,15 +41,35 @@ class LoginTokenUtil {
|
||||
Assert.notNull(auth, "Authentication must not be null");
|
||||
|
||||
String token = (String) auth.get("client_token");
|
||||
|
||||
return from(token.toCharArray(), auth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link LoginToken} from an auth response.
|
||||
*
|
||||
* @param auth {@link Map} holding a login response.
|
||||
* @return the {@link LoginToken}
|
||||
* @since 2.0
|
||||
*/
|
||||
static LoginToken from(char[] token, Map<String, Object> auth) {
|
||||
|
||||
Assert.notNull(auth, "Authentication must not be null");
|
||||
|
||||
Boolean renewable = (Boolean) auth.get("renewable");
|
||||
Number leaseDuration = (Number) auth.get("lease_duration");
|
||||
|
||||
if (leaseDuration == null) {
|
||||
leaseDuration = (Number) auth.get("ttl");
|
||||
}
|
||||
|
||||
if (renewable != null && renewable) {
|
||||
return LoginToken.renewable(token, leaseDuration.longValue());
|
||||
return LoginToken.renewable(token,
|
||||
Duration.ofSeconds(leaseDuration.longValue()));
|
||||
}
|
||||
|
||||
if (leaseDuration != null) {
|
||||
return LoginToken.of(token, leaseDuration.longValue());
|
||||
return LoginToken.of(token, Duration.ofSeconds(leaseDuration.longValue()));
|
||||
}
|
||||
|
||||
return LoginToken.of(token);
|
||||
|
||||
@@ -15,9 +15,17 @@
|
||||
*/
|
||||
package org.springframework.vault.authentication;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.authentication.AuthenticationSteps.HttpRequest;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
|
||||
import static org.springframework.vault.authentication.AuthenticationSteps.HttpRequestBuilder.get;
|
||||
|
||||
/**
|
||||
* Static Token-based {@link ClientAuthentication} method.
|
||||
*
|
||||
@@ -59,13 +67,27 @@ public class TokenAuthentication implements ClientAuthentication,
|
||||
* {@link VaultToken}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param selfLookup {@literal true} to perform a self-lookup using the given
|
||||
* {@link VaultToken}. Self-lookup will create a {@link LoginToken} and provide
|
||||
* renewability and TTL.
|
||||
* @return {@link AuthenticationSteps} for token authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(VaultToken token) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(VaultToken token,
|
||||
boolean selfLookup) {
|
||||
|
||||
Assert.notNull(token, "VaultToken must not be null");
|
||||
|
||||
if (selfLookup) {
|
||||
|
||||
HttpRequest<VaultResponse> httpRequest = get("auth/token/lookup-self").with(
|
||||
VaultHttpHeaders.from(token)).as(VaultResponse.class);
|
||||
|
||||
return AuthenticationSteps.fromHttpRequest(httpRequest).login(
|
||||
response -> LoginTokenUtil.from(token.toCharArray(),
|
||||
response.getRequiredData()));
|
||||
}
|
||||
|
||||
return AuthenticationSteps.just(token);
|
||||
}
|
||||
|
||||
@@ -76,6 +98,10 @@ public class TokenAuthentication implements ClientAuthentication,
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(this.token);
|
||||
return createAuthenticationSteps(this.token, false);
|
||||
}
|
||||
|
||||
private static Duration getLeaseDuration(@Nullable Number ttl) {
|
||||
return ttl == null ? Duration.ZERO : Duration.ofSeconds(ttl.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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 org.springframework.vault.authentication;
|
||||
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
|
||||
/**
|
||||
* Integration test base class for {@link TokenAuthentication} tests.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class TokenAuthenticationIntegrationTestBase extends
|
||||
IntegrationTestSupport {
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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 org.springframework.vault.authentication;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestWebClientFactory;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link TokenAuthentication} using
|
||||
* {@link AuthenticationStepsOperator}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class TokenAuthenticationOperatorIntegrationTests extends
|
||||
TokenAuthenticationIntegrationTestBase {
|
||||
|
||||
WebClient webClient = TestWebClientFactory.create(Settings.createSslConfiguration());
|
||||
|
||||
@Test
|
||||
public void shouldSelfLookup() {
|
||||
|
||||
VaultTokenRequest tokenRequest = VaultTokenRequest.builder()
|
||||
.ttl(Duration.ofSeconds(60)).renewable().numUses(1).build();
|
||||
|
||||
VaultToken token = prepare().getVaultOperations().opsForToken()
|
||||
.create(tokenRequest).getToken();
|
||||
|
||||
AuthenticationStepsOperator operator = new AuthenticationStepsOperator(
|
||||
TokenAuthentication.createAuthenticationSteps(token, true), webClient);
|
||||
|
||||
StepVerifier
|
||||
.create(operator.getVaultToken())
|
||||
.consumeNextWith(
|
||||
actual -> {
|
||||
|
||||
assertThat(actual).isInstanceOf(LoginToken.class);
|
||||
|
||||
LoginToken loginToken = (LoginToken) actual;
|
||||
|
||||
assertThat(loginToken.getLeaseDuration()).isBetween(
|
||||
Duration.ofSeconds(40), Duration.ofSeconds(60));
|
||||
assertThat(loginToken.isRenewable()).isTrue();
|
||||
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailDuringSelfLookup() {
|
||||
|
||||
VaultTokenRequest tokenRequest = VaultTokenRequest.builder()
|
||||
.ttl(Duration.ofSeconds(60)).renewable().numUses(1).build();
|
||||
|
||||
VaultToken token = prepare().getVaultOperations().opsForToken()
|
||||
.create(tokenRequest).getToken();
|
||||
|
||||
AuthenticationStepsOperator operator = new AuthenticationStepsOperator(
|
||||
TokenAuthentication.createAuthenticationSteps(token, true), webClient);
|
||||
|
||||
// first usage
|
||||
StepVerifier.create(operator.getVaultToken()).expectNextCount(1).verifyComplete();
|
||||
|
||||
StepVerifier.create(operator.getVaultToken()).expectError(VaultException.class)
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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 org.springframework.vault.authentication;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link TokenAuthentication} using
|
||||
* {@link AuthenticationStepsExecutor}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class TokenAuthenticationStepsIntegrationTests extends
|
||||
TokenAuthenticationIntegrationTestBase {
|
||||
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration());
|
||||
|
||||
@Test
|
||||
public void shouldSelfLookup() {
|
||||
|
||||
VaultTokenRequest tokenRequest = VaultTokenRequest.builder()
|
||||
.ttl(Duration.ofSeconds(60)).renewable().numUses(1).build();
|
||||
|
||||
VaultToken token = prepare().getVaultOperations().opsForToken()
|
||||
.create(tokenRequest).getToken();
|
||||
|
||||
AuthenticationStepsExecutor operator = new AuthenticationStepsExecutor(
|
||||
TokenAuthentication.createAuthenticationSteps(token, true), restTemplate);
|
||||
|
||||
VaultToken login = operator.login();
|
||||
assertThat(login).isInstanceOf(LoginToken.class);
|
||||
|
||||
LoginToken loginToken = (LoginToken) login;
|
||||
|
||||
assertThat(loginToken.getLeaseDuration()).isBetween(Duration.ofSeconds(40),
|
||||
Duration.ofSeconds(60));
|
||||
assertThat(loginToken.isRenewable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailDuringSelfLookup() {
|
||||
|
||||
VaultTokenRequest tokenRequest = VaultTokenRequest.builder()
|
||||
.ttl(Duration.ofSeconds(60)).renewable().numUses(1).build();
|
||||
|
||||
VaultToken token = prepare().getVaultOperations().opsForToken()
|
||||
.create(tokenRequest).getToken();
|
||||
|
||||
AuthenticationStepsExecutor operator = new AuthenticationStepsExecutor(
|
||||
TokenAuthentication.createAuthenticationSteps(token, true), restTemplate);
|
||||
|
||||
operator.login();
|
||||
assertThatThrownBy(operator::login).isInstanceOf(VaultException.class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user