Skip to content

Commit

Permalink
Merge pull request #224 from godaddy/master
Browse files Browse the repository at this point in the history
[C#] Bump up AppEncryption to v0.1.3
  • Loading branch information
nikoo28 authored Jun 10, 2020
2 parents fb1a860 + 51ef58d commit f326f91
Show file tree
Hide file tree
Showing 21 changed files with 518 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="../AppEncryption/AppEncryption.csproj" />
<ProjectReference Include="../AppEncryption.Tests/AppEncryption.Tests.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="config.yaml" CopyToOutputDirectory="Always" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public IEnumerator<object[]> GetEnumerator()

private object[] GenerateMocks(KeyState cacheIK, KeyState metaIK, KeyState cacheSK, KeyState metaSK)
{
Partition partition = new Partition(
Partition partition = new DefaultPartition(
cacheIK + "CacheIK_" + metaIK + "MetaIK_" + DateTimeUtils.GetCurrentTimeAsUtcIsoDateTimeOffset() +
"_" + Random.Next(),
cacheSK + "CacheSK_" + metaSK + "MetaSK_" + DateTimeUtils.GetCurrentTimeAsUtcIsoDateTimeOffset() + "_" + Random.Next(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Text;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using GoDaddy.Asherah.AppEncryption.Kms;
using GoDaddy.Asherah.AppEncryption.Persistence;
using GoDaddy.Asherah.AppEncryption.Tests;
using GoDaddy.Asherah.AppEncryption.Tests.AppEncryption.Persistence;
using GoDaddy.Asherah.Crypto;
using Xunit;

namespace GoDaddy.Asherah.AppEncryption.IntegrationTests.Regression
{
public class DynamoDbCompatibilityTest : IClassFixture<DynamoDBContainerFixture>, IClassFixture<MetricsFixture>
{
private const string StaticMasterKey = "thisIsAStaticMasterKeyForTesting";
private const string PartitionKey = "Id";
private const string SortKey = "Created";
private const string DefaultTableName = "EncryptionKey";

private readonly DynamoDbMetastoreImpl dynamoDbMetastoreImpl;
private readonly DynamoDbMetastoreImpl dynamoDbMetastoreImplWithKeySuffix;

public DynamoDbCompatibilityTest(DynamoDBContainerFixture dynamoDbContainerFixture)
{
// Use AWS SDK to create client and initialize table
AmazonDynamoDBConfig amazonDynamoDbConfig = new AmazonDynamoDBConfig
{
ServiceURL = dynamoDbContainerFixture.ServiceUrl,
AuthenticationRegion = "us-west-2",
};
IAmazonDynamoDB tempDynamoDbClient = new AmazonDynamoDBClient(amazonDynamoDbConfig);
CreateTableRequest request = new CreateTableRequest
{
TableName = DefaultTableName,
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition(PartitionKey, ScalarAttributeType.S),
new AttributeDefinition(SortKey, ScalarAttributeType.N),
},
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement(PartitionKey, KeyType.HASH),
new KeySchemaElement(SortKey, KeyType.RANGE),
},
ProvisionedThroughput = new ProvisionedThroughput(1L, 1L),
};
tempDynamoDbClient.CreateTableAsync(request).Wait();

// Use a builder without the suffix
dynamoDbMetastoreImpl = DynamoDbMetastoreImpl.NewBuilder()
.WithEndPointConfiguration(dynamoDbContainerFixture.ServiceUrl, "us-west-2")
.Build();

// Connect to the same metastore but initialize it with a key suffix
dynamoDbMetastoreImplWithKeySuffix = DynamoDbMetastoreImpl.NewBuilder()
.WithEndPointConfiguration(dynamoDbContainerFixture.ServiceUrl, "us-west-2")
.WithKeySuffix("us-west-2")
.Build();
}

[Fact]
private void TestRegionSuffixBackwardCompatibility()
{
string dataRowString;
string originalPayloadString;
string decryptedPayloadString;

// Encrypt originalPayloadString with metastore without key suffix
using (SessionFactory sessionFactory = SessionFactory.NewBuilder("productId", "reference_app")
.WithMetastore(dynamoDbMetastoreImpl)
.WithCryptoPolicy(new NeverExpiredCryptoPolicy())
.WithKeyManagementService(new StaticKeyManagementServiceImpl(StaticMasterKey))
.Build())
{
using (Session<byte[], byte[]> sessionBytes = sessionFactory.GetSessionBytes("shopper123"))
{
originalPayloadString = "mysupersecretpayload";
byte[] dataRowRecordBytes =
sessionBytes.Encrypt(Encoding.UTF8.GetBytes(originalPayloadString));

// Consider this us "persisting" the DRR
dataRowString = Convert.ToBase64String(dataRowRecordBytes);
}
}

// Decrypt dataRowString with metastore with key suffix
using (SessionFactory sessionFactory = SessionFactory.NewBuilder("productId", "reference_app")
.WithMetastore(dynamoDbMetastoreImplWithKeySuffix)
.WithCryptoPolicy(new NeverExpiredCryptoPolicy())
.WithKeyManagementService(new StaticKeyManagementServiceImpl(StaticMasterKey))
.Build())
{
using (Session<byte[], byte[]> sessionBytes = sessionFactory.GetSessionBytes("shopper123"))
{
byte[] newDataRowRecordBytes = Convert.FromBase64String(dataRowString);

// Decrypt the payload
decryptedPayloadString = Encoding.UTF8.GetString(sessionBytes.Decrypt(newDataRowRecordBytes));
}
}

// Verify that we were able to decrypt with a suffixed builder
Assert.Equal(decryptedPayloadString, originalPayloadString);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
namespace GoDaddy.Asherah.AppEncryption.Tests.AppEncryption
{
[Collection("Logger Fixture collection")]
public class PartitionTest
public class DefaultPartitionTest
{
private const string TestPartitionId = "test_partition_id";
private const string TestServiceId = "test_service_id";
private const string TestProductId = "test_product_id";

private readonly Partition partition;

public PartitionTest()
public DefaultPartitionTest()
{
partition = new Partition(TestPartitionId, TestServiceId, TestProductId);
partition = new DefaultPartition(TestPartitionId, TestServiceId, TestProductId);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace GoDaddy.Asherah.AppEncryption.Tests.AppEncryption.Envelope
public class EnvelopeEncryptionJsonImplTest : IClassFixture<MetricsFixture>
{
private readonly Partition partition =
new Partition("shopper_123", "payments", "ecomm");
new DefaultPartition("shopper_123", "payments", "ecomm");

// Setup DateTimeOffsets truncated to seconds and separated by hour to isolate overlap in case of interacting with multiple level keys
private readonly DateTimeOffset drkDateTime = DateTimeOffset.UtcNow.Truncate(TimeSpan.FromSeconds(1));
Expand Down Expand Up @@ -188,7 +188,7 @@ private void TestWithIntermediateKeyForReadWithKeyCachedAndNotExpiredShouldUseCa
byte[] actualBytes = envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey);
Assert.Equal(expectedBytes, actualBytes);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<DateTimeOffset>()), Times.Never);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<KeyMeta>()), Times.Never);
intermediateCryptoKeyMock.Verify(x => x.Dispose());
}

Expand All @@ -206,7 +206,7 @@ private void TestWithIntermediateKeyForReadWithKeyCachedAndNotExpiredAndNotifyEx
byte[] actualBytes = envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey);
Assert.Equal(expectedBytes, actualBytes);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<DateTimeOffset>()), Times.Never);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<KeyMeta>()), Times.Never);

