Skip to content

Commit 7be1cdc

Browse files
committed
1 parent 4b142f4 commit 7be1cdc

1 file changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* Copyright 2013-2022 the original author or authors.
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+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.awspring.cloud.autoconfigure.core;
17+
18+
import java.nio.file.Paths;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import org.springframework.beans.factory.ObjectProvider;
24+
import org.springframework.boot.autoconfigure.AutoConfiguration;
25+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
29+
import org.springframework.boot.context.properties.PropertyMapper;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.lang.Nullable;
32+
import org.springframework.util.ClassUtils;
33+
import org.springframework.util.StringUtils;
34+
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
35+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
36+
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
37+
import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain;
38+
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
39+
import software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider;
40+
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
41+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
42+
import software.amazon.awssdk.profiles.ProfileFile;
43+
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
44+
import software.amazon.awssdk.services.sts.StsClient;
45+
import software.amazon.awssdk.services.sts.auth.StsWebIdentityTokenFileCredentialsProvider;
46+
47+
/**
48+
* {@link EnableAutoConfiguration} for {@link AwsCredentialsProvider}.
49+
*
50+
* @author Maciej Walkowiak
51+
* @author Eddú Meléndez
52+
* @author Eduan Bekker
53+
*/
54+
@AutoConfiguration
55+
@ConditionalOnClass({ AwsCredentialsProvider.class, ProfileFile.class })
56+
@ConditionalOnMissingBean(AwsCredentialsProvider.class)
57+
@EnableConfigurationProperties(CredentialsProperties.class)
58+
public class CredentialsProviderAutoConfiguration {
59+
60+
private static final Logger LOGGER = LoggerFactory.getLogger(CredentialsProviderAutoConfiguration.class);
61+
62+
private static final String STS_WEB_IDENTITY_TOKEN_FILE_CREDENTIALS_PROVIDER = "software.amazon.awssdk.services.sts.auth.StsWebIdentityTokenFileCredentialsProvider";
63+
64+
private final CredentialsProperties properties;
65+
66+
private final AwsRegionProvider regionProvider;
67+
68+
private final ObjectProvider<AwsConnectionDetails> connectionDetails;
69+
70+
public CredentialsProviderAutoConfiguration(CredentialsProperties properties, AwsRegionProvider regionProvider,
71+
ObjectProvider<AwsConnectionDetails> connectionDetails) {
72+
this.properties = properties;
73+
this.regionProvider = regionProvider;
74+
this.connectionDetails = connectionDetails;
75+
}
76+
77+
@Bean
78+
public AwsCredentialsProvider credentialsProvider() {
79+
return createCredentialsProvider(this.properties, this.regionProvider, this.connectionDetails.getIfAvailable());
80+
}
81+
82+
public static AwsCredentialsProvider createCredentialsProvider(CredentialsProperties properties,
83+
AwsRegionProvider regionProvider) {
84+
return createCredentialsProvider(properties, regionProvider, null);
85+
}
86+
87+
public static AwsCredentialsProvider createCredentialsProvider(CredentialsProperties properties,
88+
AwsRegionProvider regionProvider, @Nullable AwsConnectionDetails connectionDetails) {
89+
final List<AwsCredentialsProvider> providers = new ArrayList<>();
90+
91+
if (connectionDetails != null && StringUtils.hasText(connectionDetails.getAccessKey())
92+
&& StringUtils.hasText(connectionDetails.getSecretKey())) {
93+
providers.add(createStaticCredentialsProvider(connectionDetails));
94+
}
95+
96+
if (StringUtils.hasText(properties.getAccessKey()) && StringUtils.hasText(properties.getSecretKey())) {
97+
providers.add(createStaticCredentialsProvider(properties));
98+
}
99+
100+
if (properties.isInstanceProfile()) {
101+
providers.add(InstanceProfileCredentialsProvider.create());
102+
}
103+
104+
Profile profile = properties.getProfile();
105+
if (profile != null && profile.getName() != null) {
106+
providers.add(createProfileCredentialProvider(profile));
107+
}
108+
109+
StsProperties sts = properties.getSts();
110+
if (ClassUtils.isPresent(STS_WEB_IDENTITY_TOKEN_FILE_CREDENTIALS_PROVIDER, null)) {
111+
try {
112+
providers.add(StsCredentialsProviderFactory.create(sts, regionProvider));
113+
}
114+
catch (IllegalStateException e) {
115+
LOGGER.warn(
116+
"Skipping creating `StsCredentialsProvider`. `software.amazon.awssdk:sts` is on the classpath, but neither `spring.cloud.aws.credentials.sts` properties are configured nor `AWS_WEB_IDENTITY_TOKEN_FILE` or the javaproperty `aws.webIdentityTokenFile` is set");
117+
}
118+
}
119+
120+
if (providers.isEmpty()) {
121+
return DefaultCredentialsProvider.create();
122+
}
123+
else if (providers.size() == 1) {
124+
return providers.get(0);
125+
}
126+
else {
127+
return AwsCredentialsProviderChain.builder().credentialsProviders(providers).build();
128+
}
129+
}
130+
131+
private static StaticCredentialsProvider createStaticCredentialsProvider(CredentialsProperties properties) {
132+
return StaticCredentialsProvider
133+
.create(AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
134+
}
135+
136+
private static StaticCredentialsProvider createStaticCredentialsProvider(AwsConnectionDetails connectionDetails) {
137+
return StaticCredentialsProvider
138+
.create(AwsBasicCredentials.create(connectionDetails.getAccessKey(), connectionDetails.getSecretKey()));
139+
}
140+
141+
private static ProfileCredentialsProvider createProfileCredentialProvider(Profile profile) {
142+
ProfileFile profileFile;
143+
if (profile.getPath() != null) {
144+
profileFile = ProfileFile.builder()
145+
.type(ProfileFile.Type.CREDENTIALS)
146+
.content(Paths.get(profile.getPath()))
147+
.build();
148+
}
149+
else {
150+
profileFile = ProfileFile.defaultProfileFile();
151+
}
152+
return ProfileCredentialsProvider.builder().profileName(profile.getName()).profileFile(profileFile).build();
153+
}
154+
155+
/**
156+
* Wrapper class to avoid {@link NoClassDefFoundError}.
157+
*/
158+
private static class StsCredentialsProviderFactory {
159+
160+
private static AwsCredentialsProvider create(@Nullable StsProperties stsProperties,
161+
AwsRegionProvider regionProvider) {
162+
PropertyMapper propertyMapper = PropertyMapper.get();
163+
StsWebIdentityTokenFileCredentialsProvider.Builder builder = StsWebIdentityTokenFileCredentialsProvider
164+
.builder()
165+
.stsClient(StsClient.builder()
166+
.credentialsProvider(AnonymousCredentialsProvider.create())
167+
.region(regionProvider.getRegion())
168+
.build());
169+
170+
if (stsProperties != null) {
171+
builder.asyncCredentialUpdateEnabled(stsProperties.isAsyncCredentialsUpdate());
172+
propertyMapper.from(stsProperties::getRoleArn).to(builder::roleArn);
173+
propertyMapper.from(stsProperties::getWebIdentityTokenFile)
174+
.to(b -> builder.webIdentityTokenFile(Paths.get(b)));
175+
propertyMapper.from(stsProperties::getRoleSessionName).to(builder::roleSessionName);
176+
}
177+
return builder.build();
178+
}
179+
180+
}
181+
182+
}

0 commit comments

Comments
 (0)