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,33 @@ 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
43
+ private final boolean createProviderFromSupplier ;
44
+
39
45
private final Profile profile ;
40
46
private final ProfileFile profileFile ;
47
+ private final Supplier <ProfileFile > profileFileSupplier ;
48
+ private final String profileName ;
49
+ private volatile ProfileFile currentProfileFile ;
50
+ private volatile SdkTokenProvider currentTokenProvider ;
51
+
52
+ private final Lazy <ChildProfileTokenProviderFactory > factory ;
41
53
42
- public ProfileTokenProviderLoader (ProfileFile profileFile , Profile profile ) {
43
- this .profile = Validate . paramNotNull ( profile , "profile" ) ;
54
+ public ProfileTokenProviderLoader (ProfileFile profileFile , String profileName ) {
55
+ this .createProviderFromSupplier = false ;
44
56
this .profileFile = Validate .paramNotNull (profileFile , "profileFile" );
57
+ this .profileFileSupplier = null ;
58
+ this .profileName = Validate .paramNotNull (profileName , "profileName" );
59
+ this .profile = resolveProfile (profileFile , profileName );
60
+ this .factory = new Lazy <>(this ::ssoTokenProviderFactory );
61
+ }
62
+
63
+ public ProfileTokenProviderLoader (Supplier <ProfileFile > profileFile , String profileName ) {
64
+ createProviderFromSupplier = true ;
65
+ this .profileFile = null ;
66
+ this .profileFileSupplier = Validate .paramNotNull (profileFile , "profileFile" );
67
+ this .profileName = Validate .paramNotNull (profileName , "profileName" );
68
+ this .profile = null ;
69
+ this .factory = new Lazy <>(this ::ssoTokenProviderFactory );
45
70
}
46
71
47
72
/**
@@ -55,19 +80,53 @@ public Optional<SdkTokenProvider> tokenProvider() {
55
80
* Create the SSO credentials provider based on the related profile properties.
56
81
*/
57
82
private SdkTokenProvider ssoProfileCredentialsProvider () {
83
+ if (createProviderFromSupplier ) {
84
+ return () -> ssoProfileCredentialsProvider (profileFileSupplier , profileName ).resolveToken ();
85
+ }
58
86
59
- String profileSsoSectionName = profile .property (ProfileSection .SSO_SESSION .getPropertyKeyName ())
60
- .orElseThrow (() -> new IllegalArgumentException (
61
- "Profile " + profile .name () + " does not have sso_session property" ));
87
+ return ssoProfileCredentialsProvider (profileFile , profile );
88
+ }
89
+
90
+ private SdkTokenProvider ssoProfileCredentialsProvider (ProfileFile profileFile , Profile profile ) {
91
+ String profileSsoSectionName = profileSsoSectionName (profile );
92
+ Profile ssoProfile = ssoProfile (profileFile , profileSsoSectionName );
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
+ validateRequiredProperties (ssoProfile , ProfileProperty .SSO_REGION , ProfileProperty .SSO_START_URL );
95
+
96
+ return factory .getValue ().create (profileFile , profile );
97
+ }
98
+
99
+ private synchronized SdkTokenProvider ssoProfileCredentialsProvider (Supplier <ProfileFile > profileFile , String profileName ) {
100
+ ProfileFile profileFileInstance = profileFile .get ();
101
+ Profile profileInstance = resolveProfile (profileFileInstance , profileName );
102
+ if (!Objects .equals (profileFileInstance , currentProfileFile )) {
103
+ currentProfileFile = profileFileInstance ;
104
+ currentTokenProvider = ssoProfileCredentialsProvider (profileFileInstance , profileInstance );
105
+ }
106
+
107
+ return currentTokenProvider ;
108
+ }
109
+
110
+ private Profile resolveProfile (ProfileFile profileFile , String profileName ) {
111
+ return profileFile .profile (profileName )
112
+ .orElseThrow (() -> {
113
+ String errorMessage = String .format ("Profile file contained no information for profile '%s': %s" ,
114
+ profileName , profileFile );
115
+ return SdkClientException .builder ().message (errorMessage ).build ();
116
+ });
117
+ }
118
+
119
+ private String profileSsoSectionName (Profile profile ) {
120
+ return Optional .ofNullable (profile )
121
+ .flatMap (p -> p .property (ProfileSection .SSO_SESSION .getPropertyKeyName ()))
122
+ .orElseThrow (() -> new IllegalArgumentException (
123
+ "Profile " + profileName + " does not have sso_session property" ));
124
+ }
66
125
67
- validateRequiredProperties ( ssoProfile ,
68
- ProfileProperty . SSO_REGION ,
69
- ProfileProperty . SSO_START_URL );
70
- return ssoTokenProviderFactory (). create ( profileFile , profile );
126
+ private Profile ssoProfile ( ProfileFile profileFile , String profileSsoSectionName ) {
127
+ return profileFile . getSection ( ProfileSection . SSO_SESSION . getSectionTitle (), profileSsoSectionName )
128
+ . orElseThrow (() -> new IllegalArgumentException (
129
+ "Sso-session section not found with sso-session title " + profileSsoSectionName ) );
71
130
}
72
131
73
132
/**
@@ -76,7 +135,8 @@ private SdkTokenProvider ssoProfileCredentialsProvider() {
76
135
private void validateRequiredProperties (Profile ssoProfile , String ... requiredProperties ) {
77
136
Arrays .stream (requiredProperties )
78
137
.forEach (p -> Validate .isTrue (ssoProfile .properties ().containsKey (p ),
79
- "Property '%s' was not configured for profile '%s'." , p , this .profile .name ()));
138
+ "Property '%s' was not configured for profile '%s'." ,
139
+ p , profileName ));
80
140
}
81
141
82
142
/**
@@ -88,10 +148,10 @@ private ChildProfileTokenProviderFactory ssoTokenProviderFactory() {
88
148
getClass ());
89
149
return (ChildProfileTokenProviderFactory ) ssoOidcTokenProviderFactory .getConstructor ().newInstance ();
90
150
} catch (ClassNotFoundException e ) {
91
- throw new IllegalStateException ("To use SSO OIDC related properties in the '" + profile . name () + "' profile, "
151
+ throw new IllegalStateException ("To use SSO OIDC related properties in the '" + profileName + "' profile, "
92
152
+ "the 'ssooidc' service module must be on the class path." , e );
93
153
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e ) {
94
- throw new IllegalStateException ("Failed to create the '" + profile . name () + "' token provider factory." , e );
154
+ throw new IllegalStateException ("Failed to create the '%s " + profileName + "' token provider factory." , e );
95
155
}
96
156
}
97
157
}
0 commit comments