Skip to content

Commit f2207c4

Browse files
authored
Merge pull request #17440 from iterate-ch/feature/GH-17437
Interceptor for STS AssumeRole and GetSessionToken
2 parents 308e37f + 38eeefb commit f2207c4

File tree

48 files changed

+1320
-1280
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1320
-1280
lines changed

core/src/main/java/ch/cyberduck/core/AbstractProtocol.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.util.List;
3636
import java.util.Locale;
3737
import java.util.Map;
38-
import java.util.Objects;
3938
import java.util.Set;
4039
import java.util.stream.Collectors;
4140

@@ -292,6 +291,16 @@ public boolean isPrivateKeyConfigurable() {
292291
return false;
293292
}
294293

294+
@Override
295+
public boolean isRoleConfigurable() {
296+
return false;
297+
}
298+
299+
@Override
300+
public boolean isMultiFactorConfigurable() {
301+
return false;
302+
}
303+
295304
@Override
296305
public boolean isUTCTimezone() {
297306
return true;
@@ -445,23 +454,27 @@ public boolean validate(final Credentials credentials, final LoginOptions option
445454
}
446455
}
447456
if(options.password) {
457+
if(credentials.isAnonymousLogin()) {
458+
return true;
459+
}
448460
switch(this.getType()) {
449461
case ftp:
450462
case dav:
451-
return Objects.nonNull(credentials.getPassword());
463+
// Allow blank password
464+
return credentials.isPasswordAuthentication(true);
452465
case sftp:
453466
// SFTP agent auth requires no password and no private key selection
454467
return true;
455468
default:
456-
return StringUtils.isNotBlank(credentials.getPassword());
469+
return credentials.isPasswordAuthentication();
457470
}
458471
}
459472
if(options.oauth) {
460-
// Always refresh tokens in login
473+
// Always authentication with no tokens preset
461474
return true;
462475
}
463476
if(options.token) {
464-
return StringUtils.isNotBlank(credentials.getToken());
477+
return credentials.isTokenAuthentication();
465478
}
466479
return true;
467480
}

core/src/main/java/ch/cyberduck/core/AnonymousConnectionService.java

Lines changed: 0 additions & 44 deletions
This file was deleted.

core/src/main/java/ch/cyberduck/core/Credentials.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919
*/
2020

2121
import ch.cyberduck.core.preferences.PreferencesFactory;
22+
import ch.cyberduck.core.preferences.PreferencesReader;
2223

2324
import org.apache.commons.lang3.StringUtils;
2425

26+
import java.util.HashMap;
27+
import java.util.Map;
2528
import java.util.Objects;
2629

