1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.services.sts.auth; 17 18 import static software.amazon.awssdk.services.sts.internal.StsAuthUtils.toAwsSessionCredentials; 19 20 import java.util.function.Consumer; 21 import java.util.function.Supplier; 22 import software.amazon.awssdk.annotations.NotThreadSafe; 23 import software.amazon.awssdk.annotations.SdkPublicApi; 24 import software.amazon.awssdk.annotations.ThreadSafe; 25 import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 26 import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; 27 import software.amazon.awssdk.services.sts.StsClient; 28 import software.amazon.awssdk.services.sts.model.AssumeRoleRequest; 29 import software.amazon.awssdk.utils.ToString; 30 import software.amazon.awssdk.utils.Validate; 31 import software.amazon.awssdk.utils.builder.ToCopyableBuilder; 32 33 /** 34 * An implementation of {@link AwsCredentialsProvider} that periodically sends an {@link AssumeRoleRequest} to the AWS 35 * Security Token Service to maintain short-lived sessions to use for authentication. These sessions are updated using a single 36 * calling thread (by default) or asynchronously (if {@link Builder#asyncCredentialUpdateEnabled(Boolean)} is set). 37 * 38 * If the credentials are not successfully updated before expiration, calls to {@link #resolveCredentials()} will block until 39 * they are updated successfully. 40 * 41 * Users of this provider must {@link #close()} it when they are finished using it. 42 * 43 * This is created using {@link StsAssumeRoleCredentialsProvider#builder()}. 44 */ 45 @SdkPublicApi 46 @ThreadSafe 47 public final class StsAssumeRoleCredentialsProvider 48 extends StsCredentialsProvider 49 implements ToCopyableBuilder<StsAssumeRoleCredentialsProvider.Builder, StsAssumeRoleCredentialsProvider> { 50 private Supplier<AssumeRoleRequest> assumeRoleRequestSupplier; 51 52 /** 53 * @see #builder() 54 */ StsAssumeRoleCredentialsProvider(Builder builder)55 private StsAssumeRoleCredentialsProvider(Builder builder) { 56 super(builder, "sts-assume-role-credentials-provider"); 57 Validate.notNull(builder.assumeRoleRequestSupplier, "Assume role request must not be null."); 58 59 this.assumeRoleRequestSupplier = builder.assumeRoleRequestSupplier; 60 } 61 62 /** 63 * Create a builder for an {@link StsAssumeRoleCredentialsProvider}. 64 */ builder()65 public static Builder builder() { 66 return new Builder(); 67 } 68 69 @Override getUpdatedCredentials(StsClient stsClient)70 protected AwsSessionCredentials getUpdatedCredentials(StsClient stsClient) { 71 AssumeRoleRequest assumeRoleRequest = assumeRoleRequestSupplier.get(); 72 Validate.notNull(assumeRoleRequest, "Assume role request must not be null."); 73 return toAwsSessionCredentials(stsClient.assumeRole(assumeRoleRequest).credentials()); 74 } 75 76 @Override toString()77 public String toString() { 78 return ToString.create("StsAssumeRoleCredentialsProvider"); 79 } 80 81 @Override toBuilder()82 public Builder toBuilder() { 83 return new Builder(this); 84 } 85 86 /** 87 * A builder (created by {@link StsAssumeRoleCredentialsProvider#builder()}) for creating a 88 * {@link StsAssumeRoleCredentialsProvider}. 89 */ 90 @NotThreadSafe 91 public static final class Builder extends BaseBuilder<Builder, StsAssumeRoleCredentialsProvider> { 92 private Supplier<AssumeRoleRequest> assumeRoleRequestSupplier; 93 Builder()94 private Builder() { 95 super(StsAssumeRoleCredentialsProvider::new); 96 } 97 Builder(StsAssumeRoleCredentialsProvider provider)98 private Builder(StsAssumeRoleCredentialsProvider provider) { 99 super(StsAssumeRoleCredentialsProvider::new, provider); 100 this.assumeRoleRequestSupplier = provider.assumeRoleRequestSupplier; 101 } 102 103 /** 104 * Configure the {@link AssumeRoleRequest} that should be periodically sent to the STS service to update the assumed 105 * credentials. 106 * 107 * @param assumeRoleRequest The request to send to STS whenever the assumed session expires. 108 * @return This object for chained calls. 109 */ refreshRequest(AssumeRoleRequest assumeRoleRequest)110 public Builder refreshRequest(AssumeRoleRequest assumeRoleRequest) { 111 return refreshRequest(() -> assumeRoleRequest); 112 } 113 114 /** 115 * Similar to {@link #refreshRequest(AssumeRoleRequest)}, but takes a {@link Supplier} to supply the request to 116 * STS. 117 * 118 * @param assumeRoleRequestSupplier A supplier 119 * @return This object for chained calls. 120 */ refreshRequest(Supplier<AssumeRoleRequest> assumeRoleRequestSupplier)121 public Builder refreshRequest(Supplier<AssumeRoleRequest> assumeRoleRequestSupplier) { 122 this.assumeRoleRequestSupplier = assumeRoleRequestSupplier; 123 return this; 124 } 125 126 /** 127 * Similar to {@link #refreshRequest(AssumeRoleRequest)}, but takes a lambda to configure a new 128 * {@link AssumeRoleRequest.Builder}. This removes the need to called {@link AssumeRoleRequest#builder()} and 129 * {@link AssumeRoleRequest.Builder#build()}. 130 */ refreshRequest(Consumer<AssumeRoleRequest.Builder> assumeRoleRequest)131 public Builder refreshRequest(Consumer<AssumeRoleRequest.Builder> assumeRoleRequest) { 132 return refreshRequest(AssumeRoleRequest.builder().applyMutation(assumeRoleRequest).build()); 133 } 134 135 @Override build()136 public StsAssumeRoleCredentialsProvider build() { 137 return super.build(); 138 } 139 140 } 141 } 142