From d21b12321cde3bdf9e1febda15ecf6d00949e62f Mon Sep 17 00:00:00 2001
From: Komal Makkar <komakkar@microsoft.com>
Date: Fri, 14 Aug 2020 00:44:28 -0400
Subject: [PATCH] Notification Service Azure Provider Changes

---
 pom.xml                                       |   5 +-
 provider/notification-azure/README.md         | 121 ++++++++++++
 provider/notification-azure/pom.xml           | 177 ++++++++++++++++++
 .../provider/azure/Application.java           |  31 +++
 .../provider/azure/cache/JwtCache.java        |  57 ++++++
 .../di/ServiceAccountJwtClientFactory.java    |  34 ++++
 .../azure/security/SecurityConfig.java        |  37 ++++
 .../provider/azure/util/AppProperties.java    | 118 ++++++++++++
 .../azure/util/AzureCosmosProperties.java     |  59 ++++++
 .../azure/util/AzureKeyVaultProperties.java   |  20 ++
 .../AzureServiceAccountValidatorImpl.java     |  40 ++++
 .../azure/util/GoogleServiceAccountImpl.java  |  32 ++++
 .../ServiceAccountJwtAzureClientImpl.java     | 108 +++++++++++
 .../main/resources/application-dev.properties |  15 ++
 .../resources/application-local.properties    |  39 ++++
 .../src/main/resources/application.properties |  22 +++
 .../util/ServiceAccountClientImplTest.java    | 156 +++++++++++++++
 testing/notification-test-azure/pom.xml       |  76 ++++++++
 .../api/TestPubsubEndpointHMAC.java           |  34 ++++
 .../notification/util/AzureTestUtils.java     |  55 ++++++
 .../osdu/notification/util/Config.java        |   2 -
 21 files changed, 1234 insertions(+), 4 deletions(-)
 create mode 100644 provider/notification-azure/README.md
 create mode 100644 provider/notification-azure/pom.xml
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/cache/JwtCache.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/di/ServiceAccountJwtClientFactory.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/security/SecurityConfig.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AppProperties.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureKeyVaultProperties.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/GoogleServiceAccountImpl.java
 create mode 100644 provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
 create mode 100644 provider/notification-azure/src/main/resources/application-dev.properties
 create mode 100644 provider/notification-azure/src/main/resources/application-local.properties
 create mode 100644 provider/notification-azure/src/main/resources/application.properties
 create mode 100644 provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
 create mode 100644 testing/notification-test-azure/pom.xml
 create mode 100644 testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
 create mode 100644 testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/AzureTestUtils.java

diff --git a/pom.xml b/pom.xml
index 4050891b5..82222e319 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,8 +15,8 @@
   limitations under the License.
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>org.opengroup.osdu</groupId>
 	<artifactId>os-notification</artifactId>
@@ -77,6 +77,7 @@
 	<modules>
 		<module>notification-core</module>
 		<module>provider/notification-gcp</module>
+		<module>provider/notification-azure</module>
 	</modules>
 
 	<distributionManagement>