2730
/**
2831
* Stores the login credentials
2932
*/
30-
public class Credentials implements Comparable<Credentials> {
33+
public class Credentials implements Comparable<Credentials>, PreferencesReader {
3134

3235
/**
3336
* The login name
@@ -38,13 +41,26 @@ public class Credentials implements Comparable<Credentials> {
3841
* The login password
3942
*/
4043
private String password = StringUtils.EMPTY;
44+
/**
45+
* Temporary access tokens
46+
*/
4147
private TemporaryAccessTokens tokens = TemporaryAccessTokens.EMPTY;
48+
/**
49+
* OIDC tokens
50+
*/
4251
private OAuthTokens oauth = OAuthTokens.EMPTY;
52+
/**
53+
* Custom protocol dependent properties related to authentication
54+
*/
55+
private final Map<String, String> properties = new HashMap<>();
4356

4457
/**
4558
* Private key identity for SSH public key authentication.
4659
*/
4760
private Local identity;
61+
/**
62+
* Passphrase for private key identity for SSH public key authentication.
63+
*/
4864
private String identityPassphrase = StringUtils.EMPTY;
4965

5066
/**
@@ -69,6 +85,7 @@ public Credentials(final Credentials copy) {
6985
this.password = copy.password;
7086
this.tokens = copy.tokens;
7187
this.oauth = copy.oauth;
88+
this.properties.putAll(copy.properties);
7289
this.identity = copy.identity;
7390
this.identityPassphrase = copy.identityPassphrase;
7491
this.certificate = copy.certificate;
@@ -199,15 +216,26 @@ public boolean isAnonymousLogin() {
199216
}
200217

201218
public boolean isPasswordAuthentication() {
219+
return this.isPasswordAuthentication(false);
220+
}
221+
222+
/**
223+
* @param allowblank Allow blank password
224+
*/
225+
public boolean isPasswordAuthentication(final boolean allowblank) {
226+
if(allowblank) {
227+
// Allow blank password
228+
return Objects.nonNull(password);
229+
}
202230
return StringUtils.isNotBlank(password);
203231
}
204232

205233
public boolean isTokenAuthentication() {
206-
return StringUtils.isNotBlank(tokens.getSessionToken());
234+
return tokens != TemporaryAccessTokens.EMPTY;
207235
}
208236

209237
public boolean isOAuthAuthentication() {
210-
return oauth.validate();
238+
return oauth != OAuthTokens.EMPTY;
211239
}
212240

213241
/**
@@ -273,6 +301,16 @@ public boolean isCertificateAuthentication() {
273301
return true;
274302
}
275303

304+
public Credentials withProperty(final String key, final String value) {
305+
properties.put(key, value);
306+
return this;
307+
}
308+
309+
@Override
310+
public String getProperty(final String key) {
311+
return properties.get(key);
312+
}
313+
276314
/**
277315
* @param protocol The protocol to verify against.
278316
* @param options Options
@@ -337,6 +375,7 @@ public String toString() {
337375
sb.append(", tokens='").append(tokens).append('\'');
338376
sb.append(", oauth='").append(oauth).append('\'');
339377
sb.append(", identity=").append(identity);
378+
sb.append(", properties=").append(properties);
340379
sb.append('}');
341380
return sb.toString();
342381
}

core/src/main/java/ch/cyberduck/core/Host.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import ch.cyberduck.core.ftp.FTPConnectMode;
2222
import ch.cyberduck.core.preferences.PreferencesFactory;
23+
import ch.cyberduck.core.preferences.PreferencesReader;
2324
import ch.cyberduck.core.serializer.Serializer;
2425

2526
import org.apache.commons.lang3.StringUtils;
@@ -31,7 +32,7 @@
3132
import java.util.Set;
3233
import java.util.TimeZone;
3334

34-
public class Host implements Serializable, Comparable<Host> {
35+
public class Host implements Serializable, Comparable<Host>, PreferencesReader {
3536

3637
/**
3738
* The credentials to authenticate with for the CDN
@@ -347,6 +348,7 @@ public Credentials getCredentials() {
347348
}
348349

349350
public void setCredentials(final Credentials credentials) {
351+
log.debug("Setting credentials for {} to {}", this, credentials);
350352
this.credentials = credentials;
351353
}
352354

@@ -527,11 +529,15 @@ public void setTimezone(final TimeZone timezone) {
527529
* @param key Property name
528530
* @return Value for property key
529531
*/
532+
@Override
530533
public String getProperty(final String key) {
531534
final Map<String, String> overrides = this.getCustom();
532535
if(overrides.containsKey(key)) {
533536
return overrides.get(key);
534537
}
538+
if(credentials.getProperty(key) != null) {
539+
return credentials.getProperty(key);
540+
}
535541
return protocol.getProperties().get(key);
536542
}
537543

core/src/main/java/ch/cyberduck/core/KeychainLoginService.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import ch.cyberduck.core.exception.LocalAccessDeniedException;
2323
import ch.cyberduck.core.exception.LoginCanceledException;
2424
import ch.cyberduck.core.exception.LoginFailureException;
25-
import ch.cyberduck.core.proxy.ProxyFinder;
2625
import ch.cyberduck.core.threading.CancelCallback;
2726

2827
import org.apache.commons.lang3.StringUtils;
@@ -61,8 +60,7 @@ public void validate(final Host bookmark, final LoginCallback prompt, final Logi
6160
if(StringUtils.isNotBlank(password)) {
6261
log.info("Fetched password from keychain for {}", bookmark);
6362
// No need to reinsert found password to the keychain.
64-
credentials.setSaved(false);
65-
credentials.setPassword(password);
63+
credentials.withPassword(password).setSaved(false);
6664
}
6765
}
6866
}
@@ -72,8 +70,7 @@ public void validate(final Host bookmark, final LoginCallback prompt, final Logi
7270
if(StringUtils.isNotBlank(token)) {
7371
log.info("Fetched token from keychain for {}", bookmark);
7472
// No need to reinsert found token to the keychain.
75-
credentials.setSaved(false);
76-
credentials.setToken(token);
73+
credentials.withToken(token).setSaved(false);
7774
}
7875
}
7976
}
@@ -82,26 +79,27 @@ public void validate(final Host bookmark, final LoginCallback prompt, final Logi
8279
if(StringUtils.isNotBlank(passphrase)) {
8380
log.info("Fetched private key passphrase from keychain for {}", bookmark);
8481
// No need to reinsert found token to the keychain.
85-
credentials.setSaved(false);
86-
credentials.setIdentityPassphrase(passphrase);
82+
credentials.withIdentityPassphrase(passphrase).setSaved(false);
8783
}
8884
}
8985
if(options.oauth) {
9086
final OAuthTokens tokens = keychain.findOAuthTokens(bookmark);
9187
if(tokens.validate()) {
9288
log.info("Fetched OAuth token from keychain for {}", bookmark);
9389
// No need to reinsert found token to the keychain.
94-
credentials.setSaved(tokens.isExpired());
95-
credentials.setOauth(tokens);
90+
credentials.withOauth(tokens).setSaved(tokens.isExpired());
9691
}
9792
}
9893
}
9994
if(!credentials.validate(bookmark.getProtocol(), options)) {
100-
final CredentialsConfigurator configurator = bookmark.getProtocol().getFeature(CredentialsConfigurator.class);
95+
final CredentialsConfigurator configurator = CredentialsConfiguratorFactory.get(bookmark.getProtocol());
10196
log.debug("Auto configure credentials with {}", configurator);
102-
bookmark.setCredentials(configurator.configure(bookmark));
103-
}
104-
if(!credentials.validate(bookmark.getProtocol(), options)) {
97+
final Credentials configuration = configurator.configure(bookmark);
98+
if(configuration.validate(bookmark.getProtocol(), options)) {
99+
bookmark.setCredentials(configuration);
100+
log.info("Auto configured credentials {} for {}", configuration, bookmark);
101+
return;
102+
}
105103
final StringAppender message = new StringAppender();
106104
if(options.password) {
107105
message.append(MessageFormat.format(LocaleFactory.localizedString(
@@ -157,7 +155,7 @@ public boolean prompt(final Host bookmark, final String message, final LoginCall
157155
}
158156

159157
@Override
160-
public boolean authenticate(final ProxyFinder proxy, final Session session, final ProgressListener listener,
158+
public boolean authenticate(final Session<?> session, final ProgressListener listener,
161159
final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
162160
final Host bookmark = session.getHost();
163161
final Credentials credentials = bookmark.getCredentials();
@@ -187,7 +185,7 @@ public boolean authenticate(final ProxyFinder proxy, final Session session, fina
187185
c.initCause(e);
188186
}
189187
catch(IllegalArgumentException | IllegalStateException r) {
190-
log.warn("Ignore error {} initializing faiulre {} with cause {}", r, e, c);
188+
log.warn("Ignore error {} initializing failure {} with cause {}", r, e, c);
191189
}
192190
throw c;
193191
}

core/src/main/java/ch/cyberduck/core/LoginConnectionService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,19 @@ public void connect(final Session<?> session, final CancelCallback cancel) throw
151151
}
152152
// Login
153153
try {
154-
this.authenticate(proxy, session, cancel);
154+
this.authenticate(session, cancel);
155155
}
156156
catch(BackgroundException e) {
157157
this.close(session);
158158
throw e;
159159
}
160160
}
161161

162-
private void authenticate(final ProxyFinder proxy, final Session session, final CancelCallback callback) throws BackgroundException {
163-
if(!login.authenticate(proxy, session, listener, prompt, callback)) {
162+
private void authenticate(final Session<?> session, final CancelCallback callback) throws BackgroundException {
163+
if(!login.authenticate(session, listener, prompt, callback)) {
164164
if(session.isConnected()) {
165165
// Next attempt with updated credentials but cancel when prompt is dismissed
166-
this.authenticate(proxy, session, callback);
166+
this.authenticate(session, callback);
167167
}
168168
else {
169169
// Reconnect and next attempt with updated credentials

core/src/main/java/ch/cyberduck/core/LoginService.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@
2121
import ch.cyberduck.core.exception.ConnectionCanceledException;
2222
import ch.cyberduck.core.exception.LoginCanceledException;
2323
import ch.cyberduck.core.exception.LoginFailureException;
24-
import ch.cyberduck.core.proxy.ProxyFinder;
2524
import ch.cyberduck.core.threading.CancelCallback;
2625

2726
public interface LoginService {
2827
/**
29-
* Obtain password from keychain or prompt panel
28+
* Obtain password from password store or prompt user for input
3029
*
3130
* @param bookmark Credentials
3231
* @param pompt Login prompt
@@ -37,14 +36,13 @@ public interface LoginService {
3736
/**
3837
* Login and prompt on failure
3938
*
40-
* @param proxy Proxy configuration
4139
* @param session Session
4240
* @param listener Authentication message callback
43-
* @param prompt Login prompt
41+
* @param prompt Login prompt
4442
* @param cancel Cancel callback while authentication is in progress
4543
* @return False if authentication fails
4644
* @throws LoginCanceledException Login prompt canceled by user
4745
* @throws LoginFailureException Login attempt failed
4846
*/
49-
boolean authenticate(ProxyFinder proxy, Session session, ProgressListener listener, LoginCallback prompt, CancelCallback cancel) throws BackgroundException;
47+
boolean authenticate(Session<?> session, ProgressListener listener, LoginCallback prompt, CancelCallback cancel) throws BackgroundException;
5048
}

core/src/main/java/ch/cyberduck/core/OAuthTokens.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.util.Objects;
2121

2222
public final class OAuthTokens {
23-
public static final OAuthTokens EMPTY = new OAuthTokens(null, null, Long.MAX_VALUE, null);
23+
public static final OAuthTokens EMPTY = new OAuthTokens(null, null, -1L, null);
2424

2525
private final String accessToken;
2626
private final String refreshToken;

0 commit comments

Comments
 (0)