|
26 | 26 | import ch.cyberduck.core.TemporaryAccessTokens; |
27 | 27 | import ch.cyberduck.core.aws.CustomClientConfiguration; |
28 | 28 | import ch.cyberduck.core.exception.BackgroundException; |
| 29 | +import ch.cyberduck.core.exception.LoginCanceledException; |
29 | 30 | import ch.cyberduck.core.exception.LoginFailureException; |
30 | 31 | import ch.cyberduck.core.preferences.HostPreferences; |
31 | 32 | import ch.cyberduck.core.preferences.HostPreferencesFactory; |
@@ -101,38 +102,57 @@ public String validate(final Credentials credentials) throws BackgroundException |
101 | 102 | public TemporaryAccessTokens getSessionToken(final Credentials credentials) throws BackgroundException { |
102 | 103 | final PreferencesReader settings = new ProxyPreferencesReader(bookmark, credentials); |
103 | 104 | // The purpose of the sts:GetSessionToken operation is to authenticate the user using MFA. |
104 | | - final GetSessionTokenRequest sessionTokenRequest = new GetSessionTokenRequest() |
| 105 | + final GetSessionTokenRequest request = new GetSessionTokenRequest() |
105 | 106 | .withRequestCredentialsProvider(S3CredentialsStrategy.toCredentialsProvider(credentials)); |
106 | 107 | final String mfaArn = settings.getProperty(Profile.STS_MFA_ARN_PROPERTY_KEY); |
107 | 108 | if(StringUtils.isNotBlank(mfaArn)) { |
108 | 109 | log.debug("Found MFA ARN {} for {}", mfaArn, bookmark); |
109 | | - sessionTokenRequest.setSerialNumber(mfaArn); |
110 | | - log.debug("Prompt for MFA token code"); |
111 | | - final String tokenCode = prompt.prompt( |
112 | | - bookmark, String.format("%s %s", LocaleFactory.localizedString("Multi-Factor Authentication", "S3"), |
113 | | - mfaArn), |
114 | | - LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), |
115 | | - new LoginOptions(bookmark.getProtocol()) |
116 | | - .password(true) |
117 | | - .passwordPlaceholder(LocaleFactory.localizedString("MFA Authentication Code", "S3")) |
118 | | - .keychain(false) |
119 | | - ).getPassword(); |
120 | | - sessionTokenRequest.setTokenCode(tokenCode); |
121 | | - log.debug("Request {} from {}", sessionTokenRequest, service); |
122 | | - try { |
123 | | - final GetSessionTokenResult sessionTokenResult = service.getSessionToken(sessionTokenRequest); |
124 | | - log.debug("Set credentials from {}", sessionTokenResult); |
125 | | - return new TemporaryAccessTokens( |
126 | | - sessionTokenResult.getCredentials().getAccessKeyId(), |
127 | | - sessionTokenResult.getCredentials().getSecretAccessKey(), |
128 | | - sessionTokenResult.getCredentials().getSessionToken(), |
129 | | - sessionTokenResult.getCredentials().getExpiration().getTime()); |
130 | | - } |
131 | | - catch(AWSSecurityTokenServiceException e) { |
132 | | - throw new STSExceptionMappingService().map(e); |
| 110 | + request.setSerialNumber(mfaArn); |
| 111 | + } |
| 112 | + else { |
| 113 | + if(bookmark.getProtocol().isMultiFactorConfigurable()) { |
| 114 | + // When defined in connection profile but with empty value |
| 115 | + log.debug("Prompt for MFA ARN"); |
| 116 | + try { |
| 117 | + final Credentials input = prompt.prompt(bookmark, |
| 118 | + LocaleFactory.localizedString("MFA Device Identifier", "S3"), |
| 119 | + LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), |
| 120 | + new LoginOptions().icon(bookmark.getProtocol().disk()).password(false) |
| 121 | + .passwordPlaceholder(LocaleFactory.localizedString("Serial Number or Amazon Resource Name (ARN)", "S3"))); |
| 122 | + if(input.isSaved()) { |
| 123 | + preferences.setProperty(Profile.STS_MFA_ARN_PROPERTY_KEY, input.getPassword()); |
| 124 | + } |
| 125 | + request.setSerialNumber(input.getPassword()); |
| 126 | + } |
| 127 | + catch(LoginCanceledException e) { |
| 128 | + log.warn("Canceled MFA ARN input for {}", bookmark); |
| 129 | + } |
133 | 130 | } |
134 | 131 | } |
135 | | - return TemporaryAccessTokens.EMPTY; |
| 132 | + log.debug("Prompt for MFA token code"); |
| 133 | + final String tokenCode = prompt.prompt( |
| 134 | + bookmark, String.format("%s %s", LocaleFactory.localizedString("Multi-Factor Authentication", "S3"), |
| 135 | + mfaArn), |
| 136 | + LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), |
| 137 | + new LoginOptions(bookmark.getProtocol()) |
| 138 | + .password(true) |
| 139 | + .passwordPlaceholder(LocaleFactory.localizedString("MFA Authentication Code", "S3")) |
| 140 | + .keychain(false) |
| 141 | + ).getPassword(); |
| 142 | + request.setTokenCode(tokenCode); |
| 143 | + log.debug("Request {} from {}", request, service); |
| 144 | + try { |
| 145 | + final GetSessionTokenResult result = service.getSessionToken(request); |
| 146 | + log.debug("Set credentials from {}", result); |
| 147 | + return new TemporaryAccessTokens( |
| 148 | + result.getCredentials().getAccessKeyId(), |
| 149 | + result.getCredentials().getSecretAccessKey(), |
| 150 | + result.getCredentials().getSessionToken(), |
| 151 | + result.getCredentials().getExpiration().getTime()); |
| 152 | + } |
| 153 | + catch(AWSSecurityTokenServiceException e) { |
| 154 | + throw new STSExceptionMappingService().map(e); |
| 155 | + } |
136 | 156 | } |
137 | 157 |
|
138 | 158 | /** |
@@ -181,15 +201,20 @@ public TemporaryAccessTokens assumeRole(final Credentials credentials) throws Ba |
181 | 201 | if(StringUtils.EMPTY.equals(mfaArn)) { |
182 | 202 | // When defined in connection profile but with empty value |
183 | 203 | log.debug("Prompt for MFA ARN"); |
184 | | - final Credentials input = prompt.prompt(bookmark, |
185 | | - LocaleFactory.localizedString("MFA Device Identifier", "S3"), |
186 | | - LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), |
187 | | - new LoginOptions().icon(bookmark.getProtocol().disk()).password(false) |
188 | | - .passwordPlaceholder(LocaleFactory.localizedString("Serial Number or Amazon Resource Name (ARN)", "S3"))); |
189 | | - if(input.isSaved()) { |
190 | | - preferences.setProperty(Profile.STS_MFA_ARN_PROPERTY_KEY, input.getPassword()); |
| 204 | + try { |
| 205 | + final Credentials input = prompt.prompt(bookmark, |
| 206 | + LocaleFactory.localizedString("MFA Device Identifier", "S3"), |
| 207 | + LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), |
| 208 | + new LoginOptions().icon(bookmark.getProtocol().disk()).password(false) |
| 209 | + .passwordPlaceholder(LocaleFactory.localizedString("Serial Number or Amazon Resource Name (ARN)", "S3"))); |
| 210 | + if(input.isSaved()) { |
| 211 | + preferences.setProperty(Profile.STS_MFA_ARN_PROPERTY_KEY, input.getPassword()); |
| 212 | + } |
| 213 | + request.setSerialNumber(input.getPassword()); |
| 214 | + } |
| 215 | + catch(LoginCanceledException e) { |
| 216 | + log.warn("Canceled MFA ARN input for {}", bookmark); |
191 | 217 | } |
192 | | - request.setSerialNumber(input.getPassword()); |
193 | 218 | } |
194 | 219 | } |
195 | 220 | if(request.getSerialNumber() != null) { |
|
0 commit comments