This is an automated email from the ASF dual-hosted git repository.

akshayrai09 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new d64aa98  [TE] Authorize service account to prevent config modification 
(#4341)
d64aa98 is described below

commit d64aa983e56c66265b3be794491edd10f884cbd1
Author: Akshay Rai <[email protected]>
AuthorDate: Thu Jun 20 15:02:35 2019 -0700

    [TE] Authorize service account to prevent config modification (#4341)
---
 .../datalayer/pojo/DetectionAlertConfigBean.java   |   9 ++
 .../datalayer/pojo/DetectionConfigBean.java        |   9 ++
 .../thirdeye/detection/yaml/YamlResource.java      | 107 ++++++++++++++++++---
 .../yaml/translator/ConfigTranslator.java          |  13 +++
 .../yaml/translator/DetectionConfigTranslator.java |   3 +
 .../translator/SubscriptionConfigTranslator.java   |   2 +
 .../thirdeye/detection/yaml/YamlResourceTest.java  |  21 ++--
 7 files changed, 141 insertions(+), 23 deletions(-)

diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionAlertConfigBean.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionAlertConfigBean.java
index 8bbda0e..38bcf94 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionAlertConfigBean.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionAlertConfigBean.java
@@ -51,6 +51,15 @@ public class DetectionAlertConfigBean extends AbstractBean {
   Map<String, Object> properties;
 
   Map<String, String> refLinks;
+  List<String> owners;
+
+  public List<String> getOwners() {
+    return owners;
+  }
+
+  public void setOwners(List<String> owners) {
+    this.owners = owners;
+  }
 
   public boolean isActive() {
     return active;
diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionConfigBean.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionConfigBean.java
index eee4c45..01d6996 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionConfigBean.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/datalayer/pojo/DetectionConfigBean.java
@@ -43,6 +43,15 @@ public class DetectionConfigBean extends AbstractBean {
   String yaml;
   Map<String, Object> componentSpecs;
   long lastTuningTimestamp;
+  List<String> owners;
+
+  public List<String> getOwners() {
+    return owners;
+  }
+
+  public void setOwners(List<String> owners) {
+    this.owners = owners;
+  }
 
   public Map<String, Object> getComponentSpecs() {
     return componentSpecs;
diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/YamlResource.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/YamlResource.java
index d6e6b32..a590948 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/YamlResource.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/YamlResource.java
@@ -22,6 +22,7 @@ package org.apache.pinot.thirdeye.detection.yaml;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
+import io.dropwizard.auth.Auth;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -34,9 +35,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
+import javax.annotation.security.PermitAll;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.NotAuthorizedException;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
@@ -49,6 +52,7 @@ import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.pinot.thirdeye.anomaly.task.TaskConstants;
 import org.apache.pinot.thirdeye.api.Constants;
+import org.apache.pinot.thirdeye.auth.ThirdEyePrincipal;
 import org.apache.pinot.thirdeye.dataframe.util.MetricSlice;
 import org.apache.pinot.thirdeye.datalayer.bao.DatasetConfigManager;
 import org.apache.pinot.thirdeye.datalayer.bao.DetectionAlertConfigManager;
@@ -57,9 +61,11 @@ import 
org.apache.pinot.thirdeye.datalayer.bao.EvaluationManager;
 import org.apache.pinot.thirdeye.datalayer.bao.EventManager;
 import org.apache.pinot.thirdeye.datalayer.bao.MergedAnomalyResultManager;
 import org.apache.pinot.thirdeye.datalayer.bao.MetricConfigManager;
+import org.apache.pinot.thirdeye.datalayer.bao.SessionManager;
 import org.apache.pinot.thirdeye.datalayer.bao.TaskManager;
 import org.apache.pinot.thirdeye.datalayer.dto.DetectionAlertConfigDTO;
 import org.apache.pinot.thirdeye.datalayer.dto.DetectionConfigDTO;
+import org.apache.pinot.thirdeye.datalayer.dto.SessionDTO;
 import org.apache.pinot.thirdeye.datalayer.dto.TaskDTO;
 import org.apache.pinot.thirdeye.datalayer.util.Predicate;
 import org.apache.pinot.thirdeye.datasource.DAORegistry;
@@ -106,6 +112,10 @@ public class YamlResource {
   private static final String PROP_SUBS_GROUP_NAME = "subscriptionGroupName";
   private static final String PROP_DETECTION_NAME = "detectionName";
 
+  private static final String PROP_SESSION_KEY = "sessionKey";
+  private static final String PROP_PRINCIPAL_TYPE = "principalType";
+  private static final String PROP_SERVICE = "SERVICE";
+
   // default onboarding replay period
   private static final long ONBOARDING_REPLAY_LOOKBACK = 
TimeUnit.DAYS.toMillis(30);
 
@@ -120,6 +130,7 @@ public class YamlResource {
   private final MergedAnomalyResultManager anomalyDAO;
   private final EvaluationManager evaluationDAO;
   private final TaskManager taskDAO;
+  private final SessionManager sessionDAO;
   private final DetectionPipelineLoader loader;
   private final Yaml yaml;
 
@@ -132,6 +143,7 @@ public class YamlResource {
     this.anomalyDAO = DAORegistry.getInstance().getMergedAnomalyResultDAO();
     this.taskDAO = DAORegistry.getInstance().getTaskDAO();
     this.evaluationDAO = DAORegistry.getInstance().getEvaluationManager();
+    this.sessionDAO = DAORegistry.getInstance().getSessionDAO();
     this.yaml = new Yaml();
 
     TimeSeriesLoader timeseriesLoader =
@@ -222,12 +234,23 @@ public class YamlResource {
     return Response.serverError().entity(responseMessage).build();
   }
 
+  private Response processBadAuthorizationResponse(String type, String 
operation, String payload, NotAuthorizedException e) {
+    Map<String, String> responseMessage = new HashMap<>();
+    LOG.warn("Authorization error while {} {} with payload {}", operation, 
type, payload, e);
+    responseMessage.put(type + "Msg", "Authorization Error!");
+    responseMessage.put(type + "Msg-moreInfo", "Configure owners property in " 
+ type + " config");
+    return 
Response.status(Response.Status.UNAUTHORIZED).entity(responseMessage).build();
+  }
+
   @POST
   @Path("/create-alert")
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
+  @PermitAll
   @ApiOperation("Use yaml to create both subscription and detection yaml. ")
-  public Response createYamlAlert(@ApiParam(value =  "a json contains both 
subscription and detection yaml as string")  String payload,
+  public Response createYamlAlert(
+      @Auth ThirdEyePrincipal user,
+      @ApiParam(value =  "a json contains both subscription and detection yaml 
as string")  String payload,
       @ApiParam("tuning window start time for tunable components") 
@QueryParam("startTime") long startTime,
       @ApiParam("tuning window end time for tunable components") 
@QueryParam("endTime") long endTime) throws Exception {
     Map<String, String> yamls;
@@ -266,16 +289,18 @@ public class YamlResource {
       List<DetectionAlertConfigDTO> alertConfigDTOS = 
detectionAlertConfigDAO.findByPredicate(Predicate.EQ("name", groupName));
       if (!alertConfigDTOS.isEmpty()) {
         detectionAlertConfigId = alertConfigDTOS.get(0).getId();
-        updateSubscriptionGroup(detectionAlertConfigId, subscriptionYaml);
+        updateSubscriptionGroup(user, detectionAlertConfigId, 
subscriptionYaml);
       } else {
         detectionAlertConfigId = createSubscriptionGroup(subscriptionYaml);
       }
     } catch (IllegalArgumentException e) {
       this.detectionConfigDAO.deleteById(detectionConfigId);
-      return processBadRequestResponse(PROP_SUBSCRIPTION, 
YamlOperations.CREATING.name(), payload, e);
+      return processBadRequestResponse(PROP_SUBSCRIPTION, 
YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, 
e);
+    } catch (NotAuthorizedException e) {
+      return processBadAuthorizationResponse(PROP_SUBSCRIPTION, 
YamlOperations.UPDATING.name(), payload, e);
     } catch (Exception e) {
       this.detectionConfigDAO.deleteById(detectionConfigId);
-      return processServerErrorResponse(PROP_DETECTION, 
YamlOperations.CREATING.name(), payload, e);
+      return processServerErrorResponse(PROP_DETECTION, 
YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, 
e);
     }
 
     // create an yaml onboarding task to run replay and tuning
@@ -345,16 +370,18 @@ public class YamlResource {
     return Response.ok().entity(responseMessage).build();
   }
 
-  void updateDetectionPipeline(long detectionID, String yamlDetectionConfig) {
-    updateDetectionPipeline(detectionID, yamlDetectionConfig, 0, 0);
+  private void updateDetectionPipeline(ThirdEyePrincipal user, long 
detectionID, String yamlDetectionConfig) {
+    updateDetectionPipeline(user, detectionID, yamlDetectionConfig, 0, 0);
   }
 
-  void updateDetectionPipeline(long detectionID, String payload, long 
startTime, long endTime)
+  private void updateDetectionPipeline(ThirdEyePrincipal user, long 
detectionID, String payload, long startTime, long endTime)
       throws IllegalArgumentException {
     DetectionConfigDTO existingDetectionConfig = 
this.detectionConfigDAO.findById(detectionID);
     DetectionConfigDTO detectionConfig;
     Preconditions.checkNotNull(existingDetectionConfig, "Cannot find detection 
pipeline " + detectionID);
     Preconditions.checkArgument(StringUtils.isNotBlank(payload), "The Yaml 
Payload in the request is empty.");
+
+    authorizeUser(user, detectionID, PROP_DETECTION);
     try {
       detectionConfig = buildDetectionConfigFromYaml(startTime, endTime, 
payload, existingDetectionConfig);
 
@@ -375,6 +402,43 @@ public class YamlResource {
     }
   }
 
+  private boolean isServiceAccount(ThirdEyePrincipal user) {
+    List<Predicate> predicates = new ArrayList<>();
+    predicates.add(Predicate.EQ(PROP_SESSION_KEY, user.getSessionKey()));
+    predicates.add(Predicate.EQ(PROP_PRINCIPAL_TYPE, PROP_SERVICE));
+
+    List<SessionDTO> sessionDTO = 
this.sessionDAO.findByPredicate(Predicate.AND(predicates.toArray(new 
Predicate[0])));
+    return sessionDTO != null && !sessionDTO.isEmpty();
+  }
+
+  private void validateConfigOwner(ThirdEyePrincipal user, List<String> 
owners) {
+    if (owners == null || !owners.contains(user.getName())) {
+      throw new NotAuthorizedException("Service account " + user.getName() + " 
is not authorized to access this resource.");
+    }
+  }
+
+  /**
+   * Enforce authorization only with service accounts to prevent risk
+   * of modifying other configs when making programmatic calls.
+   */
+  private void authorizeUser(ThirdEyePrincipal user, long id, String 
authEntity) {
+    if (user == null || StringUtils.isBlank(user.getName()) || 
StringUtils.isBlank(user.getSessionKey())) {
+      throw new NotAuthorizedException("Unable to find the credentials/token 
in the request");
+    }
+
+    // Authorize only service accounts
+    if (isServiceAccount(user)) {
+      if (authEntity.equals(PROP_DETECTION)) {
+        DetectionConfigDTO detectionConfig = 
this.detectionConfigDAO.findById(id);
+        validateConfigOwner(user, detectionConfig.getOwners());
+      } else if (authEntity.equals(PROP_SUBSCRIPTION)) {
+        DetectionAlertConfigDTO subscriptionConfig = 
this.detectionAlertConfigDAO.findById(id);
+        validateConfigOwner(user, subscriptionConfig.getOwners());
+      }
+    }
+    LOG.info("User " + user.getName() + " authorized successfully");
+  }
+
   /**
    Edit a detection pipeline using a YAML config
    @param payload YAML config string
@@ -387,17 +451,21 @@ public class YamlResource {
   @Path("/{id}")
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.TEXT_PLAIN)
+  @PermitAll
   @ApiOperation("Edit a detection pipeline using a YAML config")
   public Response updateDetectionPipelineApi(
+      @Auth ThirdEyePrincipal user,
       @ApiParam("yaml config") String payload,
       @ApiParam("the detection config id to edit") @PathParam("id") long id,
       @ApiParam("tuning window start time for tunable components")  
@QueryParam("startTime") long startTime,
       @ApiParam("tuning window end time for tunable components") 
@QueryParam("endTime") long endTime) {
     Map<String, String> responseMessage = new HashMap<>();
     try {
-      updateDetectionPipeline(id, payload, startTime, endTime);
+      updateDetectionPipeline(user, id, payload, startTime, endTime);
     } catch (IllegalArgumentException e) {
       return processBadRequestResponse(PROP_DETECTION, 
YamlOperations.UPDATING.name(), payload, e);
+    } catch (NotAuthorizedException e) {
+      return processBadAuthorizationResponse(PROP_DETECTION, 
YamlOperations.UPDATING.name(), payload, e);
     } catch (Exception e) {
       return processServerErrorResponse(PROP_DETECTION, 
YamlOperations.UPDATING.name(), payload, e);
     }
@@ -427,13 +495,13 @@ public class YamlResource {
     return existingDetectionConfig;
   }
 
-  long createOrUpdateDetectionPipeline(String payload) {
+  long createOrUpdateDetectionPipeline(ThirdEyePrincipal user, String payload) 
{
     Preconditions.checkArgument(StringUtils.isNotBlank(payload), "The Yaml 
Payload in the request is empty.");
     long detectionId;
     DetectionConfigDTO existingDetection = fetchExistingDetection(payload);
     if (existingDetection != null) {
       detectionId = existingDetection.getId();
-      updateDetectionPipeline(detectionId, payload);
+      updateDetectionPipeline(user, detectionId, payload);
     } else {
       detectionId = createDetectionPipeline(payload);
     }
@@ -450,14 +518,19 @@ public class YamlResource {
   @Path("/create-or-update")
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.TEXT_PLAIN)
+  @PermitAll
   @ApiOperation("Create a new detection pipeline or update existing if one 
already exists")
-  public Response createOrUpdateDetectionPipelineApi(@ApiParam("yaml config") 
String payload) {
+  public Response createOrUpdateDetectionPipelineApi(
+      @Auth ThirdEyePrincipal user,
+      @ApiParam("yaml config") String payload) {
     Map<String, String> responseMessage = new HashMap<>();
     long detectionConfigId;
     try {
-      detectionConfigId = createOrUpdateDetectionPipeline(payload);
+      detectionConfigId = createOrUpdateDetectionPipeline(user, payload);
     } catch (IllegalArgumentException e) {
       return processBadRequestResponse(PROP_DETECTION, 
YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, 
e);
+    } catch (NotAuthorizedException e) {
+      return processBadAuthorizationResponse(PROP_DETECTION, 
YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, 
e);
     } catch (Exception e) {
       return processServerErrorResponse(PROP_DETECTION, 
YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, 
e);
     }
@@ -533,17 +606,19 @@ public class YamlResource {
     oldAlertConfig.setAlertSuppressors(newAlertConfig.getAlertSuppressors());
     oldAlertConfig.setProperties(newAlertConfig.getProperties());
     oldAlertConfig.setYaml(newAlertConfig.getYaml());
+    oldAlertConfig.setOwners(newAlertConfig.getOwners());
 
     return oldAlertConfig;
   }
 
-  void updateSubscriptionGroup(long oldAlertConfigID, String yamlConfig) {
+  void updateSubscriptionGroup(ThirdEyePrincipal user, long oldAlertConfigID, 
String yamlConfig) {
     DetectionAlertConfigDTO oldAlertConfig = 
this.detectionAlertConfigDAO.findById(oldAlertConfigID);
     if (oldAlertConfig == null) {
       throw new RuntimeException("Cannot find subscription group " + 
oldAlertConfigID);
     }
     Preconditions.checkArgument(StringUtils.isNotBlank(yamlConfig), "The Yaml 
Payload in the request is empty.");
 
+    authorizeUser(user, oldAlertConfigID, PROP_SUBSCRIPTION);
     DetectionAlertConfigDTO newAlertConfig = new 
SubscriptionConfigTranslator(detectionConfigDAO, yamlConfig).translate();
     DetectionAlertConfigDTO updatedAlertConfig = 
updateDetectionAlertConfig(oldAlertConfig, newAlertConfig);
 
@@ -577,15 +652,19 @@ public class YamlResource {
   @Path("/subscription/{id}")
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.TEXT_PLAIN)
+  @PermitAll
   @ApiOperation("Edit a subscription group using a YAML config")
   public Response updateSubscriptionGroupApi(
+      @Auth ThirdEyePrincipal user,
       @ApiParam("payload") String payload,
       @ApiParam("the detection alert config id to edit") @PathParam("id") long 
id) {
     Map<String, String> responseMessage = new HashMap<>();
     try {
-      updateSubscriptionGroup(id, payload);
+      updateSubscriptionGroup(user, id, payload);
     } catch (IllegalArgumentException e) {
       return processBadRequestResponse(PROP_SUBSCRIPTION, 
YamlOperations.UPDATING.name(), payload, e);
+    } catch (NotAuthorizedException e) {
+      return processBadAuthorizationResponse(PROP_SUBSCRIPTION, 
YamlOperations.UPDATING.name(), payload, e);
     } catch (Exception e) {
       return processServerErrorResponse(PROP_SUBSCRIPTION, 
YamlOperations.UPDATING.name(), payload, e);
     }
diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/ConfigTranslator.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/ConfigTranslator.java
index a0f71c9..9a8a3e3 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/ConfigTranslator.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/ConfigTranslator.java
@@ -19,7 +19,10 @@
 
 package org.apache.pinot.thirdeye.detection.yaml.translator;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import org.apache.pinot.thirdeye.datalayer.dto.AbstractDTO;
 import org.apache.pinot.thirdeye.detection.ConfigUtils;
@@ -42,6 +45,16 @@ public abstract class ConfigTranslator<T extends 
AbstractDTO, V extends ConfigVa
     this.yaml = new Yaml();
   }
 
+  List<String> filterOwners(List<String> configuredOwners) {
+    List<String> owners = new ArrayList<>();
+    for (String configuredOwner : configuredOwners) {
+      // TODO: check if configured owner is a valid account
+      owners.add(configuredOwner.trim());
+    }
+    // Return after removing duplicates
+    return new ArrayList<>(new HashSet<>(owners));
+  }
+
   abstract T translateConfig(Map<String, Object> yamlConfigMap) throws 
IllegalArgumentException;
 
   /**
diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/DetectionConfigTranslator.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/DetectionConfigTranslator.java
index 7e76d5b..9a5c5cb 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/DetectionConfigTranslator.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/DetectionConfigTranslator.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -156,6 +157,7 @@ public class DetectionConfigTranslator extends 
ConfigTranslator<DetectionConfigD
   private static final String PROP_DETECTION_NAME = "detectionName";
   private static final String PROP_DESC_NAME = "description";
   private static final String PROP_ACTIVE = "active";
+  private static final String PROP_OWNERS = "owners";
 
   private static final String PROP_ALERTS = "alerts";
   private static final String COMPOSITE_ALERT = "COMPOSITE_ALERT";
@@ -495,6 +497,7 @@ public class DetectionConfigTranslator extends 
ConfigTranslator<DetectionConfigD
     config.setName(MapUtils.getString(yamlConfigMap, PROP_DETECTION_NAME));
     config.setDescription(MapUtils.getString(yamlConfigMap, PROP_DESC_NAME));
     config.setLastTimestamp(System.currentTimeMillis());
+    
config.setOwners(filterOwners(ConfigUtils.getList(yamlConfigMap.get(PROP_OWNERS))));
 
     config.setProperties(properties);
     config.setComponentSpecs(components);
diff --git 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/SubscriptionConfigTranslator.java
 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/SubscriptionConfigTranslator.java
index ce75b16..bc037ca 100644
--- 
a/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/SubscriptionConfigTranslator.java
+++ 
b/thirdeye/thirdeye-pinot/src/main/java/org/apache/pinot/thirdeye/detection/yaml/translator/SubscriptionConfigTranslator.java
@@ -53,6 +53,7 @@ public class SubscriptionConfigTranslator extends 
ConfigTranslator<DetectionAler
   public static final String PROP_ACTIVE = "active";
   public static final String PROP_APPLICATION = "application";
   public static final String PROP_FROM = "fromAddress";
+  public static final String PROP_OWNERS = "owners";
   public static final String PROP_EMAIL_SUBJECT_TYPE = "emailSubjectStyle";
   public static final String PROP_ALERT_SCHEMES = "alertSchemes";
   public static final String PROP_DETECTION_NAMES = "subscribedDetections";
@@ -168,6 +169,7 @@ public class SubscriptionConfigTranslator extends 
ConfigTranslator<DetectionAler
     alertConfigDTO.setName(MapUtils.getString(yamlConfigMap, 
PROP_SUBS_GROUP_NAME));
     alertConfigDTO.setApplication(MapUtils.getString(yamlConfigMap, 
PROP_APPLICATION));
     alertConfigDTO.setFrom(MapUtils.getString(yamlConfigMap, PROP_FROM));
+    
alertConfigDTO.setOwners(filterOwners(ConfigUtils.getList(yamlConfigMap.get(PROP_OWNERS))));
 
     alertConfigDTO.setCronExpression(MapUtils.getString(yamlConfigMap, 
PROP_CRON, CRON_SCHEDULE_DEFAULT));
     alertConfigDTO.setActive(MapUtils.getBooleanValue(yamlConfigMap, 
PROP_ACTIVE, true));
diff --git 
a/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/yaml/YamlResourceTest.java
 
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/yaml/YamlResourceTest.java
index 76cfdb3..3180618 100644
--- 
a/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/yaml/YamlResourceTest.java
+++ 
b/thirdeye/thirdeye-pinot/src/test/java/org/apache/pinot/thirdeye/detection/yaml/YamlResourceTest.java
@@ -1,6 +1,7 @@
 package org.apache.pinot.thirdeye.detection.yaml;
 
 import java.util.concurrent.TimeUnit;
+import org.apache.pinot.thirdeye.auth.ThirdEyePrincipal;
 import org.apache.pinot.thirdeye.datalayer.bao.DAOTestBase;
 import org.apache.pinot.thirdeye.datalayer.bao.DetectionConfigManager;
 import org.apache.pinot.thirdeye.datalayer.dto.ApplicationDTO;
@@ -25,12 +26,14 @@ public class YamlResourceTest {
   private DAOTestBase testDAOProvider;
   private YamlResource yamlResource;
   private DAORegistry daoRegistry;
+  private ThirdEyePrincipal user;
   private static long alertId1;
   private static long alertId2;
 
   @BeforeMethod
   public void beforeClass() {
     testDAOProvider = DAOTestBase.getInstance();
+    this.user = new ThirdEyePrincipal("test", "test");
     this.yamlResource = new YamlResource();
     this.daoRegistry = DAORegistry.getInstance();
     DetectionConfigManager detectionDAO = 
this.daoRegistry.getDetectionConfigManager();
@@ -58,7 +61,7 @@ public class YamlResourceTest {
   public void testCreateOrUpdateDetectionConfig() throws IOException {
     String blankYaml = "";
     try {
-      this.yamlResource.createOrUpdateDetectionPipeline(blankYaml);
+      this.yamlResource.createOrUpdateDetectionPipeline(user, blankYaml);
       Assert.fail("Exception not thrown on empty yaml");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "The Yaml Payload in the request is 
empty.");
@@ -79,7 +82,7 @@ public class YamlResourceTest {
     // Create a new detection
     String validYaml = 
IOUtils.toString(this.getClass().getResourceAsStream("detection/detection-config-1.yaml"));
     try {
-      long id = this.yamlResource.createOrUpdateDetectionPipeline(validYaml);
+      long id = this.yamlResource.createOrUpdateDetectionPipeline(user, 
validYaml);
       DetectionConfigDTO detection = 
daoRegistry.getDetectionConfigManager().findById(id);
       Assert.assertNotNull(detection);
       Assert.assertEquals(detection.getName(), "testPipeline");
@@ -90,7 +93,7 @@ public class YamlResourceTest {
     // Update above created detection
     String updatedYaml = 
IOUtils.toString(this.getClass().getResourceAsStream("detection/detection-config-2.yaml"));
     try {
-      long id = this.yamlResource.createOrUpdateDetectionPipeline(updatedYaml);
+      long id = this.yamlResource.createOrUpdateDetectionPipeline(user, 
updatedYaml);
       DetectionConfigDTO detection = 
daoRegistry.getDetectionConfigManager().findById(id);
       Assert.assertNotNull(detection);
       Assert.assertEquals(detection.getName(), "testPipeline");
@@ -190,7 +193,7 @@ public class YamlResourceTest {
     DetectionAlertConfigDTO alertDTO;
 
     try {
-      this.yamlResource.updateSubscriptionGroup(-1, "");
+      this.yamlResource.updateSubscriptionGroup(user, -1, "");
       Assert.fail("Exception not thrown when the subscription group doesn't 
exist");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "Cannot find subscription group -1");
@@ -198,7 +201,7 @@ public class YamlResourceTest {
 
     String blankYaml = "";
     try {
-      this.yamlResource.updateSubscriptionGroup(oldId, blankYaml);
+      this.yamlResource.updateSubscriptionGroup(user, oldId, blankYaml);
       Assert.fail("Exception not thrown on empty yaml");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "The Yaml Payload in the request is 
empty.");
@@ -206,7 +209,7 @@ public class YamlResourceTest {
 
     String inValidYaml = "application:test:application";
     try {
-      this.yamlResource.updateSubscriptionGroup(oldId, inValidYaml);
+      this.yamlResource.updateSubscriptionGroup(user, oldId, inValidYaml);
       Assert.fail("Exception not thrown on empty yaml");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "Could not parse as map: 
application:test:application");
@@ -214,7 +217,7 @@ public class YamlResourceTest {
 
     String noSubscriptGroupYaml = "application: test_app";
     try {
-      this.yamlResource.updateSubscriptionGroup(oldId, noSubscriptGroupYaml);
+      this.yamlResource.updateSubscriptionGroup(user, oldId, 
noSubscriptGroupYaml);
       Assert.fail("Exception not thrown on empty yaml");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "Subscription group name field 
cannot be left empty.");
@@ -222,7 +225,7 @@ public class YamlResourceTest {
 
     String appFieldMissingYaml = 
IOUtils.toString(this.getClass().getResourceAsStream("alertconfig/alert-config-1.yaml"));
     try {
-      this.yamlResource.updateSubscriptionGroup(oldId, appFieldMissingYaml);
+      this.yamlResource.updateSubscriptionGroup(user, oldId, 
appFieldMissingYaml);
       Assert.fail("Exception not thrown on empty yaml");
     } catch (Exception e) {
       Assert.assertEquals(e.getMessage(), "Application field cannot be left 
empty");
@@ -230,7 +233,7 @@ public class YamlResourceTest {
 
     String validYaml2 = 
IOUtils.toString(this.getClass().getResourceAsStream("alertconfig/alert-config-5.yaml"));
     try {
-      this.yamlResource.updateSubscriptionGroup(oldId, validYaml2);
+      this.yamlResource.updateSubscriptionGroup(user, oldId, validYaml2);
       alertDTO = daoRegistry.getDetectionAlertConfigManager().findById(oldId);
       Assert.assertNotNull(alertDTO);
       Assert.assertEquals(alertDTO.getName(), "Subscription Group Name");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to