Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit 9d85d2e

Browse files
author
jofriedm-msft
authored
Merge pull request #76 from wastore/fileencryption
Encryption at REST for files
2 parents 2c63650 + ecbb2b8 commit 9d85d2e

File tree

12 files changed

+213
-13
lines changed

12 files changed

+213
-13
lines changed

ChangeLog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
2017.XX.XX Version X.X.X
22
* Added ErrorReceivingResponseEvent which fires when a network error occurs before the responseReceivedEvent fires. If the responseReceivedEvent fires sucessfully, this new event will not fire.
33
* For Premium Accounts only, added support for getting and setting the tier on a page blob. The tier can also be set when creating or copying from an existing page blob.
4+
* Added support for server side encryption for File Service.
45

56
2017.06.21 Version 5.3.1
67
* Fixed a bug in specific upload case for block blobs. This only affects uploads greater than the max put blob threshold, that have increased the streamWriteSizeInBytes beyond the 4 MB and storeBlobContentMD5 has been disabled.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* Copyright Microsoft Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package com.microsoft.azure.storage.file;
16+
17+
18+
import java.io.IOException;
19+
import java.net.URISyntaxException;
20+
21+
import com.microsoft.azure.storage.OperationContext;
22+
import com.microsoft.azure.storage.RequestCompletedEvent;
23+
import com.microsoft.azure.storage.StorageEvent;
24+
import com.microsoft.azure.storage.StorageException;
25+
import com.microsoft.azure.storage.TestRunners.CloudTests;
26+
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
27+
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
28+
29+
import org.junit.After;
30+
import org.junit.Before;
31+
import org.junit.Ignore;
32+
import org.junit.Test;
33+
import org.junit.experimental.categories.Category;
34+
35+
import static org.junit.Assert.*;
36+
37+
@Category({ CloudTests.class, DevFabricTests.class, DevStoreTests.class })
38+
//@Ignore
39+
/* These test only works on accounts with server-side encryption enabled. */
40+
public class CloudFileServerEncryptionTests {
41+
42+
private CloudFileShare share;
43+
private CloudFileDirectory dir;
44+
private CloudFile file;
45+
private boolean requestFound;
46+
47+
@Before
48+
public void fileEncryptionTestMethodSetup() throws URISyntaxException, StorageException, IOException {
49+
this.share = FileTestHelper.getRandomShareReference();
50+
this.share.create();
51+
this.dir = this.share.getRootDirectoryReference().getDirectoryReference("dir");
52+
this.dir.create();
53+
this.file = this.share.getRootDirectoryReference().getFileReference("file");
54+
this.file.uploadText("text");
55+
}
56+
57+
@After
58+
public void fileEncryptionTestMethodTearDown() throws StorageException {
59+
this.share.deleteIfExists();
60+
}
61+
62+
@Test
63+
public void testFileAttributesEncryption() throws URISyntaxException, StorageException, IOException {
64+
this.file.downloadAttributes();
65+
assertTrue(this.file.getProperties().isServerEncrypted());
66+
67+
CloudFile testFile = this.share.getRootDirectoryReference().getFileReference("file");
68+
testFile.downloadText();
69+
assertTrue(testFile.getProperties().isServerEncrypted());
70+
}
71+
72+
@Test
73+
public void testDirectoryAttributesEncryption() throws URISyntaxException, StorageException, IOException {
74+
assertFalse(this.dir.getProperties().isServerEncrypted());
75+
76+
CloudFileDirectory testDir = this.share.getRootDirectoryReference().getDirectoryReference("dir");
77+
testDir.downloadAttributes();
78+
assertTrue(testDir.getProperties().isServerEncrypted());
79+
}
80+
81+
@Test
82+
public void testCloudFileUploadEncryption() throws URISyntaxException, StorageException, IOException {
83+
this.requestFound = false;
84+
85+
OperationContext ctxt = new OperationContext();
86+
ctxt.getRequestCompletedEventHandler().addListener(new StorageEvent<RequestCompletedEvent>() {
87+
@Override
88+
public void eventOccurred(RequestCompletedEvent eventArg) {
89+
assertTrue(eventArg.getRequestResult().isRequestServiceEncrypted());
90+
CloudFileServerEncryptionTests.this.requestFound = true;
91+
}
92+
});
93+
94+
this.file.uploadText("test", null, null, null, ctxt);
95+
assertTrue(this.requestFound);
96+
97+
this.requestFound = false;
98+
this.file.uploadProperties(null, null, ctxt);
99+
assertTrue(this.requestFound);
100+
101+
this.requestFound = false;
102+
this.file.uploadMetadata(null, null, ctxt);
103+
assertTrue(this.requestFound);
104+
}
105+
106+
@Test
107+
public void testCloudFileDirectoryEncryption() throws URISyntaxException, StorageException, IOException {
108+
this.requestFound = false;
109+
110+
OperationContext ctxt = new OperationContext();
111+
ctxt.getRequestCompletedEventHandler().addListener(new StorageEvent<RequestCompletedEvent>() {
112+
@Override
113+
public void eventOccurred(RequestCompletedEvent eventArg) {
114+
assertTrue(eventArg.getRequestResult().isRequestServiceEncrypted());
115+
CloudFileServerEncryptionTests.this.requestFound = true;
116+
}
117+
});
118+
119+
this.dir.uploadMetadata(null, null, ctxt);
120+
assertTrue(this.requestFound);
121+
122+
this.requestFound = false;
123+
CloudFileDirectory dir2 = this.share.getRootDirectoryReference().getDirectoryReference("dir2");
124+
dir2.create(null, ctxt);
125+
assertTrue(this.requestFound);
126+
}
127+
}

microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.microsoft.azure.storage.StorageCredentials;
3535
import com.microsoft.azure.storage.StorageException;
3636
import com.microsoft.azure.storage.StorageUri;
37+
import com.microsoft.azure.storage.core.BaseResponse;
3738
import com.microsoft.azure.storage.core.ExecutionEngine;
3839
import com.microsoft.azure.storage.core.SR;
3940
import com.microsoft.azure.storage.core.StorageRequest;
@@ -309,7 +310,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
309310
}
310311

311312
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
312-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
313+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
313314
blob.getProperties().setLength(0);
314315
return null;
315316
}
@@ -460,7 +461,7 @@ public Long preProcessResponse(CloudAppendBlob blob, CloudBlobClient client, Ope
460461
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
461462
blob.updateCommittedBlockCountFromResponse(this.getConnection());
462463

463-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
464+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
464465
return appendOffset;
465466
}
466467

microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.microsoft.azure.storage.StorageException;
4545
import com.microsoft.azure.storage.StorageLocation;
4646
import com.microsoft.azure.storage.StorageUri;
47+
import com.microsoft.azure.storage.core.BaseResponse;
4748
import com.microsoft.azure.storage.core.ExecutionEngine;
4849
import com.microsoft.azure.storage.core.Logger;
4950
import com.microsoft.azure.storage.core.NetworkInputStream;
@@ -2828,7 +2829,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
28282829
}
28292830

28302831
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
2831-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
2832+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
28322833
return null;
28332834
}
28342835
};
@@ -2978,8 +2979,4 @@ protected static String getParentNameFromURI(final StorageUri resourceAddress, f
29782979

29792980
return parentName;
29802981
}
2981-
2982-
protected static boolean isServerRequestEncrypted(HttpURLConnection connection) {
2983-
return Constants.TRUE.equals(connection.getHeaderField(Constants.HeaderConstants.SERVER_REQUEST_ENCRYPTED));
2984-
}
29852982
}

microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import javax.crypto.Cipher;
2222
import javax.xml.stream.XMLStreamException;
23+
2324
import java.io.ByteArrayInputStream;
2425
import java.io.ByteArrayOutputStream;
2526
import java.io.IOException;
@@ -379,7 +380,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
379380
}
380381

381382
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
382-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
383+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
383384
return null;
384385
}
385386

@@ -920,7 +921,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
920921
}
921922

922923
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
923-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
924+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
924925
return null;
925926
}
926927

@@ -1116,7 +1117,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
11161117
return null;
11171118
}
11181119

1119-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
1120+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
11201121
return null;
11211122
}
11221123

microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.microsoft.azure.storage.StorageException;
3434
import com.microsoft.azure.storage.StorageUri;
3535
import com.microsoft.azure.storage.core.Base64;
36+
import com.microsoft.azure.storage.core.BaseResponse;
3637
import com.microsoft.azure.storage.core.ExecutionEngine;
3738
import com.microsoft.azure.storage.core.RequestLocationMode;
3839
import com.microsoft.azure.storage.core.SR;
@@ -575,7 +576,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
575576
}
576577

577578
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
578-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
579+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
579580
blob.getProperties().setLength(length);
580581
blob.getProperties().setPremiumPageBlobTier(premiumBlobTier);
581582
if (premiumBlobTier != null) {
@@ -1156,7 +1157,7 @@ public Void preProcessResponse(CloudPageBlob blob, CloudBlobClient client, Opera
11561157

11571158
blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
11581159
blob.updateSequenceNumberFromResponse(this.getConnection());
1159-
this.getResult().setRequestServiceEncrypted(CloudBlob.isServerRequestEncrypted(this.getConnection()));
1160+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
11601161
return null;
11611162
}
11621163
};

microsoft-azure-storage/src/com/microsoft/azure/storage/core/BaseResponse.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ public static String getRequestId(final HttpURLConnection request) {
8080
return request.getHeaderField(Constants.HeaderConstants.REQUEST_ID_HEADER);
8181
}
8282

