Skip to content

Commit 1afce8c

Browse files
franco2002luadwsingh
authored andcommitted
Support --aws-profile option for AWS auth.
1 parent 3305e7d commit 1afce8c

File tree

3 files changed

+97
-2
lines changed

3 files changed

+97
-2
lines changed

cli/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ dependencies {
88
implementation(libs.picocli)
99
annotationProcessor(libs.picocli.codegen)
1010

11+
implementation(libs.aws.sdk.auth)
1112
implementation(libs.smithy.aws.traits)
1213
implementation(libs.smithy.waiters)
1314

@@ -22,6 +23,7 @@ dependencies {
2223
implementation(project(":client:client-http"))
2324
implementation(project(":aws:client:aws-client-core"))
2425
implementation(project(":aws:aws-sigv4"))
26+
implementation(project(":aws:sdkv2:aws-sdkv2-auth"))
2527

2628
testImplementation(platform(libs.junit.bom))
2729
testImplementation(libs.junit.jupiter.api)

cli/src/main/java/software/amazon/smithy/java/cli/SmithyCall.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import picocli.CommandLine.Command;
2525
import picocli.CommandLine.Option;
2626
import picocli.CommandLine.ArgGroup;
27+
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
2728
import software.amazon.smithy.aws.traits.ServiceTrait;
2829
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
2930
import software.amazon.smithy.java.aws.client.auth.scheme.sigv4.SigV4AuthScheme;
@@ -32,6 +33,7 @@
3233
import software.amazon.smithy.java.aws.client.core.settings.RegionSetting;
3334
import software.amazon.smithy.java.aws.client.restjson.RestJsonClientProtocol;
3435
import software.amazon.smithy.java.aws.client.restxml.RestXmlClientProtocol;
36+
import software.amazon.smithy.java.aws.sdkv2.auth.SdkCredentialsResolver;
3537
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver;
3638
import software.amazon.smithy.java.client.core.endpoint.EndpointResolver;
3739
import software.amazon.smithy.java.client.rpcv2.RpcV2CborProtocol;
@@ -95,6 +97,9 @@ static class Authentication {
9597

9698
@Option(names = { "--aws-region" }, description = "AWS region for SigV4 authentication")
9799
private String awsRegion;
100+
101+
@Option(names = { "--aws-profile", "--profile"}, description = "AWS profile to use for authentication")
102+
private String awsProfile;
98103
}
99104

100105
@Override
@@ -272,8 +277,15 @@ private void configureAuth(DynamicClient.Builder builder, ShapeId serviceInput,
272277
LOGGER.fine("Configuring SigV4 authentication with service signing name detected in model: " + signingName);
273278
builder.putConfig(RegionSetting.REGION, auth.awsRegion)
274279
.putSupportedAuthSchemes(new SigV4AuthScheme(signingName))
275-
.authSchemeResolver(AuthSchemeResolver.DEFAULT)
276-
.addIdentityResolver(new EnvironmentVariableIdentityResolver());
280+
.authSchemeResolver(AuthSchemeResolver.DEFAULT);
281+
282+
if (auth.awsProfile != null) {
283+
var profileBuilder = ProfileCredentialsProvider.builder()
284+
.profileName(auth.awsProfile);
285+
builder.addIdentityResolver(new SdkCredentialsResolver(profileBuilder.build()));
286+
} else {
287+
builder.addIdentityResolver(new EnvironmentVariableIdentityResolver());
288+
}
277289
break;
278290
case "none":
279291
builder.authSchemeResolver(AuthSchemeResolver.NO_AUTH);

cli/src/test/java/software/amazon/smithy/java/cli/SmithyCallTest.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class SmithyCallTest {
3030
private final PrintStream originalErr = System.err;
3131
private static HttpServer MOCK_SERVER;
3232
private static int PORT;
33+
private static volatile String lastAuthorizationHeader;
3334

3435
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
3536
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
@@ -46,6 +47,9 @@ static void setUpServer() throws IOException {
4647
MOCK_SERVER.setExecutor(Executors.newFixedThreadPool(1));
4748

4849
MOCK_SERVER.createContext("/", exchange -> {
50+
// Capture Authorization header for tests that need it
51+
lastAuthorizationHeader = exchange.getRequestHeaders().getFirst("Authorization");
52+
4953
String requestBody;
5054
try (InputStream is = exchange.getRequestBody()) {
5155
requestBody = new String(is.readAllBytes(), StandardCharsets.UTF_8);
@@ -92,6 +96,7 @@ static void tearDownServer() {
9296

9397
@BeforeEach
9498
void setUp() {
99+
lastAuthorizationHeader = null; // Reset captured header for each test
95100
commandLine = new CommandLine(new SmithyCall())
96101
.setCaseInsensitiveEnumValuesAllowed(true);
97102
System.setOut(new PrintStream(outContent));
@@ -346,6 +351,82 @@ void testWithNoAWSRegion() {
346351
assertTrue(error.contains("SigV4 auth requires --aws-region to be set."));
347352
}
348353

354+
@Test
355+
void testWithAWSProfileOption() throws IOException {
356+
// Create temporary AWS credentials file with test profile
357+
Path awsDir = tempDir.resolve(".aws");
358+
Files.createDirectories(awsDir);
359+
Path credentialsFile = awsDir.resolve("credentials");
360+
String credentialsContent = """
361+
[test-profile]
362+
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
363+
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
364+
""";
365+
Files.writeString(credentialsFile, credentialsContent);
366+
367+
// Point AWS SDK to our temporary credentials file
368+
String originalCredentialsFile = System.getProperty("aws.sharedCredentialsFile");
369+
System.setProperty("aws.sharedCredentialsFile", credentialsFile.toString());
370+
371+
try {
372+
Path modelFile = tempDir.resolve("sprockets-sigv4.smithy");
373+
String modelContent = """
374+
$version: "2"
375+
namespace smithy.example
376+
377+
use aws.auth#sigv4
378+
379+
@aws.protocols#awsJson1_0
380+
@sigv4(name: "execute-api")
381+
service Sprockets {
382+
operations: [CreateSprocket]
383+
}
384+
385+
operation CreateSprocket {
386+
input := {}
387+
output := {
388+
id: String
389+
}
390+
}
391+
""";
392+
Files.writeString(modelFile, modelContent);
393+
394+
String[] args = {
395+
"smithy.example#Sprockets",
396+
"CreateSprocket",
397+
"--model-path", tempDir.toString(),
398+
"--url", "http://localhost:" + PORT,
399+
"--auth", "sigv4",
400+
"--aws-region", "us-west-2",
401+
"--aws-profile", "test-profile",
402+
"--protocol", "aws_json",
403+
"--input-json", "{}"
404+
};
405+
406+
int exitCode = commandLine.execute(args);
407+
408+
String stdErr = errContent.toString();
409+
String stdOut = outContent.toString();
410+
411+
// Verify that the request was signed with SigV4 using profile credentials
412+
assertTrue(lastAuthorizationHeader != null && lastAuthorizationHeader.startsWith("AWS4-HMAC-SHA256"),
413+
"Authorization header with AWS4-HMAC-SHA256 signature should be present when using --aws-profile. " +
414+
"Captured header: " + lastAuthorizationHeader + ", Exit code: " + exitCode +
415+
", stderr: " + stdErr + ", stdout: " + stdOut);
416+
417+
assertEquals(0, exitCode, "Command should succeed. stderr: " + stdErr);
418+
String output = stdOut.trim();
419+
assertTrue(output.contains("sprocket-123"));
420+
} finally {
421+
// Restore original system property
422+
if (originalCredentialsFile != null) {
423+
System.setProperty("aws.sharedCredentialsFile", originalCredentialsFile);
424+
} else {
425+
System.clearProperty("aws.sharedCredentialsFile");
426+
}
427+
}
428+
}
429+
349430
@Test
350431
void testWithUnknownTraits() {
351432
Path modelFile = tempDir.resolve("sprockets-unknown-traits.smithy");

0 commit comments

Comments
 (0)