diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java index b6a4873aea9..98f85d0767b 100644 --- a/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java +++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java @@ -16,6 +16,7 @@ */ import ch.cyberduck.core.Credentials; +import ch.cyberduck.core.DefaultIOExceptionMappingService; import ch.cyberduck.core.Host; import ch.cyberduck.core.HostKeyCallback; import ch.cyberduck.core.HostUrlProvider; @@ -38,6 +39,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.IOException; import java.util.Collections; import com.azure.core.credential.AzureSasCredential; @@ -142,8 +144,20 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() { - // + public void disconnect() throws BackgroundException { + try { + if(client != null) { + try { + ((ApacheHttpClient) client.getHttpPipeline().getHttpClient()).getHttpClient().close(); + } + catch(IOException e) { + throw new DefaultIOExceptionMappingService().map(e); + } + } + } + finally { + super.disconnect(); + } } @Override diff --git a/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java index 9bdab1737dd..1e2fae41b65 100644 --- a/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java +++ b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.protocol.HTTP; import reactor.core.publisher.Mono; @@ -29,12 +30,16 @@ import java.net.URL; public class ApacheHttpClient implements HttpClient { - private final org.apache.http.client.HttpClient httpClient; + private final CloseableHttpClient httpClient; public ApacheHttpClient(final HttpClientBuilder builder) { this.httpClient = builder.build(); } + public CloseableHttpClient getHttpClient() { + return httpClient; + } + public Mono send(final HttpRequest azureRequest) { try { ApacheHttpRequest apacheRequest = new ApacheHttpRequest(azureRequest.getHttpMethod(), azureRequest.getUrl(), diff --git a/backblaze/src/main/java/ch/cyberduck/core/b2/B2Session.java b/backblaze/src/main/java/ch/cyberduck/core/b2/B2Session.java index f815761e70a..d1de960072d 100644 --- a/backblaze/src/main/java/ch/cyberduck/core/b2/B2Session.java +++ b/backblaze/src/main/java/ch/cyberduck/core/b2/B2Session.java @@ -68,15 +68,16 @@ protected B2ApiClient connect(final ProxyFinder proxy, final HostKeyCallback key } @Override - public void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { + fileid.clear(); client.close(); } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } finally { - fileid.clear(); + super.disconnect(); } } diff --git a/box/src/main/java/ch/cyberduck/core/box/BoxSession.java b/box/src/main/java/ch/cyberduck/core/box/BoxSession.java index e3dd7c36239..bb55bb56087 100644 --- a/box/src/main/java/ch/cyberduck/core/box/BoxSession.java +++ b/box/src/main/java/ch/cyberduck/core/box/BoxSession.java @@ -87,15 +87,16 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { + fileid.clear(); client.close(); } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } finally { - fileid.clear(); + super.disconnect(); } } diff --git a/brick/src/main/java/ch/cyberduck/core/brick/BrickSession.java b/brick/src/main/java/ch/cyberduck/core/brick/BrickSession.java index a13262ab271..a6120cecd1c 100644 --- a/brick/src/main/java/ch/cyberduck/core/brick/BrickSession.java +++ b/brick/src/main/java/ch/cyberduck/core/brick/BrickSession.java @@ -111,13 +111,18 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { - client.close(); + if(client != null) { + client.close(); + } } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } public Credentials pair(final Host bookmark, final ConnectionCallback alert, final LoginCallback prompt, final CancelCallback cancel, diff --git a/core/src/main/java/ch/cyberduck/core/CopyCredentialsHolder.java b/core/src/main/java/ch/cyberduck/core/CopyCredentialsHolder.java deleted file mode 100644 index 24bd0727f37..00000000000 --- a/core/src/main/java/ch/cyberduck/core/CopyCredentialsHolder.java +++ /dev/null @@ -1,93 +0,0 @@ -package ch.cyberduck.core; - -/* - * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -public class CopyCredentialsHolder extends Credentials implements CredentialsHolder { - - private final CredentialsHolder delegate; - - /** - * Copy credentials - * - * @param delegate Proxy - */ - public CopyCredentialsHolder(final Credentials delegate) { - super(delegate); - this.delegate = delegate; - } - - @Override - public Credentials setUsername(final String user) { - delegate.setUsername(user); - return super.setUsername(user); - } - - @Override - public Credentials setPassword(final String password) { - delegate.setPassword(password); - return super.setPassword(password); - } - - @Override - public Credentials setToken(final String token) { - delegate.setToken(token); - return super.setToken(token); - } - - @Override - public Credentials setTokens(final TemporaryAccessTokens tokens) { - delegate.setTokens(tokens); - return super.setTokens(tokens); - } - - @Override - public Credentials setOauth(final OAuthTokens oauth) { - delegate.setOauth(oauth); - return super.setOauth(oauth); - } - - @Override - public Credentials setSaved(final boolean saved) { - delegate.setSaved(saved); - return super.setSaved(saved); - } - - @Override - public Credentials setIdentity(final Local file) { - delegate.setIdentity(file); - return super.setIdentity(file); - } - - @Override - public Credentials setIdentityPassphrase(final String identityPassphrase) { - delegate.setIdentityPassphrase(identityPassphrase); - return super.setIdentityPassphrase(identityPassphrase); - } - - @Override - public Credentials setCertificate(final String certificate) { - delegate.setCertificate(certificate); - return super.setCertificate(certificate); - } - - /** - * Only reset delegate but keep copied credentials. - */ - @Override - public void reset() { - delegate.reset(); - } -} diff --git a/core/src/main/java/ch/cyberduck/core/Credentials.java b/core/src/main/java/ch/cyberduck/core/Credentials.java index 77e2e4c656a..349e266d410 100644 --- a/core/src/main/java/ch/cyberduck/core/Credentials.java +++ b/core/src/main/java/ch/cyberduck/core/Credentials.java @@ -82,8 +82,8 @@ public Credentials() { public Credentials(final Credentials copy) { this.user = copy.user; this.password = copy.password; - this.tokens = copy.tokens; - this.oauth = copy.oauth; + this.tokens = TemporaryAccessTokens.EMPTY == copy.tokens ? TemporaryAccessTokens.EMPTY : new TemporaryAccessTokens(copy.tokens); + this.oauth = OAuthTokens.EMPTY == copy.oauth ? OAuthTokens.EMPTY : new OAuthTokens(copy.oauth); this.properties.putAll(copy.properties); this.identity = copy.identity; this.identityPassphrase = copy.identityPassphrase; diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 4be0e2807f2..b23fa88e997 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -163,27 +163,36 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { } protected static Scheme getOAuthScheme(final Host bookmark) { - final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); - if(null == uri.getScheme()) { - return bookmark.getProtocol().getScheme(); + if(null != bookmark.getProtocol().getOAuthTokenUrl()) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(null == uri.getScheme()) { + return bookmark.getProtocol().getScheme(); + } + return Scheme.valueOf(uri.getScheme()); } - return Scheme.valueOf(uri.getScheme()); + return null; } protected static String getOAuthHostname(final Host bookmark) { - final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); - if(StringUtils.isNotBlank(uri.getHost())) { - return uri.getHost(); + if(null != bookmark.getProtocol().getOAuthTokenUrl()) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(StringUtils.isNotBlank(uri.getHost())) { + return uri.getHost(); + } + return bookmark.getHostname(); } - return bookmark.getHostname(); + return null; } protected static int getOAuthPort(final Host bookmark) { - final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); - if(-1 != uri.getPort()) { - return uri.getPort(); + if(null != bookmark.getProtocol().getOAuthTokenUrl()) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(-1 != uri.getPort()) { + return uri.getPort(); + } + return getOAuthScheme(bookmark).getPort(); } - return getOAuthScheme(bookmark).getPort(); + return -1; } protected static Set getOAuthPrefix(final Host bookmark) { diff --git a/core/src/main/java/ch/cyberduck/core/KeychainLoginService.java b/core/src/main/java/ch/cyberduck/core/KeychainLoginService.java index 138071f0c45..4e5a286e5af 100644 --- a/core/src/main/java/ch/cyberduck/core/KeychainLoginService.java +++ b/core/src/main/java/ch/cyberduck/core/KeychainLoginService.java @@ -85,7 +85,7 @@ public void validate(final Host bookmark, final LoginCallback prompt, final Logi if(options.oauth) { final OAuthTokens tokens = keychain.findOAuthTokens(bookmark); if(tokens.validate()) { - log.info("Fetched OAuth token from keychain for {}", bookmark); + log.info("Fetched OAuth tokens {} from keychain for {}", tokens, bookmark); // No need to reinsert found token to the keychain. credentials.setOauth(tokens).setSaved(tokens.isExpired()); } @@ -213,11 +213,5 @@ public void save(final Host bookmark) { else { log.info("Skip writing credentials for bookmark {}", bookmark.getHostname()); } - // Nullify password and tokens - log.debug("Reset credentials for {}", bookmark); - switch(bookmark.getProtocol().getStatefulness()) { - case stateless: - credentials.reset(); - } } } diff --git a/core/src/main/java/ch/cyberduck/core/Session.java b/core/src/main/java/ch/cyberduck/core/Session.java index 660212b639b..2980211c9de 100644 --- a/core/src/main/java/ch/cyberduck/core/Session.java +++ b/core/src/main/java/ch/cyberduck/core/Session.java @@ -200,12 +200,14 @@ public void interrupt() throws BackgroundException { } } - protected abstract void logout() throws BackgroundException; + protected void logout() throws BackgroundException { + host.getCredentials().reset(); + } /** * Close the connection to the remote host. Subsequent calls to #getClient() must return null. */ - protected void disconnect() { + protected void disconnect() throws BackgroundException { state = State.closed; listeners.clear(); } diff --git a/core/src/test/java/ch/cyberduck/core/NullSession.java b/core/src/test/java/ch/cyberduck/core/NullSession.java index 0f135a58c82..4b3c547b6a8 100644 --- a/core/src/test/java/ch/cyberduck/core/NullSession.java +++ b/core/src/test/java/ch/cyberduck/core/NullSession.java @@ -33,11 +33,6 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw throw new LoginCanceledException(); } - @Override - protected void logout() { - // - } - @Override public AttributedList list(final Path folder, final ListProgressListener listener) throws BackgroundException { listener.chunk(folder, AttributedList.emptyList()); diff --git a/ctera/src/main/java/ch/cyberduck/core/ctera/CteraSession.java b/ctera/src/main/java/ch/cyberduck/core/ctera/CteraSession.java index 9686c20c675..389a1fb8f1f 100644 --- a/ctera/src/main/java/ch/cyberduck/core/ctera/CteraSession.java +++ b/ctera/src/main/java/ch/cyberduck/core/ctera/CteraSession.java @@ -228,10 +228,15 @@ protected void logout() throws BackgroundException { } finally { super.logout(); - versionid.clear(); } } + @Override + public void disconnect() throws BackgroundException { + versionid.clear(); + super.disconnect(); + } + @Override @SuppressWarnings("unchecked") public T _getFeature(final Class type) { diff --git a/deepbox/src/main/java/ch/cyberduck/core/deepbox/DeepboxSession.java b/deepbox/src/main/java/ch/cyberduck/core/deepbox/DeepboxSession.java index 1230e730a57..f764f9c0eb3 100644 --- a/deepbox/src/main/java/ch/cyberduck/core/deepbox/DeepboxSession.java +++ b/deepbox/src/main/java/ch/cyberduck/core/deepbox/DeepboxSession.java @@ -182,8 +182,15 @@ public DeepcloudApiClient getDeepcloudClient() { } @Override - protected void logout() { - client.getHttpClient().close(); + public void disconnect() throws BackgroundException { + try { + if(client != null) { + client.getHttpClient().close(); + } + } + finally { + super.disconnect(); + } } @Override diff --git a/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSession.java b/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSession.java index 565f21263fe..e7394147379 100644 --- a/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSession.java +++ b/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSession.java @@ -580,10 +580,17 @@ public int hashCode() { } @Override - protected void logout() { - scheduler.shutdown(false); - client.getHttpClient().close(); - nodeid.clear(); + public void disconnect() throws BackgroundException { + try { + scheduler.shutdown(false); + nodeid.clear(); + if(client != null) { + client.getHttpClient().close(); + } + } + finally { + super.disconnect(); + } } @Override diff --git a/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxSession.java b/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxSession.java index b9b3c3b1949..fc008c25ec6 100644 --- a/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxSession.java +++ b/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxSession.java @@ -124,13 +124,16 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { ((DropboxCommonsHttpRequestExecutor) client.getRequestConfig().getHttpRequestor()).close(); } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } @Override diff --git a/eue/src/main/java/ch/cyberduck/core/eue/EueSession.java b/eue/src/main/java/ch/cyberduck/core/eue/EueSession.java index e358652c35a..8df8ad0767e 100644 --- a/eue/src/main/java/ch/cyberduck/core/eue/EueSession.java +++ b/eue/src/main/java/ch/cyberduck/core/eue/EueSession.java @@ -214,15 +214,18 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { - client.close(); + resourceid.clear(); + if(client != null) { + client.close(); + } } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } finally { - resourceid.clear(); + super.disconnect(); } } diff --git a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java index 046fa6f0890..fcf6f6e4664 100644 --- a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java +++ b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPSession.java @@ -100,7 +100,7 @@ protected void logout() throws BackgroundException { } @Override - protected void disconnect() { + protected void disconnect() throws BackgroundException { try { client.disconnect(); } diff --git a/googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveSession.java b/googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveSession.java index 21ba82d9d63..192a61b3f05 100644 --- a/googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveSession.java +++ b/googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveSession.java @@ -99,15 +99,16 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { + fileid.clear(); transport.shutdown(); } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } finally { - fileid.clear(); + super.disconnect(); } } diff --git a/googlestorage/src/main/java/ch/cyberduck/core/googlestorage/GoogleStorageSession.java b/googlestorage/src/main/java/ch/cyberduck/core/googlestorage/GoogleStorageSession.java index 09be1a5e739..15f256188b9 100644 --- a/googlestorage/src/main/java/ch/cyberduck/core/googlestorage/GoogleStorageSession.java +++ b/googlestorage/src/main/java/ch/cyberduck/core/googlestorage/GoogleStorageSession.java @@ -81,13 +81,16 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { transport.shutdown(); } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } public HttpClient getHttpClient() { diff --git a/irods/src/main/java/ch/cyberduck/core/irods/IRODSSession.java b/irods/src/main/java/ch/cyberduck/core/irods/IRODSSession.java index 821510f68c2..fa8303775b2 100644 --- a/irods/src/main/java/ch/cyberduck/core/irods/IRODSSession.java +++ b/irods/src/main/java/ch/cyberduck/core/irods/IRODSSession.java @@ -145,13 +145,16 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { client.getIRODSSession().closeSession(); } catch(JargonException e) { throw new IRODSExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } @Override diff --git a/manta/src/main/java/ch/cyberduck/core/manta/MantaSession.java b/manta/src/main/java/ch/cyberduck/core/manta/MantaSession.java index b8c96aba38b..116ceb54327 100644 --- a/manta/src/main/java/ch/cyberduck/core/manta/MantaSession.java +++ b/manta/src/main/java/ch/cyberduck/core/manta/MantaSession.java @@ -110,9 +110,14 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() { - if(client != null) { - client.closeWithWarning(); + public void disconnect() throws BackgroundException { + try { + if(client != null) { + client.closeQuietly(); + } + } + finally { + super.disconnect(); } } diff --git a/nio/src/main/java/ch/cyberduck/core/nio/LocalSession.java b/nio/src/main/java/ch/cyberduck/core/nio/LocalSession.java index 429393628ef..c7db0dbf0b0 100644 --- a/nio/src/main/java/ch/cyberduck/core/nio/LocalSession.java +++ b/nio/src/main/java/ch/cyberduck/core/nio/LocalSession.java @@ -112,6 +112,7 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw protected void logout() throws BackgroundException { final Path home = new LocalHomeFinderFeature().find(); LocalFactory.get(this.toPath(home).toString()).release(lock); + super.logout(); } protected boolean isPosixFilesystem() { diff --git a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java index 0cedef7c5bd..c60360ad904 100644 --- a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java +++ b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java @@ -106,7 +106,7 @@ public OAuth2AuthorizationService(final HttpTransport transport, final Host host final LoginCallback prompt) throws LoginCanceledException { this.transport = transport; this.host = host; - this.credentials = new CopyCredentialsHolder(host.getCredentials()); + this.credentials = host.getCredentials(); this.tokenServerUrl = tokenServerUrl; this.authorizationServerUrl = authorizationServerUrl; this.prompt = prompt; @@ -127,29 +127,27 @@ public OAuthTokens validate(final OAuthTokens saved) throws BackgroundException if(saved.validate()) { // Found existing tokens if(saved.isExpired()) { - log.warn("Refresh expired access tokens {}", saved); - // Refresh expired access key + log.warn("Refresh expired tokens {}", saved); + // Refresh expired tokens try { - final OAuthTokens refreshed = this.refresh(saved); + final OAuthTokens refreshed = this.authorizeWithRefreshToken(saved); log.debug("Refreshed tokens {} for {}", refreshed, host); - credentials.setOauth(refreshed); - return refreshed; + return this.save(refreshed); } catch(LoginFailureException e) { log.warn("Failure refreshing tokens from {} for {}", saved, host); - // Continue with new OAuth 2 flow + // Continue with authorization flow } } else { - log.debug("Returned saved OAuth tokens {} for {}", saved, host); + log.debug("Returned saved tokens {} for {}", saved, host); return saved; } } - log.warn("Missing OAuth tokens {} for {}", saved, host); + log.warn("Missing tokens {} for {}", saved, host); final OAuthTokens tokens = this.authorize(); log.debug("Retrieved tokens {} for {}", tokens, host); - credentials.setOauth(tokens); - return tokens; + return this.save(tokens); } /** @@ -197,7 +195,7 @@ public OAuthTokens authorize() throws BackgroundException { // Save access token, refresh token and id token switch(flowType) { case AuthorizationCode: - response = this.authorizeWithCode(host, prompt); + response = this.authorizeWithCode(prompt); break; case PasswordGrant: response = this.authorizeWithPassword(credentials); @@ -211,10 +209,10 @@ public OAuthTokens authorize() throws BackgroundException { System.currentTimeMillis() + response.getExpiresInSeconds() * 1000, response.getIdToken()); } - private IdTokenResponse authorizeWithCode(final Host bookmark, final LoginCallback prompt) throws BackgroundException { + private IdTokenResponse authorizeWithCode(final LoginCallback prompt) throws BackgroundException { log.debug("Request tokens with code"); - if(HostPreferencesFactory.get(bookmark).getBoolean("oauth.browser.open.warn")) { - prompt.warn(bookmark, + if(HostPreferencesFactory.get(host).getBoolean("oauth.browser.open.warn")) { + prompt.warn(host, LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), new StringAppender() .append(LocaleFactory.localizedString("Open web browser to authenticate and obtain an authorization code", "Credentials")) @@ -248,7 +246,7 @@ private IdTokenResponse authorizeWithCode(final Host bookmark, final LoginCallba final String authorizationCodeUrl = authorizationCodeUrlBuilder.build(); log.debug("Open browser with URL {}", authorizationCodeUrl); final String authorizationCode = OAuth2AuthorizationCodeProviderFactory.get().prompt( - bookmark, prompt, authorizationCodeUrl, redirectUri, state); + host, prompt, authorizationCodeUrl, redirectUri, state); if(StringUtils.isBlank(authorizationCode)) { throw new LoginCanceledException(); } @@ -297,7 +295,7 @@ private IdTokenResponse authorizeWithPassword(final Credentials credentials) thr } } - public OAuthTokens refresh(final OAuthTokens tokens) throws BackgroundException { + public OAuthTokens authorizeWithRefreshToken(final OAuthTokens tokens) throws BackgroundException { if(StringUtils.isBlank(tokens.getRefreshToken())) { log.warn("Missing refresh token in {}", tokens); return this.authorize(); diff --git a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2ErrorResponseInterceptor.java b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2ErrorResponseInterceptor.java index 1c39105409d..c1bf99c8b76 100644 --- a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2ErrorResponseInterceptor.java +++ b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2ErrorResponseInterceptor.java @@ -28,9 +28,11 @@ public class OAuth2ErrorResponseInterceptor extends DisabledServiceUnavailableRetryStrategy { private static final Logger log = LogManager.getLogger(OAuth2ErrorResponseInterceptor.class); + private final Host host; private final OAuth2RequestInterceptor service; public OAuth2ErrorResponseInterceptor(final Host host, final OAuth2RequestInterceptor service) { + this.host = host; this.service = service; } @@ -40,7 +42,7 @@ public boolean retryRequest(final HttpResponse response, final int executionCoun case HttpStatus.SC_UNAUTHORIZED: try { log.warn("Attempt to refresh OAuth tokens for failure {}", response); - service.save(service.refresh()); + service.save(service.authorizeWithRefreshToken(host.getCredentials().getOauth())); // Try again return true; } diff --git a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2RequestInterceptor.java b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2RequestInterceptor.java index 9fc2ca9458e..fd88fba74b7 100644 --- a/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2RequestInterceptor.java +++ b/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2RequestInterceptor.java @@ -23,7 +23,6 @@ import ch.cyberduck.core.Scheme; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.LoginCanceledException; -import ch.cyberduck.core.exception.LoginFailureException; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpException; @@ -46,11 +45,7 @@ public class OAuth2RequestInterceptor extends OAuth2AuthorizationService impleme private static final Logger log = LogManager.getLogger(OAuth2RequestInterceptor.class); private final ReentrantLock lock = new ReentrantLock(); - - /** - * Currently valid tokens - */ - private OAuthTokens tokens = OAuthTokens.EMPTY; + private final Host host; public OAuth2RequestInterceptor(final HttpClient client, final Host host, final LoginCallback prompt) throws LoginCanceledException { this(client, host, @@ -67,67 +62,17 @@ public OAuth2RequestInterceptor(final HttpClient client, final Host host, final public OAuth2RequestInterceptor(final HttpClient client, final Host host, final String tokenServerUrl, final String authorizationServerUrl, final String clientid, final String clientsecret, final List scopes, final boolean pkce, final LoginCallback prompt) throws LoginCanceledException { super(client, host, tokenServerUrl, authorizationServerUrl, clientid, clientsecret, scopes, pkce, prompt); - } - - @Override - public OAuthTokens validate(final OAuthTokens saved) throws BackgroundException { - return tokens = super.validate(saved); - } - - @Override - public OAuthTokens authorize() throws BackgroundException { - lock.lock(); - try { - return tokens = super.authorize(); - } - finally { - lock.unlock(); - } - } - - /** - * Refresh with cached refresh token - */ - public OAuthTokens refresh() throws BackgroundException { - lock.lock(); - try { - return tokens = this.refresh(tokens); - } - finally { - lock.unlock(); - } - } - - /** - * @param previous Refresh token - */ - @Override - public OAuthTokens refresh(final OAuthTokens previous) throws BackgroundException { - lock.lock(); - try { - return tokens = super.refresh(previous); - } - catch(LoginFailureException e) { - log.warn("Failure {} refreshing OAuth tokens", e.getMessage()); - return tokens = this.authorize(); - } - finally { - lock.unlock(); - } + this.host = host; } @Override public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { lock.lock(); try { + final OAuthTokens tokens = host.getCredentials().getOauth(); if(tokens.isExpired()) { try { - final OAuthTokens previous = tokens; - final OAuthTokens refreshed = this.refresh(tokens); - // Skip saving tokens when not changed - if(!refreshed.equals(previous)) { - this.save(refreshed); - } + this.save(this.authorizeWithRefreshToken(tokens)); } catch(BackgroundException e) { log.warn("Failure {} refreshing OAuth tokens {}", e, tokens); diff --git a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java index 1267b615494..7c0c81d2970 100644 --- a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java +++ b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java @@ -232,15 +232,18 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { - client.getExecutor().close(); + fileid.clear(); + if(client != null) { + client.getExecutor().close(); + } } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } finally { - fileid.clear(); + super.disconnect(); } } diff --git a/openstack/src/main/java/ch/cyberduck/core/openstack/SwiftSession.java b/openstack/src/main/java/ch/cyberduck/core/openstack/SwiftSession.java index 55f35c348d2..2a181b31e87 100644 --- a/openstack/src/main/java/ch/cyberduck/core/openstack/SwiftSession.java +++ b/openstack/src/main/java/ch/cyberduck/core/openstack/SwiftSession.java @@ -101,14 +101,19 @@ protected Client connect(final ProxyFinder proxy, final HostKeyCallback key, fin } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { scheduler.shutdown(false); - client.disconnect(); + if(client != null) { + client.disconnect(); + } } catch(IOException e) { throw new DefaultIOExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } @Override diff --git a/s3/src/main/java/ch/cyberduck/core/s3/S3Session.java b/s3/src/main/java/ch/cyberduck/core/s3/S3Session.java index 85abefceb6d..4aea90cfa13 100644 --- a/s3/src/main/java/ch/cyberduck/core/s3/S3Session.java +++ b/s3/src/main/java/ch/cyberduck/core/s3/S3Session.java @@ -52,11 +52,11 @@ import ch.cyberduck.core.ssl.DisabledX509TrustManager; import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; -import ch.cyberduck.core.sts.STSAssumeRoleRequestInterceptor; -import ch.cyberduck.core.sts.STSAssumeRoleWithWebIdentityRequestInterceptor; +import ch.cyberduck.core.sts.STSAssumeRoleCredentialsStrategy; +import ch.cyberduck.core.sts.STSAssumeRoleWithWebIdentityCredentialsStrategy; import ch.cyberduck.core.sts.STSAuthorizationService; -import ch.cyberduck.core.sts.STSGetSessionTokenRequestInterceptor; -import ch.cyberduck.core.sts.STSRequestInterceptor; +import ch.cyberduck.core.sts.STSCredentialsStrategy; +import ch.cyberduck.core.sts.STSGetSessionTokenCredentialsStrategy; import ch.cyberduck.core.threading.CancelCallback; import org.apache.commons.lang3.StringUtils; @@ -132,14 +132,19 @@ public S3Session(final Host host, final X509TrustManager trust, final X509KeyMan } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { scheduler.shutdown(false); - client.shutdown(); + if(client != null) { + client.shutdown(); + } } catch(ServiceException e) { throw new S3ExceptionMappingService().map(e); } + finally { + super.disconnect(); + } } protected XmlResponsesSaxParser getXmlResponseSaxParser() throws ServiceException { @@ -256,11 +261,10 @@ protected S3CredentialsStrategy configureCredentialsStrategy(final HttpClientBui } log.debug("Add interceptor {}", oauth); configuration.addInterceptorLast(oauth); - final STSAssumeRoleWithWebIdentityRequestInterceptor interceptor - = new STSAssumeRoleWithWebIdentityRequestInterceptor(oauth, host, trust, key, prompt); - log.debug("Add interceptor {}", interceptor); - configuration.addInterceptorLast(interceptor); - return interceptor; + final STSAssumeRoleWithWebIdentityCredentialsStrategy strategy + = new STSAssumeRoleWithWebIdentityCredentialsStrategy(oauth, host, trust, key, prompt); + log.debug("Return authenticator {}", strategy); + return strategy; } if(S3Session.isAwsHostname(host.getHostname())) { // Try auto-configure @@ -271,16 +275,14 @@ protected S3CredentialsStrategy configureCredentialsStrategy(final HttpClientBui } } if(host.getProtocol().isRoleConfigurable()) { - final STSRequestInterceptor interceptor = new STSAssumeRoleRequestInterceptor(host, trust, key, prompt); - log.debug("Add interceptor {}", interceptor); - configuration.addInterceptorLast(interceptor); - return interceptor; + final STSCredentialsStrategy strategy = new STSAssumeRoleCredentialsStrategy(host, trust, key, prompt); + log.debug("Return authenticator {}", strategy); + return strategy; } if(host.getProtocol().isMultiFactorConfigurable()) { - final STSRequestInterceptor interceptor = new STSGetSessionTokenRequestInterceptor(host, trust, key, prompt); - log.debug("Add interceptor {}", interceptor); - configuration.addInterceptorLast(interceptor); - return interceptor; + final STSCredentialsStrategy strategy = new STSGetSessionTokenCredentialsStrategy(host, trust, key, prompt); + log.debug("Return authenticator {}", strategy); + return strategy; } // Keep copy of credentials final Credentials credentials = new Credentials(host.getCredentials()); diff --git a/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleRequestInterceptor.java b/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleCredentialsStrategy.java similarity index 62% rename from s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleRequestInterceptor.java rename to s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleCredentialsStrategy.java index f24a7a1da3d..89be40310f5 100644 --- a/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleRequestInterceptor.java +++ b/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleCredentialsStrategy.java @@ -26,38 +26,26 @@ import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; -import org.apache.http.HttpRequestInterceptor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.concurrent.locks.ReentrantLock; - /** * Swap static access key id and secret access key with temporary credentials obtained from STS AssumeRole */ -public class STSAssumeRoleRequestInterceptor extends STSRequestInterceptor implements S3CredentialsStrategy, HttpRequestInterceptor { - private static final Logger log = LogManager.getLogger(STSAssumeRoleRequestInterceptor.class); +public class STSAssumeRoleCredentialsStrategy extends STSCredentialsStrategy implements S3CredentialsStrategy { + private static final Logger log = LogManager.getLogger(STSAssumeRoleCredentialsStrategy.class); - private final ReentrantLock lock = new ReentrantLock(); private final Host host; - public STSAssumeRoleRequestInterceptor(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { + public STSAssumeRoleCredentialsStrategy(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { super(host, trust, key, prompt); this.host = host; } @Override public TemporaryAccessTokens refresh(final Credentials credentials) throws BackgroundException { - lock.lock(); - try { - final String arn = new ProxyPreferencesReader(host, credentials).getProperty(Profile.STS_ROLE_ARN_PROPERTY_KEY, "s3.assumerole.rolearn"); - log.debug("Use ARN {}", arn); - log.debug("Retrieve temporary credentials with {}", credentials); - // AssumeRoleRequest - return tokens = this.assumeRole(credentials, arn); - } - finally { - lock.unlock(); - } + final String arn = new ProxyPreferencesReader(host, credentials).getProperty(Profile.STS_ROLE_ARN_PROPERTY_KEY, "s3.assumerole.rolearn"); + log.debug("Retrieve temporary credentials with {} for role ARN {}", credentials, arn); + return this.assumeRole(credentials, arn); } } diff --git a/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityRequestInterceptor.java b/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityCredentialsStrategy.java similarity index 60% rename from s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityRequestInterceptor.java rename to s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityCredentialsStrategy.java index b6fdd937ea4..a73171370bb 100644 --- a/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityRequestInterceptor.java +++ b/s3/src/main/java/ch/cyberduck/core/sts/STSAssumeRoleWithWebIdentityCredentialsStrategy.java @@ -21,26 +21,20 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.TemporaryAccessTokens; import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.exception.LoginFailureException; import ch.cyberduck.core.oauth.OAuth2RequestInterceptor; import ch.cyberduck.core.preferences.ProxyPreferencesReader; import ch.cyberduck.core.s3.S3CredentialsStrategy; import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; -import org.apache.http.HttpRequestInterceptor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.concurrent.locks.ReentrantLock; - /** * Swap OIDC Id token for temporary security credentials */ -public class STSAssumeRoleWithWebIdentityRequestInterceptor extends STSRequestInterceptor implements S3CredentialsStrategy, HttpRequestInterceptor { - private static final Logger log = LogManager.getLogger(STSAssumeRoleWithWebIdentityRequestInterceptor.class); - - private final ReentrantLock lock = new ReentrantLock(); +public class STSAssumeRoleWithWebIdentityCredentialsStrategy extends STSCredentialsStrategy implements S3CredentialsStrategy { + private static final Logger log = LogManager.getLogger(STSAssumeRoleWithWebIdentityCredentialsStrategy.class); /** * Handle authentication with OpenID connect retrieving token for STS @@ -48,9 +42,9 @@ public class STSAssumeRoleWithWebIdentityRequestInterceptor extends STSRequestIn private final OAuth2RequestInterceptor oauth; private final Host host; - public STSAssumeRoleWithWebIdentityRequestInterceptor(final OAuth2RequestInterceptor oauth, final Host host, - final X509TrustManager trust, final X509KeyManager key, - final LoginCallback prompt) { + public STSAssumeRoleWithWebIdentityCredentialsStrategy(final OAuth2RequestInterceptor oauth, final Host host, + final X509TrustManager trust, final X509KeyManager key, + final LoginCallback prompt) { super(host, trust, key, prompt); this.oauth = oauth; this.host = host; @@ -58,19 +52,8 @@ public STSAssumeRoleWithWebIdentityRequestInterceptor(final OAuth2RequestInterce @Override public TemporaryAccessTokens refresh(final Credentials credentials) throws BackgroundException { - lock.lock(); final String arn = new ProxyPreferencesReader(host, credentials).getProperty(Profile.STS_ROLE_ARN_PROPERTY_KEY, "s3.assumerole.rolearn"); - log.debug("Use ARN {}", arn); - try { - return tokens = this.assumeRoleWithWebIdentity(oauth.validate(credentials.getOauth()), arn); - } - catch(LoginFailureException e) { - // Expired or invalid OAuth tokens - log.warn("Failure {} authorizing. Retry with refreshed OAuth tokens", e.getMessage()); - return this.tokens = this.assumeRoleWithWebIdentity(oauth.authorize(), arn); - } - finally { - lock.unlock(); - } + log.debug("Retrieve temporary credentials with {} for role ARN {}", credentials, arn); + return this.assumeRoleWithWebIdentity(oauth.validate(credentials.getOauth()), arn); } } \ No newline at end of file diff --git a/s3/src/main/java/ch/cyberduck/core/sts/STSRequestInterceptor.java b/s3/src/main/java/ch/cyberduck/core/sts/STSCredentialsStrategy.java similarity index 53% rename from s3/src/main/java/ch/cyberduck/core/sts/STSRequestInterceptor.java rename to s3/src/main/java/ch/cyberduck/core/sts/STSCredentialsStrategy.java index 733166481ce..15cb3ac15f9 100644 --- a/s3/src/main/java/ch/cyberduck/core/sts/STSRequestInterceptor.java +++ b/s3/src/main/java/ch/cyberduck/core/sts/STSCredentialsStrategy.java @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.CopyCredentialsHolder; import ch.cyberduck.core.Credentials; import ch.cyberduck.core.Host; import ch.cyberduck.core.LoginCallback; @@ -25,37 +24,23 @@ import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.protocol.HttpContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.IOException; import java.util.concurrent.locks.ReentrantLock; /** * Swap static access key id and secret access key with temporary credentials obtained from STS AssumeRole */ -public abstract class STSRequestInterceptor extends STSAuthorizationService implements S3CredentialsStrategy, HttpRequestInterceptor { - private static final Logger log = LogManager.getLogger(STSRequestInterceptor.class); +public abstract class STSCredentialsStrategy extends STSAuthorizationService implements S3CredentialsStrategy { + private static final Logger log = LogManager.getLogger(STSCredentialsStrategy.class); private final ReentrantLock lock = new ReentrantLock(); + private final Host host; - /** - * Currently valid tokens obtained from token service - */ - protected TemporaryAccessTokens tokens = TemporaryAccessTokens.EMPTY; - - /** - * Static long-lived credentials - */ - protected final Credentials credentials; - - public STSRequestInterceptor(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { + public STSCredentialsStrategy(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { super(host, trust, key, prompt); - this.credentials = new CopyCredentialsHolder(host.getCredentials()); + this.host = host; } /** @@ -67,28 +52,20 @@ public STSRequestInterceptor(final Host host, final X509TrustManager trust, fina public abstract TemporaryAccessTokens refresh(final Credentials credentials) throws BackgroundException; @Override - public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { + public Credentials get() throws BackgroundException { lock.lock(); try { + final Credentials credentials = host.getCredentials(); + final TemporaryAccessTokens tokens = credentials.getTokens(); + // Get temporary credentials from STS using static long-lived credentials if(tokens.isExpired()) { - try { - this.refresh(credentials); - log.info("Authorizing service request with STS tokens {}", tokens); - } - catch(BackgroundException e) { - log.warn("Failure {} refreshing STS tokens {}", e, tokens); - // Follow-up error 401 handled in error interceptor - } + log.debug("Refresh expired tokens {} for {}", tokens, host); + credentials.setTokens(this.refresh(credentials)); } + return credentials; } finally { lock.unlock(); } } - - @Override - public Credentials get() throws BackgroundException { - // Get temporary credentials from STS using static long-lived credentials - return credentials.setTokens(tokens.isExpired() ? this.refresh(credentials) : tokens); - } } diff --git a/s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenRequestInterceptor.java b/s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenCredentialsStrategy.java similarity index 62% rename from s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenRequestInterceptor.java rename to s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenCredentialsStrategy.java index b414245de47..624988052f7 100644 --- a/s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenRequestInterceptor.java +++ b/s3/src/main/java/ch/cyberduck/core/sts/STSGetSessionTokenCredentialsStrategy.java @@ -26,39 +26,26 @@ import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; -import org.apache.http.HttpRequestInterceptor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.concurrent.locks.ReentrantLock; - /** * Swap static access key id and secret access key with temporary credentials obtained from STS AssumeRole */ -public class STSGetSessionTokenRequestInterceptor extends STSRequestInterceptor implements S3CredentialsStrategy, HttpRequestInterceptor { - private static final Logger log = LogManager.getLogger(STSGetSessionTokenRequestInterceptor.class); - - private final ReentrantLock lock = new ReentrantLock(); +public class STSGetSessionTokenCredentialsStrategy extends STSCredentialsStrategy implements S3CredentialsStrategy { + private static final Logger log = LogManager.getLogger(STSGetSessionTokenCredentialsStrategy.class); private final Host host; - public STSGetSessionTokenRequestInterceptor(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { + public STSGetSessionTokenCredentialsStrategy(final Host host, final X509TrustManager trust, final X509KeyManager key, final LoginCallback prompt) { super(host, trust, key, prompt); this.host = host; } @Override public TemporaryAccessTokens refresh(final Credentials credentials) throws BackgroundException { - lock.lock(); - try { - final String arn = new ProxyPreferencesReader(host, credentials).getProperty(Profile.STS_MFA_ARN_PROPERTY_KEY); - log.debug("Use ARN {}", arn); - log.debug("Retrieve temporary credentials with {}", credentials); - // GetSessionToken - return tokens = this.getSessionToken(credentials, arn); - } - finally { - lock.unlock(); - } + final String arn = new ProxyPreferencesReader(host, credentials).getProperty(Profile.STS_MFA_ARN_PROPERTY_KEY); + log.debug("Retrieve temporary credentials with {} for role ARN {}", credentials, arn); + return this.getSessionToken(credentials, arn); } } diff --git a/s3/src/test/java/ch/cyberduck/core/sts/AssumeRoleWithWebIdentityAuthenticationTest.java b/s3/src/test/java/ch/cyberduck/core/sts/AssumeRoleWithWebIdentityAuthenticationTest.java index f1f2558e8e2..a3da178d3fe 100644 --- a/s3/src/test/java/ch/cyberduck/core/sts/AssumeRoleWithWebIdentityAuthenticationTest.java +++ b/s3/src/test/java/ch/cyberduck/core/sts/AssumeRoleWithWebIdentityAuthenticationTest.java @@ -68,6 +68,8 @@ public void testSuccessfulLogin() throws BackgroundException { assertNotNull(credentials.getTokens().getSessionToken()); assertNotNull(credentials.getOauth().getIdToken()); assertNotNull(credentials.getOauth().getRefreshToken()); + assertEquals("rouser", credentials.getUsername()); + assertEquals("rouser", credentials.getPassword()); assertNotEquals(Optional.of(Long.MAX_VALUE).get(), credentials.getOauth().getExpiryInMilliseconds()); session.close(); } @@ -109,7 +111,7 @@ public void testTokenRefresh() throws BackgroundException, InterruptedException final TemporaryAccessTokens tokens = credentials.getTokens(); assertTrue(tokens.validate()); - credentials.reset(); + credentials.setOauth(OAuthTokens.EMPTY).setTokens(TemporaryAccessTokens.EMPTY); Path container = new Path("cyberduckbucket", EnumSet.of(Path.Type.directory, Path.Type.volume)); assertTrue(new S3FindFeature(session, new S3AccessControlListFeature(session)).find(container)); @@ -129,7 +131,7 @@ public void testTokenRefresh() throws BackgroundException, InterruptedException * Fetch OpenID Connect Id token initially fails because of invalid refresh token. Must re-run OAuth flow. */ @Test - public void testLoginInvalidOAuthTokensLogin() throws Exception { + public void testLoginInvalidOAuthTokens() throws Exception { final Protocol profile = new ProfilePlistReader(new ProtocolFactory(new HashSet<>(Collections.singleton(new S3Protocol())))).read( AbstractAssumeRoleWithWebIdentityTest.class.getResourceAsStream("/S3 (OIDC).cyberduckprofile")); final Credentials credentials = new Credentials("rouser", "rouser") @@ -144,14 +146,7 @@ public void testLoginInvalidOAuthTokensLogin() throws Exception { assertNotNull(session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback())); assertTrue(session.isConnected()); assertNotNull(session.getClient()); - session.login(new DisabledLoginCallback(), new DisabledCancelCallback()); - assertNotEquals(OAuthTokens.EMPTY, credentials.getOauth()); - assertNotEquals(TemporaryAccessTokens.EMPTY, credentials.getTokens()); - credentials.reset(); - assertEquals(OAuthTokens.EMPTY, credentials.getOauth()); - assertEquals(TemporaryAccessTokens.EMPTY, credentials.getTokens()); - new S3BucketListService(session).list( - new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory)), new DisabledListProgressListener()); + assertThrows(LoginFailureException.class, () -> session.login(new DisabledLoginCallback(), new DisabledCancelCallback())); } /** @@ -179,9 +174,7 @@ public void testBucketListInvalidOAuthTokensList() throws Exception { new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory)), new DisabledListProgressListener()); assertNotEquals(OAuthTokens.EMPTY, credentials.getOauth()); assertNotEquals(TemporaryAccessTokens.EMPTY, credentials.getTokens()); - credentials.reset(); - assertEquals(OAuthTokens.EMPTY, credentials.getOauth()); - assertEquals(TemporaryAccessTokens.EMPTY, credentials.getTokens()); + credentials.setOauth(OAuthTokens.EMPTY).setTokens(TemporaryAccessTokens.EMPTY); new S3BucketListService(session).list( new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory)), new DisabledListProgressListener()); } diff --git a/smb/src/main/java/ch/cyberduck/core/smb/SMBSession.java b/smb/src/main/java/ch/cyberduck/core/smb/SMBSession.java index eb80c10e7c7..a381ac1b1e3 100644 --- a/smb/src/main/java/ch/cyberduck/core/smb/SMBSession.java +++ b/smb/src/main/java/ch/cyberduck/core/smb/SMBSession.java @@ -341,22 +341,25 @@ public void releaseShare(final DiskShareWrapper share) throws BackgroundExceptio } @Override - protected void logout() throws BackgroundException { - if(session != null) { - try { + public void logout() throws BackgroundException { + try { + if(session != null) { session.logoff(); } - catch(SMBRuntimeException e) { - throw new SMBExceptionMappingService().map(e); - } - catch(TransportException e) { - throw new BackgroundException(e); - } + } + catch(SMBRuntimeException e) { + throw new SMBExceptionMappingService().map(e); + } + catch(TransportException | IllegalStateException e) { + throw new BackgroundException(e); + } + finally { + super.logout(); } } @Override - protected void disconnect() { + protected void disconnect() throws BackgroundException { try { client.close(); } diff --git a/smb/src/test/java/ch/cyberduck/core/smb/SMBRootListServiceTest.java b/smb/src/test/java/ch/cyberduck/core/smb/SMBRootListServiceTest.java index f400e18cbf7..65c005c855a 100644 --- a/smb/src/test/java/ch/cyberduck/core/smb/SMBRootListServiceTest.java +++ b/smb/src/test/java/ch/cyberduck/core/smb/SMBRootListServiceTest.java @@ -39,6 +39,5 @@ public void testListAllShares() throws Exception { assertNotEquals(TransferStatus.UNKNOWN_LENGTH, f.attributes().getSize()); assertNotEquals(Quota.unknown, f.attributes().getQuota()); } - session.close(); } } \ No newline at end of file diff --git a/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java b/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java index 907d2d7a338..a55ffb38ba9 100644 --- a/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java +++ b/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java @@ -403,20 +403,22 @@ public SFTPEngine sftp() throws LoginCanceledException { } @Override - protected void logout() throws BackgroundException { + public void logout() throws BackgroundException { try { - if(null == sftp) { - return; + if(null != sftp) { + sftp.close(); } - sftp.close(); } catch(IOException e) { throw new SFTPExceptionMappingService().map(e); } + finally { + super.logout(); + } } @Override - public void disconnect() { + public void disconnect() throws BackgroundException { try { client.close(); } diff --git a/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPasswordAuthenticationTest.java b/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPasswordAuthenticationTest.java index af088826fbc..ff454a90a88 100644 --- a/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPasswordAuthenticationTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPasswordAuthenticationTest.java @@ -20,7 +20,6 @@ import ch.cyberduck.core.DisabledLoginCallback; import ch.cyberduck.core.exception.LoginFailureException; import ch.cyberduck.core.proxy.DisabledProxyFinder; -import ch.cyberduck.core.proxy.Proxy; import ch.cyberduck.core.sftp.AbstractSFTPTest; import ch.cyberduck.test.IntegrationTest; diff --git a/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPublicKeyAuthenticationTest.java b/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPublicKeyAuthenticationTest.java index 484635916fd..1647f926130 100644 --- a/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPublicKeyAuthenticationTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/sftp/auth/SFTPPublicKeyAuthenticationTest.java @@ -22,12 +22,10 @@ import ch.cyberduck.core.Host; import ch.cyberduck.core.Local; import ch.cyberduck.core.LoginOptions; -import ch.cyberduck.core.exception.InteroperabilityException; import ch.cyberduck.core.exception.LoginCanceledException; import ch.cyberduck.core.exception.LoginFailureException; import ch.cyberduck.core.local.DefaultLocalTouchFeature; import ch.cyberduck.core.proxy.DisabledProxyFinder; -import ch.cyberduck.core.proxy.Proxy; import ch.cyberduck.core.sftp.AbstractSFTPTest; import ch.cyberduck.test.IntegrationTest; diff --git a/storegate/src/main/java/ch/cyberduck/core/storegate/StoregateSession.java b/storegate/src/main/java/ch/cyberduck/core/storegate/StoregateSession.java index 2be0045b7f6..1a7572f0bff 100644 --- a/storegate/src/main/java/ch/cyberduck/core/storegate/StoregateSession.java +++ b/storegate/src/main/java/ch/cyberduck/core/storegate/StoregateSession.java @@ -191,9 +191,14 @@ public List roots() { } @Override - protected void logout() { - client.getHttpClient().close(); + public void disconnect() throws BackgroundException { fileid.clear(); + try { + client.getHttpClient().close(); + } + finally { + super.disconnect(); + } } @Override diff --git a/webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java b/webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java index f129f99122e..31c7eac5ed5 100644 --- a/webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java +++ b/webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java @@ -126,13 +126,14 @@ protected HttpClientBuilder getConfiguration(final ProxyFinder proxy, final Logi } @Override - protected void logout() throws BackgroundException { + public void disconnect() throws BackgroundException { try { client.shutdown(); } catch(IOException e) { throw new HttpExceptionMappingService().map(e); } + super.disconnect(); } @Override