83+
/**
84+
* Gets if the request was encrypted by the server.
85+
* @param request
86+
* The response from the server.
87+
* @return A boolean indicating if the request was encrypted by the server.
88+
*/
89+
public static boolean isServerRequestEncrypted(HttpURLConnection request) {
90+
return Constants.TRUE.equals(request.getHeaderField(Constants.HeaderConstants.SERVER_REQUEST_ENCRYPTED));
91+
}
92+
8393
/**
8494
* Returns all the header/value pairs with the given prefix.
8595
*

microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFile.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.microsoft.azure.storage.blob.CloudBlob;
5151
import com.microsoft.azure.storage.blob.CloudBlobClient;
5252
import com.microsoft.azure.storage.core.Base64;
53+
import com.microsoft.azure.storage.core.BaseResponse;
5354
import com.microsoft.azure.storage.core.ExecutionEngine;
5455
import com.microsoft.azure.storage.core.Logger;
5556
import com.microsoft.azure.storage.core.NetworkInputStream;
@@ -667,6 +668,7 @@ public Void preProcessResponse(CloudFile file, CloudFileClient client, Operation
667668
}
668669

669670
file.updateEtagAndLastModifiedFromResponse(this.getConnection());
671+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
670672
return null;
671673
}
672674

@@ -2284,6 +2286,7 @@ public Void preProcessResponse(CloudFile file, CloudFileClient client, Operation
22842286
}
22852287

22862288
file.updateEtagAndLastModifiedFromResponse(this.getConnection());
2289+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
22872290
return null;
22882291
}
22892292
};
@@ -2376,6 +2379,7 @@ public Void preProcessResponse(CloudFile file, CloudFileClient client, Operation
23762379
}
23772380

23782381
file.updateEtagAndLastModifiedFromResponse(this.getConnection());
2382+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
23792383
return null;
23802384
}
23812385
};
@@ -2462,6 +2466,7 @@ public Void preProcessResponse(CloudFile file, CloudFileClient client, Operation
24622466
}
24632467

24642468
file.updateEtagAndLastModifiedFromResponse(this.getConnection());
2469+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
24652470
return null;
24662471
}
24672472
};
@@ -2544,6 +2549,7 @@ public Void preProcessResponse(CloudFile file, CloudFileClient client, Operation
25442549

25452550
file.getProperties().setLength(size);
25462551
file.updateEtagAndLastModifiedFromResponse(this.getConnection());
2552+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
25472553
return null;
25482554
}
25492555
};

microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.microsoft.azure.storage.StorageErrorCodeStrings;
3535
import com.microsoft.azure.storage.StorageException;
3636
import com.microsoft.azure.storage.StorageUri;
37+
import com.microsoft.azure.storage.core.BaseResponse;
3738
import com.microsoft.azure.storage.core.ExecutionEngine;
3839
import com.microsoft.azure.storage.core.LazySegmentedIterable;
3940
import com.microsoft.azure.storage.core.ListResponse;
@@ -238,6 +239,7 @@ public Void preProcessResponse(CloudFileDirectory directory, CloudFileClient cli
238239
final FileDirectoryAttributes attributes = FileResponse
239240
.getFileDirectoryAttributes(this.getConnection(), client.isUsePathStyleUris());
240241
directory.setProperties(attributes.getProperties());
242+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
241243
return null;
242244
}
243245
};
@@ -629,6 +631,7 @@ public Void preProcessResponse(CloudFileDirectory directory, CloudFileClient cli
629631
}
630632

631633
directory.updatePropertiesFromResponse(this.getConnection());
634+
this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
632635
return null;
633636
}
634637
};

microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileDirectoryProperties.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public final class FileDirectoryProperties {
3333
*/
3434
private Date lastModified;
3535

36+
/**
37+
* Represents the directory's server-side encryption status.
38+
*/
39+
private boolean serverEncrypted;
40+
3641
/**
3742
* Gets the ETag value of the directory.
3843
* <p>
@@ -58,6 +63,15 @@ public Date getLastModified() {
5863
return this.lastModified;
5964
}
6065

66+
/**
67+
* Gets the directory's server-side encryption status.
68+
*
69+
* @return A <code>boolean</code> which specifies the directory's encryption status.
70+
*/
71+
public boolean isServerEncrypted() {
72+
return serverEncrypted;
73+
}
74+
6175
/**
6276
* Sets the ETag value on the directory.
6377
*
@@ -68,6 +82,16 @@ protected void setEtag(final String etag) {
6882
this.etag = etag;
6983
}
7084

85+
/**
86+
* Sets the directory's server-side encryption status.
87+
*
88+
* @param serverEncrypted
89+
* A <code>boolean</code> which specifies the encryption status to set.
90+
*/
91+
protected void setServerEncrypted(boolean serverEncrypted) {
92+
this.serverEncrypted = serverEncrypted;
93+
}
94+
7195
/**
7296
* Sets the last modified time on the directory.
7397
*

0 commit comments

Comments
 (0)