Skip to content

Add support for bearer token auth #3401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 7, 2022
Merged
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 @@ -223,6 +223,9 @@ private void linkAuthorizationToRequestShapeForAwsProtocol(AuthType authType, Sh
case V4_UNSIGNED_BODY:
shape.setRequestSignerClassFqcn("software.amazon.awssdk.auth.signer.Aws4UnsignedPayloadSigner");
break;
case BEARER:
shape.setRequestSignerClassFqcn("software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner");
break;
case NONE:
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public enum AuthType {
V4("v4"),
V4_UNSIGNED_BODY("v4-unsigned-body"),
S3("s3"),
S3V4("s3v4")
S3V4("s3v4"),
BEARER("bearer")
;

private final String value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider;
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.utils.BearerAuthUtils;

public class AsyncClientBuilderClass implements ClassSpec {
private final IntermediateModel model;
Expand Down Expand Up @@ -61,6 +64,10 @@ public TypeSpec poetSpec() {
}
}

if (BearerAuthUtils.usesBearerAuth(model)) {
builder.addMethod(bearerTokenProviderMethod());
}

return builder.addMethod(buildClientMethod()).build();
}

Expand Down Expand Up @@ -96,6 +103,17 @@ private MethodSpec buildClientMethod() {
.build();
}

private MethodSpec bearerTokenProviderMethod() {
return MethodSpec.methodBuilder("tokenProvider").addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(SdkTokenProvider.class, "tokenProvider")
.returns(builderClassName)
.addStatement("clientConfiguration.option($T.TOKEN_PROVIDER, tokenProvider)",
AwsClientOption.class)
.addStatement("return this")
.build();
}

@Override
public ClassName className() {
return builderClassName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.auth.signer.Aws4Signer;
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider;
import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider;
import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner;
import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder;
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
import software.amazon.awssdk.codegen.internal.Utils;
Expand All @@ -41,6 +44,7 @@
import software.amazon.awssdk.codegen.model.service.AuthType;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.utils.BearerAuthUtils;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientOption;
Expand Down Expand Up @@ -99,16 +103,22 @@ public TypeSpec poetSpec() {
mergeInternalDefaultsMethod().ifPresent(builder::addMethod);

builder.addMethod(finalizeServiceConfigurationMethod());
builder.addMethod(defaultSignerMethod());
defaultAwsAuthSignerMethod().ifPresent(builder::addMethod);
builder.addMethod(signingNameMethod());

if (model.getCustomizationConfig().getServiceConfig().getClassName() != null) {
builder.addMethod(setServiceConfigurationMethod())
.addMethod(beanStyleSetServiceConfigurationMethod());
}

if (BearerAuthUtils.usesBearerAuth(model)) {
builder.addMethod(defaultBearerTokenProviderMethod());
builder.addMethod(defaultTokenAuthSignerMethod());
}

addServiceHttpConfigIfNeeded(builder, model);


return builder.build();
}

Expand All @@ -127,12 +137,13 @@ private MethodSpec signingNameMethod() {
.build();
}

private MethodSpec defaultSignerMethod() {
return MethodSpec.methodBuilder("defaultSigner")
.returns(Signer.class)
.addModifiers(PRIVATE)
.addCode(signerDefinitionMethodBody())
.build();
private Optional<MethodSpec> defaultAwsAuthSignerMethod() {
return awsAuthSignerDefinitionMethodBody().map(body -> MethodSpec.methodBuilder("defaultSigner")
.returns(Signer.class)
.addModifiers(PRIVATE)
.addCode(body)
.build());

}

private MethodSpec serviceEndpointPrefixMethod() {
Expand Down Expand Up @@ -161,18 +172,25 @@ private MethodSpec mergeServiceDefaultsMethod() {
.addModifiers(PROTECTED, FINAL)
.returns(SdkClientConfiguration.class)
.addParameter(SdkClientConfiguration.class, "config")
.addCode("return config.merge(c -> c.option($T.SIGNER, defaultSigner())\n",
SdkAdvancedClientOption.class)
.addCode(" .option($T"
+ ".CRC32_FROM_COMPRESSED_DATA_ENABLED, $L)",
SdkClientOption.class, crc32FromCompressedDataEnabled);
.addCode("return config.merge(c -> c");

if (defaultAwsAuthSignerMethod().isPresent()) {
builder.addCode(".option($T.SIGNER, defaultSigner())\n", SdkAdvancedClientOption.class);
}
builder.addCode(".option($T.CRC32_FROM_COMPRESSED_DATA_ENABLED, $L)\n",
SdkClientOption.class, crc32FromCompressedDataEnabled);

String clientConfigClassName = model.getCustomizationConfig().getServiceConfig().getClassName();
if (StringUtils.isNotBlank(clientConfigClassName)) {
builder.addCode(".option($T.SERVICE_CONFIGURATION, $T.builder().build())",
builder.addCode(".option($T.SERVICE_CONFIGURATION, $T.builder().build())\n",
SdkClientOption.class, ClassName.bestGuess(clientConfigClassName));
}

if (BearerAuthUtils.usesBearerAuth(model)) {
builder.addCode(".option($T.TOKEN_PROVIDER, defaultTokenProvider())\n", AwsClientOption.class);
builder.addCode(".option($T.TOKEN_SIGNER, defaultTokenSigner())", SdkAdvancedClientOption.class);
}

builder.addCode(");");
return builder.build();
}
Expand Down Expand Up @@ -368,14 +386,16 @@ private CodeBlock serviceSpecificHttpConfigMethodBody(String serviceDefaultFqcn,
return builder.build();
}

private CodeBlock signerDefinitionMethodBody() {
private Optional<CodeBlock> awsAuthSignerDefinitionMethodBody() {
AuthType authType = model.getMetadata().getAuthType();
switch (authType) {
case V4:
return v4SignerDefinitionMethodBody();
return Optional.of(v4SignerDefinitionMethodBody());
case S3:
case S3V4:
return s3SignerDefinitionMethodBody();
return Optional.of(s3SignerDefinitionMethodBody());
case BEARER:
return Optional.empty();
default:
throw new UnsupportedOperationException("Unsupported signer type: " + authType);
}
Expand All @@ -385,11 +405,28 @@ private CodeBlock v4SignerDefinitionMethodBody() {
return CodeBlock.of("return $T.create();", Aws4Signer.class);
}


private CodeBlock s3SignerDefinitionMethodBody() {
return CodeBlock.of("return $T.create();\n",
ClassName.get("software.amazon.awssdk.auth.signer", "AwsS3V4Signer"));
}

private MethodSpec defaultBearerTokenProviderMethod() {
return MethodSpec.methodBuilder("defaultTokenProvider")
.returns(SdkTokenProvider.class)
.addModifiers(PRIVATE)
.addStatement("return $T.create()", DefaultAwsTokenProvider.class)
.build();
}

private MethodSpec defaultTokenAuthSignerMethod() {
return MethodSpec.methodBuilder("defaultTokenSigner")
.returns(Signer.class)
.addModifiers(PRIVATE)
.addStatement("return $T.create()", BearerTokenSigner.class)
.build();
}

@Override
public ClassName className() {
return builderClassName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@
import com.squareup.javapoet.TypeVariableName;
import java.util.function.Consumer;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider;
import software.amazon.awssdk.auth.token.credentials.aws.DefaultAwsTokenProvider;
import software.amazon.awssdk.auth.token.signer.aws.BearerTokenSigner;
import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.utils.BearerAuthUtils;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;


public class BaseClientBuilderInterface implements ClassSpec {
Expand Down Expand Up @@ -62,6 +67,10 @@ public TypeSpec poetSpec() {
builder.addMethod(serviceConfigurationConsumerBuilderMethod());
}

if (generateTokenProviderMethod()) {
builder.addMethod(tokenProviderMethod());
}

return builder.build();
}

Expand Down Expand Up @@ -113,6 +122,29 @@ private MethodSpec serviceConfigurationConsumerBuilderMethod() {
.build();
}

private boolean generateTokenProviderMethod() {
return BearerAuthUtils.usesBearerAuth(model);
}

private MethodSpec tokenProviderMethod() {
return MethodSpec.methodBuilder("tokenProvider")
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.returns(TypeVariableName.get("B"))
.addParameter(SdkTokenProvider.class, "tokenProvider")
.addJavadoc("Set the token provider to use for bearer token authorization. This is optional, if none "
+ "is provided, the SDK will use {@link $T}.\n"
+ "<p>\n"
+ "If the service, or any of its operations require Bearer Token Authorization, then the "
+ "SDK will default to this token provider to retrieve the token to use for authorization.\n"
+ "<p>\n"
+ "This provider works in conjunction with the {@code $T.TOKEN_SIGNER} set on the client. "
+ "By default it is {@link $T}.",
DefaultAwsTokenProvider.class,
SdkAdvancedClientOption.class,
BearerTokenSigner.class)
.build();
}

@Override
public ClassName className() {
return builderInterfaceName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.auth.token.credentials.SdkTokenProvider;
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.utils.BearerAuthUtils;

public class SyncClientBuilderClass implements ClassSpec {
private final IntermediateModel model;
Expand Down Expand Up @@ -61,6 +64,10 @@ public TypeSpec poetSpec() {
}
}

if (BearerAuthUtils.usesBearerAuth(model)) {
builder.addMethod(tokenProviderMethodImpl());
}

return builder.addMethod(buildClientMethod()).build();
}

Expand Down Expand Up @@ -96,6 +103,17 @@ private MethodSpec buildClientMethod() {
.build();
}

private MethodSpec tokenProviderMethodImpl() {
return MethodSpec.methodBuilder("tokenProvider").addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(SdkTokenProvider.class, "tokenProvider")
.returns(builderClassName)
.addStatement("clientConfiguration.option($T.TOKEN_PROVIDER, tokenProvider)",
AwsClientOption.class)
.addStatement("return this")
.build();
}

@Override
public ClassName className() {
return builderClassName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ public CodeBlock executionHandler(OperationModel opModel) {
.add(".withErrorResponseHandler(errorResponseHandler)\n")
.add(hostPrefixExpression(opModel))
.add(discoveredEndpoint(opModel))
.add(credentialType(opModel, model))
.add(".withInput($L)\n", opModel.getInput().getVariableName())
.add(".withMetricCollector(apiCallMetricCollector)")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
Expand Down Expand Up @@ -244,6 +245,7 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(hostPrefixExpression(opModel))
.add(discoveredEndpoint(opModel))
.add(credentialType(opModel, model))
.add(asyncRequestBody)
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import software.amazon.awssdk.codegen.model.intermediate.ShapeType;
import software.amazon.awssdk.codegen.model.service.AuthType;
import software.amazon.awssdk.codegen.poet.PoetExtension;
import software.amazon.awssdk.codegen.utils.BearerAuthUtils;
import software.amazon.awssdk.core.CredentialType;
import software.amazon.awssdk.core.client.handler.SyncClientHandler;
import software.amazon.awssdk.core.runtime.transform.AsyncStreamingRequestMarshaller;
import software.amazon.awssdk.core.runtime.transform.StreamingRequestMarshaller;
Expand Down Expand Up @@ -110,6 +112,15 @@ default String discoveredEndpoint(OperationModel opModel) {
: "";
}

default CodeBlock credentialType(OperationModel opModel, IntermediateModel model) {

if (BearerAuthUtils.isOpBearerAuth(model, opModel)) {
return CodeBlock.of(".credentialType($T.TOKEN)\n", CredentialType.class);
} else {
return CodeBlock.of("");
}
}

/**
* For sync streaming operations, wrap request marshaller in {@link StreamingRequestMarshaller} class.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public CodeBlock executionHandler(OperationModel opModel) {
.add(".withErrorResponseHandler(errorResponseHandler)\n")
.add(hostPrefixExpression(opModel))
.add(discoveredEndpoint(opModel))
.add(credentialType(opModel, intermediateModel))
.add(".withInput($L)", opModel.getInput().getVariableName())
.add(".withMetricCollector(apiCallMetricCollector)")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
Expand Down Expand Up @@ -146,6 +147,7 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper
asyncMarshaller(intermediateModel, opModel, marshaller, "protocolFactory"))
.add(".withResponseHandler(responseHandler)\n")
.add(".withErrorResponseHandler(errorResponseHandler)\n")
.add(credentialType(opModel, intermediateModel))
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public CodeBlock executionHandler(OperationModel opModel) {
.add(".withMetricCollector(apiCallMetricCollector)\n" +
hostPrefixExpression(opModel) +
discoveredEndpoint(opModel))
.add(credentialType(opModel, model))
.add(".withInput($L)", opModel.getInput().getVariableName())
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel))
Expand Down Expand Up @@ -207,6 +208,7 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper
}

builder.add(hostPrefixExpression(opModel))
.add(credentialType(opModel, model))
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(asyncRequestBody(opModel))
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
Expand Down
Loading