From 0f10985e1a55fc662d788a9be47c68d178639759 Mon Sep 17 00:00:00 2001
From: helayoty <hebaelayoty@gmail.com>
Date: Thu, 3 Oct 2019 02:03:34 -0700
Subject: [PATCH] apply modification in headerInfo and RequestInfo

---
 indexer-service-azure/pom.xml                 |  10 --
 .../indexer/azure/api/AADController.java      |  20 +--
 .../org/opendes/indexer/azure/api/Hello.java  |  24 ----
 .../security/BasicAuthSecurityConfig.java     |  52 ++++++++
 .../azure/security/WhoamiController.java      |  39 ++++++
 .../azure/util/HeadersInfoAzureImpl.java      |   4 +-
 .../indexer/azure/util/RequestInfoImpl.java   |  28 +++--
 .../util/ServiceAccountJwtClientImpl.java     | 118 +++++-------------
 8 files changed, 143 insertions(+), 152 deletions(-)
 delete mode 100644 indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/Hello.java
 create mode 100644 indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/BasicAuthSecurityConfig.java
 create mode 100644 indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/WhoamiController.java

diff --git a/indexer-service-azure/pom.xml b/indexer-service-azure/pom.xml
index 96ffaea82..8684f39a6 100644
--- a/indexer-service-azure/pom.xml
+++ b/indexer-service-azure/pom.xml
@@ -85,16 +85,6 @@
             <artifactId>msal4j</artifactId>
             <version>0.5.0-preview</version>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>org.json</groupId>-->
-<!--            <artifactId>json</artifactId>-->
-<!--            <version>20090211</version>-->
-<!--        </dependency>-->
-        <!-- Spring 3 dependencies -->
-<!--        <dependency>-->
-<!--            <groupId>org.springframework.boot</groupId>-->
-<!--            <artifactId>spring-boot-starter-thymeleaf</artifactId>-->
-<!--        </dependency>-->
     </dependencies>
 
     <build>
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/AADController.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/AADController.java
index 7e380a6d0..e91874ed2 100644
--- a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/AADController.java
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/AADController.java
@@ -23,25 +23,7 @@ public class AADController {
 
         String token  =  service.getIdToken("common");
 
-        String oboApiCallRes = callOboService(token);
-
-        return new ResponseEntity<>(HttpStatus.OK);
-    }
-
-    private String callOboService(String accessToken){
-        RestTemplate restTemplate = new RestTemplate();
-
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_JSON);
-
-        headers.set("Authorization", "Bearer " + accessToken);
-
-        HttpEntity<String> entity = new HttpEntity<>(null, headers);
-
-        String result = restTemplate.exchange("http://localhost:8081/api", HttpMethod.GET,
-                entity, String.class).getBody();
-
-        return result;
+        return new ResponseEntity<String>(token, HttpStatus.OK);
     }
 }
 
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/Hello.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/Hello.java
deleted file mode 100644
index a76de3480..000000000
--- a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/api/Hello.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.opendes.indexer.azure.api;
-
-import org.opendes.core.util.IServiceAccountJwtClient;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.security.PermitAll;
-
-@RestController
-@RequestMapping
-public class Hello {
-
-    @GetMapping("/hello")
-    @PermitAll
-   public String Default() {
-       return "Hello Azure Indexer!!!";
-   }
-
-}
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/BasicAuthSecurityConfig.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/BasicAuthSecurityConfig.java
new file mode 100644
index 000000000..69f11d5e3
--- /dev/null
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/BasicAuthSecurityConfig.java
@@ -0,0 +1,52 @@
+//  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.opendes.indexer.azure.security;
+
+import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+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.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter {
+    @Autowired
+    private AADAppRoleStatelessAuthenticationFilter appRoleAuthFilter;
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                .csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
+                .and()
+                .authorizeRequests()
+                .antMatchers("/", "/index.html","/obo_api",
+                        "/index-worker", "/_dps/task-handlers", "/_dps/task-handlers/**",
+                        "/reindex",
+                        "/v2/api-docs",
+                        "/swagger-resources/**",
+                        "/configuration/security",
+                        "/swagger",
+                        "/swagger-ui.html",
+                        "/webjars/**").permitAll()
+                .anyRequest().authenticated()
+                .and()
+                .addFilterBefore(appRoleAuthFilter, UsernamePasswordAuthenticationFilter.class);
+    }
+}
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/WhoamiController.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/WhoamiController.java
new file mode 100644
index 000000000..d682b70a6
--- /dev/null
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/security/WhoamiController.java
@@ -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.
+
+package org.opendes.indexer.azure.security;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class WhoamiController {
+    @RequestMapping(value = {"/", "/whoami"})
+    @ResponseBody
+    public String whoami() {
+        final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+
+        String userName = auth.getName();
+        String roles = String.valueOf(auth.getAuthorities());
+        String details = String.valueOf(auth.getPrincipal());
+
+        return "user: " + userName + "<BR>" +
+                "roles: " + roles + "<BR>" +
+                "details: " + details;
+    }
+}
+
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/HeadersInfoAzureImpl.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/HeadersInfoAzureImpl.java
index 86b3f3276..6a0416eff 100644
--- a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/HeadersInfoAzureImpl.java
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/HeadersInfoAzureImpl.java
@@ -42,8 +42,6 @@ public class HeadersInfoAzureImpl implements IHeadersInfo {
         FORBIDDEN_FROM_LOGGING.add(DpsHeaders.ON_BEHALF_OF);
     }
 
-    private static final HashSet<String> FORWARDED_HEADERS = new HashSet<>();
-
     @Override
     public DpsHeaders getHeaders() {
         if (headersMap == null) {
@@ -78,7 +76,7 @@ public class HeadersInfoAzureImpl implements IHeadersInfo {
         Preconditions.checkNotNull(input, "input headers cannot be null");
 
         DpsHeaders output = DpsHeaders.createFromMap(input);
-        output.addCorrelationIdIfMissing();
+        //output.addCorrelationIdIfMissing();
         return output;
     }
 
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/RequestInfoImpl.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/RequestInfoImpl.java
index fc8d95928..08839dac4 100644
--- a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/RequestInfoImpl.java
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/RequestInfoImpl.java
@@ -3,14 +3,12 @@ package org.opendes.indexer.azure.util;
 import com.google.common.base.Strings;
 import org.apache.http.HttpStatus;
 import org.opendes.core.model.DeploymentEnvironment;
-import org.opendes.core.util.AppException;
-import org.opendes.core.util.Config;
-import org.opendes.core.util.IHeadersInfo;
-import org.opendes.core.util.IServiceAccountJwtClient;
+import org.opendes.core.util.*;
 import org.opendes.indexer.util.IRequestInfo;
 import org.opengroup.osdu.client.api.DpsHeaders;
 import org.opengroup.osdu.client.multitenancy.TenantInfo;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.web.context.annotation.RequestScope;
 
@@ -23,6 +21,9 @@ import static org.opengroup.osdu.client.api.DpsHeaders.AUTHORIZATION;
 @RequestScope
 public class RequestInfoImpl implements IRequestInfo {
 
+    @Autowired
+    private DpsHeaders dpsHeaders;
+
     @Autowired
     private IHeadersInfo headersInfo;
     @Autowired
@@ -31,8 +32,13 @@ public class RequestInfoImpl implements IRequestInfo {
     @Autowired
     private TenantInfo tenantInfo;
 
+    @Value("${DEPLOYMENT_ENVIRONMENT}")
+    private String DEPLOYMENT_ENVIRONMENT;
+
+
     @Override
     public DpsHeaders getHeaders() {
+
         return this.headersInfo.getHeaders();
     }
 
@@ -53,19 +59,18 @@ public class RequestInfoImpl implements IRequestInfo {
 
     @Override
     public DpsHeaders getHeadersWithDwdAuthZ() {
-        DpsHeaders output = this.headersInfo.getHeaders();
-        output.put(AUTHORIZATION, this.checkOrGetAuthorizationHeader());
-        return output;
+        this.dpsHeaders.put(AUTHORIZATION, this.checkOrGetAuthorizationHeader());
+        return this.headersInfo.getHeaders();
     }
 
     @Override
-    public boolean isCronRequest() { return false; }
+    public boolean isCronRequest() { return false;}
 
     @Override
-    public boolean isTaskQueueRequest() { return false; }
+    public boolean isTaskQueueRequest() {return false;}
 
-    private String checkOrGetAuthorizationHeader() {
-        if (Config.getDeploymentEnvironment() == DeploymentEnvironment.LOCAL) {
+    public String checkOrGetAuthorizationHeader() {
+        if (DeploymentEnvironment.valueOf(DEPLOYMENT_ENVIRONMENT) == DeploymentEnvironment.LOCAL) {
             String authHeader = this.headersInfo.getHeaders().getAuthorization();
             if (Strings.isNullOrEmpty(authHeader)) {
                 throw new AppException(HttpStatus.SC_UNAUTHORIZED, "Invalid authorization header", "Authorization token cannot be empty");
@@ -75,5 +80,4 @@ public class RequestInfoImpl implements IRequestInfo {
             return "Bearer " + this.serviceAccountJwtClient.getIdToken(tenantInfo.getName());
         }
     }
-
 }
diff --git a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/ServiceAccountJwtClientImpl.java b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/ServiceAccountJwtClientImpl.java
index c3aad79a3..ae4e49f44 100644
--- a/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/ServiceAccountJwtClientImpl.java
+++ b/indexer-service-azure/src/main/java/org/opendes/indexer/azure/util/ServiceAccountJwtClientImpl.java
@@ -1,7 +1,10 @@
 package org.opendes.indexer.azure.util;
 
+import com.auth0.jwt.JWT;
 import com.auth0.jwt.exceptions.JWTDecodeException;
-import com.microsoft.aad.msal4j.*;
+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.opendes.core.cache.JwtCache;
 import org.opendes.core.logging.JaxRsDpsLog;
@@ -19,6 +22,7 @@ import org.springframework.web.context.annotation.RequestScope;
 
 
 import javax.naming.ServiceUnavailableException;
+import java.net.MalformedURLException;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -31,114 +35,60 @@ public class ServiceAccountJwtClientImpl implements IServiceAccountJwtClient {
     @Autowired
     private IHeadersInfo headersInfoAzure;
     @Autowired
+    private DpsHeaders dpsHeaders;
+    @Autowired
     private JwtCache cacheService;
     @Autowired
     private JaxRsDpsLog log;
 
     @Autowired
     private AADConfiguration configuration;
-//
-//    public String getIdToken(String tenantName) {
-//        this.log.info("Tenant name received for auth token is: " + tenantName);
-//        TenantInfo tenant = this.tenantInfoServiceProvider.getTenantInfo(tenantName);
-//        if (tenant == null) {
-//            this.log.error("Invalid tenant name receiving from azure");
-//            throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from azure");
-//        }
-//        String ACCESS_TOKEN = "";
-//        try {
-//
-//            IdToken cachedToken = this.cacheService.get(tenant.getServiceAccount());
-//            this.headersInfoAzure.getHeaders().put(DpsHeaders.USER_EMAIL, tenant.getServiceAccount());
-//
-//            if (!IdToken.refreshToken(cachedToken)) {
-//                ACCESS_TOKEN = cachedToken.getTokenValue();
-//            }
-//
-//            ExecutorService service = Executors.newFixedThreadPool(1);
-//            AuthenticationContext context = null;
-//
-//            try {
-//                context = new AuthenticationContext(configuration.getAuthority(), false, service);
-//                ClientCredential credential = new ClientCredential(configuration.getClientId(), configuration.getSecretKey());
-//                Future<AuthenticationResult> future = context.acquireToken(configuration.getOboApi(), credential, null);
-//
-//                ACCESS_TOKEN =  future.get().getAccessToken();
-//
-//                if (future == null) {
-//                    log.error(String.format("Azure Authentication: %s", future.get().getAccessToken()));
-//                    throw new AppException(HttpStatus.SC_FORBIDDEN, "Access denied", "The user is not authorized to perform this action");
-//                }
-//                IdToken idToken = IdToken.builder().tokenValue(ACCESS_TOKEN).expirationTimeMillis(JWT.decode(ACCESS_TOKEN).getExpiresAt().getTime()).build();
-//
-//                this.cacheService.put(tenant.getServiceAccount(), idToken);
-//
-//            } catch (InterruptedException e) {
-//                e.printStackTrace();
-//            } catch (ExecutionException e) {
-//                e.printStackTrace();
-//            } catch (MalformedURLException e) {
-//                e.printStackTrace();
-//            } finally {
-//                service.shutdown();
-//            }
-//        } catch (JWTDecodeException e) {
-//            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Invalid token, error decoding", e);
-//        } catch (AppException e) {
-//            throw e;
-//        } catch (Exception e) {
-//            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Error generating token", e);
-//        }
-//
-//        return ACCESS_TOKEN;
-//    }
 
     public String getIdToken(String tenantName) {
-
         this.log.info("Tenant name received for auth token is: " + tenantName);
         TenantInfo tenant = this.tenantInfoServiceProvider.getTenantInfo(tenantName);
         if (tenant == null) {
             this.log.error("Invalid tenant name receiving from azure");
             throw new AppException(HttpStatus.SC_BAD_REQUEST, "Invalid tenant Name", "Invalid tenant Name from azure");
         }
-
-        String authToken = "";
-        IAuthenticationResult updatedResult;
+        String ACCESS_TOKEN = "";
         try {
 
             IdToken cachedToken = this.cacheService.get(tenant.getServiceAccount());
             this.headersInfoAzure.getHeaders().put(DpsHeaders.USER_EMAIL, tenant.getServiceAccount());
+            this.dpsHeaders.put(DpsHeaders.USER_EMAIL, tenant.getServiceAccount());
 
             if (!IdToken.refreshToken(cachedToken)) {
-               authToken = cachedToken.getTokenValue();
-               return authToken;
+                ACCESS_TOKEN = cachedToken.getTokenValue();
             }
 
-            ConfidentialClientApplication application = ConfidentialClientApplication.builder(
-                    configuration.getClientId(),
-                    ClientCredentialFactory.create(configuration.getSecretKey()))
-                    .authority(configuration.getAuthority())
-                    .build();
+            ExecutorService service = Executors.newFixedThreadPool(1);
+            AuthenticationContext context = null;
+
+            try {
+                context = new AuthenticationContext(configuration.getAuthority(), false, service);
+                ClientCredential credential = new ClientCredential(configuration.getClientId(), configuration.getSecretKey());
+                Future<AuthenticationResult> future = context.acquireToken(configuration.getOboApi(), credential, null);
+
+                ACCESS_TOKEN =  future.get().getAccessToken();
 
-            SilentParameters silentParameters =
-                    SilentParameters.builder(Collections.singleton(configuration.getOboApi()))
-                            .build();
-            CompletableFuture<IAuthenticationResult> auth = application.acquireTokenSilently(silentParameters);
+                if (future == null) {
+                    log.error(String.format("Azure Authentication: %s", future.get().getAccessToken()));
+                    throw new AppException(HttpStatus.SC_FORBIDDEN, "Access denied", "The user is not authorized to perform this action");
+                }
+                IdToken idToken = IdToken.builder().tokenValue(ACCESS_TOKEN).expirationTimeMillis(JWT.decode(ACCESS_TOKEN).getExpiresAt().getTime()).build();
 
-            updatedResult =  auth.join();
+                this.cacheService.put(tenant.getServiceAccount(), idToken);
 
-            if (updatedResult == null) {
-                throw new ServiceUnavailableException("authentication result was null");
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (ExecutionException e) {
+                e.printStackTrace();
+            } catch (MalformedURLException e) {
+                e.printStackTrace();
+            } finally {
+                service.shutdown();
             }
-//            if (updatedResult == null){
-//                OnBehalfOfParameters parameters =
-//                        OnBehalfOfParameters.builder(Collections.singleton(configuration.getOboApi()),
-//                                new UserAssertion(authToken))
-//                                .build();
-//
-//                updatedResult = application.acquireToken(parameters).join();
-//            }
-            authToken = updatedResult.accessToken();
         } catch (JWTDecodeException e) {
             throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Invalid token, error decoding", e);
         } catch (AppException e) {
@@ -147,6 +97,6 @@ public class ServiceAccountJwtClientImpl implements IServiceAccountJwtClient {
             throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Persistence error", "Error generating token", e);
         }
 
-        return authToken;
+        return ACCESS_TOKEN;
     }
 }
-- 
GitLab