HADOOP-18795. S3A DelegationToken plugin to expand return type of binding (#5821)
Adds a class DelegationBindingInfo which contains binding info beyond just the AWS credential list. The binding class can be expanded when needed. Until then, all existing implementations will work, as the new method DelegationBindingInfo deploy(AbstractS3ATokenIdentifier retrievedIdentifier) falls back to the original methods.
This commit is contained in:
parent
82c8070e93
commit
104a323f6f
@ -198,15 +198,37 @@ protected <T extends AbstractS3ATokenIdentifier> T convertTokenIdentifier(
|
|||||||
return (T) identifier;
|
return (T) identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy, returning the binding information.
|
||||||
|
* The base implementation calls
|
||||||
|
*
|
||||||
|
* @param retrievedIdentifier any identifier -null if deployed unbonded.
|
||||||
|
* @return binding information
|
||||||
|
* @throws IOException any failure.
|
||||||
|
*/
|
||||||
|
public DelegationBindingInfo deploy(AbstractS3ATokenIdentifier retrievedIdentifier)
|
||||||
|
throws IOException {
|
||||||
|
requireServiceStarted();
|
||||||
|
AWSCredentialProviderList credentialProviders =
|
||||||
|
retrievedIdentifier == null
|
||||||
|
? deployUnbonded()
|
||||||
|
: bindToTokenIdentifier(retrievedIdentifier);
|
||||||
|
return new DelegationBindingInfo()
|
||||||
|
.withCredentialProviders(credentialProviders);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform any actions when deploying unbonded, and return a list
|
* Perform any actions when deploying unbonded, and return a list
|
||||||
* of credential providers.
|
* of credential providers.
|
||||||
* @return non-empty list of AWS credential providers to use for
|
* @return non-empty list of AWS credential providers to use for
|
||||||
* authenticating this client with AWS services.
|
* authenticating this client with AWS services.
|
||||||
* @throws IOException any failure.
|
* @throws IOException any failure.
|
||||||
|
* @throws UnsupportedOperationException in the base implementation.
|
||||||
*/
|
*/
|
||||||
public abstract AWSCredentialProviderList deployUnbonded()
|
public AWSCredentialProviderList deployUnbonded()
|
||||||
throws IOException;
|
throws IOException {
|
||||||
|
throw new UnsupportedOperationException("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind to the token identifier, returning the credential providers to use
|
* Bind to the token identifier, returning the credential providers to use
|
||||||
@ -214,11 +236,14 @@ public abstract AWSCredentialProviderList deployUnbonded()
|
|||||||
* @param retrievedIdentifier the unmarshalled data
|
* @param retrievedIdentifier the unmarshalled data
|
||||||
* @return non-empty list of AWS credential providers to use for
|
* @return non-empty list of AWS credential providers to use for
|
||||||
* authenticating this client with AWS services.
|
* authenticating this client with AWS services.
|
||||||
* @throws IOException any failure.
|
* @throws IOException any failure
|
||||||
|
* @throws UnsupportedOperationException in the base implementation.
|
||||||
*/
|
*/
|
||||||
public abstract AWSCredentialProviderList bindToTokenIdentifier(
|
public AWSCredentialProviderList bindToTokenIdentifier(
|
||||||
AbstractS3ATokenIdentifier retrievedIdentifier)
|
AbstractS3ATokenIdentifier retrievedIdentifier)
|
||||||
throws IOException;
|
throws IOException {
|
||||||
|
throw new UnsupportedOperationException("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new subclass of {@link AbstractS3ATokenIdentifier}.
|
* Create a new subclass of {@link AbstractS3ATokenIdentifier}.
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.apache.hadoop.fs.s3a.auth.delegation;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.s3a.AWSCredentialProviderList;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binding information returned by the token provider.
|
||||||
|
*/
|
||||||
|
public final class DelegationBindingInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of credential providers.
|
||||||
|
*/
|
||||||
|
private AWSCredentialProviderList credentialProviders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of credential providers.
|
||||||
|
* @return list of credential providers
|
||||||
|
*/
|
||||||
|
public AWSCredentialProviderList getCredentialProviders() {
|
||||||
|
return credentialProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set builder value.
|
||||||
|
* @param value non null value
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
public DelegationBindingInfo withCredentialProviders(final AWSCredentialProviderList value) {
|
||||||
|
credentialProviders = requireNonNull(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -123,7 +123,12 @@ public class S3ADelegationTokens extends AbstractDTService {
|
|||||||
/**
|
/**
|
||||||
* List of cred providers; unset until {@link #bindToDelegationToken(Token)}.
|
* List of cred providers; unset until {@link #bindToDelegationToken(Token)}.
|
||||||
*/
|
*/
|
||||||
private Optional<AWSCredentialProviderList> credentialProviders
|
//private Optional<AWSCredentialProviderList> credentialProviders = Optional.empty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delegation binding information; unset until {@link #bindToDelegationToken(Token)}.
|
||||||
|
*/
|
||||||
|
private Optional<DelegationBindingInfo> bindingInfo
|
||||||
= Optional.empty();
|
= Optional.empty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,10 +240,7 @@ protected void serviceStop() throws Exception {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the unbonded deployment operations.
|
* Perform the unbonded deployment operations.
|
||||||
* Create the AWS credential provider chain to use
|
* Create and store the binding information.
|
||||||
* when talking to AWS when there is no delegation token to work with.
|
|
||||||
* authenticating this client with AWS services, and saves it
|
|
||||||
* to {@link #credentialProviders}
|
|
||||||
*
|
*
|
||||||
* @throws IOException any failure.
|
* @throws IOException any failure.
|
||||||
*/
|
*/
|
||||||
@ -248,7 +250,7 @@ private void deployUnbonded()
|
|||||||
checkState(!isBoundToDT(),
|
checkState(!isBoundToDT(),
|
||||||
"Already Bound to a delegation token");
|
"Already Bound to a delegation token");
|
||||||
LOG.debug("No delegation tokens present: using direct authentication");
|
LOG.debug("No delegation tokens present: using direct authentication");
|
||||||
credentialProviders = Optional.of(tokenBinding.deployUnbonded());
|
bindingInfo = Optional.of(tokenBinding.deploy(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,12 +262,12 @@ private void deployUnbonded()
|
|||||||
* <ol>
|
* <ol>
|
||||||
* <li>{@link #boundDT} is set to the retrieved token.</li>
|
* <li>{@link #boundDT} is set to the retrieved token.</li>
|
||||||
* <li>{@link #decodedIdentifier} is set to the extracted identifier.</li>
|
* <li>{@link #decodedIdentifier} is set to the extracted identifier.</li>
|
||||||
* <li>{@link #credentialProviders} is set to the credential
|
* <li>{@link #bindingInfo} is set to the information
|
||||||
* provider(s) returned by the token binding.</li>
|
* returned by the token binding.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* If unsuccessful, {@link #deployUnbonded()} is called for the
|
* If unsuccessful, {@link #deployUnbonded()} is called for the
|
||||||
* unbonded codepath instead, which will set
|
* unbonded codepath instead, which will set
|
||||||
* {@link #credentialProviders} to its value.
|
* {@link #bindingInfo} to its value.
|
||||||
*
|
*
|
||||||
* This means after this call (and only after) the token operations
|
* This means after this call (and only after) the token operations
|
||||||
* can be invoked.
|
* can be invoked.
|
||||||
@ -276,14 +278,14 @@ private void deployUnbonded()
|
|||||||
* @throws IOException selection/extraction/validation failure.
|
* @throws IOException selection/extraction/validation failure.
|
||||||
*/
|
*/
|
||||||
private void bindToAnyDelegationToken() throws IOException {
|
private void bindToAnyDelegationToken() throws IOException {
|
||||||
checkState(!credentialProviders.isPresent(), E_ALREADY_DEPLOYED);
|
checkState(!bindingInfo.isPresent(), E_ALREADY_DEPLOYED);
|
||||||
Token<AbstractS3ATokenIdentifier> token = selectTokenFromFSOwner();
|
Token<AbstractS3ATokenIdentifier> token = selectTokenFromFSOwner();
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
bindToDelegationToken(token);
|
bindToDelegationToken(token);
|
||||||
} else {
|
} else {
|
||||||
deployUnbonded();
|
deployUnbonded();
|
||||||
}
|
}
|
||||||
if (credentialProviders.get().size() == 0) {
|
if (getCredentialProviders().size() == 0) {
|
||||||
throw new DelegationTokenIOException("No AWS credential providers"
|
throw new DelegationTokenIOException("No AWS credential providers"
|
||||||
+ " created by Delegation Token Binding "
|
+ " created by Delegation Token Binding "
|
||||||
+ tokenBinding.getName());
|
+ tokenBinding.getName());
|
||||||
@ -306,7 +308,7 @@ private void bindToAnyDelegationToken() throws IOException {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void resetTokenBindingToDT(final Token<AbstractS3ATokenIdentifier> token)
|
void resetTokenBindingToDT(final Token<AbstractS3ATokenIdentifier> token)
|
||||||
throws IOException{
|
throws IOException{
|
||||||
credentialProviders = Optional.empty();
|
bindingInfo = Optional.empty();
|
||||||
bindToDelegationToken(token);
|
bindToDelegationToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,8 +319,8 @@ void resetTokenBindingToDT(final Token<AbstractS3ATokenIdentifier> token)
|
|||||||
* <ol>
|
* <ol>
|
||||||
* <li>{@link #boundDT} is set to {@code token}.</li>
|
* <li>{@link #boundDT} is set to {@code token}.</li>
|
||||||
* <li>{@link #decodedIdentifier} is set to the extracted identifier.</li>
|
* <li>{@link #decodedIdentifier} is set to the extracted identifier.</li>
|
||||||
* <li>{@link #credentialProviders} is set to the credential
|
* <li>{@link #bindingInfo} is set to the info
|
||||||
* provider(s) returned by the token binding.</li>
|
* returned by the token binding.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* @param token token to decode and bind to.
|
* @param token token to decode and bind to.
|
||||||
* @throws IOException selection/extraction/validation failure.
|
* @throws IOException selection/extraction/validation failure.
|
||||||
@ -327,7 +329,7 @@ void resetTokenBindingToDT(final Token<AbstractS3ATokenIdentifier> token)
|
|||||||
public void bindToDelegationToken(
|
public void bindToDelegationToken(
|
||||||
final Token<AbstractS3ATokenIdentifier> token)
|
final Token<AbstractS3ATokenIdentifier> token)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkState(!credentialProviders.isPresent(), E_ALREADY_DEPLOYED);
|
checkState(!bindingInfo.isPresent(), E_ALREADY_DEPLOYED);
|
||||||
boundDT = Optional.of(token);
|
boundDT = Optional.of(token);
|
||||||
AbstractS3ATokenIdentifier dti = extractIdentifier(token);
|
AbstractS3ATokenIdentifier dti = extractIdentifier(token);
|
||||||
LOG.info("Using delegation token {}", dti);
|
LOG.info("Using delegation token {}", dti);
|
||||||
@ -335,8 +337,7 @@ public void bindToDelegationToken(
|
|||||||
try (DurationInfo ignored = new DurationInfo(LOG, DURATION_LOG_AT_INFO,
|
try (DurationInfo ignored = new DurationInfo(LOG, DURATION_LOG_AT_INFO,
|
||||||
"Creating Delegation Token")) {
|
"Creating Delegation Token")) {
|
||||||
// extract the credential providers.
|
// extract the credential providers.
|
||||||
credentialProviders = Optional.of(
|
bindingInfo = Optional.of(tokenBinding.deploy(dti));
|
||||||
tokenBinding.bindToTokenIdentifier(dti));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,8 +471,9 @@ public DelegationTokenIssuer[] getAdditionalTokenIssuers()
|
|||||||
*/
|
*/
|
||||||
public AWSCredentialProviderList getCredentialProviders()
|
public AWSCredentialProviderList getCredentialProviders()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return credentialProviders.orElseThrow(
|
return bindingInfo.map(DelegationBindingInfo::getCredentialProviders)
|
||||||
() -> new DelegationTokenIOException("Not yet bonded"));
|
.orElseThrow(() ->
|
||||||
|
new DelegationTokenIOException("Not yet bonded"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user