Skip to content

Commit 1a5ff43

Browse files
authored
Fix being unable to use a SSO profile in a source_profile chain (#2155)
1 parent 9259d05 commit 1a5ff43

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Fix being unable to use a SSO profile in a credential chain"
4+
}

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/profiles/ProfileCredentialProviderFactory.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private class ProfileCredentialsIdentifierSso(
7272
) : ProfileCredentialsIdentifier(profileName, defaultRegionId, credentialType),
7373
SsoRequiredInteractiveCredentials
7474

75-
class ProfileCredentialProviderFactory : CredentialProviderFactory {
75+
class ProfileCredentialProviderFactory(private val ssoCache: SsoCache = diskCache) : CredentialProviderFactory {
7676
private val profileHolder = ProfileHolder()
7777

7878
override val id = PROFILE_FACTORY_ID
@@ -220,7 +220,7 @@ class ProfileCredentialProviderFactory : CredentialProviderFactory {
220220
profile.requiredProperty(SSO_URL),
221221
ssoRegion,
222222
SsoPrompt,
223-
diskCache,
223+
ssoCache,
224224
ssoOidcClient
225225
)
226226

@@ -327,8 +327,8 @@ class ProfileCredentialProviderFactory : CredentialProviderFactory {
327327
this.requiresSso(profiles) -> ProfileCredentialsIdentifierSso(
328328
name,
329329
defaultRegion,
330-
diskCache,
331-
this.requiredProperty(SSO_URL),
330+
ssoCache,
331+
this.traverseCredentialChain(profiles).map { it.property(SSO_URL) }.first { it.isPresent }.get(),
332332
requestedProfileType
333333
)
334334
else -> ProfileCredentialsIdentifier(name, defaultRegion, requestedProfileType)

jetbrains-core/tst/software/aws/toolkits/jetbrains/core/credentials/ProfileCredentialProviderFactoryTest.kt

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.nhaarman.mockitokotlin2.reset
2323
import com.nhaarman.mockitokotlin2.stub
2424
import com.nhaarman.mockitokotlin2.times
2525
import com.nhaarman.mockitokotlin2.verify
26+
import kotlinx.coroutines.runBlocking
2627
import org.assertj.core.api.Assertions.assertThat
2728
import org.assertj.core.api.Assertions.assertThatThrownBy
2829
import org.assertj.core.api.Condition
@@ -42,6 +43,7 @@ import software.amazon.awssdk.http.SdkHttpFullResponse
4243
import software.aws.toolkits.core.credentials.CredentialIdentifier
4344
import software.aws.toolkits.core.credentials.CredentialsChangeEvent
4445
import software.aws.toolkits.core.credentials.CredentialsChangeListener
46+
import software.aws.toolkits.core.credentials.sso.SsoCache
4547
import software.aws.toolkits.core.region.ToolkitRegionProvider
4648
import software.aws.toolkits.core.rules.SystemPropertyHelper
4749
import software.aws.toolkits.jetbrains.core.credentials.profiles.ProfileCredentialProviderFactory
@@ -648,6 +650,62 @@ class ProfileCredentialProviderFactoryTest {
648650
}
649651
}
650652

653+
@Test
654+
fun mfaProfilesAlwaysNeedLogin() {
655+
profileFile.writeToFile(
656+
"""
657+
[profile role]
658+
role_arn=arn1
659+
role_session_name=testSession
660+
external_id=externalId
661+
mfa_serial=someSerialArn
662+
source_profile=source_profile
663+
664+
[profile source_profile]
665+
aws_access_key_id=BarAccessKey
666+
aws_secret_access_key=BarSecretKey
667+
""".trimIndent()
668+
)
669+
670+
createProviderFactory()
671+
672+
assertThat(runBlocking { (findCredentialIdentifier("role") as InteractiveCredential).userActionRequired() }).isTrue()
673+
}
674+
675+
@Test
676+
fun ssoProfilesCanIdentifyIfTheyNeedLogin() {
677+
profileFile.writeToFile(
678+
"""
679+
[profile valid]
680+
sso_start_url=ValidUrl
681+
sso_region=us-east-2
682+
sso_account_id=111222333444
683+
sso_role_name=RoleName
684+
685+
[profile expired]
686+
sso_start_url=ExpiredUrl
687+
sso_region=us-east-2
688+
sso_account_id=111222333444
689+
sso_role_name=RoleName
690+
691+
[profile chain]
692+
source_profile = valid
693+
role_arn = AssumedRoleArn
694+
""".trimIndent()
695+
)
696+
697+
val ssoCache = mock<SsoCache> {
698+
on { loadAccessToken(("ValidUrl")) }.thenReturn(mock())
699+
on { loadAccessToken(("ExpiredUrl")) }.thenReturn(null)
700+
}
701+
702+
createProviderFactory(ssoCache)
703+
704+
assertThat(runBlocking { (findCredentialIdentifier("valid") as InteractiveCredential).userActionRequired() }).isFalse()
705+
assertThat(runBlocking { (findCredentialIdentifier("expired") as InteractiveCredential).userActionRequired() }).isTrue()
706+
assertThat(runBlocking { (findCredentialIdentifier("chain") as InteractiveCredential).userActionRequired() }).isFalse()
707+
}
708+
651709
private fun File.writeToFile(content: String) {
652710
WriteCommandAction.runWriteCommandAction(projectRule.project) {
653711
FileUtil.createIfDoesntExist(this)
@@ -663,8 +721,8 @@ class ProfileCredentialProviderFactoryTest {
663721
}
664722
}
665723

666-
private fun createProviderFactory(): ProfileCredentialProviderFactory {
667-
val factory = ProfileCredentialProviderFactory()
724+
private fun createProviderFactory(ssoCache: SsoCache = mock()): ProfileCredentialProviderFactory {
725+
val factory = ProfileCredentialProviderFactory(ssoCache)
668726
factory.setUp(profileLoadCallback)
669727

670728
return factory

0 commit comments

Comments
 (0)