Skip to content
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

fix: Add sso credentials integration test #1129

Merged
merged 14 commits into from
Sep 21, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ func addIntegrationTestTarget(_ name: String) {
"README.md",
"Resources/ECSIntegTestApp/"
]
case "AWSS3":
additionalDependencies = ["AWSSSOAdmin"]
default:
break
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import XCTest
import AWSS3
import AWSClientRuntime
import AWSSSOAdmin

/* Prerequisites to run the SSO credentials provider integration test(s):
*
* [Manual]
* 1. Enable IAM Identity Center AWS Organization for the AWS account used to run integration test if it hasn't been already.
*
* [Automatic]
* 2. Create a read-only permission set in IAM Identity Center called "SSOCredProvIntegTestPermSet".
*
* [Manual]
* 3. Create a user in IAM Identity Center.
* 4. Give the created user access to your AWS account with the created permission set.
* 5. Retrieve username, password, and SSO start URL of the IAM Identity Store user. Configure SSO config using these values (aws sso configure).
* 6. Create SSO token using AWS CLI (aws sso login --profile <profile-name-set-during-aws-sso-configure>).
* 7. Run the test.
*
* Note: Enabling AWS organization and creating IAM identity store have no exposed API as of 9/17/2023 for programmatic activation / creation.
*
* Step 1, 3, 4, 5 have to be done only once per account.
*/
class SSOCredentialsProviderTests : XCTestCase {
var client: S3Client!
var ssoClient: SSOAdminClient!
// Change this region string to the region where AWS SSO instance is in.
let region = "us-west-2"

private var iamIdentityCenterInstanceArn: String = ""
private let permissionSetName = "SSOCredProvIntegTestPermSet"
private var permissionSetArn: String = ""
private let awsReadOnlyPolicy = "arn:aws:iam::aws:policy/ReadOnlyAccess"


override func setUp() async throws {
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved
// Use default credentials provider chain for setup
ssoClient = try SSOAdminClient(region: "us-west-2")
try await createPermissionSetIfNeeded()

// Create a S3 client that uses SSO credentials provider
try await setUpClient()
}

// The test calls listBuckets() and forces S3Client to use SSOCredentialsProvider
func test_listBuckets() async throws {
_ = try await client.listBuckets(input: ListBucketsInput())
}

override func tearDown() async throws {
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved
// No action required.
}

/* HELPER METHODS */
private func createPermissionSetIfNeeded() async throws {
// Get IAM identity center instanceArn
let listInstancesOutput = try await ssoClient.listInstances(input: ListInstancesInput())
iamIdentityCenterInstanceArn = listInstancesOutput.instances![0].instanceArn!
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved

do {
// Create permission set and save its ARN
let createPermissionSetOutput = try await ssoClient.createPermissionSet(input: CreatePermissionSetInput(
description: "Permission set for testing SSO credentials provider.",
instanceArn: iamIdentityCenterInstanceArn,
name: permissionSetName
))
permissionSetArn = createPermissionSetOutput.permissionSet!.permissionSetArn!
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved


// Attach ReadOnly AWS-managed policy to the created permission set
let _ = try await ssoClient.attachManagedPolicyToPermissionSet(input: AttachManagedPolicyToPermissionSetInput(
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved
instanceArn: iamIdentityCenterInstanceArn,
managedPolicyArn: awsReadOnlyPolicy,
permissionSetArn: permissionSetArn))
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved
sichanyoo marked this conversation as resolved.
Show resolved Hide resolved
} catch let error as AWSSSOAdmin.ConflictException {
if error.message == "PermissionSet with name \(permissionSetName) already exists." {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assume error messages can change at any time. Is there a more reliable way to verify this error condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently there's no other way to check the specific cause for the error other than checking the message contained int he error. So as a workaround I now look for smaller substring using contains() to reduce dependency on the entire error message string staying the same. Now it only checks that \(permissionSetName) already exists is part of the error message.

return
} else {
throw error
}
}
}

private func setUpClient() async throws {
// Setup SSOCredentialsProvider
let SSOCredentialsProvider = try SSOCredentialsProvider()

// Setup S3ClientConfiguration to use SSOCredentialsProvider
let testConfig = try await S3Client.S3ClientConfiguration()
testConfig.credentialsProvider = SSOCredentialsProvider
testConfig.region = region

// Initialize our S3 client with the specified configuration
client = S3Client(config: testConfig)
}
}
Loading