// TODO : Add verify for notification not being called once implemented
intermediateCryptoKeyMock.Verify(x => x.Dispose());
Expand All @@ -228,7 +228,7 @@ private void TestWithIntermediateKeyForReadWithKeyCachedAndExpiredAndNotifyExpir
byte[] actualBytes = envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey);
Assert.Equal(expectedBytes, actualBytes);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<DateTimeOffset>()), Times.Never);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(It.IsAny<KeyMeta>()), Times.Never);

// TODO : Add verify for notification not being called once implemented
intermediateCryptoKeyMock.Verify(x => x.Dispose());
Expand All @@ -238,7 +238,7 @@ private void TestWithIntermediateKeyForReadWithKeyCachedAndExpiredAndNotifyExpir
private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCannotCacheAndNotExpiredShouldLookup()
{
keyMetaMock.Setup(x => x.Created).Returns(ikDateTime);
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(It.IsAny<DateTimeOffset>()))
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(It.IsAny<KeyMeta>()))
.Returns(intermediateCryptoKeyMock.Object);

byte[] expectedBytes = { 0, 1, 2, 3 };
Expand All @@ -247,7 +247,7 @@ private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCannotCacheAndNotE
byte[] actualBytes = envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey);
Assert.Equal(expectedBytes, actualBytes);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object.Created));
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object));
intermediateKeyCacheMock.Verify(x => x.PutAndGetUsable(It.IsAny<DateTimeOffset>(), It.IsAny<CryptoKey>()), Times.Never);
intermediateCryptoKeyMock.Verify(x => x.Dispose());
}
Expand All @@ -256,7 +256,7 @@ private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCannotCacheAndNotE
private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCanCacheAndNotExpiredShouldLookupAndCache()
{
keyMetaMock.Setup(x => x.Created).Returns(ikDateTime);
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(ikDateTime))
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(keyMetaMock.Object))
.Returns(intermediateCryptoKeyMock.Object);
cryptoPolicyMock.Setup(x => x.CanCacheIntermediateKeys()).Returns(true);
intermediateCryptoKeyMock.Setup(x => x.GetCreated()).Returns(ikDateTime);
Expand All @@ -270,7 +270,7 @@ private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCanCacheAndNotExpi
byte[] actualBytes = envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey);
Assert.Equal(expectedBytes, actualBytes);
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object.Created));
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object));
intermediateKeyCacheMock.Verify(x => x.PutAndGetUsable(intermediateCryptoKeyMock.Object.GetCreated(), intermediateCryptoKeyMock.Object));
intermediateCryptoKeyMock.Verify(x => x.Dispose());
}
Expand All @@ -279,7 +279,7 @@ private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCanCacheAndNotExpi
private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCanCacheAndCacheUpdateFailsShouldLookupAndFailAndDisposeKey()
{
keyMetaMock.Setup(x => x.Created).Returns(ikDateTime);
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(It.IsAny<DateTimeOffset>()))
envelopeEncryptionJsonImplSpy.Setup(x => x.GetIntermediateKey(It.IsAny<KeyMeta>()))
.Returns(intermediateCryptoKeyMock.Object);
cryptoPolicyMock.Setup(x => x.CanCacheIntermediateKeys()).Returns(true);
intermediateKeyCacheMock.Setup(x => x.PutAndGetUsable(It.IsAny<DateTimeOffset>(), It.IsAny<CryptoKey>()))
Expand All @@ -290,7 +290,7 @@ private void TestWithIntermediateKeyForReadWithKeyNotCachedAndCanCacheAndCacheUp

