17
17
18
18
import java .lang .reflect .InvocationTargetException ;
19
19
import java .util .Arrays ;
20
+ import java .util .Objects ;
20
21
import java .util .Optional ;
22
+ import java .util .function .Supplier ;
21
23
import software .amazon .awssdk .annotations .SdkInternalApi ;
22
24
import software .amazon .awssdk .auth .token .credentials .ChildProfileTokenProviderFactory ;
23
25
import software .amazon .awssdk .auth .token .credentials .SdkTokenProvider ;
26
+ import software .amazon .awssdk .core .exception .SdkClientException ;
24
27
import software .amazon .awssdk .core .internal .util .ClassLoaderHelper ;
25
28
import software .amazon .awssdk .profiles .Profile ;
26
29
import software .amazon .awssdk .profiles .ProfileFile ;
27
30
import software .amazon .awssdk .profiles .ProfileProperty ;
28
31
import software .amazon .awssdk .profiles .internal .ProfileSection ;
32
+ import software .amazon .awssdk .utils .Lazy ;
29
33
import software .amazon .awssdk .utils .Validate ;
30
34
31
35
/**
@@ -36,12 +40,17 @@ public final class ProfileTokenProviderLoader {
36
40
private static final String SSO_OIDC_TOKEN_PROVIDER_FACTORY =
37
41
"software.amazon.awssdk.services.ssooidc.SsoOidcProfileTokenProviderFactory" ;
38
42
39
- private final Profile profile ;
40
- private final ProfileFile profileFile ;
43
+ private final Supplier <ProfileFile > profileFileSupplier ;
44
+ private final String profileName ;
45
+ private volatile ProfileFile currentProfileFile ;
46
+ private volatile SdkTokenProvider currentTokenProvider ;
41
47
42
- public ProfileTokenProviderLoader (ProfileFile profileFile , Profile profile ) {
43
- this .profile = Validate .paramNotNull (profile , "profile" );
44
- this .profileFile = Validate .paramNotNull (profileFile , "profileFile" );
48
+ private final Lazy <ChildProfileTokenProviderFactory > factory ;
49
+
50
+ public ProfileTokenProviderLoader (Supplier <ProfileFile > profileFile , String profileName ) {
51
+ this .profileFileSupplier = Validate .paramNotNull (profileFile , "profileFile" );
52
+ this .profileName = Validate .paramNotNull (profileName , "profileName" );
53
+ this .factory = new Lazy <>(this ::ssoTokenProviderFactory );
45
54
}
46
55
47
56
/**
@@ -55,19 +64,53 @@ public Optional<SdkTokenProvider> tokenProvider() {
55
64
* Create the SSO credentials provider based on the related profile properties.
56
65
*/
57
66
private SdkTokenProvider ssoProfileCredentialsProvider () {
67
+ return () -> ssoProfileCredentialsProvider (profileFileSupplier , profileName ).resolveToken ();
68
+ }
69
+
70
+ private SdkTokenProvider ssoProfileCredentialsProvider (ProfileFile profileFile , Profile profile ) {
71
+ String profileSsoSectionName = profileSsoSectionName (profile );
72
+ Profile ssoProfile = ssoProfile (profileFile , profileSsoSectionName );
73
+
74
+ validateRequiredProperties (ssoProfile , ProfileProperty .SSO_REGION , ProfileProperty .SSO_START_URL );
75
+
76
+ return factory .getValue ().create (profileFile , profile );
77
+ }
58
78
59
- String profileSsoSectionName = profile .property (ProfileSection .SSO_SESSION .getPropertyKeyName ())
60
- .orElseThrow (() -> new IllegalArgumentException (
61
- "Profile " + profile .name () + " does not have sso_session property" ));
79
+ private SdkTokenProvider ssoProfileCredentialsProvider (Supplier <ProfileFile > profileFile , String profileName ) {
80
+ ProfileFile profileFileInstance = profileFile .get ();
81
+ if (!Objects .equals (profileFileInstance , currentProfileFile )) {
82
+ synchronized (this ) {
83
+ if (!Objects .equals (profileFileInstance , currentProfileFile )) {
84
+ Profile profileInstance = resolveProfile (profileFileInstance , profileName );
85
+ currentProfileFile = profileFileInstance ;
86
+ currentTokenProvider = ssoProfileCredentialsProvider (profileFileInstance , profileInstance );
87
+ }
88
+ }
89
+ }
90
+
91
+ return currentTokenProvider ;
92
+ }
62
93
63
- Profile ssoProfile = profileFile .getSection (ProfileSection .SSO_SESSION .getSectionTitle (), profileSsoSectionName )
64
- .orElseThrow (() -> new IllegalArgumentException (
65
- "Sso-session section not found with sso-session title " + profileSsoSectionName ));
94
+ private Profile resolveProfile (ProfileFile profileFile , String profileName ) {
95
+ return profileFile .profile (profileName )
96
+ .orElseThrow (() -> {
97
+ String errorMessage = String .format ("Profile file contained no information for profile '%s': %s" ,
98
+ profileName , profileFile );
99
+ return SdkClientException .builder ().message (errorMessage ).build ();
100
+ });
101
+ }
102
+
103
+ private String profileSsoSectionName (Profile profile ) {
104
+ return Optional .ofNullable (profile )
105
+ .flatMap (p -> p .property (ProfileSection .SSO_SESSION .getPropertyKeyName ()))
106
+ .orElseThrow (() -> new IllegalArgumentException (
107
+ "Profile " + profileName + " does not have sso_session property" ));
108
+ }
66
109
67
- validateRequiredProperties ( ssoProfile ,
68
- ProfileProperty . SSO_REGION ,
69
- ProfileProperty . SSO_START_URL );
70
- return ssoTokenProviderFactory (). create ( profileFile , profile );
110
+ private Profile ssoProfile ( ProfileFile profileFile , String profileSsoSectionName ) {
111
+ return profileFile . getSection ( ProfileSection . SSO_SESSION . getSectionTitle (), profileSsoSectionName )
112
+ . orElseThrow (() -> new IllegalArgumentException (
113
+ "Sso-session section not found with sso-session title " + profileSsoSectionName ) );
71
114
}
72
115
73
116
/**
@@ -76,7 +119,8 @@ private SdkTokenProvider ssoProfileCredentialsProvider() {
76
119
private void validateRequiredProperties (Profile ssoProfile , String ... requiredProperties ) {
77
120
Arrays .stream (requiredProperties )
78
121
.forEach (p -> Validate .isTrue (ssoProfile .properties ().containsKey (p ),
79
- "Property '%s' was not configured for profile '%s'." , p , this .profile .name ()));
122
+ "Property '%s' was not configured for profile '%s'." ,
123
+ p , profileName ));
80
124
}
81
125
82
126
/**
@@ -88,10 +132,10 @@ private ChildProfileTokenProviderFactory ssoTokenProviderFactory() {
88
132
getClass ());
89
133
return (ChildProfileTokenProviderFactory ) ssoOidcTokenProviderFactory .getConstructor ().newInstance ();
90
134
} catch (ClassNotFoundException e ) {
91
- throw new IllegalStateException ("To use SSO OIDC related properties in the '" + profile . name () + "' profile, "
135
+ throw new IllegalStateException ("To use SSO OIDC related properties in the '" + profileName + "' profile, "
92
136
+ "the 'ssooidc' service module must be on the class path." , e );
93
137
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e ) {
94
- throw new IllegalStateException ("Failed to create the '" + profile . name () + "' token provider factory." , e );
138
+ throw new IllegalStateException ("Failed to create the '%s " + profileName + "' token provider factory." , e );
95
139
}
96
140
}
97
141
}
0 commit comments