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 bded86cba08..6f509d86e50 100644 --- a/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java +++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java @@ -24,7 +24,9 @@ import ch.cyberduck.core.HostKeyCallback; import ch.cyberduck.core.HostPasswordStore; import ch.cyberduck.core.ListService; +import ch.cyberduck.core.LocaleFactory; import ch.cyberduck.core.LoginCallback; +import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.Path; import ch.cyberduck.core.PreferencesUseragentProvider; import ch.cyberduck.core.Scheme; @@ -72,6 +74,7 @@ import com.microsoft.azure.storage.SendingRequestEvent; import com.microsoft.azure.storage.StorageCredentials; import com.microsoft.azure.storage.StorageCredentialsAccountAndKey; +import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.blob.BlobRequestOptions; import com.microsoft.azure.storage.blob.CloudBlobClient; @@ -99,8 +102,15 @@ public AzureSession(final Host h, final X509TrustManager trust, final X509KeyMan @Override public CloudBlobClient connect(final Proxy proxy, final HostKeyCallback callback, final LoginCallback prompt) throws BackgroundException { try { - final StorageCredentialsAccountAndKey credentials - = new StorageCredentialsAccountAndKey(host.getCredentials().getUsername(), "null"); + final StorageCredentials credentials; + if(host.getProtocol().isTokenConfigurable()) { + credentials = new StorageCredentialsSharedAccessSignature(prompt.prompt(host, + LocaleFactory.localizedString("Provide additional login credentials", "Credentials"), + LocaleFactory.localizedString("Shared Access Signature (SAS) Token", "Azure"), new LoginOptions(host.getProtocol())).getPassword()); + } + else { + credentials = new StorageCredentialsAccountAndKey(host.getCredentials().getUsername(), "null"); + } // Client configured with no credentials final URI uri = new URI(String.format("%s://%s", Scheme.https, host.getHostname())); final CloudBlobClient client = new CloudBlobClient(uri, credentials); @@ -152,9 +162,9 @@ public void eventOccurred(final SendingRequestEvent event) { @Override public void login(final Proxy proxy, final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException { - // Update credentials final StorageCredentials credentials = client.getCredentials(); if(credentials instanceof StorageCredentialsAccountAndKey) { + // Update credentials ((StorageCredentialsAccountAndKey) credentials).updateKey(host.getCredentials().getPassword()); } // Fetch reference for directory to check login credentials diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java index 06d05e3bb80..9464b1015fd 100644 --- a/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java +++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java @@ -49,6 +49,39 @@ public void testConnect() throws Exception { assertFalse(session.isConnected()); } + @Test + public void testConnectSharedAccessSignature() throws Exception { + final Host host = new Host(new AzureProtocol() { + @Override + public boolean isUsernameConfigurable() { + return false; + } + + @Override + public boolean isPasswordConfigurable() { + return false; + } + + @Override + public boolean isTokenConfigurable() { + return true; + } + }, "kahy9boj3eib.blob.core.windows.net", new Credentials( + System.getProperties().getProperty("azure.account"), System.getProperties().getProperty("azure.key") + )); + final AzureSession session = new AzureSession(host); + new LoginConnectionService(new DisabledLoginCallback() { + @Override + public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) throws LoginCanceledException { + return new Credentials(null, "?sv=2017-07-29&ss=bfqt&srt=sco&sp=rwdlacup&se=2018-05-09T15:53:42Z&st=2018-05-08T07:53:42Z&spr=https&sig=Kx6DSSb4hqpqLfpuik0ngfvRS0TT%2BnYX87No8%2B4Sjzo%3D"); + } + }, new DisabledHostKeyCallback(), + new DisabledPasswordStore(), new DisabledProgressListener()).connect(session, PathCache.empty(), new DisabledCancelCallback()); + assertTrue(session.isConnected()); + session.close(); + assertFalse(session.isConnected()); + } + @Test(expected = LoginCanceledException.class) public void testConnectInvalidKey() throws Exception { final Host host = new Host(new AzureProtocol(), "kahy9boj3eib.blob.core.windows.net", new Credentials(