22// SPDX-License-Identifier: Apache-2.0
33//
44/// A simple example that shows how to use the AWS SDK for Swift to
5- /// authenticate using optional static credentials and an AWS IAM role ARN .
5+ /// authenticate using SSO credentials from AWS Identity Center .
66
77// snippet-start:[swift.identity.sso.imports]
88import ArgumentParser
9- import AWSClientRuntime
109import AWSS3
1110import AWSSDKIdentity
1211import AWSSTS
1312import Foundation
1413import SmithyIdentity
15- import ClientRuntime
1614// snippet-end:[swift.identity.sso.imports]
1715
1816struct ExampleCommand : ParsableCommand {
@@ -35,24 +33,19 @@ struct ExampleCommand: ParsableCommand {
3533
3634 /// Called by ``main()`` to do the actual running of the AWS
3735 /// example.
38- // snippet-start:[swift.identity.sso.command.runasync]
3936 func runAsync( ) async throws {
40- // If credentials are specified, create a credential identity
41- // resolver that uses them to authenticate. This identity will be used
42- // to ask for permission to use the specified role.
43-
44- print ( " Creating resolver... " )
4537 do {
38+ // snippet-start: [swift.identity.sso.create-resolver]
4639 let identityResolver = try SSOAWSCredentialIdentityResolver (
4740 profileName: profile,
4841 configFilePath: config,
4942 credentialsFilePath: credentials
5043 )
51- dump ( identityResolver , name : " Identity resolver: " )
44+ // snippet-end: [swift.identity.sso.create- resolver]
5245
53- // Use the credential identity resolver to access AWS S3.
46+ // Call the function that fetches the Amazon S3 bucket names, then
47+ // output the names.
5448
55- print ( " Listing bucket names... " )
5649 let names = try await getBucketNames ( identityResolver: identityResolver)
5750
5851 print ( " Found \( names. count) buckets: " )
@@ -64,88 +57,8 @@ struct ExampleCommand: ParsableCommand {
6457 throw error
6558 }
6659 }
67- // snippet-end:[swift.identity.sso.command.runasync]
68- }
69-
70- /// An `Error` type used to return errors from the
71- /// `assumeRole(identityResolver: roleArn:)` function.
72- enum AssumeRoleExampleError : Error {
73- /// An error indicating that the STS `AssumeRole` request failed.
74- case assumeRoleFailed
75- /// An error indicating that the returned credentials were missing
76- /// required information.
77- case incompleteCredentials
78- /// An error indicating that no credentials were returned by `AssumeRole`.
79- case missingCredentials
80-
81- /// Return a human-readable explanation of the error.
82- var errorDescription : String ? {
83- switch self {
84- case . assumeRoleFailed:
85- return " Unable to assume the specified role. "
86- case . incompleteCredentials:
87- return " AWS STS returned incomplete credentials. "
88- case . missingCredentials:
89- return " AWS STS did not return any credentials for the specified role. "
90- }
91- }
9260}
9361
94- // snippet-start:[swift.identity.sso.assumeRole-function]
95- /// Assume the specified role. If any kind of credential identity resolver is
96- /// specified, that identity is adopted before assuming the role.
97- ///
98- /// - Parameters:
99- /// - identityResolver: Any kind of `AWSCredentialIdentityResolver`. If
100- /// provided, this identity is adopted before attempting to assume the
101- /// specified role.
102- /// - roleArn: The ARN of the AWS role to assume.
103- ///
104- /// - Throws: Re-throws STS errors. Also can throw any
105- /// `AssumeRoleExampleError`.
106- /// - Returns: An `AWSCredentialIdentity` containing the temporary credentials
107- /// assigned.
108- func assumeRole( identityResolver: ( any AWSCredentialIdentityResolver ) ? ,
109- roleArn: String ) async throws -> AWSCredentialIdentity {
110- print ( " ASSUMEROLE " )
111- let stsConfiguration = try await STSClient . STSClientConfiguration (
112- awsCredentialIdentityResolver: identityResolver
113- )
114- let stsClient = STSClient ( config: stsConfiguration)
115-
116- // Assume the role and return the assigned credentials.
117-
118- // snippet-start: [swift.sts.sts.AssumeRole]
119- let input = AssumeRoleInput (
120- roleArn: roleArn,
121- roleSessionName: " AssumeRole-Example "
122- )
123-
124- let output = try await stsClient. assumeRole ( input: input)
125-
126- guard let credentials = output. credentials else {
127- throw AssumeRoleExampleError . missingCredentials
128- }
129-
130- guard let accessKey = credentials. accessKeyId,
131- let secretKey = credentials. secretAccessKey,
132- let sessionToken = credentials. sessionToken else {
133- throw AssumeRoleExampleError . incompleteCredentials
134- }
135- // snippet-end: [swift.sts.sts.AssumeRole]
136-
137- // Return an `AWSCredentialIdentity` object with the temporary
138- // credentials.
139-
140- let awsCredentials = AWSCredentialIdentity (
141- accessKey: accessKey,
142- secret: secretKey,
143- sessionToken: sessionToken
144- )
145- return awsCredentials
146- }
147- // snippet-end:[swift.identity.sso.assumeRole-function]
148-
14962/// Return an array containing the names of all available buckets using
15063/// the specified credential identity resolver to authenticate.
15164///
@@ -159,8 +72,8 @@ func assumeRole(identityResolver: (any AWSCredentialIdentityResolver)?,
15972func getBucketNames( identityResolver: ( any AWSCredentialIdentityResolver ) ? )
16073 async throws -> [ String ] {
16174 do {
162- // Get an S3Client with which to access Amazon S3.
16375 // snippet-start:[swift.identity.sso.use-resolver]
76+ // Get an S3Client with which to access Amazon S3.
16477 let configuration = try await S3Client . S3ClientConfiguration (
16578 awsCredentialIdentityResolver: identityResolver
16679 )
@@ -169,7 +82,7 @@ func getBucketNames(identityResolver: (any AWSCredentialIdentityResolver)?)
16982 // Use "Paginated" to get all the buckets. This lets the SDK handle
17083 // the 'continuationToken' in "ListBucketsOutput".
17184 let pages = client. listBucketsPaginated (
172- input: ListBucketsInput ( maxBuckets: 10 )
85+ input: ListBucketsInput ( maxBuckets: 10 )
17386 )
17487 // snippet-end:[swift.identity.sso.use-resolver]
17588
@@ -179,18 +92,21 @@ func getBucketNames(identityResolver: (any AWSCredentialIdentityResolver)?)
17992 do {
18093 for try await page in pages {
18194 guard let buckets = page. buckets else {
182- print ( " Error: page is empty. " )
95+ // For this example, if the bucket list reference for the
96+ // page is `nil`, print an error and continue on with the
97+ // next page.
98+ print ( " ERROR: page is empty. " )
18399 continue
184100 }
185101
102+ // Add the page's bucket names to the list.
186103 for bucket in buckets {
187104 bucketNames. append ( bucket. name ?? " <unknown> " )
188105 }
189106 }
190107
191108 return bucketNames
192109 } catch {
193- //print("ERROR: listBuckets:", dump(error))
194110 throw error
195111 }
196112 }
@@ -199,12 +115,13 @@ func getBucketNames(identityResolver: (any AWSCredentialIdentityResolver)?)
199115/// The program's asynchronous entry point.
200116@main
201117struct Main {
118+ /// The function that serves as the main asynchronous entry point for the
119+ /// example. It parses the command line using the Swift Argument Parser,
120+ /// then calls the `runAsync()` function to run the example itself.
202121 static func main( ) async {
203122 let args = Array ( CommandLine . arguments. dropFirst ( ) )
204123
205124 do {
206- //await SDKLoggingSystem().initialize(logLevel: .debug)
207- SDKDefaultIO . setLogLevel ( level: . trace)
208125 let command = try ExampleCommand . parse ( args)
209126 try await command. runAsync ( )
210127 } catch {
0 commit comments