Commit c97ba571 authored by Aliaksei Darafeyeu's avatar Aliaksei Darafeyeu Committed by neelesh thakur
Browse files

adds CryptographyClientFactory andEventGridManagerFactory

parent 8f36fe29
......@@ -369,6 +369,7 @@ MIT
The following software have components provided under the terms of this license:
- Azure Java Client Authentication Library for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
- Azure Java Client Runtime for ARM (from https://github.com/Azure/autorest-clientruntime-for-java)
- Azure Java Client Runtime for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
- Azure Metrics Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
- Azure Spring Boot AutoConfigure (from https://github.com/Microsoft/azure-spring-boot)
......@@ -387,11 +388,13 @@ The following software have components provided under the terms of this license:
- Microsoft Azure Java Core Library (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure Netty HTTP Client Library (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure SDK annotations (from https://github.com/Microsoft/java-api-annotations)
- Microsoft Azure SDK for EventGrid Management (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure SDK for SQL API of Azure Cosmos DB Service (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure SDK for Service Bus (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure SDK for eventgrid (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure client library for Blob Storage (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure client library for Identity (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure client library for KeyVault Keys (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure client library for KeyVault Secrets (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure common module for Storage (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure internal Avro module for Storage (from https://github.com/Azure/azure-sdk-for-java)
......@@ -464,6 +467,7 @@ The following software have components provided under the terms of this license:
- Joda-Time (from http://www.joda.org/joda-time/)
- LatencyUtils (from http://latencyutils.github.io/LatencyUtils/)
- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
- Microsoft Azure SDK for EventGrid Management (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure SDK for SQL API of Azure Cosmos DB Service (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure client library for Blob Storage (from https://github.com/Azure/azure-sdk-for-java)
- Project Lombok (from https://projectlombok.org)
......
......@@ -20,7 +20,7 @@
<groupId>org.opengroup.osdu</groupId>
<artifactId>core-lib-azure</artifactId>
<packaging>jar</packaging>
<version>0.0.57</version>
<version>0.0.58</version>
<name>core-lib-azure</name>
<properties>
......@@ -49,9 +49,11 @@
<reactor.version>Dysprosium-SR12</reactor.version>
<netty.version>4.1.51.Final</netty.version>
<lombok.version>1.18.16</lombok.version>
<osdu.oscorecommon.version>0.3.18</osdu.oscorecommon.version>
<osdu.oscorecommon.version>0.3.23</osdu.oscorecommon.version>
<mockito-junit-jupiter.version>2.23.0</mockito-junit-jupiter.version>
<spring-boot-starter-log4j2.version>2.3.4.RELEASE</spring-boot-starter-log4j2.version>
<azure-mgmt-eventgrid.version>1.0.0-beta-3</azure-mgmt-eventgrid.version>
<azure-security-keyvault-keys.version>4.2.3</azure-security-keyvault-keys.version>
</properties>
<licenses>
......@@ -247,6 +249,22 @@
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-eventgrid</artifactId>
<version>1.2.0</version>
<exclusions>
<exclusion>
<artifactId>azure-client-runtime</artifactId>
<groupId>com.microsoft.azure</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.azure.eventgrid.v2020_04_01_preview</groupId>
<artifactId>azure-mgmt-eventgrid</artifactId>
<version>${azure-mgmt-eventgrid.version}</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-keys</artifactId>
<version>${azure-security-keyvault-keys.version}</version>
</dependency>
</dependencies>
......
package org.opengroup.osdu.azure.cache;
import org.opengroup.osdu.core.common.cache.VmCache;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.azure.security.keyvault.keys.cryptography.CryptographyClient;
/**
* Implementation of ICache for CryptographyClient.
*/
@Lazy
@Component
public class CryptographyClientCache extends VmCache<String, CryptographyClient> {
/**
* Default cache constructor.
*/
public CryptographyClientCache() {
super(60 * 60, 1000);
}
/**
* @param key cache key
* @return true if found in cache
*/
public boolean containsKey(final String key) {
return this.get(key) != null;
}
}
package org.opengroup.osdu.azure.cache;
import org.opengroup.osdu.core.common.cache.VmCache;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.microsoft.azure.management.eventgrid.v2020_04_01_preview.implementation.EventGridManager;
/**
* Implementation of ICache for CryptographyClient.
*/
@Lazy
@Component
public class EventGridManagerCache extends VmCache<String, EventGridManager> {
/**
* Default cache constructor.
*/
public EventGridManagerCache() {
super(60 * 60, 1000);
}
/**
* @param key cache key
* @return true if found in cache
*/
public boolean containsKey(final String key) {
return this.get(key) != null;
}
}
package org.opengroup.osdu.azure.cryptography;
import com.azure.security.keyvault.keys.cryptography.CryptographyClient;
/**
* Interface for Cryptography Client Factory to return appropriate
* cryptographyClient based on the data partition id.
*/
public interface CryptographyClientFactory {
/**
*
* @param partitionId partition id
* @return CryptographyClient
*/
CryptographyClient getClient(String partitionId);
}
package org.opengroup.osdu.azure.cryptography;
import org.opengroup.osdu.azure.cache.CryptographyClientCache;
import org.opengroup.osdu.azure.partition.PartitionInfoAzure;
import org.opengroup.osdu.azure.partition.PartitionServiceClient;
import org.opengroup.osdu.common.Validators;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.keys.cryptography.CryptographyClient;
import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder;
/**
* Implementation for CryptographyClientFactory.
*/
@Component
public class CryptographyClientFactoryImpl implements CryptographyClientFactory {
@Autowired
private PartitionServiceClient partitionService;
@Autowired
private CryptographyClientCache clientCache;
/**
* @param partitionId partition id
* @return CryptographyClient
*/
@Override
public CryptographyClient getClient(final String partitionId) {
Validators.checkNotNullAndNotEmpty(partitionId, "partitionId");
String cacheKey = partitionId + "-cryptographyClient";
if (clientCache.containsKey(cacheKey)) {
return clientCache.get(cacheKey);
}
PartitionInfoAzure pi = partitionService.getPartition(partitionId);
CryptographyClient cryptographyClient = new CryptographyClientBuilder()
.keyIdentifier(pi.getCryptographyEncryptionKeyIdentifier())
.credential(new DefaultAzureCredentialBuilder().build())
.buildClient();
clientCache.put(cacheKey, cryptographyClient);
return cryptographyClient;
}
}
package org.opengroup.osdu.azure.eventgridmanager;
import com.microsoft.azure.management.eventgrid.v2020_04_01_preview.implementation.EventGridManager;
/**
* Interface for Event Grid Manager Factory to return appropriate EventGridManager based on the data partition id.
*/
public interface EventGridManagerFactory {
/**
* @param partitionId partition id
* @return EventGridManager
*/
EventGridManager getManager(String partitionId);
}
package org.opengroup.osdu.azure.eventgridmanager;
import org.opengroup.osdu.azure.cache.EventGridManagerCache;
import org.opengroup.osdu.azure.partition.PartitionInfoAzure;
import org.opengroup.osdu.azure.partition.PartitionServiceClient;
import org.opengroup.osdu.azure.util.AzureTokenCredentialsService;
import org.opengroup.osdu.common.Validators;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.microsoft.azure.credentials.AzureTokenCredentials;
import com.microsoft.azure.management.eventgrid.v2020_04_01_preview.implementation.EventGridManager;
import com.microsoft.rest.LogLevel;
/**
* Interface for Event Grid Manager Factory to return appropriate EventGridManager based on the data partition id.
*/
@Component
public class EventGridManagerFactoryImpl implements EventGridManagerFactory {
@Autowired
private PartitionServiceClient partitionService;
@Autowired
private EventGridManagerCache clientCache;
@Autowired
private AzureTokenCredentialsService credentialsService;
/**
* @param partitionId partition id
* @return EventGridManager
*/
public EventGridManager getManager(final String partitionId) {
Validators.checkNotNullAndNotEmpty(partitionId, "partitionId");
String cacheKey = partitionId + "-eventGridManager";
if (clientCache.containsKey(cacheKey)) {
return clientCache.get(cacheKey);
}
PartitionInfoAzure pi = partitionService.getPartition(partitionId);
AzureTokenCredentials credentials = credentialsService.getAppTokenCredentials(pi.getAzureSubscriptionId());
EventGridManager eventGridManager = EventGridManager.configure().withLogLevel(LogLevel.BASIC)
.authenticate(credentials, credentials.defaultSubscriptionId());
clientCache.put(cacheKey, eventGridManager);
return eventGridManager;
}
}
......@@ -67,6 +67,15 @@ public class PartitionInfoAzure {
@SerializedName("eventgrid-recordstopic-accesskey")
private Property eventGridRecordsTopicAccessKeyConfig;
@SerializedName("eventgrid-resourcegroup")
private Property eventGridResourceGroupConfig;
@SerializedName("encryption-key-identifier")
private Property cryptographyEncryptionKeyIdentifierConfig;
@SerializedName("subscription-id")
private Property azureSubscriptionIdConfig;
private Property servicePrincipalAppIdConfig = Property.builder().value("app-dev-sp-username").sensitive(true).build();
private SecretClient secretClient;
......@@ -232,6 +241,36 @@ public class PartitionInfoAzure {
return String.valueOf(this.getEventGridRecordsTopicAccessKeyConfig().getValue());
}
/**
* @return partition event grid ResourceGroup
*/
public String getEventGridResourceGroup() {
if (this.getEventGridResourceGroupConfig().isSensitive()) {
return getSecret(this.getEventGridResourceGroupConfig());
}
return String.valueOf(this.getEventGridResourceGroupConfig().getValue());
}
/**
* @return partition Encryption Key Identifier
*/
public String getCryptographyEncryptionKeyIdentifier() {
if (this.getCryptographyEncryptionKeyIdentifierConfig().isSensitive()) {
return getSecret(this.getCryptographyEncryptionKeyIdentifierConfig());
}
return String.valueOf(this.getCryptographyEncryptionKeyIdentifierConfig().getValue());
}
/**
* @return partition azure subscriptionId
*/
public String getAzureSubscriptionId() {
if (this.getAzureSubscriptionIdConfig().isSensitive()) {
return getSecret(this.getAzureSubscriptionIdConfig());
}
return String.valueOf(this.getAzureSubscriptionIdConfig().getValue());
}
/**
* @param client KV secret client
*/
......
package org.opengroup.osdu.azure.util;
import java.util.HashMap;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.stereotype.Component;
import com.microsoft.azure.AzureEnvironment;
import com.microsoft.azure.credentials.ApplicationTokenCredentials;
import com.microsoft.azure.credentials.AzureTokenCredentials;
/**
* Class to generate the ApplicationTokenCredentials for Event Grid Manager.
*/
@Component
public class AzureTokenCredentialsService {
@Inject
@Named("APP_DEV_SP_USERNAME")
private String clientID;
@Inject
@Named("APP_DEV_SP_PASSWORD")
private String clientSecret;
@Inject
@Named("APP_DEV_SP_TENANT_ID")
private String tenantId;
/**
* @param subscriptionId string
* @return ApplicationTokenCredentials
*/
public AzureTokenCredentials getAppTokenCredentials(final String subscriptionId) {
AzureEnvironment azureEnvironment = new AzureEnvironment(new HashMap<>());
azureEnvironment.endpoints().putAll(AzureEnvironment.AZURE.endpoints());
return new ApplicationTokenCredentials(clientID, tenantId, clientSecret, azureEnvironment)
.withDefaultSubscriptionId(subscriptionId);
}
}
package org.opengroup.osdu.azure.cryptography;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.azure.cache.CryptographyClientCache;
import org.opengroup.osdu.azure.partition.PartitionInfoAzure;
import org.opengroup.osdu.azure.partition.PartitionServiceClient;
import org.opengroup.osdu.core.common.partition.Property;
import com.azure.security.keyvault.keys.cryptography.CryptographyClient;
@ExtendWith(MockitoExtension.class)
class CryptographyClientFactoryImplTest {
private static final String VALID_DATA_PARTITION_ID = "validDataPartitionId";
public static final String IDENTIFIER = "https://test-vault.vault.azure.net/keys/test-key/key-version";
@Mock
private PartitionServiceClient partitionService;
@Mock
private CryptographyClientCache clientCache;
@InjectMocks
private CryptographyClientFactoryImpl factory;
@Test
void should_throwException_given_nullDataPartitionId() {
NullPointerException nullPointerException = Assertions.assertThrows(NullPointerException.class,
() -> this.factory.getClient(null));
assertEquals("partitionId cannot be null!", nullPointerException.getMessage());
}
@Test
void should_throwException_given_emptyDataPartitionId() {
IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class,
() -> this.factory.getClient(""));
assertEquals("partitionId cannot be empty!", illegalArgumentException.getMessage());
}
@Test
void should_return_validClient_given_validPartitionId() {
// Setup
when(this.partitionService.getPartition(VALID_DATA_PARTITION_ID)).thenReturn(
PartitionInfoAzure.builder()
.idConfig(Property.builder().value(VALID_DATA_PARTITION_ID).build())
.cryptographyEncryptionKeyIdentifierConfig(Property.builder().value(IDENTIFIER).build()).build());
when(this.clientCache.containsKey(any())).thenReturn(false);
// Act
CryptographyClient eventGridClient = this.factory.getClient(VALID_DATA_PARTITION_ID);
// Assert
assertNotNull(eventGridClient);
verify(this.clientCache, times(1)).put(any(), any());
}
}
\ No newline at end of file
package org.opengroup.osdu.azure.eventgridmanager;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.azure.cache.EventGridManagerCache;
import org.opengroup.osdu.azure.partition.PartitionInfoAzure;
import org.opengroup.osdu.azure.partition.PartitionServiceClient;
import org.opengroup.osdu.azure.util.AzureTokenCredentialsService;
import org.opengroup.osdu.core.common.partition.Property;
import org.springframework.beans.factory.annotation.Autowired;
import com.azure.security.keyvault.secrets.SecretClient;
import com.microsoft.azure.AzureEnvironment;
import com.microsoft.azure.credentials.AzureTokenCredentials;
import com.microsoft.azure.management.eventgrid.v2020_04_01_preview.implementation.EventGridManager;
@ExtendWith(MockitoExtension.class)
class EventGridManagerFactoryImplTest {
private static final String VALID_DATA_PARTITION_ID = "validDataPartitionId";
public static final String SUBSCRIPTION_ID = "subscription-id";
@Mock
private AzureTokenCredentialsService credentialsService;
@Mock
private PartitionServiceClient partitionService;
@Mock
private EventGridManagerCache clientCache;
@InjectMocks
private EventGridManagerFactoryImpl factory;
@Test
void should_throwException_given_nullDataPartitionId() {
NullPointerException nullPointerException = Assertions.assertThrows(NullPointerException.class,
() -> this.factory.getManager(null));
assertEquals("partitionId cannot be null!", nullPointerException.getMessage());
}
@Test
void should_throwException_given_emptyDataPartitionId() {
IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class,
() -> this.factory.getManager(""));
assertEquals("partitionId cannot be empty!", illegalArgumentException.getMessage());
}
@Test
void should_return_validClient_given_validPartitionId() {
// Setup
when(this.partitionService.getPartition(VALID_DATA_PARTITION_ID)).thenReturn(
PartitionInfoAzure.builder()
.idConfig(Property.builder().value(VALID_DATA_PARTITION_ID).build())
.azureSubscriptionIdConfig(Property.builder().value(SUBSCRIPTION_ID).build()).build());
AzureTokenCredentials azureTokenCredentials = Mockito.mock(AzureTokenCredentials.class);
when(azureTokenCredentials.defaultSubscriptionId()).thenReturn(SUBSCRIPTION_ID);
when(azureTokenCredentials.environment()).thenReturn(AzureEnvironment.AZURE);
when(credentialsService.getAppTokenCredentials(SUBSCRIPTION_ID)).thenReturn(azureTokenCredentials);
when(this.clientCache.containsKey(any())).thenReturn(false);
// Act
EventGridManager eventGridClient = this.factory.getManager(VALID_DATA_PARTITION_ID);
// Assert
assertNotNull(eventGridClient);
verify(this.clientCache, times(1)).put(any(), any());
}
}
\ No newline at end of file
package org.opengroup.osdu.azure.util;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.azure.security.keyvault.secrets.SecretClient;
import com.microsoft.azure.credentials.AzureTokenCredentials;
@ExtendWith(MockitoExtension.class)
class AzureTokenCredentialsServiceTest {
public static final String SUBSCRIPTION_ID = "subscription-id";
@Mock
private SecretClient secretClient;
@InjectMocks
private AzureTokenCredentialsService azureTokenCredentialsService;
@Test
void should_return_credential() {
AzureTokenCredentials credentials = azureTokenCredentialsService.getAppTokenCredentials(SUBSCRIPTION_ID);
assertNotNull(credentials);
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment