Commit d171f9ca authored by Komal Makkar's avatar Komal Makkar Committed by Hema Vishnu Pola [Microsoft]
Browse files

Added Logs and Jacoco

parent a5a4d87a
......@@ -41,65 +41,47 @@
<reactor.netty.version>0.9.0.RELEASE</reactor.netty.version>
<reactor.core.version>3.3.0.RELEASE</reactor.core.version>
</properties>
<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
<version>${azure.version}</version>
</dependency>
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-core-common</artifactId>
<version>0.3.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>applicationinsights-logging-logback</artifactId>
<version>[2.0,)</version>
</dependency>
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-core-common</artifactId>
<version>0.3.4</version>
</dependency>
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>core-lib-azure</artifactId>
<version>0.0.17</version>
<version>0.0.22</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>notification-core</artifactId>
......@@ -116,6 +98,7 @@
<artifactId>reactor-netty</artifactId>
<version>${reactor.netty.version}</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
......@@ -135,21 +118,61 @@
</exclusions>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.0.0</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.11.0</version>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.23.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>${gitlab-server}</id>
<url>https://community.opengroup.org/api/v4/groups/17/-/packages/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>${gitlab-server}</id>
<url>https://community.opengroup.org/api/v4/projects/44/packages/maven</url>
</repository>
<snapshotRepository>
<id>${gitlab-server}</id>
<url>https://community.opengroup.org/api/v4/projects/44/packages/maven</url>
</snapshotRepository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
......@@ -178,4 +201,20 @@
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<!-- select non-aggregate reports -->
<report>report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</project>
\ No newline at end of file
......@@ -15,6 +15,7 @@
package org.opengroup.osdu.notification.provider.azure.pubsub;
import com.google.gson.JsonObject;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.notification.provider.interfaces.IPubsubHandshakeHandler;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -24,9 +25,16 @@ import org.springframework.stereotype.Component;
@Component
public class EventGridHandshakeHandler implements IPubsubHandshakeHandler {
@Autowired
private EventGridRequestBodyExtractor eventGridRequestBodyExtractor;
private JaxRsDpsLog logger;
@Autowired
EventGridHandshakeHandler(JaxRsDpsLog logger, EventGridRequestBodyExtractor eventGridRequestBodyExtractor) {
this.logger = logger;
this.eventGridRequestBodyExtractor = eventGridRequestBodyExtractor;
}
/**
* Extract Handshake response string form Handshake request.
* TODO: Check if there is a need to verify subscription name with
......@@ -35,19 +43,10 @@ public class EventGridHandshakeHandler implements IPubsubHandshakeHandler {
*/
@Override
public String getHandshakeResponse() {
String response;
try {
String validationCode = this.eventGridRequestBodyExtractor.getValidationCodeForHandshake();
JsonObject jsonResponse = new JsonObject();
jsonResponse.addProperty("ValidationResponse", validationCode);
response = jsonResponse.toString();
} catch (Exception exception) {
throw new AppException(HttpStatus.BAD_REQUEST.value(), "Request payload parsing error",
"Unable to parse request payload.", exception);
}
String validationCode = this.eventGridRequestBodyExtractor.getValidationCodeForHandshake();
JsonObject jsonResponse = new JsonObject();
jsonResponse.addProperty("ValidationResponse", validationCode);
return response;
return jsonResponse.toString();
}
}
\ No newline at end of file
}
......@@ -49,11 +49,11 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
private static final Gson GSON = new Gson();
private static final ObjectMapper objectMapper = new ObjectMapper();
private JsonObject root = null;
private HttpServletRequest httpServletRequest;
private JaxRsDpsLog log;
private final JsonObject root = null;
private final HttpServletRequest httpServletRequest;
private final JaxRsDpsLog logger;
private NotificationRequest notificationRequest;
private final NotificationRequest notificationRequest;
private NotificationData notificationData;
private HandshakeRequestData handshakeRequestData;
private boolean isHandshakeRequest;
......@@ -61,7 +61,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
@Autowired
public EventGridRequestBodyExtractor(HttpServletRequest httpServletRequest, JaxRsDpsLog log) {
this.httpServletRequest = httpServletRequest;
this.log = log;
this.logger = log;
this.notificationRequest = extractNotificationRequestFromHttpRequest();
}
......@@ -73,6 +73,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
*/
public Map<String, String> extractAttributesFromRequestBody() {
if(isHandshakeRequest) {
logger.error("Invalid Event Grid Message. Is a handshake request");
return null;
}
return this.notificationData.getAttributes();
......@@ -86,6 +87,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
*/
public String extractDataFromRequestBody() {
if(isHandshakeRequest) {
logger.error("Invalid Event Grid Message. Is a handshake request");
return null;
}
return new String(Base64.getDecoder().decode(notificationData.getData()));
......@@ -100,6 +102,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
public String extractNotificationIdFromRequestBody() {
String subscriptionId = httpServletRequest.getHeader(SUBSCRIPTION_ID);
if (Strings.isNullOrEmpty(subscriptionId)) {
logger.error("Invalid Event Grid Message. Subscription Id is null or empty");
throw new AppException(HttpStatus.BAD_REQUEST.value(), "Invalid Event Grid Message", "Subscription ID not found");
}
return subscriptionId;
......@@ -123,6 +126,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
*/
public String getValidationCodeForHandshake() {
if(!isHandshakeRequest) {
logger.error("Invalid Event Grid Message. Is not a handshake request");
return null;
}
return this.handshakeRequestData.getValidationCode();
......@@ -154,6 +158,7 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
extractNotificationData(notificationRequest);
}
} catch (Exception e) {
logger.error("Invalid Event Grid Message. %s", e.getMessage());
throw new AppException(HttpStatus.BAD_REQUEST.value(), "Request payload parsing error",
"Unable to parse request payload.", "Request contents are null or empty");
}
......
......@@ -17,6 +17,7 @@ package org.opengroup.osdu.notification.provider.azure.util;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.notification.provider.interfaces.IAppProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
......@@ -49,6 +50,9 @@ public class AppProperties implements IAppProperties {
@Autowired
private SecretClient secretClient;
@Autowired
private JaxRsDpsLog logger;
private String authURL;
private String authClientID;
......@@ -102,11 +106,13 @@ public class AppProperties implements IAppProperties {
private String getKeyVaultSecret(SecretClient kv, String secretName) {
KeyVaultSecret secret = kv.getSecret(secretName);
if (secret == null) {
logger.error(String.format("Secret unexpectedly missing from KeyVault response for secret with name %s", secretName));
throw new IllegalStateException(String.format("No secret found with name %s", secretName));
}
String secretValue = secret.getValue();
if (secretValue == null) {
logger.error(String.format("Secret unexpectedly missing from KeyVault response for secret with name %s", secretName));
throw new IllegalStateException(String.format(
"Secret unexpectedly missing from KeyVault response for secret with name %s", secretName));
}
......
......@@ -4,11 +4,11 @@ import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Configuration;
import javax.inject.Named;
@Component
@Configuration
public class AzureCosmosProperties {
@Value("${tenantinfo.container.name}")
......@@ -42,7 +42,7 @@ public class AzureCosmosProperties {
return cosmosDBName;
}
public String getKeyVaultSecret(SecretClient kv, String secretName) {
private String getKeyVaultSecret(SecretClient kv, String secretName) {
KeyVaultSecret secret = kv.getSecret(secretName);
if (secret == null) {
throw new IllegalStateException(String.format("No secret found with name %s", secretName));
......
......@@ -14,11 +14,8 @@
package org.opengroup.osdu.notification.provider.azure.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.opengroup.osdu.notification.provider.interfaces.IServiceAccountValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
......
......@@ -27,6 +27,7 @@ public class GoogleServiceAccountImpl implements IGoogleServiceAccount {
@Override
public String getIdToken(String keyString, String audience) {
// TODO : Check if it is to be supported
throw new AuthenticationNotSupportedException();
}
}
......@@ -44,8 +44,7 @@ public class ServiceAccountJwtAzureClientImpl implements IServiceAccountJwtClien
private IJwtCache tenantJwtCache;
public String getIdToken(String tenantName) {
// TODO : Add logs.
TenantInfo tenant = tenantInfoServiceProvider.getTenantInfo(tenantName);
TenantInfo tenant = this.tenantInfoServiceProvider.getTenantInfo(tenantName);
if (tenant == null) {
throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from azure");
}
......@@ -55,7 +54,7 @@ public class ServiceAccountJwtAzureClientImpl implements IServiceAccountJwtClien
try {
// TODO : Refactor to move ID token form Common.Core.model.search to Common.core
IdToken cachedToken = (IdToken) tenantJwtCache.get(tenant.getName());
IdToken cachedToken = (IdToken) this.tenantJwtCache.get(tenant.getName());
if ((cachedToken != null) && !IdToken.refreshToken(cachedToken)) {
return "Bearer " + cachedToken.getTokenValue();
......@@ -66,12 +65,8 @@ public class ServiceAccountJwtAzureClientImpl implements IServiceAccountJwtClien
ACCESS_TOKEN = getAccessToken(service);
IdToken idToken = IdToken.builder().tokenValue(ACCESS_TOKEN).expirationTimeMillis(JWT.decode(ACCESS_TOKEN).getExpiresAt().getTime()).build();
tenantJwtCache.put(tenant.getName(), idToken);
} catch (AppException e) {
throw e;
} catch (Exception e) {
throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Error generating token", e);
} finally {
this.tenantJwtCache.put(tenant.getName(), idToken);
} finally {
if(service != null) {
service.shutdown();
}
......
......@@ -15,6 +15,7 @@
# Log settings
logging.level.org.springframework.web=DEBUG
spring.profiles.active=local
LOG_PREFIX=notification
# Service settings
app.entitlements=${entitlements_service_endpoint}
......@@ -37,3 +38,11 @@ tenantInfo.container.name=TenantInfo
# Azure KeyVault configuration
azure.keyvault.url=${KEYVAULT_URI}
# Application name
spring.application.name=notification-azure
# Logging configuration
logging.transaction.enabled=true
logging.slf4jlogger.enabled=true
logging.mdccontext.enabled=true
\ No newline at end of file
......@@ -22,6 +22,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.notification.provider.azure.pubsub.EventGridHandshakeHandler;
import org.opengroup.osdu.notification.provider.azure.pubsub.EventGridRequestBodyExtractor;
......@@ -35,14 +36,17 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EventGridHandshakeHandlerTest {
@Mock
EventGridRequestBodyExtractor eventGridRequestBodyExtractor;
private EventGridRequestBodyExtractor eventGridRequestBodyExtractor;
@Mock
private JaxRsDpsLog logger;
@InjectMocks
@Spy
private EventGridHandshakeHandler sut;
@Test
public void should_returnValidResponse_getHandshakeResponse() throws IOException {
public void should_returnValidResponse_getHandshakeResponse() {
// Set up
when(sut.getHandshakeResponse()).thenReturn("testValidationCode");
String expectedResponse = "{\"ValidationResponse\":\"testValidationCode\"}";
......@@ -55,9 +59,9 @@ public class EventGridHandshakeHandlerTest {
}
@Test
public void should_throw_getHandshakeResponse() throws IOException {
public void should_throw_getHandshakeResponse() {
// Set up
when(sut.getHandshakeResponse())
when(eventGridRequestBodyExtractor.getValidationCodeForHandshake())
.thenThrow(new AppException(HttpStatus.BAD_REQUEST.value(), "Request payload parsing error", "" ));
try{
// Act
......@@ -67,7 +71,6 @@ public class EventGridHandshakeHandlerTest {
fail("Should Throw Exception");
} catch (AppException appException){
Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), appException.getError().getCode());
Assert.assertEquals("Unable to parse request payload.", appException.getError().getMessage());
} catch (Exception exception) {
fail("Should Throw AppException");
}
......
// 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 org.opengroup.osdu.notification.util;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.notification.provider.azure.util.AppProperties;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doReturn;
import static org.mockito.MockitoAnnotations.initMocks;
public class AppPropertiesTests {
@Mock
private SecretClient kv;
@Mock
private KeyVaultSecret secret;
@Mock
private JaxRsDpsLog logger;
@InjectMocks
private AppProperties sut;
@Before
public void init() {
initMocks(this);
}
@Test
public void should_throwWhenSecretNameIsNull_getKeyVaultSecret() {
// Set-Up
doReturn(null).when(kv).getSecret("secret-name");
// Act
IllegalStateException exception = assertThrows(IllegalStateException.class, () ->{
sut.getAuthClientSecret();
});
// Assert
assertEquals("No secret found with name secret-name", exception.getMessage());
}
@Test
public void should_throwWhenSecretIsMissing_getKeyVaultSecret() {
// Set-Up
doReturn(null).when(secret).getValue();
doReturn(secret).when(kv).getSecret("secret-name");
// Act
IllegalStateException exception = assertThrows(IllegalStateException.class, () ->{
sut.getAuthClientSecret();
});
// Assert
assertEquals("Secret unexpectedly missing from KeyVault response for secret with name secret-name", exception.getMessage());
}
@Test
public void should_returnRightClientAuth_getCosmosKey() {
// Set-Up
doReturn("client-auth-secret").when(secret).getValue();
doReturn(secret).when(kv).getSecret("app-dev-sp-password");
// Act
String secretValue = sut.getAuthClientSecret();
// Assert
assertEquals( "client-auth-secret", secretValue);
}
@Test
public void should_returnRightCosmosSecret_getCosmosKey() {
// Set-Up
doReturn("cosmos-endpoint-secret").when(secret).getValue();
doReturn(secret).when(kv).getSecret("app-dev-sp-username");
// Act
String secretValue = sut.getAuthClientID();