Skip to content

Commit 22c16ee

Browse files
authored
Follow-up feedback for arn-anywhere (#3039)
1 parent a3b8e10 commit 22c16ee

File tree

4 files changed

+43
-30
lines changed

4 files changed

+43
-30
lines changed

jetbrains-core/it/software/aws/toolkits/jetbrains/services/federation/AwsConsoleUrlFactoryIntegrationTest.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import com.intellij.testFramework.TestApplicationManager
77
import com.intellij.util.io.HttpRequests
88
import org.assertj.core.api.Assertions.assertThat
99
import org.junit.Assume.assumeFalse
10+
import org.junit.Rule
1011
import org.junit.Test
1112
import org.junit.runner.RunWith
1213
import org.junit.runners.Parameterized
1314
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider
15+
import software.aws.toolkits.core.ConnectionSettings
1416
import software.aws.toolkits.core.region.AwsRegion
17+
import software.aws.toolkits.jetbrains.core.credentials.MockCredentialManagerRule
1518
import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider
1619

1720
@RunWith(Parameterized::class)
@@ -28,6 +31,10 @@ class AwsConsoleUrlFactoryIntegrationTest(@Suppress("UNUSED_PARAMETER") regionId
2831
}
2932
}
3033

34+
@Rule
35+
@JvmField
36+
val credRule = MockCredentialManagerRule()
37+
3138
/**
3239
* There is currently no good way to test this in our integration CI fleet, so this test suite only runs locally
3340
*/
@@ -42,8 +49,9 @@ class AwsConsoleUrlFactoryIntegrationTest(@Suppress("UNUSED_PARAMETER") regionId
4249
}
4350
assumeFalse("Skipping console sign-in test for $region since a credentials profile was not available", profileName.isNullOrBlank())
4451

45-
val credProvider = ProfileCredentialsProvider.create(profileName)
46-
val signinUrl = AwsConsoleUrlFactory().getSigninUrl(credentials = credProvider.resolveCredentials(), destination = "", region = region)
52+
val credProvider = credRule.createCredentialProvider(profileName, ProfileCredentialsProvider.create(profileName).resolveCredentials())
53+
val credSettings = ConnectionSettings(credProvider, region)
54+
val signinUrl = AwsConsoleUrlFactory.getSigninUrl(credSettings, destination = "")
4755
val responseCode = HttpRequests.request(signinUrl)
4856
// don't throw because it'll print the signin token as part of the exception
4957
.throwStatusCodeException(false)

jetbrains-core/src/software/aws/toolkits/jetbrains/services/federation/AwsConsoleUrlFactory.kt

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@ import org.apache.http.client.entity.UrlEncodedFormEntity
1111
import org.apache.http.client.methods.HttpPost
1212
import org.apache.http.impl.client.HttpClientBuilder
1313
import org.apache.http.message.BasicNameValuePair
14-
import software.amazon.awssdk.auth.credentials.AwsCredentials
15-
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
1614
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials
17-
import software.amazon.awssdk.regions.Region
1815
import software.amazon.awssdk.services.sts.StsClient
16+
import software.aws.toolkits.core.ConnectionSettings
1917
import software.aws.toolkits.core.region.AwsRegion
2018
import software.aws.toolkits.jetbrains.core.AwsClientManager
2119
import java.time.Duration
2220

