/** * Copyright Microsoft Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.microsoft.azure.storage.blob; import junit.framework.Assert; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.security.InvalidKeyException; import java.util.Calendar; import java.util.Date; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.TimeZone; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import com.microsoft.azure.storage.Constants; import com.microsoft.azure.storage.core.PathUtility; import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.IPRange; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResponseReceivedEvent; import com.microsoft.azure.storage.SecondaryTests; import com.microsoft.azure.storage.SendingRequestEvent; import com.microsoft.azure.storage.SharedAccessProtocols; import com.microsoft.azure.storage.SharedAccessAccountPermissions; import com.microsoft.azure.storage.SharedAccessAccountPolicy; import com.microsoft.azure.storage.SharedAccessAccountResourceType; import com.microsoft.azure.storage.SharedAccessAccountService; import com.microsoft.azure.storage.SharedAccessProtocols; import com.microsoft.azure.storage.StorageCredentials; import com.microsoft.azure.storage.StorageCredentialsAnonymous; import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.TestHelper; import com.microsoft.azure.storage.TestRunners; import com.microsoft.azure.storage.TestRunners.CloudTests; import com.microsoft.azure.storage.TestRunners.DevFabricTests; import com.microsoft.azure.storage.TestRunners.DevStoreTests; import com.microsoft.azure.storage.TestRunners.SlowTests; import static org.junit.Assert.*; @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class SasTests { protected CloudBlobContainer container; protected CloudBlockBlob blob; @Before public void blobSasTestMethodSetUp() throws URISyntaxException, StorageException, IOException { this.container = BlobTestHelper.getRandomContainerReference(); this.container.create(); this.blob = (CloudBlockBlob) BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, "test", 100, null); } @After public void blobSasTestMethodTearDown() throws StorageException { this.container.deleteIfExists(); } @Test public void testApiVersion() throws InvalidKeyException, StorageException, URISyntaxException { SharedAccessBlobPolicy sp1 = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 3600); String sas = this.blob.generateSharedAccessSignature(sp1, null); // should not be appended before signing assertEquals(-1, sas.indexOf(Constants.QueryConstants.API_VERSION)); OperationContext ctx = new OperationContext(); ctx.getResponseReceivedEventHandler().addListener(new StorageEvent<ResponseReceivedEvent>() { @Override public void eventOccurred(ResponseReceivedEvent eventArg) { // should be appended after signing HttpURLConnection conn = (HttpURLConnection) eventArg.getConnectionObject(); assertTrue(conn.getURL().toString().indexOf(Constants.QueryConstants.API_VERSION) != -1); } }); CloudBlockBlob sasBlob = new CloudBlockBlob(new URI(this.blob.getUri().toString() + "?" + sas)); sasBlob.uploadMetadata(null, null, ctx); } @Test @Category(SecondaryTests.class) public void testIpAcl() throws StorageException, URISyntaxException, InvalidKeyException, InterruptedException, UnknownHostException { // Generate policies SharedAccessBlobPolicy sp = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.LIST), 3600); IPRange range1 = new IPRange("0.0.0.0", "255.255.255.255"); IPRange range2 = new IPRange("0.0.0.0"); // Ensure access attempt from invalid IP fails IPRange sourceIP = null; try { String containerSasNone = this.container.generateSharedAccessSignature(sp, null, range2, null); CloudBlobContainer noneContainer = new CloudBlobContainer(PathUtility.addToQuery(this.container.getUri(), containerSasNone)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), noneContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob noneBlob = noneContainer.getBlockBlobReference(this.blob.getName()); noneBlob.download(new ByteArrayOutputStream()); fail(); } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); final String[] words = ex.getMessage().split(" "); // final word String lastWord = words[words.length - 1]; // strip trailing period lastWord = lastWord.substring(0, lastWord.length() - 1); sourceIP = new IPRange(lastWord); } // Ensure access attempt from the single allowed IP succeeds String containerSasOne = this.container.generateSharedAccessSignature(sp, null, sourceIP, null); CloudBlobContainer oneContainer = new CloudBlobContainer(PathUtility.addToQuery(this.container.getUri(), containerSasOne)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), oneContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob oneBlob = oneContainer.getBlockBlobReference(this.blob.getName()); oneBlob.download(new ByteArrayOutputStream()); // Ensure access attempt from one of many valid IPs succeeds String containerSasAll = this.container.generateSharedAccessSignature(sp, null, range1, null); CloudBlobContainer allContainer = new CloudBlobContainer(PathUtility.addToQuery(this.container.getUri(), containerSasAll)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), allContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob allBlob = allContainer.getBlockBlobReference(this.blob.getName()); allBlob.download(new ByteArrayOutputStream()); } @Test @Category(SecondaryTests.class) public void testProtocolRestrictions() throws StorageException, URISyntaxException, InvalidKeyException, InterruptedException { // Generate policy SharedAccessBlobPolicy sp = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.LIST), 3600); // Generate container SAS and URI String containerSasHttps = this.container.generateSharedAccessSignature( sp, null, null, SharedAccessProtocols.HTTPS_ONLY); String containerSasHttp = this.container.generateSharedAccessSignature( sp, null, null, SharedAccessProtocols.HTTPS_HTTP); final URI httpUri = new URI("http", this.container.getUri().getAuthority(), this.container.getUri().getPath(), this.container.getUri().getQuery(), null); final URI httpsUri = new URI("https", this.container.getUri().getAuthority(), this.container.getUri().getPath(), this.container.getUri().getQuery(), null); // Ensure attempt from http fails against HTTPS_ONLY try { CloudBlobContainer httpContainer = new CloudBlobContainer( PathUtility.addToQuery(httpUri, containerSasHttps)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), httpContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob httpBlob = httpContainer.getBlockBlobReference(this.blob.getName()); httpBlob.download(new ByteArrayOutputStream()); fail(); } catch (StorageException ex) { assertEquals(Constants.HeaderConstants.HTTP_UNUSED_306, ex.getHttpStatusCode()); assertEquals(SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS, ex.getMessage()); } // Ensure attempt from https succeeds against HTTPS_ONLY CloudBlobContainer httpsContainer = new CloudBlobContainer( PathUtility.addToQuery(httpsUri, containerSasHttps)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), httpsContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob httpsBlob = httpsContainer.getBlockBlobReference(this.blob.getName()); httpsBlob.download(new ByteArrayOutputStream()); //Ensure attempts from both https and http succeed against HTTPS_HTTP CloudBlobContainer httpContainer = new CloudBlobContainer( PathUtility.addToQuery(httpUri, containerSasHttp)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), httpContainer.getServiceClient().getCredentials().getClass().toString()); CloudBlockBlob httpBlob = httpContainer.getBlockBlobReference(this.blob.getName()); httpBlob.download(new ByteArrayOutputStream()); httpsContainer = new CloudBlobContainer( PathUtility.addToQuery(httpsUri, containerSasHttp)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), httpsContainer.getServiceClient().getCredentials().getClass().toString()); httpsBlob = httpsContainer.getBlockBlobReference(this.blob.getName()); httpsBlob.download(new ByteArrayOutputStream()); } @Test @Category ({ SecondaryTests.class, SlowTests.class }) public void testContainerSaS() throws IllegalArgumentException, StorageException, URISyntaxException, InvalidKeyException, InterruptedException { SharedAccessBlobPolicy sp1 = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 3600); SharedAccessBlobPolicy sp2 = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.LIST), 3600); BlobContainerPermissions perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("full", sp1); perms.getSharedAccessPolicies().put("readlist", sp2); this.container.uploadPermissions(perms); Thread.sleep(30000); String containerReadListSas = this.container.generateSharedAccessSignature(sp2, null); CloudBlobContainer readListContainer = new CloudBlobContainer(PathUtility.addToQuery(this.container.getUri(), containerReadListSas)); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), readListContainer.getServiceClient() .getCredentials().getClass().toString()); CloudBlockBlob blobFromSasContainer = readListContainer.getBlockBlobReference(this.blob.getName()); blobFromSasContainer.download(new ByteArrayOutputStream()); // do not give the client and check that the new container's client has the correct perms CloudBlobContainer containerFromUri = new CloudBlobContainer(PathUtility.addToQuery( readListContainer.getStorageUri(), this.container.generateSharedAccessSignature(null, "readlist"))); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), containerFromUri.getServiceClient() .getCredentials().getClass().toString()); // create credentials from sas StorageCredentials creds = new StorageCredentialsSharedAccessSignature( this.container.generateSharedAccessSignature(null, "readlist")); CloudBlobClient bClient = new CloudBlobClient(this.container.getServiceClient().getStorageUri(), creds); CloudBlobContainer containerFromClient = bClient.getContainerReference(this.container.getName()); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), containerFromClient.getServiceClient() .getCredentials().getClass().toString()); assertEquals(bClient, containerFromClient.getServiceClient()); } @Test @Category(SlowTests.class) public void testContainerUpdateSAS() throws InvalidKeyException, StorageException, IOException, URISyntaxException, InterruptedException { //Create a policy with read/write access and get SAS. SharedAccessBlobPolicy policy = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE), 3600); BlobContainerPermissions perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("readwrite", policy); this.container.uploadPermissions(perms); Thread.sleep(30000); String sasToken = this.container.generateSharedAccessSignature(policy, null); CloudBlockBlob blob = (CloudBlockBlob) BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, "blockblob", 64, null); testAccess(sasToken, EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE), null, this.container, blob); //Change the policy to only read and update SAS. SharedAccessBlobPolicy policy2 = createSharedAccessPolicy(EnumSet.of(SharedAccessBlobPermissions.READ), 3600); perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("read", policy2); this.container.uploadPermissions(perms); Thread.sleep(30000); // Extra check to make sure that we have actually updated the SAS token. String sasToken2 = this.container.generateSharedAccessSignature(policy2, null); CloudBlobContainer sasContainer = new CloudBlobContainer(PathUtility.addToQuery(this.container.getUri(), sasToken2)); try { BlobTestHelper.uploadNewBlob(sasContainer, BlobType.BLOCK_BLOB, "blockblob", 64, null); Assert.fail(); } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); } } @Test @Category(SlowTests.class) public void testContainerSASCombinations() throws StorageException, URISyntaxException, IOException, InvalidKeyException, InterruptedException { EnumSet<SharedAccessBlobPermissions> permissions; Map<Integer, CloudBlobContainer> containers = new HashMap<Integer, CloudBlobContainer>(); try{ for (int bits = 0x1; bits < 0x40; bits++) { containers.put(bits, BlobTestHelper.getRandomContainerReference()); containers.get(bits).createIfNotExists(); permissions = EnumSet.noneOf(SharedAccessBlobPermissions.class); addPermissions(permissions, bits); BlobContainerPermissions perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("readwrite" + bits, createSharedAccessPolicy(permissions, 3600)); containers.get(bits).uploadPermissions(perms); } Thread.sleep(30000); for (int bits = 0x1; bits < 0x40; bits++) { String sasToken = containers.get(bits).generateSharedAccessSignature(null, "readwrite" + bits); permissions = EnumSet.noneOf(SharedAccessBlobPermissions.class); addPermissions(permissions, bits); CloudAppendBlob testAppendBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob( containers.get(bits), BlobType.APPEND_BLOB, "appendblob", 64, null); testAccess(sasToken, permissions, null, containers.get(bits), testAppendBlob); CloudBlockBlob testBlockBlob = (CloudBlockBlob) BlobTestHelper.uploadNewBlob( containers.get(bits), BlobType.BLOCK_BLOB, "blockblob", 64, null); testAccess(sasToken, permissions, null, containers.get(bits), testBlockBlob); CloudPageBlob testPageBlob = (CloudPageBlob) BlobTestHelper.uploadNewBlob( containers.get(bits), BlobType.PAGE_BLOB, "pageblob", 512, null); testAccess(sasToken, permissions, null, containers.get(bits), testPageBlob); } } finally { for (int bits = 0x1; bits < containers.size(); bits++) { containers.get(bits).deleteIfExists(); } } } @Test @Category(SlowTests.class) public void testContainerPublicAccess() throws StorageException, IOException, URISyntaxException, InterruptedException { CloudBlockBlob testBlockBlob = (CloudBlockBlob) BlobTestHelper.uploadNewBlob( this.container, BlobType.BLOCK_BLOB, "blockblob", 64, null); CloudPageBlob testPageBlob = (CloudPageBlob) BlobTestHelper.uploadNewBlob( this.container, BlobType.PAGE_BLOB, "pageblob", 512, null); BlobContainerPermissions permissions = new BlobContainerPermissions(); permissions.setPublicAccess(BlobContainerPublicAccessType.CONTAINER); this.container.uploadPermissions(permissions); Thread.sleep(35000); testAccess(null, EnumSet.of(SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.READ), null, this.container, testBlockBlob); testAccess(null, EnumSet.of(SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.READ), null, this.container, testPageBlob); permissions.setPublicAccess(BlobContainerPublicAccessType.BLOB); this.container.uploadPermissions(permissions); Thread.sleep(30000); testAccess(null, EnumSet.of(SharedAccessBlobPermissions.READ), null, this.container, testBlockBlob); testAccess(null, EnumSet.of(SharedAccessBlobPermissions.READ), null, this.container, testPageBlob); } @Test public void testAppendBlobSASCombinations() throws URISyntaxException, StorageException, InvalidKeyException, IOException { for (int bits = 0x1; bits < 0x20; bits++) { final EnumSet<SharedAccessBlobPermissions> permissions = EnumSet.noneOf(SharedAccessBlobPermissions.class); addPermissions(permissions, bits); testBlobAccess(this.container, BlobType.APPEND_BLOB, permissions, null); } } @Test public void testBlockBlobSASCombinations() throws URISyntaxException, StorageException, InvalidKeyException, IOException { for (int bits = 0x1; bits < 0x20; bits++) { final EnumSet<SharedAccessBlobPermissions> permissions = EnumSet.noneOf(SharedAccessBlobPermissions.class); addPermissions(permissions, bits); testBlobAccess(this.container, BlobType.BLOCK_BLOB, permissions, null); } } @Test public void testPageBlobSASCombinations() throws InvalidKeyException, StorageException, IOException, URISyntaxException { for (int bits = 0x1; bits < 0x20; bits++) { final EnumSet<SharedAccessBlobPermissions> permissions = EnumSet.noneOf(SharedAccessBlobPermissions.class); addPermissions(permissions, bits); testBlobAccess(this.container, BlobType.PAGE_BLOB, permissions, null); } } @Test @Category(SlowTests.class) public void testBlobSaS() throws InvalidKeyException, IllegalArgumentException, StorageException, URISyntaxException, InterruptedException { SharedAccessBlobPolicy sp = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.LIST), 3600); BlobContainerPermissions perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("readperm", sp); this.container.uploadPermissions(perms); Thread.sleep(30000); CloudBlockBlob sasBlob = new CloudBlockBlob(new URI(this.blob.getUri().toString() + "?" + this.blob.generateSharedAccessSignature(null, "readperm"))); sasBlob.download(new ByteArrayOutputStream()); // do not give the client and check that the new blob's client has the correct perms CloudBlob blobFromUri = new CloudBlockBlob(PathUtility.addToQuery(this.blob.getStorageUri(), this.blob.generateSharedAccessSignature(null, "readperm"))); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), blobFromUri.getServiceClient() .getCredentials().getClass().toString()); // create credentials from sas StorageCredentials creds = new StorageCredentialsSharedAccessSignature( this.blob.generateSharedAccessSignature(null, "readperm")); CloudBlobClient bClient = new CloudBlobClient(sasBlob.getServiceClient().getStorageUri(), creds); CloudBlockBlob blobFromClient = bClient.getContainerReference(this.blob.getContainer().getName()) .getBlockBlobReference(this.blob.getName()); assertEquals(StorageCredentialsSharedAccessSignature.class.toString(), blobFromClient.getServiceClient() .getCredentials().getClass().toString()); assertEquals(bClient, blobFromClient.getServiceClient()); } @Test @Category(SlowTests.class) public void testBlobSaSWithSharedAccessBlobHeaders() throws InvalidKeyException, IllegalArgumentException, StorageException, URISyntaxException, InterruptedException { SharedAccessBlobPolicy sp = createSharedAccessPolicy(EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST), 3600); BlobContainerPermissions perms = new BlobContainerPermissions(); perms.getSharedAccessPolicies().put("readperm", sp); this.container.uploadPermissions(perms); Thread.sleep(30000); SharedAccessBlobHeaders headers = new SharedAccessBlobHeaders(); headers.setCacheControl("no-cache"); headers.setContentDisposition("attachment; filename=\"fname.ext\""); headers.setContentEncoding("gzip"); headers.setContentLanguage("da"); headers.setContentType("text/html; charset=utf-8"); CloudBlockBlob sasBlob = new CloudBlockBlob(new URI(this.blob.getUri().toString() + "?" + this.blob.generateSharedAccessSignature(null, headers, "readperm"))); OperationContext context = new OperationContext(); context.getSendingRequestEventHandler().addListener(new StorageEvent<SendingRequestEvent>() { @Override public void eventOccurred(SendingRequestEvent eventArg) { HttpURLConnection connection = (HttpURLConnection) eventArg.getConnectionObject(); assertEquals("no-cache", connection.getHeaderField(Constants.HeaderConstants.CACHE_CONTROL)); assertEquals("attachment; filename=\"fname.ext\"", connection.getHeaderField(Constants.HeaderConstants.CONTENT_DISPOSITION)); assertEquals("gzip", connection.getHeaderField(Constants.HeaderConstants.CONTENT_ENCODING)); assertEquals("da", connection.getHeaderField(Constants.HeaderConstants.CONTENT_LANGUAGE)); assertEquals("text/html; charset=utf-8", connection.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE)); } }); sasBlob.download(new ByteArrayOutputStream(), null, null, context); } @Test public void testAppendBlobCopyWithSasAndSnapshot() throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); CloudAppendBlob source = this.container.getAppendBlobReference(blobName); source.createOrReplace(); byte[] buffer = BlobTestHelper.getRandomBuffer(512); ByteArrayInputStream stream = new ByteArrayInputStream(buffer); source.upload(stream, buffer.length); source.getMetadata().put("Test", "value"); source.uploadMetadata(); SharedAccessBlobPolicy policy = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); CloudAppendBlob copy = this.container.getAppendBlobReference("copy"); String sasToken = copy.generateSharedAccessSignature(policy, null); CloudAppendBlob copySas = new CloudAppendBlob(new URI(copy.getUri().toString() + "?" + sasToken)); // Generate account SAS for the source // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); CloudAppendBlob snapshot = (CloudAppendBlob) source.createSnapshot(); CloudAppendBlob sasBlob = (CloudAppendBlob) sasClient.getContainerReference(container.getName()) .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); sasBlob.exists(); String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); BlobTestHelper.waitForCopy(copySas); copySas.downloadAttributes(); BlobProperties prop1 = copySas.getProperties(); BlobProperties prop2 = sasBlob.getProperties(); assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition()); assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); assertEquals(prop1.getContentType(), prop2.getContentType()); assertEquals("value", copySas.getMetadata().get("Test")); assertEquals(copyId, copySas.getCopyState().getCopyId()); snapshot.delete(); source.delete(); copySas.delete(); } @Test public void testBlockBlobCopyWithSasAndSnapshot() throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); CloudBlockBlob source = this.container.getBlockBlobReference(blobName); String data = "String data"; source.uploadText(data, Constants.UTF8_CHARSET, null, null, null); byte[] buffer = BlobTestHelper.getRandomBuffer(512); ByteArrayInputStream stream = new ByteArrayInputStream(buffer); source.upload(stream, buffer.length); source.getMetadata().put("Test", "value"); source.uploadMetadata(); SharedAccessBlobPolicy policy = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); CloudBlockBlob copy = this.container.getBlockBlobReference("copy"); String sasToken = copy.generateSharedAccessSignature(policy, null); CloudBlockBlob copySas = new CloudBlockBlob(new URI(copy.getUri().toString() + "?" + sasToken)); // Generate account SAS for the source // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); CloudBlockBlob snapshot = (CloudBlockBlob) source.createSnapshot(); CloudBlockBlob sasBlob = (CloudBlockBlob) sasClient.getContainerReference(container.getName()) .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); sasBlob.exists(); String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); BlobTestHelper.waitForCopy(copySas); copySas.downloadAttributes(); BlobProperties prop1 = copySas.getProperties(); BlobProperties prop2 = sasBlob.getProperties(); assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition()); assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); assertEquals(prop1.getContentType(), prop2.getContentType()); assertEquals("value", copySas.getMetadata().get("Test")); assertEquals(copyId, copySas.getCopyState().getCopyId()); snapshot.delete(); source.delete(); copySas.delete(); } @Test public void testPageBlobCopyWithSasAndSnapshot() throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); CloudPageBlob source = this.container.getPageBlobReference(blobName); source.create(1024); byte[] buffer = BlobTestHelper.getRandomBuffer(512); ByteArrayInputStream stream = new ByteArrayInputStream(buffer); source.upload(stream, buffer.length); source.getMetadata().put("Test", "value"); source.uploadMetadata(); SharedAccessBlobPolicy policy = createSharedAccessPolicy( EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST, SharedAccessBlobPermissions.DELETE), 5000); CloudPageBlob copy = this.container.getPageBlobReference("copy"); String sasToken = copy.generateSharedAccessSignature(policy, null); CloudPageBlob copySas = new CloudPageBlob(new URI(copy.getUri().toString() + "?" + sasToken)); // Generate account SAS for the source // Cannot generate a SAS directly on a snapshot and the SAS for the destination is only for the destination SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy(); accountPolicy.setPermissions(EnumSet.of(SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.WRITE)); accountPolicy.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); accountPolicy.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.OBJECT, SharedAccessAccountResourceType.CONTAINER)); accountPolicy.setSharedAccessExpiryTime(policy.getSharedAccessExpiryTime()); final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(accountPolicy, false); CloudPageBlob snapshot = (CloudPageBlob) source.createSnapshot(); CloudPageBlob sasBlob = (CloudPageBlob) sasClient.getContainerReference(container.getName()) .getBlobReferenceFromServer(snapshot.getName(), snapshot.snapshotID, null, null, null); sasBlob.exists(); String copyId = copySas.startCopy(BlobTestHelper.defiddler(sasBlob)); BlobTestHelper.waitForCopy(copySas); copySas.downloadAttributes(); BlobProperties prop1 = copySas.getProperties(); BlobProperties prop2 = sasBlob.getProperties(); assertEquals(prop1.getCacheControl(), prop2.getCacheControl()); assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding()); assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition()); assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage()); assertEquals(prop1.getContentMD5(), prop2.getContentMD5()); assertEquals(prop1.getContentType(), prop2.getContentType()); assertEquals("value", copySas.getMetadata().get("Test")); assertEquals(copyId, copySas.getCopyState().getCopyId()); snapshot.delete(); source.delete(); copySas.delete(); } private final static SharedAccessBlobPolicy createSharedAccessPolicy(EnumSet<SharedAccessBlobPermissions> sap, int expireTimeInSeconds) { Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.setTime(new Date()); cal.add(Calendar.SECOND, expireTimeInSeconds); SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy(); policy.setPermissions(sap); policy.setSharedAccessExpiryTime(cal.getTime()); return policy; } @SuppressWarnings("unused") private static void testAccess(String sasToken, EnumSet<SharedAccessBlobPermissions> permissions, SharedAccessBlobHeaders headers, CloudBlobContainer container, CloudBlob blob) throws StorageException, URISyntaxException, IOException { final StorageCredentials credentials; final int permissionsErrorCode; if (sasToken == null) { credentials = StorageCredentialsAnonymous.ANONYMOUS; permissionsErrorCode = HttpURLConnection.HTTP_NOT_FOUND; } else { credentials = new StorageCredentialsSharedAccessSignature(sasToken); permissionsErrorCode = HttpURLConnection.HTTP_FORBIDDEN; } if (container != null) { container = new CloudBlobContainer(credentials.transformUri(container.getUri())); blob = BlobTestHelper.getBlobReference(blob.getProperties().getBlobType(), container, blob.getName()); } else { blob = BlobTestHelper.getBlobReference(blob.getProperties().getBlobType(), credentials, blob.getUri()); } if (container != null) { if (permissions.contains(SharedAccessBlobPermissions.LIST)) { for (ListBlobItem listedBlob : container.listBlobs()); } else { try { for (ListBlobItem listedBlob : container.listBlobs()); Assert.fail(); } catch (NoSuchElementException ex) { assertEquals(permissionsErrorCode, ((StorageException) ex.getCause()).getHttpStatusCode()); } } } if (container != null) { int uploadSize = (blob.getProperties().getBlobType() == BlobType.BLOCK_BLOB) ? 512 : 0; if (permissions.contains(SharedAccessBlobPermissions.CREATE) || permissions.contains(SharedAccessBlobPermissions.WRITE)) { BlobTestHelper.uploadNewBlob(container, blob.getProperties().getBlobType(), "", uploadSize, null); } else { try { BlobTestHelper.uploadNewBlob(container, blob.getProperties().getBlobType(), "", uploadSize, null); fail(); } catch (StorageException ex) { assertEquals(permissionsErrorCode, ex.getHttpStatusCode()); } } } if (container != null && blob instanceof CloudAppendBlob) { if (permissions.contains(SharedAccessBlobPermissions.ADD) || permissions.contains(SharedAccessBlobPermissions.WRITE)) { final CloudAppendBlob appBlob = (CloudAppendBlob) blob; appBlob.appendBlock(BlobTestHelper.getRandomDataStream(512), 512); } else { try { final CloudAppendBlob appBlob = (CloudAppendBlob) blob; appBlob.appendBlock(BlobTestHelper.getRandomDataStream(512), 512); fail(); } catch (StorageException ex) { assertEquals(permissionsErrorCode, ex.getHttpStatusCode()); } } } if (permissions.contains(SharedAccessBlobPermissions.READ)) { blob.downloadAttributes(); // Test headers if (headers != null) { if (headers.getCacheControl() != null) { Assert.assertEquals(headers.getCacheControl(), blob.getProperties().getCacheControl()); } if (headers.getContentDisposition() != null) { Assert.assertEquals(headers.getContentDisposition(), blob.getProperties().getContentDisposition()); } if (headers.getContentEncoding() != null) { Assert.assertEquals(headers.getContentEncoding(), blob.getProperties().getContentEncoding()); } if (headers.getContentLanguage() != null) { Assert.assertEquals(headers.getContentLanguage(), blob.getProperties().getContentLanguage()); } if (headers.getContentType() != null) { Assert.assertEquals(headers.getContentType(), blob.getProperties().getContentType()); } } } else { try { blob.downloadAttributes(); Assert.fail(); } catch (StorageException ex) { assertEquals(permissionsErrorCode, ex.getHttpStatusCode()); } } if (permissions.contains(SharedAccessBlobPermissions.WRITE)) { blob.uploadMetadata(); } else { try { blob.uploadMetadata(); Assert.fail(); } catch (StorageException ex) { assertEquals(permissionsErrorCode, ex.getHttpStatusCode()); } } if (permissions.contains(SharedAccessBlobPermissions.DELETE)) { blob.delete(); } else { try { blob.delete(); Assert.fail(); } catch (StorageException ex) { assertEquals(permissionsErrorCode, ex.getHttpStatusCode()); } } } private static void testBlobAccess(CloudBlobContainer container, BlobType type, EnumSet<SharedAccessBlobPermissions> permissions, SharedAccessBlobHeaders headers) throws StorageException, IOException, URISyntaxException, InvalidKeyException { CloudBlob blob = BlobTestHelper.uploadNewBlob(container, type, SR.BLOB, 512, null); SharedAccessBlobPolicy policy = createSharedAccessPolicy(permissions, 3600); String sasToken = blob.generateSharedAccessSignature(policy, headers, null); testAccess(sasToken, permissions, headers, null, blob); } private static void addPermissions(EnumSet<SharedAccessBlobPermissions> permissions, int i) { if ((i & 0x1) == 0x1) { permissions.add(SharedAccessBlobPermissions.READ); } if ((i & 0x2) == 0x2) { permissions.add(SharedAccessBlobPermissions.ADD); } if ((i & 0x4) == 0x4) { permissions.add(SharedAccessBlobPermissions.CREATE); } if ((i & 0x8) == 0x8) { permissions.add(SharedAccessBlobPermissions.WRITE); } if ((i & 0x10) == 0x10) { permissions.add(SharedAccessBlobPermissions.DELETE); } if ((i & 0x20) == 0x20) { permissions.add(SharedAccessBlobPermissions.LIST); } } }