diff --git a/provider/notification-azure/README.md b/provider/notification-azure/README.md
new file mode 100644
index 000000000..bacbd92b8
--- /dev/null
+++ b/provider/notification-azure/README.md
@@ -0,0 +1,121 @@
+## Running Locally
+
+### Requirements
+
+In order to run this service locally, you will need the following:
+
+- [Maven 3.6.0+](https://maven.apache.org/download.cgi)
+- [AdoptOpenJDK8](https://adoptopenjdk.net/)
+- Infrastructure dependencies, deployable through the relevant [infrastructure template](https://dev.azure.com/slb-des-ext-collaboration/open-data-ecosystem/_git/infrastructure-templates?path=%2Finfra&version=GBmaster&_a=contents)
+- While not a strict dependency, example commands in this document use [bash](https://www.gnu.org/software/bash/)
+
+### General Tips
+
+**Environment Variable Management**
+The following tools make environment variable configuration simpler
+ - [direnv](https://direnv.net/) - for a shell/terminal environment
+ - [EnvFile](https://plugins.jetbrains.com/plugin/7861-envfile) - for [Intellij IDEA](https://www.jetbrains.com/idea/)
+
+**Lombok**
+This project uses [Lombok](https://projectlombok.org/) for code generation. You may need to configure your IDE to take advantage of this tool.
+ - [Intellij configuration](https://projectlombok.org/setup/intellij)
+ - [VSCode configuration](https://projectlombok.org/setup/vscode)
+
+
+### Environment Variables
+
+In order to run the service locally, you will need to have the following environment variables defined.
+
+**Note** The following command can be useful to pull secrets from keyvault:
+```bash
+az keyvault secret show --vault-name $KEY_VAULT_NAME --name $KEY_VAULT_SECRET_NAME --query value -otsv
+```
+
+**Required to run service**
+
+| name | value | description | sensitive? | source |
+| ---  | ---   | ---         | ---        | ---    |
+| `LOG_PREFIX` | `notification` | Logging prefix | no | - |
+| `app.entitlements` | ex `https://foo-entitlements.azurewebsites.net` | Entitlements API endpoint | no | output of infrastructure deployment |
+| `app.register`| ex `https://foo-register.azurewebsites.net`| Registration Service API endpoint | no | output of infrastructure deployment |
+| `AUTHORIZE_API_KEY` | `********` | The API key clients will need to use when calling the entitlements | yes | -- |
+| `azure.application-insights.instrumentation-key` | `********` | API Key for App Insights | yes | output of infrastructure deployment |
+| `azure.activedirectory.client-id` | `********` | AAD client application ID | yes | output of infrastructure deployment |
+| `azure.activedirectory.AppIdUri` | `api://${azure.activedirectory.client-id}` | URI for AAD Application | no | -- |
+| `azure.activedirectory.session-stateless` | `true` | Flag run in stateless mode (needed by AAD dependency) | no | -- |
+| `KEYVAULT_URI` | ex `https://foo-keyvault.vault.azure.net/` | URI of KeyVault that holds application secrets | no | output of infrastructure deployment |
+
+
+### Configure Maven
+
+Check that maven is installed:
+```bash
+$ mvn --version
+Apache Maven 3.6.0
+Maven home: /usr/share/maven
+Java version: 1.8.0_212, vendor: AdoptOpenJDK, runtime: /usr/lib/jvm/jdk8u212-b04/jre
+...
+```
+
+You will need to configure access to the remote maven repository that holds the OSDU dependencies. This file should live within `~/.m2/settings.xml`:
+```bash
+$ cat ~/.m2/settings.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+    <servers>
+        <server>
+            <id>os-core</id>
+            <username>mvn-pat</username>
+            <!-- Treat this auth token like a password. Do not share it with anyone, including Microsoft support. -->
+            <password>$PERSONAL_ACCESS_TOKEN_GOES_HERE</password>
+        </server>
+    </servers>
+</settings>
+```
+
+### Build and run the application
+
+After configuring your environment as specified above, you can follow these steps to build and run the application.
+1. Navigate to the root of the schema project, os-schema. For building the project using command line, run below command :
+    ```bash
+    mvn clean install
+    ```
+    This will build the core project as well as all the underlying projects. If we want  to build projects for specific cloud vendor, we can use mvn --projects command. For example, if we want to build only for Azure, we can use below command :
+    ```bash
+    mvn --projects notification-core,provider/notification-azure clean install
+    ```
+2. Run schema service in command line. We need to select which cloud vendor specific schema-service we want to run. For example, if we want to run schema-service for Azure, run the below command : 
+    ```bash 
+    # Running Azure : 
+    java -jar  provider\schema-azure\target\os-notification-azure-0.0.1-SNAPSHOT-spring-boot.jar
+3. The port and path for the service endpoint can be configured in ```application.properties``` in the provider folder as following. If not specified, then  the web container (ex. Tomcat) default is used: 
+    ```bash
+    server.servlet.contextPath=/api/notification/v1/
+    server.port=8080
+    ```
+
+## Debugging
+
+Jet Brains - the authors of Intellij IDEA, have written an [excellent guide](https://www.jetbrains.com/help/idea/debugging-your-first-java-application.html) on how to debug java programs.
+
+
+## Deploying service 
+
+TBD
+
+## License
+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](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.
diff --git a/provider/notification-azure/pom.xml b/provider/notification-azure/pom.xml
new file mode 100644
index 000000000..69593aaf8
--- /dev/null
+++ b/provider/notification-azure/pom.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opengroup.osdu</groupId>
+    <artifactId>notification-azure</artifactId>
+    <version>1.0.0</version>
+    <name>notification-azure</name>
+    <description>Azure implementation for Notification service</description>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>org.opengroup.osdu</groupId>
+        <artifactId>os-notification</artifactId>
+        <version>1.0.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <java.version>8</java.version>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <azure.version>2.1.7</azure.version>
+        <springframework.version>4.3.0.RELEASE</springframework.version>
+        <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.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</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>
+        </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>
+            <version>1.0.0</version>
+        </dependency>
+
+        <!--
+		 Override the spring-boot version of these dependencies to the ones
+		 required by the azure-core library. This needs to be done for each
+		 app that depends on this library
+ 		-->
+        <dependency>
+            <groupId>io.projectreactor.netty</groupId>
+            <artifactId>reactor-netty</artifactId>
+            <version>${reactor.netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+            <version>${reactor.core.version}</version>
+        </dependency>
+
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+            <version>2.1.6.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>3.0.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                        <configuration>
+                            <classifier>spring-boot</classifier>
+                            <mainClass>
+                                org.opengroup.osdu.notification.provider.azure.Application
+                            </mainClass>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.4.2</version>
+                <configuration>
+                    <useSystemClassLoader>false</useSystemClassLoader>
+                    <threadCount>1</threadCount>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
new file mode 100644
index 000000000..79a9ffdb6
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
@@ -0,0 +1,31 @@
+// 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.provider.azure;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@SpringBootApplication
+@ComponentScan({"org.opengroup.osdu"})
+@EnableAsync
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(new Class[]{Application.class}, args);
+    }
+}
+
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/cache/JwtCache.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/cache/JwtCache.java
new file mode 100644
index 000000000..4c3dffbc9
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/cache/JwtCache.java
@@ -0,0 +1,57 @@
+//  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.provider.azure.cache;
+
+import org.opengroup.osdu.core.common.cache.VmCache;
+import org.opengroup.osdu.core.common.model.search.IdToken;
+import org.opengroup.osdu.core.common.provider.interfaces.IJwtCache;
+import org.opengroup.osdu.notification.provider.azure.util.AppProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Named;
+
+@Component
+public class JwtCache implements IJwtCache<String, IdToken> {
+    private VmCache<String, IdToken> cache;
+
+    // Azure service account id_token can be requested only for 1 hr
+    private final static int EXPIRED_AFTER = 59;
+
+    public JwtCache(@Named("MAX_CACHE_VALUE_SIZE") String cacheSize){
+        cache = new VmCache<>(EXPIRED_AFTER * 60, Integer.parseInt(cacheSize));
+    }
+
+    @Override
+    public void put(String s, IdToken o) {
+        this.cache.put(s, o);
+    }
+
+    @Override
+    public IdToken get(String s) {
+        return this.cache.get(s);
+    }
+
+    @Override
+    public void delete(String s) {
+        this.cache.delete(s);
+    }
+
+    @Override
+    public void clearAll() {
+        this.cache.clearAll();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/di/ServiceAccountJwtClientFactory.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/di/ServiceAccountJwtClientFactory.java
new file mode 100644
index 000000000..708834922
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/di/ServiceAccountJwtClientFactory.java
@@ -0,0 +1,34 @@
+// 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.provider.azure.di;
+
+import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
+import org.opengroup.osdu.notification.provider.azure.util.AppProperties;
+import org.opengroup.osdu.notification.provider.azure.util.ServiceAccountJwtAzureClientImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+public class ServiceAccountJwtClientFactory extends AbstractFactoryBean<IServiceAccountJwtClient> {
+
+    @Override
+    public IServiceAccountJwtClient createInstance() throws Exception {
+        return new ServiceAccountJwtAzureClientImpl();
+    }
+
+    @Override
+    public final Class<?> getObjectType() {
+        return IServiceAccountJwtClient.class;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/security/SecurityConfig.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/security/SecurityConfig.java
new file mode 100644
index 000000000..853b37b2a
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/security/SecurityConfig.java
@@ -0,0 +1,37 @@
+// 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.provider.azure.security;
+
+import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import javax.inject.Inject;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Override
+    protected void configure(HttpSecurity httpSecurity) throws Exception {
+        // TODO : Add antMatchers after Swagger changes merge
+        // TODO : Add the authZ
+        httpSecurity
+                .csrf().disable();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AppProperties.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AppProperties.java
new file mode 100644
index 000000000..10bac0d15
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AppProperties.java
@@ -0,0 +1,118 @@
+/*
+// 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.provider.azure.util;
+
+import com.azure.cosmos.CosmosClient;
+import com.azure.security.keyvault.secrets.SecretClient;
+import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
+import org.opengroup.osdu.azure.KeyVaultFacade;
+import org.opengroup.osdu.notification.utils.IAppProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Named;
+
+@Component
+public class AppProperties implements IAppProperties {
+
+    @Value("${app.entitlements}")
+    private String authorizeAPI;
+
+    @Value("${app.register}")
+    private String registerAPI;
+
+    @Value("${app.expireTime}")
+    private String expireTime;
+
+    @Value("${app.maxCacheSize}")
+    private String maxCacheSize;
+
+    @Value("${aad.oboApi}")
+    private String aadOboAPI;
+
+    @Value("${app.maxCacheSize")
+    private String CacheValueSize;
+
+    @Autowired
+    private SecretClient secretClient;
+
+    private String authURL;
+
+    private String authClientID;
+
+    private String authClientSecret;
+
+    public String getAadClientID() {
+        return aadOboAPI;
+    }
+
+    public String getAuthorizeAPI() {
+        return this.authorizeAPI;
+    }
+
+    public String getRegisterAPI() {
+        return this.registerAPI;
+    }
+
+    public String getAuthClientSecret() {
+        if(this.authClientSecret == null) {
+            this.authClientSecret = getKeyVaultSecret(this.secretClient, "app-dev-sp-password");
+        }
+
+        return this.authClientSecret;
+    }
+
+    public String getAuthClientID() {
+        if(this.authClientID == null) {
+            this.authClientID = getKeyVaultSecret(this.secretClient, "app-dev-sp-username");
+        }
+
+        return this.authClientID;
+    }
+
+    public String getAuthURL() {
+        if(this.authURL == null) {
+            String urlFormat = "https://login.microsoftonline.com/%s/oauth2/token/";
+            String tenant = getKeyVaultSecret(this.secretClient, "app-dev-sp-tenant-id");
+            this.authURL = String.format(urlFormat, tenant);
+        }
+
+        return this.authURL;
+    }
+
+    @Bean
+    @Named("MAX_CACHE_VALUE_SIZE")
+    public String getMaxCacheSize() {
+        return maxCacheSize;
+    }
+
+    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));
+        }
+
+        String secretValue = secret.getValue();
+        if (secretValue == null) {
+            throw new IllegalStateException(String.format(
+                    "Secret unexpectedly missing from KeyVault response for secret with name %s", secretName));
+        }
+
+        return secretValue;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
new file mode 100644
index 000000000..22bb7ee41
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
@@ -0,0 +1,59 @@
+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.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Named;
+
+@Component
+public class AzureCosmosProperties {
+
+    @Value("${tenantinfo.container.name}")
+    private String tenantInfoContainerName;
+
+    @Value("${azure.cosmosdb.database}")
+    private String cosmosDBName;
+
+    // TODO : Move away from Named beans.
+    @Bean
+    @Named("COSMOS_ENDPOINT")
+    public String cosmosEndpoint(SecretClient kv) {
+        return getKeyVaultSecret(kv, "cosmos-endpoint");
+    }
+
+    @Bean
+    @Named("COSMOS_KEY")
+    public String cosmosKey(SecretClient kv) {
+        return getKeyVaultSecret(kv, "cosmos-primary-key");
+    }
+
+    @Bean
+    @Named("COSMOS_CONTAINER_NAME")
+    public String containerName() {
+        return tenantInfoContainerName;
+    }
+
+    @Bean
+    @Named("COSMOS_DB_NAME")
+    public String cosmosDBName() {
+        return cosmosDBName;
+    }
+
+    public 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));
+        }
+
+        String secretValue = secret.getValue();
+        if (secretValue == null) {
+            throw new IllegalStateException(String.format(
+                    "Secret unexpectedly missing from KeyVault response for secret with name %s", secretName));
+        }
+
+        return secretValue;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureKeyVaultProperties.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureKeyVaultProperties.java
new file mode 100644
index 000000000..6c4fe6f19
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureKeyVaultProperties.java
@@ -0,0 +1,20 @@
+package org.opengroup.osdu.notification.provider.azure.util;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Named;
+
+@Component
+public class AzureKeyVaultProperties {
+
+    @Value("${azure.keyvault.url}")
+    private String keyVaultURL;
+
+    @Bean
+    @Named("KEY_VAULT_URL")
+    public String getKeyVaultURL() {
+        return keyVaultURL;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
new file mode 100644
index 000000000..7f153b364
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
@@ -0,0 +1,40 @@
+// 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.provider.azure.util;
+
+import org.opengroup.osdu.notification.utils.ServiceAccountValidator;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AzureServiceAccountValidatorImpl implements ServiceAccountValidator {
+
+    @Override
+    public boolean isValidPublisherServiceAccount(String jwt) {
+        // TODO : Implement the service account verification for PubSub Role
+        // TODO : Also check the need and means to verify the other Roles.
+
+        // Marking it to return true, for the integration tests.
+        return true;
+    }
+
+    @Override
+    public boolean isValidServiceAccount(String jwt, String userIdentity, String... audiences) {
+        // TODO : Implement the service account verification for PubSub Role
+        // TODO : Also check the need and means to verify the other Roles.
+
+        // Marking it to return true, for the integration tests.
+        return true;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/GoogleServiceAccountImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/GoogleServiceAccountImpl.java
new file mode 100644
index 000000000..ed4631926
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/GoogleServiceAccountImpl.java
@@ -0,0 +1,32 @@
+// 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.provider.azure.util;
+
+import lombok.SneakyThrows;
+import org.opengroup.osdu.notification.utils.IGoogleServiceAccount;
+import org.springframework.stereotype.Component;
+
+import javax.naming.AuthenticationNotSupportedException;
+
+@Component
+public class GoogleServiceAccountImpl implements IGoogleServiceAccount {
+
+    @SneakyThrows
+    @Override
+    public String getIdToken(String keyString, String audience) {
+        // TODO : Check if it is to be supported
+        throw new AuthenticationNotSupportedException();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
new file mode 100644
index 000000000..5d6d99334
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
@@ -0,0 +1,108 @@
+// 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.provider.azure.util;
+
+import com.auth0.jwt.JWT;
+import com.microsoft.aad.adal4j.AuthenticationContext;
+import com.microsoft.aad.adal4j.AuthenticationResult;
+import com.microsoft.aad.adal4j.ClientCredential;
+import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.search.IdToken;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.provider.interfaces.IJwtCache;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
+import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.net.MalformedURLException;
+import java.util.concurrent.*;
+
+@Component
+public class ServiceAccountJwtAzureClientImpl implements IServiceAccountJwtClient {
+
+    @Autowired
+    private AppProperties config;
+
+    @Autowired
+    private ITenantFactory tenantInfoServiceProvider;
+
+    @Autowired
+    private IJwtCache tenantJwtCache;
+
+    public String getIdToken(String tenantName) {
+        // TODO : Add logs.
+        TenantInfo tenant = tenantInfoServiceProvider.getTenantInfo(tenantName);
+        if (tenant == null) {
+            throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from azure");
+        }
+
+        String ACCESS_TOKEN = "";
+        ExecutorService service = null;
+
+        try {
+            // TODO : Refactor to move ID token form Common.Core.model.search to Common.core
+            IdToken cachedToken = (IdToken) tenantJwtCache.get(tenant.getName());
+
+            if ((cachedToken != null) && !IdToken.refreshToken(cachedToken)) {
+                return cachedToken.getTokenValue();
+            }
+
+            // TODO : Control the thread count via config and pool should be created once.
+            service = Executors.newFixedThreadPool(1);
+
+            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 {
+            if(service != null) {
+                service.shutdown();
+            }
+        }
+        return ACCESS_TOKEN;
+    }
+
+    // TODO : Refactor for making it test-able.
+    // THIS METHOD IS PUBLIC ONLY TO ENABLE UNIT TESTING
+    public String getAccessToken(ExecutorService service) {
+        AuthenticationContext context = null;
+        ClientCredential credential = null;
+        String ACCESS_TOKEN = null;
+        try {
+            context = new AuthenticationContext(this.config.getAuthURL(), false, service);
+            credential = new ClientCredential(this.config.getAuthClientID(), this.config.getAuthClientSecret());
+
+            Future<AuthenticationResult> future = context.acquireToken(this.config.getAadClientID(), credential, null);
+
+            if (future == null) {
+                throw new AppException(HttpStatus.SC_FORBIDDEN, "Access denied", "The user is not authorized to perform this action");
+            }
+            ACCESS_TOKEN = future.get().getAccessToken();
+        } catch (MalformedURLException malformedURLException) {
+            malformedURLException.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } catch (ExecutionException e) {
+            e.printStackTrace();
+        }
+        return ACCESS_TOKEN;
+    }
+}
+
diff --git a/provider/notification-azure/src/main/resources/application-dev.properties b/provider/notification-azure/src/main/resources/application-dev.properties
new file mode 100644
index 000000000..8b813dc17
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/application-dev.properties
@@ -0,0 +1,15 @@
+#  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.
+
+spring.profiles.active=dev
diff --git a/provider/notification-azure/src/main/resources/application-local.properties b/provider/notification-azure/src/main/resources/application-local.properties
new file mode 100644
index 000000000..dede88f26
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/application-local.properties
@@ -0,0 +1,39 @@
+#  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.
+
+# Log settings
+logging.level.org.springframework.web=DEBUG
+spring.profiles.active=local
+
+# Service settings
+app.entitlements=${entitlements_service_endpoint}
+app.register=${registeration_service_endpoint}
+app.project=opendes
+server.port=8080
+
+# Azure AD configuration
+azure.activedirectory.client-id=${aad_client_id}
+azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
+azure.activedirectory.session-stateless=true
+
+aad.oboApi=${aad_client_id}
+azure.application-insights.instrumentation-key=${appinsights_key}
+
+# Azure CosmosDB configuration
+azure.cosmosdb.uri=${cosmosdb_account}
+azure.cosmosdb.database=${cosmosdb_database}
+tenantInfo.container.name=TenantInfo
+
+# Azure KeyVault configuration
+azure.keyvault.url=${KEYVAULT_URI}
diff --git a/provider/notification-azure/src/main/resources/application.properties b/provider/notification-azure/src/main/resources/application.properties
new file mode 100644
index 000000000..b002ba804
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/application.properties
@@ -0,0 +1,22 @@
+#  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.
+
+LOG_PREFIX=notification
+server.servlet.contextPath=/
+app.expireTime=300
+app.maxCacheSize=10
+server.error.whitelabel.enabled=false
+
+
+
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
new file mode 100644
index 000000000..5153d6205
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
@@ -0,0 +1,156 @@
+// 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 org.apache.http.HttpStatus;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.search.IdToken;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
+import org.opengroup.osdu.notification.provider.azure.cache.JwtCache;
+import org.opengroup.osdu.notification.provider.azure.util.AppProperties;
+import org.opengroup.osdu.notification.provider.azure.util.ServiceAccountJwtAzureClientImpl;
+
+import java.util.concurrent.ExecutorService;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ServiceAccountClientImplTest {
+
+    final String tenantName = "Test Tenant";
+    final String validToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkdW1teUBkdW1teS5jb20iLCJpc3MiOiJkdW1teUBkdW1teS5jb20iLCJhdWQiOiJkdW1teS5kdW1teS5jb20iLCJpYXQiOjE1NTYxMzcyNzMsImV4cCI6MTU1NjIzMDk3OSwicHJvdmlkZXIiOiJkdW1teS5jb20iLCJjbGllbnQiOiJkdW1teS5jb20iLCJ1c2VyaWQiOiJkdW1teXRlc3Rlci5jb20iLCJlbWFpbCI6ImR1bW15dGVzdGVyLmNvbSIsImF1dGh6IjoiIiwibGFzdG5hbWUiOiJkdW1teSIsImZpcnN0bmFtZSI6ImR1bW15IiwiY291bnRyeSI6IiIsImNvbXBhbnkiOiIiLCJqb2J0aXRsZSI6IiIsInN1YmlkIjoiZHVtbXlpZCIsImlkcCI6ImR1bW15IiwiaGQiOiJkdW1teS5jb20iLCJkZXNpZCI6ImR1bW15aWQiLCJjb250YWN0X2VtYWlsIjoiZHVtbXlAZHVtbXkuY29tIiwianRpIjoiNGEyMWYyYzItZjU5Yy00NWZhLTk0MTAtNDNkNDdhMTg4ODgwIn0.nkiyKtfXXxAlC60iDjXuB2EAGDfZiVglP-CyU1T4etc";
+    final String invalidToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkdW1teUBkdW1teS5jb20iLCJpc3MiOiJkdW1teUBkdW1teS5jb20iLCJhdWQiOiJkdW1teS5kdW1teS5jb20iLCJpYXQiOjE1NTYxMzcyNzMsImV4cCI6MTU1NjIzMDk3OSwicHJvdmlkZXIiOiJkdW1teS5jb20iLCJjbGllbnQiOiJkdW1teS5jb20iLCJ1c2VyaWQiOiJkdW1teXRlc3Rlci5jb20iLCJlbWFpbCI6ImR1bW15dGVzdGVyLmNvbSIsImF1dGh6IjoiIiwibGFzdG5hbWUiOiJkdW1teSIsImZpcnN0bmFtZSI6ImR1bW15IiwiY291bnRyeSI6IiIsImNvbXBhbnkiOiIiLCJqb2J0aXRsZSI6IiIsInN1YmlkIjoiZHVtbXlpZCIsImlkcCI6ImR1bW15IiwiaGQiOiJkdW1teS5jb20iLCJkZXNpZCI6ImR1bW15aWQiLCJjb250YWN0X2VtYWlsIjoiZHVtbXlAZHVtbXkuY29tIiwianRpIjoiNGEyMWYyYzItZjU5Yy00NWZhLTk0MTAtNDNkNDdhMTg4ODgwIn0.nkiyKtfXXxAlC60iDjXuB2EAGDfZiVglP-CyU1T4etc";
+
+    @Mock
+    private ITenantFactory tenantInfoServiceProvider;
+
+    @Mock
+    private TenantInfo tenantInfo;
+
+    @Mock
+    private IdToken idToken;
+
+    @Mock
+    private ExecutorService executorService;
+
+    @Mock
+    private AppProperties appProperties;
+
+    @Mock
+    private JwtCache tenantJwtCacheMock;
+
+    @InjectMocks
+    @Spy
+    private ServiceAccountJwtAzureClientImpl sut;
+
+    @Before
+    public void setup() {
+        initMocks(this);
+        when(tenantInfo.getName()).thenReturn(tenantName);
+        when(this.tenantInfoServiceProvider.getTenantInfo(tenantName)).thenReturn(tenantInfo);
+        idToken = IdToken.builder().tokenValue(validToken).expirationTimeMillis(System.currentTimeMillis() + 10000000L).build();
+    }
+
+    @Test
+    public void should_throwAppException_getIdTokenTest() {
+        // Set up
+        when(this.tenantInfoServiceProvider.getTenantInfo(tenantName)).thenReturn(null);
+        try {
+            // Act
+            sut.getIdToken(tenantName);
+
+            // Assert
+            fail("Should throw exception");
+        } catch (AppException e) {
+            Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, e.getError().getCode());
+            Assert.assertEquals("Invalid tenant Name from azure", e.getError().getMessage());
+        } catch (Exception e) {
+            fail("Should not throw this exception" + e.getMessage());
+        }
+    }
+
+    @Test
+    public void should_getTokenFromCache_getIdTokenTest() {
+        // SetUp
+        when(tenantJwtCacheMock.get(any())).thenReturn(idToken);
+
+        // Act
+        String returnedIdToken = sut.getIdToken(tenantName);
+
+        // Assert
+        Assert.assertEquals(idToken.getTokenValue(), returnedIdToken);
+    }
+
+    @Test
+    public void should_updateCache_getIdTokenTest() {
+        // Set up
+        when(tenantJwtCacheMock.get(any())).thenReturn(idToken);
+
+        // Act
+        String returnedToken = this.sut.getIdToken(tenantName);
+
+        // Assert
+        Assert.assertEquals(validToken, returnedToken);
+    }
+
+    @Test
+    public void should_throw500ForInvalidAccessTokenResponse_getIdToken() {
+        try {
+            // Act
+            this.sut.getIdToken(tenantName);
+
+            // Assert
+            fail("Should throw exception");
+        } catch (AppException e) {
+            Assert.assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getError().getCode());
+            Assert.assertEquals("Error generating token", e.getError().getMessage());
+        } catch (Exception e) {
+            fail("Should not throw this exception" + e.getMessage());
+        }
+    }
+
+    @Test
+    public void should_return403GivenInvalidApplicationProperties_getAccessToken() {
+        when(appProperties.getAuthURL()).thenReturn("https://login.microsoftonline.com/s/oauth2/token/");
+        when(appProperties.getAuthClientID()).thenReturn("testAuthClientID");
+        when(appProperties.getAuthClientSecret()).thenReturn("testAuthClientSecret");
+        when(appProperties.getAadClientID()).thenReturn("testAadClientID");
+
+        try {
+            // Act
+            sut.getAccessToken(executorService);
+
+            // Assert
+            fail("Should throw exception");
+        } catch (AppException appException) {
+            Assert.assertEquals(HttpStatus.SC_FORBIDDEN, appException.getError().getCode());
+        } catch (Exception e) {
+            fail("Should not throw this exception" + e.getMessage());
+        }
+    }
+}
+
diff --git a/testing/notification-test-azure/pom.xml b/testing/notification-test-azure/pom.xml
new file mode 100644
index 000000000..cacbfac57
--- /dev/null
+++ b/testing/notification-test-azure/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-2020, Schlumberger
+  ~
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opengroup.osdu</groupId>
+    <artifactId>notification-test-azure</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>notification-test-azure</name>
+    <description>Integration tests Azure for notification</description>
+    <packaging>jar</packaging>
+
+    <properties>
+        <java.version>8</java.version>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+    </properties>
+
+    <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/143/packages/maven</url>
+        </repository>
+        <snapshotRepository>
+            <id>${gitlab-server}</id>
+            <url>https://community.opengroup.org/api/v4/projects/143/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opengroup.osdu.notification</groupId>
+            <artifactId>notification-test-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opengroup.osdu</groupId>
+            <artifactId>os-core-common</artifactId>
+            <version>0.0.20</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opengroup.osdu</groupId>
+            <artifactId>core-lib-azure</artifactId>
+            <version>0.0.17</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
new file mode 100644
index 000000000..a18328c34
--- /dev/null
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
@@ -0,0 +1,34 @@
+package org.opengroup.osdu.notification.api;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.opengroup.osdu.notification.util.Config;
+import org.opengroup.osdu.notification.util.AzureTestUtils;
+import org.opengroup.osdu.notification.util.RestDescriptor;
+import org.opengroup.osdu.notification.util.TestUtils;
+
+public class TestPubsubEndpointHMAC extends PubsubEndpointHMACTests {
+
+    @BeforeClass
+    public static void classSetup() throws Exception {
+        PubsubEndpointHMACTests.classSetup();
+    }
+
+    @AfterClass
+    public static void classTearDown() throws Exception {
+    }
+
+    @Before
+    @Override
+    public void setup() throws Exception {
+        this.testUtils = new AzureTestUtils();
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        this.testUtils = null;
+    }
+}
\ No newline at end of file
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/AzureTestUtils.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/AzureTestUtils.java
new file mode 100644
index 000000000..0af4600be
--- /dev/null
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/AzureTestUtils.java
@@ -0,0 +1,55 @@
+package org.opengroup.osdu.notification.util;
+
+import com.google.common.base.Strings;
+import org.opengroup.osdu.azure.util.AzureServicePrincipal;
+
+public class AzureTestUtils extends TestUtils {
+
+    public AzureTestUtils() {
+
+    }
+
+    // TODO : Revisit for synchronized block
+    @Override
+    public synchronized String getOpsToken() throws Exception {
+        if (Strings.isNullOrEmpty(opsToken)) {
+            opsToken = getToken(System.getProperty("INTEGRATION_TESTER", System.getenv("INTEGRATION_TESTER")),
+                    System.getProperty("TESTER_SERVICEPRINCIPAL_SECRET", System.getenv("TESTER_SERVICEPRINCIPAL_SECRET")));
+        }
+        return "Bearer " + opsToken;
+    }
+
+    @Override
+    public synchronized String getAdminToken() throws Exception {
+        if (Strings.isNullOrEmpty(adminToken)) {
+            adminToken = getToken(System.getProperty("INTEGRATION_TESTER", System.getenv("INTEGRATION_TESTER")),
+                    System.getProperty("TESTER_SERVICEPRINCIPAL_SECRET", System.getenv("TESTER_SERVICEPRINCIPAL_SECRET")));
+        }
+        return "Bearer " + adminToken;
+    }
+
+    @Override
+    public synchronized String getEditorToken() throws Exception {
+        if (Strings.isNullOrEmpty(editorToken)) {
+            editorToken = getToken(System.getProperty("INTEGRATION_TESTER", System.getenv("INTEGRATION_TESTER")),
+                    System.getProperty("TESTER_SERVICEPRINCIPAL_SECRET", System.getenv("TESTER_SERVICEPRINCIPAL_SECRET")));
+        }
+        return "Bearer " + editorToken;
+    }
+
+    @Override
+    public synchronized String getNoAccessToken() throws Exception {
+        if (Strings.isNullOrEmpty(noAccessToken)) {
+            noAccessToken = getToken(System.getProperty("NO_DATA_ACCESS_TESTER", System.getenv("NO_DATA_ACCESS_TESTER")),
+                    System.getProperty("NO_DATA_ACCESS_TESTER_SERVICEPRINCIPAL_SECRET", System.getenv("NO_DATA_ACCESS_TESTER_SERVICEPRINCIPAL_SECRET")));
+        }
+        return "Bearer " + noAccessToken;
+    }
+
+    private String getToken(String sp_id, String sp_secret) throws Exception {
+        String tenant_id = System.getProperty("AZURE_AD_TENANT_ID", System.getenv("AZURE_AD_TENANT_ID"));
+        String app_resource_id = System.getProperty("AZURE_AD_APP_RESOURCE_ID", System.getenv("AZURE_AD_APP_RESOURCE_ID"));
+
+        return new AzureServicePrincipal().getIdToken(sp_id, sp_secret, tenant_id, app_resource_id);
+    }
+}
diff --git a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
index e1fafaf80..486680fb5 100644
--- a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
+++ b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
@@ -33,14 +33,12 @@ public class Config {
 
     public static Config Instance() {
         String env = getEnvironment();
-
         config.ClientTenant = "nonexistenttenant";
         config.IntegrationAudience = "245464679631-ktfdfpl147m1mjpbutl00b3cmffissgq.apps.googleusercontent.com";
         config.OsduTenant = "opendes";
         config.Topic = "records-changed";
 
         config.hmacSecretValue = System.getProperty("HMAC_SECRET", System.getenv("HMAC_SECRET"));
-
         if (env.equalsIgnoreCase("LOCAL")) {
             //make sure to run register service on a different port. You can also choose to point to Register service that is running in cloud
             String registerUrl = "http://localhost:8081/";
-- 
GitLab