Skip to content

HOWTO: Assume Role With Saml in java sdk 2.x #1016

Description

@mscharp

This may be a bug, or a misunderstanding of how to use the 2.0 sdk to assume a role with SAML. In short, I would like to use Secure Token Service to authenticate with my Identity Provider and then once authenticated, assume a role in AWS to use when calling different services.

Expected Behavior

Currently, I am using the StsAssumeRoleWithSamlCredentialProvider. Once I configure the credential provider and give it a mechanism to get a valid saml assertion from my Identity Provider, I should be able to give that credential provider to any other service client so that it will use those credentials when making API calls. Those other services should NOT attempt to get credentials from any other sources ( this includes the DefaultCredentialProvider which looks in a myriad of places).

Current Behavior

When I pass the StsAssumeRoleWithSamlCredentialProvider to another service client ( such as CloudWatchLogsClient ), and initiate a request, the request fails with multiple "Unable to load credentials from ***" errors. Here is one of the stack traces:

[http-nio-8080-exec-1] DEBUG software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain - Unable to load credentials from SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId). software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId). at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97) at software.amazon.awssdk.auth.credentials.internal.SystemSettingsCredentialsProvider.resolveCredentials(SystemSettingsCredentialsProvider.java:58) at software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain.resolveCredentials(AwsCredentialsProviderChain.java:91) at software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider.resolveCredentials(DefaultCredentialsProvider.java:92) at software.amazon.awssdk.awscore.client.handler.AwsClientHandlerUtils.createExecutionContext(AwsClientHandlerUtils.java:70) at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.createExecutionContext(AwsSyncClientHandler.java:68) at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:68) at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44) at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55) at software.amazon.awssdk.services.sts.DefaultStsClient.assumeRoleWithSAML(DefaultStsClient.java:370) at software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithSamlCredentialsProvider.getUpdatedCredentials(StsAssumeRoleWithSamlCredentialsProvider.java:69) at software.amazon.awssdk.services.sts.auth.StsCredentialsProvider.updateSessionCredentials(StsCredentialsProvider.java:68) at software.amazon.awssdk.utils.cache.CachedSupplier.refreshCache(CachedSupplier.java:132) at software.amazon.awssdk.utils.cache.CachedSupplier.get(CachedSupplier.java:89) at software.amazon.awssdk.services.sts.auth.StsCredentialsProvider.resolveCredentials(StsCredentialsProvider.java:78) at software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithSamlCredentialsProvider.resolveCredentials(StsAssumeRoleWithSamlCredentialsProvider.java:42) at software.amazon.awssdk.awscore.client.handler.AwsClientHandlerUtils.createExecutionContext(AwsClientHandlerUtils.java:70) at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.createExecutionContext(AwsSyncClientHandler.java:68) at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:68) at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44) at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55) at software.amazon.awssdk.services.cloudwatchlogs.DefaultCloudWatchLogsClient.getLogEvents(DefaultCloudWatchLogsClient.java:1836) at logs.GetAWSLogs.getLogs(GetAWSLogs.java:167)

What I think may be the cause of this issue is that the StsAssumeRoleWithSamlCredentialsProvider uses the StsClient to make the request. The default StsClient uses the DefaultCredentialsProvider to authenticate with AWS in order to make the request. You can override the credentials provider in the StsClient with the overrideConfiguration method, but since the StsAssumeRoleWithSamlCredentialsProvider requires the StsClient, it seems that its a "chicken and egg" scenario. You can't configure the Sts..CredentialsProvider without an StsClient, but the StsClient needs a credentials provider itself...

Guidance on how to correctly assume a role, or if this is truly a bug, then a quick fix would be very much appreciated.

Steps to Reproduce (for bugs)

`
ProxyConfiguration proxyConfig = null;
try {
proxyConfig = ProxyConfiguration
.builder()
.endpoint(new URI("http_proxy"))
.build();
} catch (URISyntaxException e) {
e.printStackTrace();
}

AWSSAMLAuthenticationConfiguration config = AWSSAMLAuthenticationConfiguration
            .builder()
            .userName(ad_user)
            .userPass(ad_pass)
            .roleName(aws_role)
            .region(Region.US_EAST_1)
            .proxyConfig(proxyConfig)
            .build();

SdkHttpClient httpClient = ApacheHttpClient
        .builder()
        .proxyConfiguration(proxyConfig)
        .build();

AssumeRoleWithSamlRequest request = AssumeRoleWithSamlRequest
        .builder()
        .durationSeconds(900)
        .roleArn(ROLE_ARN)
        .principalArn("PRINCIPAL_ARN")
        .build();

SamlIdentityProviderServiceFactory factory = new SamlIdentityProviderServiceFactory();
SamlIdentityProviderService service = factory.getService(config);

Supplier<AssumeRoleWithSamlRequest> supplier = () ->
        request.toBuilder()
               .samlAssertion(service.getValidAssertion())
               .build();

cp = StsAssumeRoleWithSamlCredentialsProvider
        .builder()
        .stsClient(StsClient.builder().region(Region.US_EAST_1).httpClient(httpClient).build())
        .asyncCredentialUpdateEnabled(true)
        .refreshRequest(supplier)
        .build();

cw = CloudWatchLogsClient.builder()
                .httpClient(httpClient)
                .region(Region.US_EAST_1)
                .credentialsProvider(cp)
                .build();

GetLogEventsResponse logEventsResponse = cw.getLogEvents(GetLogEventsRequest.builder()
                                                                            .logGroupName(logGroup)
                                                                            .logStreamName(logStream)
                                                                            .startFromHead(true)
                                                                            .build());

`

Context

Without the ability to correctly assume a role via saml, we cannot migrate to the 2.0 version of the SDK.

Your Environment

  • AWS Java SDK version used: 2.3.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestA feature should be added or improved.p1This is a high priority issue

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions