From ef5cf49134202e14ad949a3bb492cdaa29b0c3ca Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 22 Nov 2023 21:07:42 +0100 Subject: [PATCH 01/11] Save OAuth tokens with port number from token URL. --- .../core/DefaultHostPasswordStore.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index d53258e390c..5c463d6f7ab 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -153,12 +153,12 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { try { final String expiry = this.getPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); return (new OAuthTokens( - this.getPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Access Token", prefix)), - this.getPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Refresh Token", prefix)), expiry != null ? Long.parseLong(expiry) : -1L, - this.getPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, String.format("%s OIDC Id Token", prefix)))); } catch(LocalAccessDeniedException e) { @@ -174,6 +174,16 @@ protected String getOAuthHostname(final Host bookmark) { return bookmark.getHostname(); } + protected int getOAuthPort(final Host bookmark) { + if(-1 != URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getPort()) { + return URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getPort(); + } + if(null == URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getScheme()) { + return bookmark.getPort(); + } + return Scheme.valueOf(URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getScheme()).getPort(); + } + private String getOAuthPrefix(final Host bookmark) { if(StringUtils.isNotBlank(bookmark.getCredentials().getUsername())) { return String.format("%s (%s)", bookmark.getProtocol().getDescription(), bookmark.getCredentials().getUsername()); @@ -217,12 +227,12 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { final String prefix = this.getOAuthPrefix(bookmark); if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - bookmark.getPort(), this.getOAuthHostname(bookmark), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix), credentials.getOauth().getAccessToken()); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - bookmark.getPort(), this.getOAuthHostname(bookmark), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix), credentials.getOauth().getRefreshToken()); } // Save expiry @@ -232,7 +242,7 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - bookmark.getPort(), this.getOAuthHostname(bookmark), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix), credentials.getOauth().getIdToken()); } } @@ -264,11 +274,11 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { if(protocol.isOAuthConfigurable()) { final String prefix = this.getOAuthPrefix(bookmark); if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.deletePassword(protocol.getScheme(), bookmark.getPort(), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.deletePassword(protocol.getScheme(), bookmark.getPort(), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix)); } // Save expiry @@ -276,7 +286,7 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { this.deletePassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.deletePassword(protocol.getScheme(), bookmark.getPort(), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix)); } } From 1f257ff200d4d98585772cddacd258898d6b52bd Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 22 Nov 2023 21:35:26 +0100 Subject: [PATCH 02/11] Save new tokens using OAuth Client ID as prefix. Fix #15284. --- .../core/CredentialManagerPasswordStore.cs | 94 ++++++++----- .../core/DefaultHostPasswordStore.java | 130 ++++++++++-------- 2 files changed, 135 insertions(+), 89 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index f6da6922965..8027c258b63 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -21,8 +21,11 @@ using ch.cyberduck.core.preferences; using Ch.Cyberduck.Core.CredentialManager; using org.apache.logging.log4j; +using org.apache.logging.log4j.core.net; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using System.Net; using System.Text; using static Windows.Win32.Security.Credentials.CRED_PERSIST; @@ -61,9 +64,12 @@ public override void delete(Host bookmark) logger.info(string.Format("Delete password for bookmark {0}", bookmark)); } var target = ToUri(bookmark); - if (!WinCredentialManager.RemoveCredentials(target.AbsoluteUri)) + foreach (Uri descriptor in target) { - base.delete(bookmark); + if (!WinCredentialManager.RemoveCredentials(descriptor.AbsoluteUri)) + { + base.delete(bookmark); + } } } @@ -86,7 +92,7 @@ public override void deletePassword(Scheme scheme, int port, string hostName, st public override string findLoginPassword(Host bookmark) { - var target = ToUri(bookmark); + var target = ToUri(bookmark)[0]; var cred = WinCredentialManager.GetCredentials(target.AbsoluteUri); if (!string.IsNullOrWhiteSpace(cred.Password)) { @@ -101,7 +107,7 @@ public override string findLoginToken(Host bookmark) { logger.info(string.Format("Fetching login token from keychain for {0}", bookmark)); } - var target = ToUri(bookmark); + var target = ToUri(bookmark)[0]; var cred = WinCredentialManager.GetCredentials(target.AbsoluteUri); if (cred.Attributes is Dictionary attrs && attrs.TryGetValue("Token", out var token) @@ -119,21 +125,30 @@ public override OAuthTokens findOAuthTokens(Host bookmark) logger.info(string.Format("Fetching OAuth tokens from keychain for {0}", bookmark)); } var target = ToUri(bookmark); - var cred = WinCredentialManager.GetCredentials(target.AbsoluteUri); - if (cred.Attributes is Dictionary attrs - && attrs.TryGetValue("OAuth Access Token", out var accessToken)) + foreach(Uri descriptor in target) { - attrs.TryGetValue("OAuth Refresh Token", out var refreshToken); - attrs.TryGetValue("OIDC Id Token", out var idToken); - long expiry = default; - if (attrs.TryGetValue("OAuth Expiry", out var expiryValue)) + var cred = WinCredentialManager.GetCredentials(descriptor.AbsoluteUri); + if (cred.Attributes is Dictionary attrs) { - long.TryParse(expiryValue, out expiry); + attrs.TryGetValue("OAuth Access Token", out var accessToken); + attrs.TryGetValue("OAuth Refresh Token", out var refreshToken); + attrs.TryGetValue("OIDC Id Token", out var idToken); + long expiry = default; + if (attrs.TryGetValue("OAuth Expiry", out var expiryValue)) + { + long.TryParse(expiryValue, out expiry); + } + OAuthTokens tokens = new(accessToken, refreshToken, new(expiry), idToken); + if(tokens.validate()) + { + return tokens; + } + // Continue } - return new(accessToken, refreshToken, new(expiry), idToken); - } - return base.findOAuthTokens(bookmark); + return base.findOAuthTokens(bookmark); + } + return OAuthTokens.EMPTY; } public override string findPrivateKeyPassphrase(Host bookmark) @@ -142,7 +157,7 @@ public override string findPrivateKeyPassphrase(Host bookmark) { logger.info(string.Format("Fetching private key passphrase from keychain for {0}", bookmark)); } - var target = ToUri(bookmark); + var target = ToUri(bookmark)[0]; var cred = WinCredentialManager.GetCredentials(target.AbsoluteUri); if (cred.Attributes is Dictionary attrs && attrs.TryGetValue("Private Key Passphrase", out var passphrase) @@ -172,7 +187,7 @@ public override void save(Host bookmark) { logger.info(string.Format("Add password for bookmark {0}", bookmark)); } - var target = ToUri(bookmark); + var target = ToUri(bookmark)[0]; var credential = bookmark.getCredentials(); var winCred = new WindowsCredentialManagerCredential( @@ -209,29 +224,42 @@ public override void save(Host bookmark) } } - private static Uri ToUri(Host bookmark) + private static Uri[] ToUri(Host bookmark) { - var protocol = bookmark.getProtocol(); - var credentials = bookmark.getCredentials(); - - var targetBuilder = new UriBuilder(PreferencesFactory.get().getProperty("application.container.name"), string.Empty); - var pathBuilder = new StringBuilder(); - pathBuilder.Append(protocol.getIdentifier()); - if (protocol.isHostnameConfigurable() || !(protocol.isTokenConfigurable() || protocol.isOAuthConfigurable())) + Collection descriptors = new(); + foreach(string descriptor in ToDescriptor(bookmark)) { - pathBuilder.Append(":" + bookmark.getHostname()); - if (protocol.isPortConfigurable() && !Equals(protocol.getDefaultPort(), bookmark.getPort())) + var protocol = bookmark.getProtocol(); + var credentials = bookmark.getCredentials(); + + var targetBuilder = new UriBuilder(PreferencesFactory.get().getProperty("application.container.name"), string.Empty); + var pathBuilder = new StringBuilder(); + pathBuilder.Append(descriptor); + if (protocol.isHostnameConfigurable() || !(protocol.isTokenConfigurable() || protocol.isOAuthConfigurable())) + { + pathBuilder.Append(":" + bookmark.getHostname()); + if (protocol.isPortConfigurable() && !Equals(protocol.getDefaultPort(), bookmark.getPort())) + { + pathBuilder.Append(":" + bookmark.getPort()); + } + } + targetBuilder.Path = pathBuilder.ToString(); + if (!string.IsNullOrWhiteSpace(credentials.getUsername())) { - pathBuilder.Append(":" + bookmark.getPort()); + targetBuilder.Query = "user=" + credentials.getUsername(); } + descriptors.Add(targetBuilder.Uri); } - targetBuilder.Path = pathBuilder.ToString(); - if (!string.IsNullOrWhiteSpace(credentials.getUsername())) + return descriptors.ToArray(); + } + + private static string[] ToDescriptor(Host bookmark) + { + if(bookmark.getProtocol().isOAuthConfigurable()) { - targetBuilder.Query = "user=" + credentials.getUsername(); + return new string[] { bookmark.getProtocol().getOAuthClientId(), bookmark.getProtocol().getIdentifier() }; } - - return targetBuilder.Uri; + return new string[] { bookmark.getProtocol().getIdentifier() }; } } } diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 5c463d6f7ab..7e9ed07165e 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -148,23 +148,30 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { if(log.isInfoEnabled()) { log.info(String.format("Fetching OAuth tokens from keychain for %s", bookmark)); } - final String prefix = this.getOAuthPrefix(bookmark); - final String hostname = this.getOAuthHostname(bookmark); - try { - final String expiry = this.getPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); - return (new OAuthTokens( - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, - String.format("%s OAuth2 Access Token", prefix)), - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, - String.format("%s OAuth2 Refresh Token", prefix)), - expiry != null ? Long.parseLong(expiry) : -1L, - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, - String.format("%s OIDC Id Token", prefix)))); - } - catch(LocalAccessDeniedException e) { - log.warn(String.format("Failure %s searching in keychain", e)); - return OAuthTokens.EMPTY; + final String[] descriptors = this.getOAuthPrefix(bookmark); + for(String prefix : descriptors) { + final String hostname = this.getOAuthHostname(bookmark); + try { + final String expiry = this.getPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); + final OAuthTokens tokens = new OAuthTokens( + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + String.format("%s OAuth2 Access Token", prefix)), + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + String.format("%s OAuth2 Refresh Token", prefix)), + expiry != null ? Long.parseLong(expiry) : -1L, + this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + String.format("%s OIDC Id Token", prefix))); + if(tokens.validate()) { + return tokens; + } + // Continue + } + catch(LocalAccessDeniedException e) { + log.warn(String.format("Failure %s searching in keychain", e)); + return OAuthTokens.EMPTY; + } } + return OAuthTokens.EMPTY; } protected String getOAuthHostname(final Host bookmark) { @@ -184,11 +191,17 @@ protected int getOAuthPort(final Host bookmark) { return Scheme.valueOf(URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getScheme()).getPort(); } - private String getOAuthPrefix(final Host bookmark) { + private String[] getOAuthPrefix(final Host bookmark) { if(StringUtils.isNotBlank(bookmark.getCredentials().getUsername())) { - return String.format("%s (%s)", bookmark.getProtocol().getDescription(), bookmark.getCredentials().getUsername()); - } - return bookmark.getProtocol().getDescription(); + return new String[]{ + String.format("%s (%s)", bookmark.getProtocol().getOAuthClientId(), bookmark.getCredentials().getUsername()), + String.format("%s (%s)", bookmark.getProtocol().getDescription(), bookmark.getCredentials().getUsername()) + }; + } + return new String[]{ + bookmark.getProtocol().getOAuthClientId(), + bookmark.getProtocol().getDescription() + }; } @Override @@ -224,26 +237,29 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { credentials.getToken()); } if(credentials.isOAuthAuthentication()) { - final String prefix = this.getOAuthPrefix(bookmark); - if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OAuth2 Access Token", prefix), credentials.getOauth().getAccessToken()); - } - if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OAuth2 Refresh Token", prefix), credentials.getOauth().getRefreshToken()); - } - // Save expiry - if(credentials.getOauth().getExpiryInMilliseconds() != null) { - this.addPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix), - String.valueOf(credentials.getOauth().getExpiryInMilliseconds())); - } - if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OIDC Id Token", prefix), credentials.getOauth().getIdToken()); + final String[] descriptors = this.getOAuthPrefix(bookmark); + for(String prefix : descriptors) { + if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { + this.addPassword(bookmark.getProtocol().getScheme(), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OAuth2 Access Token", prefix), credentials.getOauth().getAccessToken()); + } + if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { + this.addPassword(bookmark.getProtocol().getScheme(), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OAuth2 Refresh Token", prefix), credentials.getOauth().getRefreshToken()); + } + // Save expiry + if(credentials.getOauth().getExpiryInMilliseconds() != null) { + this.addPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix), + String.valueOf(credentials.getOauth().getExpiryInMilliseconds())); + } + if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { + this.addPassword(bookmark.getProtocol().getScheme(), + this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OIDC Id Token", prefix), credentials.getOauth().getIdToken()); + } + break; } } } @@ -272,22 +288,24 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { protocol.getTokenPlaceholder() : String.format("%s (%s)", protocol.getTokenPlaceholder(), credentials.getUsername())); } if(protocol.isOAuthConfigurable()) { - final String prefix = this.getOAuthPrefix(bookmark); - if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OAuth2 Access Token", prefix)); - } - if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OAuth2 Refresh Token", prefix)); - } - // Save expiry - if(credentials.getOauth().getExpiryInMilliseconds() != null) { - this.deletePassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); - } - if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), - String.format("%s OIDC Id Token", prefix)); + final String[] descriptors = this.getOAuthPrefix(bookmark); + for(String prefix : descriptors) { + if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OAuth2 Access Token", prefix)); + } + if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OAuth2 Refresh Token", prefix)); + } + // Save expiry + if(credentials.getOauth().getExpiryInMilliseconds() != null) { + this.deletePassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); + } + if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { + this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + String.format("%s OIDC Id Token", prefix)); + } } } } From 5a51554d7ea92d421bb1a71b99722a7d9a38a5bc Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 23 Nov 2023 14:25:54 +0100 Subject: [PATCH 03/11] Make utility methods static. --- .../core/DefaultHostPasswordStore.java | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 7e9ed07165e..f717c7c8243 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -148,18 +148,18 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { if(log.isInfoEnabled()) { log.info(String.format("Fetching OAuth tokens from keychain for %s", bookmark)); } - final String[] descriptors = this.getOAuthPrefix(bookmark); + final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { - final String hostname = this.getOAuthHostname(bookmark); + final String hostname = getOAuthHostname(bookmark); try { - final String expiry = this.getPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); + final String expiry = this.getPassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); final OAuthTokens tokens = new OAuthTokens( - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Access Token", prefix)), - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Refresh Token", prefix)), expiry != null ? Long.parseLong(expiry) : -1L, - this.getPassword(bookmark.getProtocol().getScheme(), this.getOAuthPort(bookmark), hostname, + this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, String.format("%s OIDC Id Token", prefix))); if(tokens.validate()) { return tokens; @@ -174,24 +174,26 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { return OAuthTokens.EMPTY; } - protected String getOAuthHostname(final Host bookmark) { - if(StringUtils.isNotBlank(URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getHost())) { - return URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getHost(); + private static String getOAuthHostname(final Host bookmark) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(StringUtils.isNotBlank(uri.getHost())) { + return uri.getHost(); } return bookmark.getHostname(); } - protected int getOAuthPort(final Host bookmark) { - if(-1 != URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getPort()) { - return URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getPort(); + private static int getOAuthPort(final Host bookmark) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(-1 != uri.getPort()) { + return uri.getPort(); } - if(null == URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getScheme()) { + if(null == uri.getScheme()) { return bookmark.getPort(); } - return Scheme.valueOf(URI.create(bookmark.getProtocol().getOAuthTokenUrl()).getScheme()).getPort(); + return Scheme.valueOf(uri.getScheme()).getPort(); } - private String[] getOAuthPrefix(final Host bookmark) { + private static String[] getOAuthPrefix(final Host bookmark) { if(StringUtils.isNotBlank(bookmark.getCredentials().getUsername())) { return new String[]{ String.format("%s (%s)", bookmark.getProtocol().getOAuthClientId(), bookmark.getCredentials().getUsername()), @@ -237,26 +239,26 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { credentials.getToken()); } if(credentials.isOAuthAuthentication()) { - final String[] descriptors = this.getOAuthPrefix(bookmark); + final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix), credentials.getOauth().getAccessToken()); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix), credentials.getOauth().getRefreshToken()); } // Save expiry if(credentials.getOauth().getExpiryInMilliseconds() != null) { - this.addPassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix), + this.addPassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix), String.valueOf(credentials.getOauth().getExpiryInMilliseconds())); } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { this.addPassword(bookmark.getProtocol().getScheme(), - this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix), credentials.getOauth().getIdToken()); } break; @@ -288,22 +290,22 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { protocol.getTokenPlaceholder() : String.format("%s (%s)", protocol.getTokenPlaceholder(), credentials.getUsername())); } if(protocol.isOAuthConfigurable()) { - final String[] descriptors = this.getOAuthPrefix(bookmark); + final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix)); } // Save expiry if(credentials.getOauth().getExpiryInMilliseconds() != null) { - this.deletePassword(this.getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); + this.deletePassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.deletePassword(protocol.getScheme(), this.getOAuthPort(bookmark), this.getOAuthHostname(bookmark), + this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix)); } } From 2a366bb431c8a4d0afcc3673733f226f33e469c2 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 23 Nov 2023 14:33:13 +0100 Subject: [PATCH 04/11] Get scheme from OAuth token URL. --- .../core/DefaultHostPasswordStore.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index f717c7c8243..2f7ac6f1b1d 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -154,12 +154,12 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { try { final String expiry = this.getPassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); final OAuthTokens tokens = new OAuthTokens( - this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, + this.getPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Access Token", prefix)), - this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, + this.getPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), hostname, String.format("%s OAuth2 Refresh Token", prefix)), expiry != null ? Long.parseLong(expiry) : -1L, - this.getPassword(bookmark.getProtocol().getScheme(), getOAuthPort(bookmark), hostname, + this.getPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), hostname, String.format("%s OIDC Id Token", prefix))); if(tokens.validate()) { return tokens; @@ -174,6 +174,14 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { return OAuthTokens.EMPTY; } + private static Scheme getOAuthScheme(final Host bookmark) { + final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); + if(null == uri.getScheme()) { + return bookmark.getProtocol().getScheme(); + } + return Scheme.valueOf(uri.getScheme()); + } + private static String getOAuthHostname(final Host bookmark) { final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); if(StringUtils.isNotBlank(uri.getHost())) { @@ -187,10 +195,7 @@ private static int getOAuthPort(final Host bookmark) { if(-1 != uri.getPort()) { return uri.getPort(); } - if(null == uri.getScheme()) { - return bookmark.getPort(); - } - return Scheme.valueOf(uri.getScheme()).getPort(); + return getOAuthScheme(bookmark).getPort(); } private static String[] getOAuthPrefix(final Host bookmark) { @@ -242,12 +247,12 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), + this.addPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix), credentials.getOauth().getAccessToken()); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), + this.addPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix), credentials.getOauth().getRefreshToken()); } @@ -257,7 +262,7 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { String.valueOf(credentials.getOauth().getExpiryInMilliseconds())); } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.addPassword(bookmark.getProtocol().getScheme(), + this.addPassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix), credentials.getOauth().getIdToken()); } @@ -293,11 +298,11 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { if(StringUtils.isNotBlank(credentials.getOauth().getAccessToken())) { - this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), + this.deletePassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Access Token", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getRefreshToken())) { - this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), + this.deletePassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OAuth2 Refresh Token", prefix)); } // Save expiry @@ -305,7 +310,7 @@ public void delete(final Host bookmark) throws LocalAccessDeniedException { this.deletePassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); } if(StringUtils.isNotBlank(credentials.getOauth().getIdToken())) { - this.deletePassword(protocol.getScheme(), getOAuthPort(bookmark), getOAuthHostname(bookmark), + this.deletePassword(getOAuthScheme(bookmark), getOAuthPort(bookmark), getOAuthHostname(bookmark), String.format("%s OIDC Id Token", prefix)); } } From 3bf26e8f18a0d4aaf40dbb075017eb3a04954fcb Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 23 Nov 2023 14:34:38 +0100 Subject: [PATCH 05/11] Extract field. --- .../java/ch/cyberduck/core/DefaultHostPasswordStore.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 2f7ac6f1b1d..3caf194780b 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -218,6 +218,7 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { return; } final Credentials credentials = bookmark.getCredentials(); + final Protocol protocol = bookmark.getProtocol(); if(log.isInfoEnabled()) { log.info(String.format("Save credentials %s for bookmark %s", credentials, bookmark)); } @@ -234,13 +235,13 @@ public void save(final Host bookmark) throws LocalAccessDeniedException { log.warn(String.format("No password in credentials for bookmark %s", bookmark.getHostname())); return; } - this.addPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), + this.addPassword(protocol.getScheme(), bookmark.getPort(), bookmark.getHostname(), credentials.getUsername(), credentials.getPassword()); } if(credentials.isTokenAuthentication()) { - this.addPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), + this.addPassword(protocol.getScheme(), bookmark.getPort(), bookmark.getHostname(), StringUtils.isEmpty(credentials.getUsername()) ? - bookmark.getProtocol().getTokenPlaceholder() : String.format("%s (%s)", bookmark.getProtocol().getTokenPlaceholder(), credentials.getUsername()), + protocol.getTokenPlaceholder() : String.format("%s (%s)", protocol.getTokenPlaceholder(), credentials.getUsername()), credentials.getToken()); } if(credentials.isOAuthAuthentication()) { From dfc52f333bad895fbc71441b2455b3ff75309c1c Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 23 Nov 2023 14:37:39 +0100 Subject: [PATCH 06/11] Review. --- .../ch/cyberduck/core/CredentialManagerPasswordStore.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index 8027c258b63..9d334c5a3a1 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -66,11 +66,9 @@ public override void delete(Host bookmark) var target = ToUri(bookmark); foreach (Uri descriptor in target) { - if (!WinCredentialManager.RemoveCredentials(descriptor.AbsoluteUri)) - { - base.delete(bookmark); - } + WinCredentialManager.RemoveCredentials(descriptor.AbsoluteUri); } + base.delete(bookmark); } public override void deletePassword(string serviceName, string user) @@ -145,7 +143,6 @@ public override OAuthTokens findOAuthTokens(Host bookmark) } // Continue } - return base.findOAuthTokens(bookmark); } return OAuthTokens.EMPTY; From 59a2ca99831293e0b778dc2e6b5532cf49f24c24 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 23 Nov 2023 14:42:42 +0100 Subject: [PATCH 07/11] Change type. --- .../ch/cyberduck/core/CredentialManagerPasswordStore.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index 9d334c5a3a1..409d4d622c6 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -21,11 +21,8 @@ using ch.cyberduck.core.preferences; using Ch.Cyberduck.Core.CredentialManager; using org.apache.logging.log4j; -using org.apache.logging.log4j.core.net; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; using System.Net; using System.Text; using static Windows.Win32.Security.Credentials.CRED_PERSIST; @@ -221,9 +218,9 @@ public override void save(Host bookmark) } } - private static Uri[] ToUri(Host bookmark) + private static List ToUri(Host bookmark) { - Collection descriptors = new(); + List descriptors = new(); foreach(string descriptor in ToDescriptor(bookmark)) { var protocol = bookmark.getProtocol(); @@ -247,7 +244,7 @@ private static Uri[] ToUri(Host bookmark) } descriptors.Add(targetBuilder.Uri); } - return descriptors.ToArray(); + return descriptors; } private static string[] ToDescriptor(Host bookmark) From edd9d3a00598fde24b13e084f53538bef50dfc5c Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 29 Nov 2023 10:45:46 +0100 Subject: [PATCH 08/11] Add test. --- .../core/DefaultHostPasswordStore.java | 8 +-- .../core/DefaultHostPasswordStoreTest.java | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 core/src/test/java/ch/cyberduck/core/DefaultHostPasswordStoreTest.java diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 3caf194780b..88c9ca69989 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -174,7 +174,7 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { return OAuthTokens.EMPTY; } - private static Scheme getOAuthScheme(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(); @@ -182,7 +182,7 @@ private static Scheme getOAuthScheme(final Host bookmark) { return Scheme.valueOf(uri.getScheme()); } - private static String getOAuthHostname(final Host bookmark) { + protected static String getOAuthHostname(final Host bookmark) { final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); if(StringUtils.isNotBlank(uri.getHost())) { return uri.getHost(); @@ -190,7 +190,7 @@ private static String getOAuthHostname(final Host bookmark) { return bookmark.getHostname(); } - private static int getOAuthPort(final Host bookmark) { + protected static int getOAuthPort(final Host bookmark) { final URI uri = URI.create(bookmark.getProtocol().getOAuthTokenUrl()); if(-1 != uri.getPort()) { return uri.getPort(); @@ -198,7 +198,7 @@ private static int getOAuthPort(final Host bookmark) { return getOAuthScheme(bookmark).getPort(); } - private static String[] getOAuthPrefix(final Host bookmark) { + protected static String[] getOAuthPrefix(final Host bookmark) { if(StringUtils.isNotBlank(bookmark.getCredentials().getUsername())) { return new String[]{ String.format("%s (%s)", bookmark.getProtocol().getOAuthClientId(), bookmark.getCredentials().getUsername()), diff --git a/core/src/test/java/ch/cyberduck/core/DefaultHostPasswordStoreTest.java b/core/src/test/java/ch/cyberduck/core/DefaultHostPasswordStoreTest.java new file mode 100644 index 00000000000..d4eeb09608a --- /dev/null +++ b/core/src/test/java/ch/cyberduck/core/DefaultHostPasswordStoreTest.java @@ -0,0 +1,67 @@ +package ch.cyberduck.core; + +/* + * Copyright (c) 2002-2023 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. + */ + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class DefaultHostPasswordStoreTest { + + @Test + public void testGetOAuthPrefix() { + final String[] prefix = DefaultHostPasswordStore.getOAuthPrefix(new Host(new TestProtocol(Scheme.https) { + @Override + public String getOAuthClientId() { + return "clientid"; + } + + @Override + public String getOAuthClientSecret() { + return "clientsecret"; + } + + @Override + public String getOAuthRedirectUrl() { + return "x-cyberduck-action:oauth"; + } + })); + assertEquals("clientid", prefix[0]); + assertEquals("Test", prefix[1]); + } + + @Test + public void testGetOAuthPrefixWithUsername() { + final String[] prefix = DefaultHostPasswordStore.getOAuthPrefix(new Host(new TestProtocol(Scheme.https) { + @Override + public String getOAuthClientId() { + return "clientid"; + } + + @Override + public String getOAuthClientSecret() { + return "clientsecret"; + } + + @Override + public String getOAuthRedirectUrl() { + return "x-cyberduck-action:oauth"; + } + }).withCredentials(new Credentials("user"))); + assertEquals("clientid (user)", prefix[0]); + assertEquals("Test (user)", prefix[1]); + } +} \ No newline at end of file From 9c2bfb83c6198c634c54fd22ec88516dbf9fae99 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 29 Nov 2023 10:51:27 +0100 Subject: [PATCH 09/11] Logging. --- .../ch/cyberduck/core/CredentialManagerPasswordStore.cs | 2 +- .../java/ch/cyberduck/core/DefaultHostPasswordStore.java | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index 409d4d622c6..1f2e08cf021 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -138,7 +138,7 @@ public override OAuthTokens findOAuthTokens(Host bookmark) { return tokens; } - // Continue + // Continue with deprecated descriptors } return base.findOAuthTokens(bookmark); } diff --git a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java index 88c9ca69989..43ba07a8364 100644 --- a/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java +++ b/core/src/main/java/ch/cyberduck/core/DefaultHostPasswordStore.java @@ -150,7 +150,13 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { } final String[] descriptors = getOAuthPrefix(bookmark); for(String prefix : descriptors) { + if(log.isDebugEnabled()) { + log.debug(String.format("Search with prefix %s", prefix)); + } final String hostname = getOAuthHostname(bookmark); + if(log.isDebugEnabled()) { + log.debug(String.format("Search with hostname %s", hostname)); + } try { final String expiry = this.getPassword(getOAuthHostname(bookmark), String.format("%s OAuth2 Token Expiry", prefix)); final OAuthTokens tokens = new OAuthTokens( @@ -164,7 +170,7 @@ public OAuthTokens findOAuthTokens(final Host bookmark) { if(tokens.validate()) { return tokens; } - // Continue + // Continue with deprecated descriptors } catch(LocalAccessDeniedException e) { log.warn(String.format("Failure %s searching in keychain", e)); From 4e91997364a2dab9c17f2d4d958c5cee78976b69 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 29 Nov 2023 10:53:27 +0100 Subject: [PATCH 10/11] Rename var. --- .../ch/cyberduck/core/CredentialManagerPasswordStore.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index 1f2e08cf021..310dfc35b01 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -60,8 +60,8 @@ public override void delete(Host bookmark) { logger.info(string.Format("Delete password for bookmark {0}", bookmark)); } - var target = ToUri(bookmark); - foreach (Uri descriptor in target) + var targets = ToUri(bookmark); + foreach (Uri descriptor in targets) { WinCredentialManager.RemoveCredentials(descriptor.AbsoluteUri); } @@ -119,8 +119,8 @@ public override OAuthTokens findOAuthTokens(Host bookmark) { logger.info(string.Format("Fetching OAuth tokens from keychain for {0}", bookmark)); } - var target = ToUri(bookmark); - foreach(Uri descriptor in target) + var targets = ToUri(bookmark); + foreach(Uri descriptor in targets) { var cred = WinCredentialManager.GetCredentials(descriptor.AbsoluteUri); if (cred.Attributes is Dictionary attrs) From 3aba693ee5fc516d71a7225c96c601f0a22570fd Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 29 Nov 2023 11:09:01 +0100 Subject: [PATCH 11/11] Only fallback to base implementation after trying all descriptors. --- .../csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs index 310dfc35b01..ed08cface49 100644 --- a/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs +++ b/core/src/main/csharp/ch/cyberduck/core/CredentialManagerPasswordStore.cs @@ -140,9 +140,8 @@ public override OAuthTokens findOAuthTokens(Host bookmark) } // Continue with deprecated descriptors } - return base.findOAuthTokens(bookmark); } - return OAuthTokens.EMPTY; + return base.findOAuthTokens(bookmark); } public override string findPrivateKeyPassphrase(Host bookmark)