Assert.Throws<AppEncryptionException>(() => envelopeEncryptionJsonImplSpy.Object.WithIntermediateKeyForRead(
keyMetaMock.Object, functionWithIntermediateKey));
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object.Created));
envelopeEncryptionJsonImplSpy.Verify(x => x.GetIntermediateKey(keyMetaMock.Object));
intermediateCryptoKeyMock.Verify(x => x.Dispose());
}

Expand Down Expand Up @@ -1262,7 +1262,8 @@ private void TestGetIntermediateKeyWithParentKeyMetaShouldSucceed()
envelopeEncryptionJsonImplSpy.Setup(x => x.DecryptKey(keyRecord, systemCryptoKeyMock.Object))
.Returns(intermediateCryptoKeyMock.Object);

CryptoKey actualIntermediateKey = envelopeEncryptionJsonImplSpy.Object.GetIntermediateKey(ikDateTime);
keyMetaMock.Setup(x => x.Created).Returns(ikDateTime);
CryptoKey actualIntermediateKey = envelopeEncryptionJsonImplSpy.Object.GetIntermediateKey(keyMetaMock.Object);
Assert.Equal(intermediateCryptoKeyMock.Object, actualIntermediateKey);
envelopeEncryptionJsonImplSpy.Verify(x => x.WithExistingSystemKey(
(KeyMeta)keyRecord.ParentKeyMeta, false, It.IsAny<Func<CryptoKey, CryptoKey>>()));
Expand All @@ -1279,7 +1280,7 @@ private void TestGetIntermediateKeyWithoutParentKeyMetaShouldFail()
envelopeEncryptionJsonImplSpy.Setup(x => x.LoadKeyRecord(It.IsAny<string>(), ikDateTime))
.Returns(keyRecord);

Assert.Throws<MetadataMissingException>(() => envelopeEncryptionJsonImplSpy.Object.GetIntermediateKey(ikDateTime));
Assert.Throws<MetadataMissingException>(() => envelopeEncryptionJsonImplSpy.Object.GetIntermediateKey(keyMetaMock.Object));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class AppJsonEncryptionImplTest : IClassFixture<MetricsFixture>

public AppJsonEncryptionImplTest()
{
partition = new Partition("PARTITION", "SYSTEM", "PRODUCT");
partition = new DefaultPartition("PARTITION", "SYSTEM", "PRODUCT");
Dictionary<string, JObject> memoryPersistence = new Dictionary<string, JObject>();

dataPersistence = new AdhocPersistence<JObject>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,11 @@ private void TestDbConnectionClosedAfterStore()
// Verify that DbConnection is closed at the end of the function call
Assert.Equal(ConnectionState.Closed, dbConnection.State);
}

[Fact]
private void TestKeySuffixShouldReturnEmpty()
{
Assert.Equal(string.Empty, adoMetastoreImplSpy.Object.GetKeySuffix());
}
}
}
Loading

0 comments on commit f326f91

Please sign in to comment.