1
15
16 package software.amazon.awssdk.auth.credentials;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import software.amazon.awssdk.annotations.SdkPublicApi;
24 import software.amazon.awssdk.core.exception.SdkClientException;
25 import software.amazon.awssdk.utils.IoUtils;
26 import software.amazon.awssdk.utils.Logger;
27 import software.amazon.awssdk.utils.SdkAutoCloseable;
28 import software.amazon.awssdk.utils.ToString;
29 import software.amazon.awssdk.utils.Validate;
30
31
46 @SdkPublicApi
47 public final class AwsCredentialsProviderChain implements AwsCredentialsProvider, SdkAutoCloseable {
48 private static final Logger log = Logger.loggerFor(AwsCredentialsProviderChain.class);
49
50 private final List<AwsCredentialsProvider> credentialsProviders;
51
52 private final boolean reuseLastProviderEnabled;
53
54 private volatile AwsCredentialsProvider lastUsedProvider;
55
56
59 private AwsCredentialsProviderChain(BuilderImpl builder) {
60 this.reuseLastProviderEnabled = builder.reuseLastProviderEnabled;
61 this.credentialsProviders = Collections.unmodifiableList(
62 Validate.notEmpty(builder.credentialsProviders, "No credential providers were specified."));
63 }
64
65
68 public static Builder builder() {
69 return new BuilderImpl();
70 }
71
72
78 public static AwsCredentialsProviderChain of(AwsCredentialsProvider... awsCredentialsProviders) {
79 return builder().credentialsProviders(awsCredentialsProviders).build();
80 }
81
82 @Override
83 public AwsCredentials resolveCredentials() {
84 if (reuseLastProviderEnabled && lastUsedProvider != null) {
85 return lastUsedProvider.resolveCredentials();
86 }
87
88 List<String> exceptionMessages = null;
89 for (AwsCredentialsProvider provider : credentialsProviders) {
90 try {
91 AwsCredentials credentials = provider.resolveCredentials();
92
93 log.debug(() -> "Loading credentials from " + provider);
94
95 lastUsedProvider = provider;
96 return credentials;
97 } catch (RuntimeException e) {
98
99 String message = provider + ": " + e.getMessage();
100 log.debug(() -> "Unable to load credentials from " + message , e);
101
102 if (exceptionMessages == null) {
103 exceptionMessages = new ArrayList<>();
104 }
105 exceptionMessages.add(message);
106 }
107 }
108
109 throw SdkClientException.builder()
110 .message("Unable to load credentials from any of the providers in the chain " +
111 this + " : " + exceptionMessages)
112 .build();
113 }
114
115 @Override
116 public void close() {
117 credentialsProviders.forEach(c -> IoUtils.closeIfCloseable(c, null));
118 }
119
120 @Override
121 public String toString() {
122 return ToString.builder("AwsCredentialsProviderChain")
123 .add("credentialsProviders", credentialsProviders)
124 .build();
125 }
126
127
130 public interface Builder {
131
132
139 Builder reuseLastProviderEnabled(Boolean reuseLastProviderEnabled);
140
141
144 Builder credentialsProviders(Collection<? extends AwsCredentialsProvider> credentialsProviders);
145
146
149 Builder credentialsProviders(AwsCredentialsProvider... credentialsProviders);
150
151
154 Builder addCredentialsProvider(AwsCredentialsProvider credentialsProviders);
155
156 AwsCredentialsProviderChain build();
157 }
158
159 private static final class BuilderImpl implements Builder {
160 private Boolean reuseLastProviderEnabled = true;
161 private List<AwsCredentialsProvider> credentialsProviders = new ArrayList<>();
162
163 private BuilderImpl() {
164 }
165
166 @Override
167 public Builder reuseLastProviderEnabled(Boolean reuseLastProviderEnabled) {
168 this.reuseLastProviderEnabled = reuseLastProviderEnabled;
169 return this;
170 }
171
172 public void setReuseLastProviderEnabled(Boolean reuseLastProviderEnabled) {
173 reuseLastProviderEnabled(reuseLastProviderEnabled);
174 }
175
176 @Override
177 public Builder credentialsProviders(Collection<? extends AwsCredentialsProvider> credentialsProviders) {
178 this.credentialsProviders = new ArrayList<>(credentialsProviders);
179 return this;
180 }
181
182 public void setCredentialsProviders(Collection<? extends AwsCredentialsProvider> credentialsProviders) {
183 credentialsProviders(credentialsProviders);
184 }
185
186 @Override
187 public Builder credentialsProviders(AwsCredentialsProvider... credentialsProviders) {
188 return credentialsProviders(Arrays.asList(credentialsProviders));
189 }
190
191 @Override
192 public Builder addCredentialsProvider(AwsCredentialsProvider credentialsProviders) {
193 this.credentialsProviders.add(credentialsProviders);
194 return this;
195 }
196
197 @Override
198 public AwsCredentialsProviderChain build() {
199 return new AwsCredentialsProviderChain(this);
200 }
201 }
202 }
203