/**
* 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;
import com.microsoft.azure.storage.blob.BlobTestHelper;
import com.microsoft.azure.storage.blob.BlobType;
import com.microsoft.azure.storage.blob.CloudAppendBlob;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.file.CloudFile;
import com.microsoft.azure.storage.file.CloudFileClient;
import com.microsoft.azure.storage.file.CloudFileShare;
import com.microsoft.azure.storage.file.FileTestHelper;
import com.microsoft.azure.storage.queue.CloudQueue;
import com.microsoft.azure.storage.queue.CloudQueueClient;
import com.microsoft.azure.storage.queue.CloudQueueMessage;
import com.microsoft.azure.storage.queue.MessageUpdateFields;
import com.microsoft.azure.storage.queue.QueueTestHelper;
import com.microsoft.azure.storage.table.CloudTable;
import com.microsoft.azure.storage.table.CloudTableClient;
import com.microsoft.azure.storage.table.DynamicTableEntity;
import com.microsoft.azure.storage.table.EntityProperty;
import com.microsoft.azure.storage.table.TableOperation;
import com.microsoft.azure.storage.table.TableTestHelper;
import com.microsoft.azure.storage.TestRunners.CloudTests;
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
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.NoSuchElementException;
import java.util.TimeZone;
import static org.junit.Assert.*;
@Category({ TestRunners.DevFabricTests.class, TestRunners.DevStoreTests.class, TestRunners.CloudTests.class })
public class AccountSasTests {
private static final String DOES_NOT_EXIST_ERROR_MESSAGE = "The specified resource does not exist.";
private static final String ENUMERATION_ERROR_MESSAGE =
"An error occurred while enumerating the result, check the original exception for details.";
private static final String INVALID_PERMISSION_MESSAGE =
"This request is not authorized to perform this operation using this permission.";
private static final String INVALID_RESOURCE_TYPE_MESSAGE =
"This request is not authorized to perform this operation using this resource type.";
private static final String INVALID_SERVICE_MESSAGE =
"This request is not authorized to perform this operation using this service.";
private static final String QUERY_PARAM_MISSING_MESSAGE =
"Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.";
private static final int ADD_CODE = 0x1;
private static final int CREATE_CODE = 0x2;
private static final int DELETE_CODE = 0x4;
private static final int LIST_CODE = 0x8;
private static final int PROCESS_CODE = 0x10;
private static final int READ_CODE = 0x20;
private static final int UPDATE_CODE = 0x40;
private static final int WRITE_CODE = 0x80;
private static final int OBJECT_CODE = 0x100;
private static final int CONTAINER_CODE = 0x200;
private static final int SERVICE_CODE = 0x400;
// 0x7ff
private static final int FULL_PERMS_CODE =
ADD_CODE | CREATE_CODE | DELETE_CODE | LIST_CODE | PROCESS_CODE | READ_CODE |
UPDATE_CODE | WRITE_CODE | OBJECT_CODE | CONTAINER_CODE | SERVICE_CODE;
private static final int EMPTY_PERMS_CODE = 0x0;
private CloudBlobClient blobClient;
private CloudBlobContainer blobContainer;
private CloudFileClient fileClient;
private CloudFileShare fileShare;
private CloudQueueClient queueClient;
private CloudQueue queueQueue;
private CloudTableClient tableClient;
private CloudTable tableTable;
@Before
public void accountSasTestMethodSetup() throws URISyntaxException, StorageException, IOException {
this.blobClient = TestHelper.createCloudBlobClient();
this.blobContainer = BlobTestHelper.getRandomContainerReference();
this.fileClient = TestHelper.createCloudFileClient();
this.fileShare = FileTestHelper.getRandomShareReference();
this.queueClient = TestHelper.createCloudQueueClient();
this.queueQueue = QueueTestHelper.getRandomQueueReference();
this.tableClient = TestHelper.createCloudTableClient();
this.tableTable = TableTestHelper.getRandomTableReference();
}
@After
public void accountSasTestMethodTearDown() throws StorageException, URISyntaxException {
this.blobContainer.deleteIfExists();
this.fileShare.deleteIfExists();
this.queueQueue.deleteIfExists();
this.tableTable.deleteIfExists();
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testInvalidIP() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Arbitrary non-IP string
String ip = "not an IP";
try {
new IPRange(ip);
fail("Invalid IP address should throw");
}
catch (IllegalArgumentException ex) {
assertEquals(UnknownHostException.class, ex.getCause().getClass());
assertEquals(String.format(SR.INVALID_IP_ADDRESS, ip), ex.getMessage());
}
// IPv6 Address
ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
try {
new IPRange(ip);
fail("Invalid IP address should throw");
}
catch (IllegalArgumentException ex) {
assertEquals(ClassCastException.class, ex.getCause().getClass());
assertEquals(String.format(SR.INVALID_IP_ADDRESS, ip), ex.getMessage());
}
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testBlobServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// A file policy should not work on blobs or containers
try {
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A queue policy should not work on blobs or containers
try {
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A table policy should not work on blobs or containers
try {
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testBlobIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255");
IPRange noneIP = new IPRange("0.0.0.0");
// Ensure access attempt from invalid IP fails
IPRange sourceIP = null;
try {
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, noneIP, null));
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);
}
finally {
this.blobContainer.deleteIfExists();
}
// Ensure access attempt from the single allowed IP succeeds
this.blobContainer = BlobTestHelper.getRandomContainerReference();
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, sourceIP, null));
// Ensure access attempt from one of many valid IPs succeeds
this.blobContainer = BlobTestHelper.getRandomContainerReference();
testBlobAccountSas(this.blobContainer, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, allIP, null));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testBlobProtocolAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Ensure attempt from http fails against HTTPS_ONLY
try {
testBlobAccountSas(this.blobContainer, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_ONLY));
fail();
}
catch (IllegalArgumentException ex) {
assertEquals(SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS, ex.getMessage());
}
finally {
this.blobContainer.deleteIfExists();
}
// Ensure attempt from https succeeds against HTTPS_ONLY
this.blobContainer = BlobTestHelper.getRandomContainerReference();
testBlobAccountSas(this.blobContainer, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_ONLY));
// Ensure attempts from both https and http succeed against HTTPS_HTTP
this.blobContainer = BlobTestHelper.getRandomContainerReference();
testBlobAccountSas(this.blobContainer, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_HTTP));
this.blobContainer = BlobTestHelper.getRandomContainerReference();
testBlobAccountSas(this.blobContainer, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, SharedAccessProtocols.HTTPS_HTTP));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testBlobAccountSasCombinations()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Test full and empty permissions
testBlobAccountSas(false, AccountSasTests.FULL_PERMS_CODE);
testBlobAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE);
// Test each individual permission
testBlobAccountSas(false, AccountSasTests.ADD_CODE);
testBlobAccountSas(false, AccountSasTests.CREATE_CODE);
testBlobAccountSas(false, AccountSasTests.DELETE_CODE);
testBlobAccountSas(false, AccountSasTests.LIST_CODE);
testBlobAccountSas(false, AccountSasTests.READ_CODE);
testBlobAccountSas(false, AccountSasTests.WRITE_CODE);
testBlobAccountSas(false, AccountSasTests.OBJECT_CODE);
testBlobAccountSas(false, AccountSasTests.CONTAINER_CODE);
testBlobAccountSas(false, AccountSasTests.SERVICE_CODE);
// Test an arbitrary combination of permissions.
final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE |
AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE;
testBlobAccountSas(false, bits);
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testFileServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// A blob policy should not work on files or shares
try {
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A queue policy should not work on files or shares
try {
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A table policy should not work on files or shares
try {
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testFileIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255");
IPRange noneIP = new IPRange("0.0.0.0");
// Ensure access attempt from invalid IP fails
IPRange sourceIP = null;
try {
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, noneIP, null));
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);
}
finally {
this.fileShare.deleteIfExists();
}
// Ensure access attempt from the single allowed IP succeeds
this.fileShare = FileTestHelper.getRandomShareReference();
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, sourceIP, null));
// Ensure access attempt from one of many valid IPs succeeds
this.fileShare = FileTestHelper.getRandomShareReference();
testFileAccountSas(this.fileShare, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, allIP, null));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testFileProtocolAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Ensure attempt from http fails against HTTPS_ONLY
try {
testFileAccountSas(this.fileShare, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_ONLY));
fail();
}
catch (IllegalArgumentException ex) {
assertEquals(SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS, ex.getMessage());
}
finally {
this.fileShare.deleteIfExists();
}
// Ensure attempt from https succeeds against HTTPS_ONLY
this.fileShare = FileTestHelper.getRandomShareReference();
testFileAccountSas(this.fileShare, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_ONLY));
// Ensure attempts from both https and http succeed against HTTPS_HTTP
this.fileShare = FileTestHelper.getRandomShareReference();
testFileAccountSas(this.fileShare, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_HTTP));
this.fileShare = FileTestHelper.getRandomShareReference();
testFileAccountSas(this.fileShare, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, SharedAccessProtocols.HTTPS_HTTP));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testFileAccountSasCombinations()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Test full and empty permissions
testFileAccountSas(false, AccountSasTests.FULL_PERMS_CODE);
testFileAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE);
// Test each individual permission
testFileAccountSas(false, AccountSasTests.CREATE_CODE);
testFileAccountSas(false, AccountSasTests.DELETE_CODE);
testFileAccountSas(false, AccountSasTests.LIST_CODE);
testFileAccountSas(false, AccountSasTests.READ_CODE);
testFileAccountSas(false, AccountSasTests.WRITE_CODE);
testFileAccountSas(false, AccountSasTests.OBJECT_CODE);
testFileAccountSas(false, AccountSasTests.CONTAINER_CODE);
testFileAccountSas(false, AccountSasTests.SERVICE_CODE);
// Test an arbitrary combination of permissions.
final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE |
AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE;
testFileAccountSas(false, bits);
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testQueueServiceAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
// A blob policy should not work on queues
try {
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A file policy should not work on queues
try {
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A table policy should not work on queues
try {
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testQueueIPAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255");
IPRange noneIP = new IPRange("0.0.0.0");
// Ensure access attempt from invalid IP fails
IPRange sourceIP = null;
try {
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, noneIP, null));
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);
}
finally {
this.queueQueue.deleteIfExists();
}
// Ensure access attempt from the single allowed IP succeeds
this.queueQueue = QueueTestHelper.getRandomQueueReference();
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, sourceIP, null));
// Ensure access attempt from one of many valid IPs succeeds
this.queueQueue = QueueTestHelper.getRandomQueueReference();
testQueueAccountSas(this.queueQueue, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, allIP, null));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testQueueProtocolAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
// Ensure attempt from http fails against HTTPS_ONLY
try {
testQueueAccountSas(this.queueQueue, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_ONLY));
fail();
}
catch (IllegalArgumentException ex) {
assertEquals(SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS, ex.getMessage());
}
finally {
this.queueQueue.deleteIfExists();
}
// Ensure attempt from https succeeds against HTTPS_ONLY
this.queueQueue = QueueTestHelper.getRandomQueueReference();
testQueueAccountSas(this.queueQueue, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_ONLY));
// Ensure attempts from both https and http succeed against HTTPS_HTTP
this.queueQueue = QueueTestHelper.getRandomQueueReference();
testQueueAccountSas(this.queueQueue, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_HTTP));
this.queueQueue = QueueTestHelper.getRandomQueueReference();
testQueueAccountSas(this.queueQueue, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, SharedAccessProtocols.HTTPS_HTTP));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testQueueAccountSasCombinations()
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
// Test full and empty permissions
testQueueAccountSas(false, AccountSasTests.FULL_PERMS_CODE);
testQueueAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE);
// Test each individual permission
testQueueAccountSas(false, AccountSasTests.ADD_CODE);
testQueueAccountSas(false, AccountSasTests.CREATE_CODE);
testQueueAccountSas(false, AccountSasTests.DELETE_CODE);
testQueueAccountSas(false, AccountSasTests.LIST_CODE);
testQueueAccountSas(false, AccountSasTests.PROCESS_CODE);
testQueueAccountSas(false, AccountSasTests.READ_CODE);
testQueueAccountSas(false, AccountSasTests.UPDATE_CODE);
testQueueAccountSas(false, AccountSasTests.WRITE_CODE);
testQueueAccountSas(false, AccountSasTests.OBJECT_CODE);
testQueueAccountSas(false, AccountSasTests.CONTAINER_CODE);
testQueueAccountSas(false, AccountSasTests.SERVICE_CODE);
// Test an arbitrary combination of permissions.
final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE |
AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE;
testQueueAccountSas(false, bits);
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testTableServiceAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// A blob policy should not work on tables
try {
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.BLOB, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A file policy should not work on tables
try {
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.FILE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
// A queue policy should not work on tables
try {
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.QUEUE, null, null));
fail();
}
catch (StorageException ex) {
assertEquals(AccountSasTests.INVALID_SERVICE_MESSAGE, ex.getMessage());
}
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testTableIPAccountSas() throws InvalidKeyException, StorageException, URISyntaxException, IOException {
IPRange allIP = new IPRange("0.0.0.0", "255.255.255.255");
IPRange noneIP = new IPRange("0.0.0.0");
// Ensure access attempt from invalid IP fails
IPRange sourceIP = null;
try {
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, noneIP, null));
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);
}
finally {
this.tableTable.deleteIfExists();
}
// Ensure access attempt from the single allowed IP succeeds
this.tableTable = TableTestHelper.getRandomTableReference();
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, sourceIP, null));
// Ensure access attempt from one of many valid IPs succeeds
this.tableTable = TableTestHelper.getRandomTableReference();
testTableAccountSas(this.tableTable, false,
generatePolicy(AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, allIP, null));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testTableProtocolAccountSas()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Ensure attempt from http fails against HTTPS_ONLY
try {
testTableAccountSas(this.tableTable, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_ONLY));
fail();
}
catch (IllegalArgumentException ex) {
assertEquals(SR.CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS, ex.getMessage());
}
finally {
this.tableTable.deleteIfExists();
}
// Ensure attempt from https succeeds against HTTPS_ONLY
this.tableTable = TableTestHelper.getRandomTableReference();
testTableAccountSas(this.tableTable, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_ONLY));
// Ensure attempts from both https and http succeed against HTTPS_HTTP
this.tableTable = TableTestHelper.getRandomTableReference();
testTableAccountSas(this.tableTable, true, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_HTTP));
this.tableTable = TableTestHelper.getRandomTableReference();
testTableAccountSas(this.tableTable, false, generatePolicy(
AccountSasTests.FULL_PERMS_CODE, SharedAccessAccountService.TABLE, null, SharedAccessProtocols.HTTPS_HTTP));
}
@Test
@Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public void testTableAccountSasCombinations()
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
// Test full and empty permissions
testTableAccountSas(false, AccountSasTests.FULL_PERMS_CODE);
testTableAccountSas(false, AccountSasTests.EMPTY_PERMS_CODE);
// Test each individual permission
testTableAccountSas(false, AccountSasTests.ADD_CODE);
testTableAccountSas(false, AccountSasTests.CREATE_CODE);
testTableAccountSas(false, AccountSasTests.DELETE_CODE);
testTableAccountSas(false, AccountSasTests.LIST_CODE);
testTableAccountSas(false, AccountSasTests.READ_CODE);
testTableAccountSas(false, AccountSasTests.UPDATE_CODE);
testTableAccountSas(false, AccountSasTests.WRITE_CODE);
testTableAccountSas(false, AccountSasTests.OBJECT_CODE);
testTableAccountSas(false, AccountSasTests.CONTAINER_CODE);
testTableAccountSas(false, AccountSasTests.SERVICE_CODE);
// Test an arbitrary combination of permissions.
final int bits = AccountSasTests.OBJECT_CODE | AccountSasTests.SERVICE_CODE | AccountSasTests.READ_CODE |
AccountSasTests.CREATE_CODE | AccountSasTests.DELETE_CODE;
testTableAccountSas(false, bits);
}
private void testBlobAccountSas(final boolean useHttps, final int bits)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.BLOB, null, null);
this.blobContainer = this.blobClient.getContainerReference("blobtest" + bits);
try {
testBlobAccountSas(this.blobContainer, useHttps, policy);
}
catch (StorageException ex) {
if (bits < AccountSasTests.OBJECT_CODE ||
bits % AccountSasTests.OBJECT_CODE == AccountSasTests.EMPTY_PERMS_CODE) {
// Expected failure if permissions or resource type is empty.
assertEquals(AccountSasTests.QUERY_PARAM_MISSING_MESSAGE, ex.getMessage());
}
else {
throw ex;
}
}
finally {
this.blobContainer.deleteIfExists();
}
}
private void testBlobAccountSas(CloudBlobContainer container, boolean useHttps, SharedAccessAccountPolicy policy)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
assertNotNull(container);
assertNotNull(policy);
assertFalse(container.exists());
final CloudBlobClient sasClient = TestHelper.createCloudBlobClient(policy, useHttps);
URI sasUri = sasClient.getContainerReference(container.getName()).getUri();
sasUri = sasClient.getCredentials().transformUri(sasUri);
final CloudBlobContainer sasContainer = new CloudBlobContainer(sasUri);
// Test creating the container
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) {
sasContainer.create();
}
else {
try {
sasContainer.create();
fail();
}
catch (StorageException ex) {
if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) {
throw ex;
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
container.create();
}
}
assertTrue(container.exists());
// Test listing the containers on the client
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) {
assertEquals(sasContainer.getName(),
sasClient.listContainers(sasContainer.getName()).iterator().next().getName());
}
else {
try {
sasClient.listContainers(sasContainer.getName()).iterator().next();
fail();
}
catch (NoSuchElementException ex) {
assertEquals(AccountSasTests.ENUMERATION_ERROR_MESSAGE, ex.getMessage());
assertEquals(sasContainer.getName(),
this.blobClient.listContainers(sasContainer.getName()).iterator().next().getName());
}
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) {
// Test creating a new blob
CloudAppendBlob blob = null;
CloudAppendBlob sasBlob = null;
if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob(
sasContainer, BlobType.APPEND_BLOB, null, 0, null);
blob = container.getAppendBlobReference(sasBlob.getName());
}
else {
try {
sasBlob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob(
sasContainer, BlobType.APPEND_BLOB, null, 0, null);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
blob = (CloudAppendBlob) BlobTestHelper.uploadNewBlob(
container, BlobType.APPEND_BLOB, null, 0, null);
sasBlob = (CloudAppendBlob) BlobTestHelper.getBlobReference(
BlobType.APPEND_BLOB, sasContainer, blob.getName());
}
}
assertTrue(blob.exists());
// Test uploading data to the blob
final int length = 512;
ByteArrayInputStream sourceStream = BlobTestHelper.getRandomDataStream(length);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasBlob.appendBlock(sourceStream, length);
}
else {
try {
sasBlob.appendBlock(sourceStream, length);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
sourceStream = BlobTestHelper.getRandomDataStream(length);
blob.appendBlock(sourceStream, length);
}
}
// Test downloading data from the blob
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
if (policy.getPermissions().contains(SharedAccessAccountPermissions.READ)) {
sasBlob.download(outStream);
}
else {
try {
sasBlob.download(outStream);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
blob.download(outStream);
}
}
TestHelper.assertStreamsAreEqual(sourceStream, new ByteArrayInputStream(outStream.toByteArray()));
if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasBlob.delete();
}
else {
try {
sasBlob.delete();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
blob.delete();
}
}
assertFalse(blob.exists());
}
else {
try {
BlobTestHelper.uploadNewBlob(sasContainer, BlobType.APPEND_BLOB, null, 0, null);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
BlobTestHelper.uploadNewBlob(container, BlobType.APPEND_BLOB, null, 0, null);
}
}
// Test deleting the container
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasContainer.delete();
}
else {
try {
sasContainer.delete();
fail();
}
catch (StorageException ex) {
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
container.delete();
}
}
}
private void testFileAccountSas(final boolean useHttps, final int bits)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.FILE, null, null);
this.fileShare = this.fileClient.getShareReference("filetest" + bits);
try {
testFileAccountSas(this.fileShare, useHttps, policy);
}
catch (StorageException ex) {
if (bits < AccountSasTests.OBJECT_CODE ||
bits % AccountSasTests.OBJECT_CODE == AccountSasTests.EMPTY_PERMS_CODE) {
// Expected failure if permissions or resource type is empty.
assertEquals(AccountSasTests.QUERY_PARAM_MISSING_MESSAGE, ex.getMessage());
}
else {
throw ex;
}
}
finally {
this.fileShare.deleteIfExists();
}
}
private void testFileAccountSas(CloudFileShare share, boolean useHttps, SharedAccessAccountPolicy policy)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
assertNotNull(share);
assertNotNull(policy);
assertFalse(share.exists());
final CloudFileClient sasClient = TestHelper.createCloudFileClient(policy, useHttps);
URI sasUri = sasClient.getShareReference(share.getName()).getUri();
sasUri = sasClient.getCredentials().transformUri(sasUri);
final CloudFileShare sasShare = new CloudFileShare(sasUri);
// Test creating the share
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) {
sasShare.create();
}
else {
try {
sasShare.create();
fail();
}
catch (StorageException ex) {
if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) {
throw ex;
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
share.create();
}
}
assertTrue(share.exists());
// Test listing the shares on the client
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) {
assertEquals(sasShare.getName(), sasClient.listShares(sasShare.getName()).iterator().next().getName());
}
else {
try {
sasClient.listShares(sasShare.getName()).iterator().next();
fail();
}
catch (NoSuchElementException ex) {
assertEquals(AccountSasTests.ENUMERATION_ERROR_MESSAGE, ex.getMessage());
assertEquals(sasShare.getName(),
this.fileClient.listShares(sasShare.getName()).iterator().next().getName());
}
}
final int length = 512;
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) {
// Test creating a new file
CloudFile file = null;
CloudFile sasFile = null;
sasFile = sasShare.getRootDirectoryReference().getFileReference(FileTestHelper.generateRandomFileName());
if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasFile.create(length);
file = share.getRootDirectoryReference().getFileReference(sasFile.getName());
}
else {
try {
sasFile.create(length);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
file = FileTestHelper.uploadNewFile(share, FileTestHelper.getRandomDataStream(0), length, null);
sasFile = sasShare.getRootDirectoryReference().getFileReference(file.getName());
}
}
assertTrue(file.exists());
//Test writing data to a file
final ByteArrayInputStream sourcestream = FileTestHelper.getRandomDataStream(length);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasFile.upload(sourcestream, length);
}
else {
try {
sasFile.upload(sourcestream, length);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
file.upload(sourcestream, length);
}
}
// Test downloading data from the file
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
if (policy.getPermissions().contains(SharedAccessAccountPermissions.READ)) {
sasFile.download(outStream);
}
else {
try {
sasFile.download(outStream);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
file.download(outStream);
}
}
TestHelper.assertStreamsAreEqual(sourcestream, new ByteArrayInputStream(outStream.toByteArray()));
if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasFile.delete();
}
else {
try {
sasFile.delete();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
file.delete();
}
}
assertFalse(file.exists());
}
else {
try {
FileTestHelper.uploadNewFile(sasShare, FileTestHelper.getRandomDataStream(0), length, null);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
FileTestHelper.uploadNewFile(share, FileTestHelper.getRandomDataStream(0), length, null);
}
}
// Test deleting the share
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasShare.delete();
}
else {
try {
sasShare.delete();
fail();
}
catch (StorageException ex) {
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
share.delete();
}
}
}
private void testQueueAccountSas(final boolean useHttps, final int bits)
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.QUEUE, null, null);
this.queueQueue = this.queueClient.getQueueReference("queuetest" + bits);
try {
testQueueAccountSas(this.queueQueue, useHttps, policy);
}
catch (StorageException ex) {
if (bits < AccountSasTests.OBJECT_CODE ||
bits % AccountSasTests.OBJECT_CODE == AccountSasTests.EMPTY_PERMS_CODE) {
// Expected failure if permissions or resource type is empty.
assertEquals(AccountSasTests.QUERY_PARAM_MISSING_MESSAGE, ex.getMessage());
}
else {
throw ex;
}
}
finally {
this.queueQueue.deleteIfExists();
}
}
private void testQueueAccountSas(CloudQueue queue, boolean useHttps, SharedAccessAccountPolicy policy)
throws InvalidKeyException, StorageException, URISyntaxException, IOException, InterruptedException {
assertNotNull(policy);
assertNotNull(queue);
assertFalse(queue.exists());
final CloudQueueClient sasClient = TestHelper.createCloudQueueClient(policy, useHttps);
URI sasUri = sasClient.getQueueReference(queue.getName()).getUri();
sasUri = sasClient.getCredentials().transformUri(sasUri);
final CloudQueue sasQueue = new CloudQueue(sasUri);
final String key = "testkey";
final String value = "testvalue";
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
// Test creating the queue
if (policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasQueue.create();
}
else {
try {
sasQueue.create();
fail();
}
catch (StorageException ex) {
if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) {
throw ex;
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
queue.create();
}
}
// Test queue metadata
queue.setMetadata(new HashMap<String, String>());
queue.getMetadata().put(key, Constants.ID);
queue.uploadMetadata();
sasQueue.setMetadata(new HashMap<String, String>());
if (policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE)) {
sasQueue.getMetadata().put(key, value);
sasQueue.uploadMetadata();
}
else {
try {
sasQueue.getMetadata().put(key, value);
sasQueue.uploadMetadata();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
queue.getMetadata().put(key, value);
queue.uploadMetadata();
}
}
queue.downloadAttributes();
assertEquals(value, queue.getMetadata().get(key));
}
else {
try {
sasQueue.create();
fail();
}
catch (StorageException ex) {
if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) {
throw ex;
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
queue.create();
}
}
assertTrue(queue.exists());
// Test listing the queues on the client
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.SERVICE) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.LIST))) {
assertEquals(sasQueue.getName(), sasClient.listQueues(sasQueue.getName()).iterator().next().getName());
}
else {
try {
sasClient.listQueues(sasQueue.getName()).iterator().next();
fail();
}
catch (NoSuchElementException ex) {
assertEquals(AccountSasTests.ENUMERATION_ERROR_MESSAGE, ex.getMessage());
assertEquals(sasQueue.getName(),
this.queueClient.listQueues(sasQueue.getName()).iterator().next().getName());
}
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) {
// Test inserting a message into a queue
if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD)) {
sasQueue.addMessage(new CloudQueueMessage(value));
}
else {
try {
sasQueue.addMessage(new CloudQueueMessage(value));
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
queue.addMessage(new CloudQueueMessage(value));
}
}
// Test peeking at a message in the queue
CloudQueueMessage message = null;
if (policy.getPermissions().contains(SharedAccessAccountPermissions.READ)) {
message = sasQueue.peekMessage();
}
else {
try {
sasQueue.peekMessage();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
message = queue.peekMessage();
}
}
assertEquals(value, message.getMessageContentAsString());
// Test getting a message from the queue
if (policy.getPermissions().contains(SharedAccessAccountPermissions.PROCESS_MESSAGES)) {
message = sasQueue.retrieveMessage();
}
else {
try {
sasQueue.retrieveMessage();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
message = queue.retrieveMessage();
}
}
// Test updating a message in the queue
message.setMessageContent(key);
OperationContext oc = new OperationContext();
if (policy.getPermissions().contains(SharedAccessAccountPermissions.UPDATE)) {
sasQueue.updateMessage(message, 1, EnumSet.of(MessageUpdateFields.CONTENT), null, oc);
}
else {
try {
sasQueue.updateMessage(message, 1, EnumSet.of(MessageUpdateFields.CONTENT), null, oc);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
queue.updateMessage(message, 1, EnumSet.of(MessageUpdateFields.CONTENT), null, oc);
}
}
assertEquals(oc.getLastResult().getStatusCode(), HttpURLConnection.HTTP_NO_CONTENT);
Thread.sleep(1000);
message = queue.peekMessage();
assertEquals(key, message.getMessageContentAsString());
// Test clearing all messages from the queue.
queue.addMessage(new CloudQueueMessage(key));
queue.addMessage(new CloudQueueMessage(value));
if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasQueue.clear();
}
else {
try {
sasQueue.clear();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
queue.clear();
}
}
assertEquals(null, queue.peekMessage());
}
else {
try {
sasQueue.peekMessage();
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
queue.peekMessage();
}
}
// Test deleting the queue
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasQueue.delete();
}
else {
try {
sasQueue.delete();
fail();
}
catch (StorageException ex) {
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
queue.delete();
}
}
}
private void testTableAccountSas(final boolean useHttps, final int bits)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
SharedAccessAccountPolicy policy = generatePolicy(bits, SharedAccessAccountService.TABLE, null, null);
this.tableTable = this.tableClient.getTableReference("tabletest" + bits);
try {
testTableAccountSas(this.tableTable, useHttps, policy);
}
catch (StorageException ex) {
if (bits < AccountSasTests.OBJECT_CODE ||
bits % AccountSasTests.OBJECT_CODE == AccountSasTests.EMPTY_PERMS_CODE) {
// Expected failure if permissions or resource type is empty.
assertEquals(AccountSasTests.QUERY_PARAM_MISSING_MESSAGE, ex.getMessage());
}
else {
throw ex;
}
}
finally {
this.fileShare.deleteIfExists();
}
}
private void testTableAccountSas(CloudTable table, boolean useHttps, SharedAccessAccountPolicy policy)
throws InvalidKeyException, StorageException, URISyntaxException, IOException {
assertNotNull(policy);
assertNotNull(table);
assertFalse(table.exists());
final CloudTableClient sasClient = TestHelper.createCloudTableClient(policy, useHttps);
URI sasUri = sasClient.getTableReference(table.getName()).getUri();
sasUri = sasClient.getCredentials().transformUri(sasUri);
final CloudTable sasTable = new CloudTable(sasUri);
final String key = "testkey";
final String value = "testvalue";
final String value2 = "testvalue2";
final String partition1 = "testpartition1";
final String partition2 = "testpartition2";
final String row1 = "testrow1";
final String row2 = "testrow2";
// Test creating the table
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
(policy.getPermissions().contains(SharedAccessAccountPermissions.CREATE) ||
policy.getPermissions().contains(SharedAccessAccountPermissions.WRITE))) {
sasTable.create();
}
else {
try {
sasTable.create();
fail();
}
catch (StorageException ex) {
if (AccountSasTests.QUERY_PARAM_MISSING_MESSAGE.equals(ex.getMessage())) {
throw ex;
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
table.create();
}
}
assertTrue(table.exists());
// Test listing the tables on the client
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.LIST)) {
assertEquals(sasTable.getName(), sasClient.listTables(sasTable.getName()).iterator().next());
}
else {
try {
sasClient.listTables(sasTable.getName()).iterator().next();
fail();
}
catch (NoSuchElementException ex) {
assertEquals(AccountSasTests.ENUMERATION_ERROR_MESSAGE, ex.getMessage());
assertEquals(sasTable.getName(),
this.tableClient.listTables(sasTable.getName()).iterator().next());
}
}
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.OBJECT)) {
// Test inserting an entity into a table
final HashMap<String, EntityProperty> columns = new HashMap<String, EntityProperty>();
columns.put(key, new EntityProperty(value));
final DynamicTableEntity entity = new DynamicTableEntity(partition1, row1, columns);
TableOperation op = TableOperation.insert(entity);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD)) {
sasTable.execute(op);
}
else {
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
table.execute(op);
}
}
op = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class);
DynamicTableEntity result = (DynamicTableEntity) table.execute(op).getResultAsType();
assertEquals(value, result.getProperties().get(key).getValueAsString());
// Test merging an entity in a table
entity.getProperties().put(key, new EntityProperty(value2));
op = TableOperation.merge(entity);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.UPDATE)) {
sasTable.execute(op);
}
else {
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
table.execute(op);
}
}
// Test retrieving an entity from a table
op = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class);
result = null;
if (policy.getPermissions().contains(SharedAccessAccountPermissions.READ)) {
result = (DynamicTableEntity) sasTable.execute(op).getResultAsType();
}
else {
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
result = (DynamicTableEntity) table.execute(op).getResultAsType();
}
}
assertEquals(value2, result.getProperties().get(key).getValueAsString());
// Test insert or merge on two entities
entity.getProperties().put(key, new EntityProperty(value));
op = TableOperation.insertOrMerge(entity);
final HashMap<String, EntityProperty> columns2 = new HashMap<String, EntityProperty>();
columns2.put(key, new EntityProperty(value2));
final DynamicTableEntity entity2 = new DynamicTableEntity(partition2, row2, columns2);
TableOperation op2 = TableOperation.insertOrMerge(entity2);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.ADD) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.UPDATE)) {
sasTable.execute(op);
sasTable.execute(op2);
}
else {
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
try {
sasTable.execute(op2);
fail();
}
catch (StorageException exeption) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, exeption);
table.execute(op);
table.execute(op2);
}
}
}
TableOperation retrieveOp = TableOperation.retrieve(partition2, row2, DynamicTableEntity.class);
result = (DynamicTableEntity) table.execute(retrieveOp).getResultAsType();
assertEquals(value2, result.getProperties().get(key).getValueAsString());
retrieveOp = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class);
result = (DynamicTableEntity) table.execute(retrieveOp).getResultAsType();
assertEquals(value, result.getProperties().get(key).getValueAsString());
// Test deleting an entity from a table.
op = TableOperation.delete(entity);
if (policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasTable.execute(op);
}
else {
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
table.execute(op);
}
}
try {
table.execute(op);
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.DOES_NOT_EXIST_ERROR_MESSAGE, ex);
}
}
else {
TableOperation op = TableOperation.retrieve(partition1, row1, DynamicTableEntity.class);
try {
sasTable.execute(op);
fail();
}
catch (StorageException ex) {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
table.execute(op);
}
}
// Test deleting the share
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER) &&
policy.getPermissions().contains(SharedAccessAccountPermissions.DELETE)) {
sasTable.delete();
}
else {
try {
sasTable.delete();
fail();
}
catch (StorageException ex) {
if (policy.getResourceTypes().contains(SharedAccessAccountResourceType.CONTAINER)) {
assertMessagesMatch(AccountSasTests.INVALID_PERMISSION_MESSAGE, ex);
}
else {
assertMessagesMatch(AccountSasTests.INVALID_RESOURCE_TYPE_MESSAGE, ex);
}
table.delete();
}
}
}
private static void assertMessagesMatch(String expectedMessage, StorageException ex) {
final String message = ex.getExtendedErrorInformation().getErrorMessage().split("\n")[0];
assertEquals(expectedMessage, message);
}
private static SharedAccessAccountPolicy generatePolicy(
final int bits, final SharedAccessAccountService service, IPRange ipRange, SharedAccessProtocols protocols) {
EnumSet<SharedAccessAccountService> services = EnumSet.noneOf(SharedAccessAccountService.class);
EnumSet<SharedAccessAccountPermissions> permissions = EnumSet.noneOf(SharedAccessAccountPermissions.class);
EnumSet<SharedAccessAccountResourceType> resourceTypes = EnumSet.noneOf(SharedAccessAccountResourceType.class);
services.add(service);
if ((bits & AccountSasTests.ADD_CODE) == AccountSasTests.ADD_CODE) {
permissions.add(SharedAccessAccountPermissions.ADD);
}
if ((bits & AccountSasTests.CREATE_CODE) == AccountSasTests.CREATE_CODE) {
permissions.add(SharedAccessAccountPermissions.CREATE);
}
if ((bits & AccountSasTests.DELETE_CODE) == AccountSasTests.DELETE_CODE) {
permissions.add(SharedAccessAccountPermissions.DELETE);
}
if ((bits & AccountSasTests.LIST_CODE) == AccountSasTests.LIST_CODE) {
permissions.add(SharedAccessAccountPermissions.LIST);
}
if ((bits & AccountSasTests.PROCESS_CODE) == AccountSasTests.PROCESS_CODE) {
permissions.add(SharedAccessAccountPermissions.PROCESS_MESSAGES);
}
if ((bits & AccountSasTests.READ_CODE) == AccountSasTests.READ_CODE) {
permissions.add(SharedAccessAccountPermissions.READ);
}
if ((bits & AccountSasTests.UPDATE_CODE) == AccountSasTests.UPDATE_CODE) {
permissions.add(SharedAccessAccountPermissions.UPDATE);
}
if ((bits & AccountSasTests.WRITE_CODE) == AccountSasTests.WRITE_CODE) {
permissions.add(SharedAccessAccountPermissions.WRITE);
}
if ((bits & AccountSasTests.OBJECT_CODE) == AccountSasTests.OBJECT_CODE) {
resourceTypes.add(SharedAccessAccountResourceType.OBJECT);
}
if ((bits & AccountSasTests.CONTAINER_CODE) == AccountSasTests.CONTAINER_CODE) {
resourceTypes.add(SharedAccessAccountResourceType.CONTAINER);
}
if ((bits & AccountSasTests.SERVICE_CODE) == AccountSasTests.SERVICE_CODE) {
resourceTypes.add(SharedAccessAccountResourceType.SERVICE);
}
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
cal.setTime(new Date());
cal.add(Calendar.SECOND, 300);
SharedAccessAccountPolicy policy = new SharedAccessAccountPolicy();
policy.setServices(services);
policy.setPermissions(permissions);
policy.setResourceTypes(resourceTypes);
policy.setRange(ipRange);
policy.setProtocols(protocols);
policy.setSharedAccessExpiryTime(cal.getTime());
return policy;
}
}