23-
class AwsConsoleUrlFactory(
24-
private val httpClientBuilder: HttpClientBuilder = HttpClientBuilder.create()
25-
) {
21+
object AwsConsoleUrlFactory {
22+
private val defaultHttpClientBuilder: HttpClientBuilder by lazy { HttpClientBuilder.create() }
23+
2624
fun federationUrl(region: AwsRegion): String {
2725
// https://docs.aws.amazon.com/general/latest/gr/signin-service.html
2826
// https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Beijing.html
@@ -63,10 +61,14 @@ class AwsConsoleUrlFactory(
6361
return "$consoleHome${fragment ?: "/"}"
6462
}
6563

66-
fun getSigninToken(credentials: AwsCredentials, region: AwsRegion): String {
67-
val creds = if (credentials !is AwsSessionCredentials) {
68-
val stsClient: StsClient = AwsClientManager.getInstance()
69-
.createUnmanagedClient(AwsCredentialsProvider { credentials }, Region.of(region.id))
64+
fun getSigninUrl(connectionSettings: ConnectionSettings, destination: String?, httpClientBuilder: HttpClientBuilder = defaultHttpClientBuilder): String {
65+
return getSigninUrl(getSigninToken(connectionSettings, httpClientBuilder), destination, connectionSettings.region)
66+
}
67+
68+
fun getSigninToken(connectionSettings: ConnectionSettings, httpClientBuilder: HttpClientBuilder = defaultHttpClientBuilder): String {
69+
val resolvedCreds = connectionSettings.credentials.resolveCredentials()
70+
val sessionCredentials = if (resolvedCreds !is AwsSessionCredentials) {
71+
val stsClient = AwsClientManager.getInstance().getClient<StsClient>(connectionSettings)
7072

7173
val tokenResponse = stsClient.use { client ->
7274
client.getFederationToken {
@@ -82,14 +84,14 @@ class AwsConsoleUrlFactory(
8284

8385
tokenResponse.credentials().let { AwsSessionCredentials.create(it.accessKeyId(), it.secretAccessKey(), it.sessionToken()) }
8486
} else {
85-
credentials
87+
resolvedCreds
8688
}
8789

8890
val sessionJson = mapper.writeValueAsString(
8991
GetSigninTokenRequest(
90-
sessionId = creds.accessKeyId(),
91-
sessionKey = creds.secretAccessKey(),
92-
sessionToken = creds.sessionToken()
92+
sessionId = sessionCredentials.accessKeyId(),
93+
sessionKey = sessionCredentials.secretAccessKey(),
94+
sessionToken = sessionCredentials.sessionToken()
9395
)
9496
)
9597

@@ -99,7 +101,7 @@ class AwsConsoleUrlFactory(
99101
"Session" to sessionJson
100102
).map { BasicNameValuePair(it.key, it.value) }
101103

102-
val request = HttpPost(federationUrl(region))
104+
val request = HttpPost(federationUrl(connectionSettings.region))
103105
.apply {
104106
entity = UrlEncodedFormEntity(params)
105107
}
@@ -130,10 +132,6 @@ class AwsConsoleUrlFactory(
130132
return "${federationUrl(region)}?${UrlEncodedFormEntity(params).toUrlEncodedString()}"
131133
}
132134

133-
fun getSigninUrl(credentials: AwsCredentials, destination: String?, region: AwsRegion): String {
134-
return getSigninUrl(getSigninToken(credentials, region), destination, region)
135-
}
136-
137135
private val mapper = jacksonObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
138136
}
139137

jetbrains-core/src/software/aws/toolkits/jetbrains/services/federation/psireferences/ArnReference.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,9 @@ class ArnReference(element: PsiElement, textRange: TextRange, private val arn: S
3434
return
3535
}
3636

37-
val (credProvider, region) = connectionSettings
3837
ApplicationManager.getApplication().executeOnPooledThread {
3938
try {
40-
BrowserUtil.browse(AwsConsoleUrlFactory().getSigninUrl(credProvider.resolveCredentials(), "/go/view/$arn", region))
39+
BrowserUtil.browse(AwsConsoleUrlFactory.getSigninUrl(connectionSettings, "/go/view/$arn"))
4140
} catch (e: StsException) {
4241
val message = message("general.open_in_aws_console.no_permission")
4342
notifyError(content = message, project = project)

jetbrains-core/tst/software/aws/toolkits/jetbrains/services/federation/AwsConsoleUrlFactoryTest.kt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,34 @@ import software.amazon.awssdk.auth.credentials.AwsSessionCredentials
2929
import software.amazon.awssdk.services.sts.StsClient
3030
import software.amazon.awssdk.services.sts.model.GetFederationTokenRequest
3131
import software.amazon.awssdk.services.sts.model.GetFederationTokenResponse
32+
import software.aws.toolkits.core.ConnectionSettings
3233
import software.aws.toolkits.core.utils.tryOrNull
3334
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
34-
import software.aws.toolkits.jetbrains.core.region.US_EAST_1
35+
import software.aws.toolkits.jetbrains.core.credentials.MockCredentialManagerRule
36+
import software.aws.toolkits.jetbrains.core.region.getDefaultRegion
3537
import java.net.InetAddress
3638

3739
class AwsConsoleUrlFactoryTest {
3840
val applicationRule = ApplicationRule()
3941
val mockClientManager = MockClientManagerRule()
42+
val mockCredentialManager = MockCredentialManagerRule()
4043

4144
@Rule
4245
@JvmField
43-
val ruleChain = RuleChain(applicationRule, mockClientManager)
46+
val ruleChain = RuleChain(applicationRule, mockClientManager, mockCredentialManager)
4447

4548
@Rule
4649
@JvmField
4750
val wireMock = WireMockRule(WireMockConfiguration.wireMockConfig().dynamicPort())
4851

4952
private lateinit var stsMock: StsClient
53+
private lateinit var httpBuilderMock: HttpClientBuilder
5054
private lateinit var httpClient: CloseableHttpClient
5155
private lateinit var sut: AwsConsoleUrlFactory
5256

5357
@Before
5458
fun setUp() {
55-
val httpBuilderMock = mock<HttpClientBuilder>()
59+
httpBuilderMock = mock<HttpClientBuilder>()
5660
httpClient = HttpClientBuilder.create()
5761
.setRoutePlanner(HttpRoutePlanner { _, _, _ -> HttpRoute(HttpHost(InetAddress.getLoopbackAddress(), wireMock.port(), "http")) })
5862
.build()
@@ -73,7 +77,7 @@ class AwsConsoleUrlFactoryTest {
7377
)
7478
)
7579

76-
sut = AwsConsoleUrlFactory(httpBuilderMock)
80+
sut = AwsConsoleUrlFactory
7781
}
7882

7983
@After
@@ -84,14 +88,17 @@ class AwsConsoleUrlFactoryTest {
8488
@Test
8589
fun `getSigninToken uses temporary credentials as-is`() {
8690
val tempCreds = AwsSessionCredentials.create("accessKey", "secretKey", "sessionToken")
91+
val connectionSettings = ConnectionSettings(mockCredentialManager.createCredentialProvider("tempCreds", tempCreds), getDefaultRegion())
8792

8893
verifyNoMoreInteractions(stsMock)
89-
assertThat(sut.getSigninToken(tempCreds, US_EAST_1)).isEqualTo("signinToken")
94+
assertThat(sut.getSigninToken(connectionSettings, httpBuilderMock)).isEqualTo("signinToken")
9095
}
9196

9297
@Test
9398
fun `getSigninToken requests federation token for long-term credentials`() {
9499
val longCreds = AwsBasicCredentials.create("basicKeyId", "basicSecretKey")
100+
val connectionSettings = ConnectionSettings(mockCredentialManager.createCredentialProvider("longCreds", longCreds), getDefaultRegion())
101+
95102
whenever(stsMock.getFederationToken(any<GetFederationTokenRequest>())).thenReturn(
96103
GetFederationTokenResponse.builder()
97104
.credentials {
@@ -102,14 +109,15 @@ class AwsConsoleUrlFactoryTest {
102109
.build()
103110
)
104111

105-
assertThat(sut.getSigninToken(longCreds, US_EAST_1)).isEqualTo("signinToken")
112+
assertThat(sut.getSigninToken(connectionSettings, httpBuilderMock)).isEqualTo("signinToken")
106113
}
107114

108115
@Test
109116
fun `build sign-in url`() {
110117
val tempCreds = AwsSessionCredentials.create("accessKey", "secretKey", "sessionToken")
118+
val connectionSettings = ConnectionSettings(mockCredentialManager.createCredentialProvider("tempCreds", tempCreds), getDefaultRegion())
111119

112-
assertThat(sut.getSigninUrl(tempCreds, destination = "/something", region = US_EAST_1))
120+
assertThat(sut.getSigninUrl(connectionSettings = connectionSettings, destination = "/something", httpClientBuilder = httpBuilderMock))
113121
.isEqualTo(
114122
"""
115123
https://signin.aws.amazon.com/federation?Action=login&SigninToken=signinToken&Destination=https%3A%2F%2Fus-east-1.console.aws.amazon.com%2Fsomething

0 commit comments

Comments
 (0)