X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=it%2Fotf.git;a=blobdiff_plain;f=otf-service-api%2Fsrc%2Fmain%2Fjava%2Forg%2Foran%2Fotf%2Fapi%2Fservice%2Fimpl%2FTestInstanceServiceImpl.java;fp=otf-service-api%2Fsrc%2Fmain%2Fjava%2Forg%2Foran%2Fotf%2Fapi%2Fservice%2Fimpl%2FTestInstanceServiceImpl.java;h=d1712069a0c2582f829ba8c7d1395ee7e4f316d3;hp=0000000000000000000000000000000000000000;hb=14f6f95c84a4a1fa8774190db4a03fd0214ec55f;hpb=f49bd1efeaaddd4891c1f329b18d8cfb28b3e75b diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java new file mode 100644 index 0000000..d171206 --- /dev/null +++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java @@ -0,0 +1,807 @@ +/* Copyright (c) 2019 AT&T Intellectual Property. # +# # +# 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.oran.otf.api.service.impl; + +import org.oran.otf.api.Utilities; +import org.oran.otf.api.Utilities.LogLevel; +import org.oran.otf.api.handler.CamundaProcessExecutionHandler; +import org.oran.otf.api.service.TestInstanceService; +import org.oran.otf.common.model.Group; +import org.oran.otf.common.model.TestDefinition; +import org.oran.otf.common.model.TestInstance; +import org.oran.otf.common.model.User; +import org.oran.otf.common.model.local.BpmnInstance; +import org.oran.otf.common.model.local.TestInstanceCreateRequest; +import org.oran.otf.common.model.local.WorkflowRequest; +import org.oran.otf.common.repository.GroupRepository; +import org.oran.otf.common.repository.TestDefinitionRepository; +import org.oran.otf.common.repository.TestInstanceRepository; +import org.oran.otf.common.repository.UserRepository; +import org.oran.otf.common.utility.Utility; +import org.oran.otf.common.utility.database.Generic; +import org.oran.otf.common.utility.http.ResponseUtility; +import org.oran.otf.common.utility.permissions.PermissionChecker; +import org.oran.otf.common.utility.permissions.UserPermission; +import com.google.common.base.Strings; +import org.bson.types.ObjectId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.*; + +@Service +public class TestInstanceServiceImpl implements TestInstanceService { + @Autowired + CamundaProcessExecutionHandler camundaProcessExecutionHandler; + @Autowired + UserRepository userRepository; + @Autowired + TestInstanceRepository testInstanceRepository; + @Autowired + TestDefinitionRepository testDefinitionRepository; + @Autowired + GroupRepository groupRepository; + + private static final Logger logger = LoggerFactory.getLogger(TestInstanceServiceImpl.class); + private static final String logPrefix = Utility.getLoggerPrefix(); + + @Override + public Response execute(String testInstanceId, String authorization, WorkflowRequest request) { + try { + if (request == null) { + return ResponseUtility.Build.badRequestWithMessage("Request body is null."); + } + + // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request + // response. + if (!Utilities.isObjectIdValid(testInstanceId)) { + String error = + String.format( + "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).", + logPrefix, testInstanceId); + return ResponseUtility.Build.badRequestWithMessage(error); + } + + // Create an ObjectId now that we know the provided String was valid. + ObjectId oiTestInstanceId = new ObjectId(testInstanceId); + // Check if the testInstance exists, otherwise return a not found response. + TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId); + if (testInstance == null) { + String error = + String.format( + "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId); + return ResponseUtility.Build.notFoundWithMessage(error); + } + // Check if the testDefinition exists. + TestDefinition testDefinition = + Generic.findByIdGeneric(testDefinitionRepository, testInstance.getTestDefinitionId()); + if (testDefinition == null) { + String error = + String.format( + "%sThe testDefinition with _id, %s, was not found.", + logPrefix, testInstance.getTestDefinitionId().toString()); + return ResponseUtility.Build.notFoundWithMessage(error); + } + + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format( + "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // If the mechanizedId is not an OTF mechanizedId, check if the user is authorized to + // execute + // the test instance. This is required because the executorId only needs to be read from the + // otf-frontend component. The user/group system is not fully integrated with AAF, so this + // is + // required. A better way might be to use certificates to check identities. + Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString())); + // if we cant find the test instance group then we cant check the permission + if (testInstanceGroup == null) { + return ResponseUtility.Build. + badRequestWithMessage( + String.format("Can not find test instance group, id:%s", testInstance.getGroupId().toString())); + } + // If the mechanizedId is authorized, set the executorId in the WorkflowRequest to the + // mechanizedId's ObjectId to make sure that the executorId isn't spoofed. Only use the + // executorId sent with the request if it uses the OTF mechanizedId because we "trust" it. + if (isOtfMechanizedIdentifier(mechanizedIdUser.getEmail()) && request.getExecutorId() != null) { + mechanizedIdUser = Utilities.resolveOptional(userRepository.findById(request.getExecutorId().toString())); + } else { + request.setExecutorId(mechanizedIdUser.get_id()); + } + if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup, UserPermission.Permission.EXECUTE,groupRepository)) { + String error = + String.format( + "%sUnauthorized the execute test instance with _id, %s.", + logPrefix, testInstanceId); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Set the test instance _id after authorization. + request.setTestInstanceId(testInstance.get_id()); + + // Check if the test instance is disabled. + if (testInstance.isDisabled()) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("The test instance with identifier %s is disabled.", testInstanceId)); + } + // Check if the test definition is disabled. + if (testDefinition.isDisabled()) { + return ResponseUtility.Build.badRequestWithMessage( + String.format( + "The test definition with identifier %s is disabled.", + testInstance.getTestDefinitionId().toString())); + } + + // Send the request to Camunda. + return camundaProcessExecutionHandler.startProcessInstance(request); + } catch (Exception e) { + Utilities.printStackTrace(e, LogLevel.ERROR); + return ResponseUtility.Build.internalServerError(); + } + } + + @Override + public Response createByTestDefinitionId( + String testDefinitionId, String authorization, TestInstanceCreateRequest request) { + try { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format( + "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Check if the String correctly parses as an ObjectId. + if (!Utilities.isObjectIdValid(testDefinitionId)) { + return ResponseUtility.Build.badRequestWithMessage( + String.format( + "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId)); + } + ObjectId oiTestDefintionId = new ObjectId(testDefinitionId); + + // Find the testDefinition + TestDefinition testDefinition = + Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId); + if (testDefinition == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format("Test definition with id, %s, was not found.", testDefinitionId)); + } + // Check if the mechanizedId has access to the test definition. + Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString())); + if (testDefGroup == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString())); + } +// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have read access to test definition in group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } +// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have write access to the group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } + if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup, + Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository)) + { + return ResponseUtility.Build.unauthorizedWithMessage( + String.format( + "MechanizedId, %s, does not have access (read/write) to the group with name, %s", + mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); + } + // Get the latest version of the test definition to link it with the test instance + BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, true); + if (bpmnInstance == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with id, %s, does not have any versions associated with it.", + testDefinitionId)); + } + + TestInstance testInstance = + new TestInstance( + new ObjectId(), + request.getTestInstanceName(), + request.getTestInstanceDescription(), + testDefinition.getGroupId(), + testDefinition.get_id(), + bpmnInstance.getProcessDefinitionId(), + request.isUseLatestTestDefinition(), + false, + request.isSimulationMode(), + request.getMaxExecutionTimeInMillis(), + request.getPfloInput(), + new HashMap<>(), + request.getSimulationVthInput(), + request.getTestData(), + request.getVthInput(), + new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis()), + mechanizedIdUser.get_id(), + mechanizedIdUser.get_id()); + + return Response.ok() + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(testInstance.toString()) + .build(); + } catch (Exception e) { + Utilities.printStackTrace(e, LogLevel.ERROR); + return ResponseUtility.Build.internalServerError(); + } + } + + @Override + public Response createByTestDefinitionId( + String testDefinitionId, + int version, + String authorization, + TestInstanceCreateRequest request) { + try { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format( + "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Check if the String correctly parses as an ObjectId. + if (!Utilities.isObjectIdValid(testDefinitionId)) { + return ResponseUtility.Build.badRequestWithMessage( + String.format( + "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId)); + } + ObjectId oiTestDefintionId = new ObjectId(testDefinitionId); + + // Find the testDefinition + TestDefinition testDefinition = + Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId); + if (testDefinition == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format("Test definition with id, %s, was not found.", testDefinitionId)); + } + // permission checking + Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString())); + if (testDefGroup == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString())); + } + // if not otf email and is not authorized +// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) { +//// return ResponseUtility.Build.unauthorizedWithMessage( +//// String.format( +//// "MechanizedId, %s, does not have read access to test definition in group with name, %s", +//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +//// } +//// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) { +//// return ResponseUtility.Build.unauthorizedWithMessage( +//// String.format( +//// "MechanizedId, %s, does not have write access to the group with name, %s", +//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +//// } + if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup, + Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository)) + { + return ResponseUtility.Build.unauthorizedWithMessage( + String.format( + "MechanizedId, %s, does not have access (read/write) to the group with name, %s", + mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); + } + // Get the latest version of the test definition to link it with the test instance + BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false); + if (bpmnInstance == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with id, %s, does not have any versions associated with it.", + testDefinitionId)); + } + + TestInstance testInstance = + new TestInstance( + new ObjectId(), + request.getTestInstanceName(), + request.getTestInstanceDescription(), + testDefinition.getGroupId(), + testDefinition.get_id(), + bpmnInstance.getProcessDefinitionId(), + request.isUseLatestTestDefinition(), + false, + request.isSimulationMode(), + request.getMaxExecutionTimeInMillis(), + request.getPfloInput(), + new HashMap<>(), + request.getSimulationVthInput(), + request.getTestData(), + request.getVthInput(), + new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis()), + mechanizedIdUser.get_id(), + mechanizedIdUser.get_id()); + + return Response.ok() + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(testInstance.toString()) + .build(); + } catch (Exception e) { + Utilities.printStackTrace(e, LogLevel.ERROR); + return ResponseUtility.Build.internalServerError(); + } + } + + @Override + public Response createByProcessDefinitionKey( + String processDefinitionKey, String authorization, TestInstanceCreateRequest request) { + try { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format( + "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Check if the String correctly parses as an ObjectId. + if (Strings.isNullOrEmpty(processDefinitionKey)) { + return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required."); + } + + // Find the testDefinition + TestDefinition testDefinition = + testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null); + if (testDefinition == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with processDefinitionKey, %s, was not found.", + processDefinitionKey)); + } + + Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString())); + if (testDefGroup == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString())); + } + // if not otf email and is not authorized +// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have read access to test definition in group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } +// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have write access to the group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } + if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup, + Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository)) + { + return ResponseUtility.Build.unauthorizedWithMessage( + String.format( + "MechanizedId, %s, does not have access (read/write) to the group with name, %s", + mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); + } + // Get the latest version of the test definition to link it with the test instance + BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, false); + if (bpmnInstance == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with id, %s, does not have any versions associated with it.", + testDefinition.get_id().toString())); + } + + TestInstance testInstance = + new TestInstance( + new ObjectId(), + request.getTestInstanceName(), + request.getTestInstanceDescription(), + testDefinition.getGroupId(), + testDefinition.get_id(), + bpmnInstance.getProcessDefinitionId(), + request.isUseLatestTestDefinition(), + false, + request.isSimulationMode(), + request.getMaxExecutionTimeInMillis(), + request.getPfloInput(), + new HashMap<>(), + request.getSimulationVthInput(), + request.getTestData(), + request.getVthInput(), + new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis()), + mechanizedIdUser.get_id(), + mechanizedIdUser.get_id()); + + return Response.ok() + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(testInstance.toString()) + .build(); + } catch (Exception e) { + Utilities.printStackTrace(e, LogLevel.ERROR); + return ResponseUtility.Build.internalServerError(); + } + } + + @Override + public Response createByProcessDefinitionKey( + String processDefinitionKey, + int version, + String authorization, + TestInstanceCreateRequest request) { + try { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format( + "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Check if the String correctly parses as an ObjectId. + if (Strings.isNullOrEmpty(processDefinitionKey)) { + return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required."); + } + + // Find the testDefinition + TestDefinition testDefinition = + testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null); + if (testDefinition == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with processDefinitionKey, %s, was not found.", + processDefinitionKey)); + } + + Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString())); + if (testDefGroup == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString())); + } + // if not otf email and is not authorized +// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have read access to test definition in group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } +// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) { +// return ResponseUtility.Build.unauthorizedWithMessage( +// String.format( +// "MechanizedId, %s, does not have write access to the group with name, %s", +// mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); +// } + if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup, + Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository)) + { + return ResponseUtility.Build.unauthorizedWithMessage( + String.format( + "MechanizedId, %s, does not have access (read/write) to the group with name, %s", + mechanizedIdUser.getEmail(), testDefGroup.getGroupName())); + } + // Get the latest version of the test definition to link it with the test instance + BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false); + if (bpmnInstance == null) { + return ResponseUtility.Build.notFoundWithMessage( + String.format( + "Test definition with id, %s, does not have any versions associated with it.", + testDefinition.get_id().toString())); + } + + TestInstance testInstance = + new TestInstance( + new ObjectId(), + request.getTestInstanceName(), + request.getTestInstanceDescription(), + testDefinition.getGroupId(), + testDefinition.get_id(), + bpmnInstance.getProcessDefinitionId(), + request.isUseLatestTestDefinition(), + false, + request.isSimulationMode(), + request.getMaxExecutionTimeInMillis(), + request.getPfloInput(), + new HashMap<>(), + request.getSimulationVthInput(), + request.getTestData(), + request.getVthInput(), + new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis()), + mechanizedIdUser.get_id(), + mechanizedIdUser.get_id()); + + return Response.ok() + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(testInstance.toString()) + .build(); + } catch (Exception e) { + Utilities.printStackTrace(e, LogLevel.ERROR); + return ResponseUtility.Build.internalServerError(); + } + } + + @Override + public Response findById(String testInstanceId, String authorization) { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request + // response. + if (!Utilities.isObjectIdValid(testInstanceId)) { + String error = + String.format( + "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).", + logPrefix, testInstanceId); + return ResponseUtility.Build.badRequestWithMessage(error); + } + + // Create an ObjectId now that we know the provided String was valid. + ObjectId oiTestInstanceId = new ObjectId(testInstanceId); + // Check if the testInstance exists, otherwise return a not found response. + TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId); + if (testInstance == null) { + String error = + String.format( + "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId); + return ResponseUtility.Build.notFoundWithMessage(error); + } + + Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString())); + if (testInstanceGroup == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Can not find test instance's group, group name :%s", testInstance.get_id().toString())); + } + if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) { + return ResponseUtility.Build.unauthorizedWithMessage( + String.format( + "User %s does not have read access to test instance group, group name: %s.", + mechanizedIdUser.getEmail(), testInstanceGroup.getGroupName())); + } + return Response.ok(testInstance.toString(), MediaType.APPLICATION_JSON_TYPE).build(); + } + + @Override + public Response findByProcessDefinitionKey(String processDefinitionKey, String authorization) { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + Optional optionalTestDefinition = + testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey); + TestDefinition testDefinition = optionalTestDefinition.orElse(null); + if (testDefinition == null) { + return Utilities.Http.BuildResponse.badRequestWithMessage( + String.format( + "Cannot find test instance because a test" + + " definition with the process definition key (%s) does not exist.", + processDefinitionKey)); + } + + List testInstances = + testInstanceRepository.findAllByTestDefinitionId(testDefinition.get_id()); + if (testInstances.isEmpty()) { + return Utilities.Http.BuildResponse.badRequestWithMessage( + String.format( + "No test instances found with process " + "definition key (%s).", + processDefinitionKey)); + } + + List result = new ArrayList<>(); + for (TestInstance testInstance : testInstances) { + Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString())); + if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) { + result.add(testInstance); + } + } + + return Response.ok(result.toString()).build(); + } + + @Override + public Response findByProcessDefinitionKeyAndVersion( + String processDefinitionKey, String version, String authorization) { + // Check if a user associated with the mechanizedId used in the authorization header exists in + // the database. + User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository); + if (mechanizedIdUser == null) { + String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization); + if (decodedAuth == null) { + return ResponseUtility.Build.badRequestWithMessage( + String.format("Unable to decode authorization header: %s", authorization)); + } + String error = + String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]); + return ResponseUtility.Build.unauthorizedWithMessage(error); + } + + Optional optionalTestDefinition = + testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey); + TestDefinition testDefinition = optionalTestDefinition.orElse(null); + + if (testDefinition == null) { + return Utilities.Http.BuildResponse.badRequestWithMessage( + String.format( + "Cannot find test instance because a test" + + " definition with the process definition key (%s) does not exist.", + processDefinitionKey)); + } + + int iVersion; + try { + iVersion = Integer.parseInt(version); + } catch (NumberFormatException nfe) { + return Utilities.Http.BuildResponse.badRequestWithMessage("Version must be a valid integer."); + } + + BpmnInstance bpmnInstance = + testDefinition.getBpmnInstances().stream() + .filter(_bpmnInstance -> _bpmnInstance.getVersion() == iVersion) + .findAny() + .orElse(null); + + if (bpmnInstance == null) { + return Utilities.Http.BuildResponse.badRequestWithMessage( + String.format("Cannot find any test instances using " + "version %s.", version)); + } + + List testInstances = + testInstanceRepository.findAllByTestDefinitionIdAndPDId( + testDefinition.get_id(), bpmnInstance.getProcessDefinitionId()); + + if (testInstances.isEmpty()) { + return Utilities.Http.BuildResponse.badRequestWithMessage( + String.format( + "No test instances found with process " + "definition key (%s).", + processDefinitionKey)); + } + + List result = new ArrayList<>(); + for (TestInstance testInstance : testInstances) { + Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString())); + if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) { + result.add(testInstance); + } + } + + return Response.ok(result.toString()).build(); + } + + private boolean isOtfMechanizedIdentifier(String email) { + return email.equalsIgnoreCase("email@localhost") + || email.equalsIgnoreCase("email@localhost") + || email.equalsIgnoreCase("email@localhost") + || email.equalsIgnoreCase("email@localhost") + || email.equalsIgnoreCase("email@localhost"); + } + + private BpmnInstance findBpmnInstance(TestDefinition testDefinition, int version, boolean latest) + throws Exception { + BpmnInstance bpmnInstance = null; + int maxVersion = Integer.MIN_VALUE; + // Check if the version exists + for (BpmnInstance bi : testDefinition.getBpmnInstances()) { + // If this field is null or empty, it means the bpmn hasn't been deployed, or there was a + // creation error on the Test Definition page (UI). Skip the field so the user isn't allowed + // to create a test instance based off this bpmn instance. + if (Strings.isNullOrEmpty(bi.getProcessDefinitionId())) { + continue; + } + + // Split the processDefinitionId based on it's format: + // {processDefinitionKey}:{version}:{processDefinitionId}. + String processDefinitionId = bi.getProcessDefinitionId(); + String[] processDefinitionIdSplit = processDefinitionId.split(":"); + if (processDefinitionIdSplit.length != 3) { + throw new Exception( + String.format( + "testDefinition[%s].bpmnInstances.processDefinitionId[%s] is invalid.", + testDefinition.get_id().toString(), bi.getProcessDefinitionId())); + } + + String sVersion = processDefinitionIdSplit[1]; + int currentVersion = Integer.parseInt(sVersion); + if (latest && currentVersion > maxVersion) { + bpmnInstance = bi; + } else if (currentVersion == version) { + bpmnInstance = bi; + break; + } + } + + return bpmnInstance; + } + +// private boolean isAuthorized(User user, Group group, String permission, GroupRepository groupRepository) { +// if (isOtfMechanizedIdentifier(user.getEmail())) { +// return true; +// } +// return PermissionChecker.isAuthorized(user, group, permission.toUpperCase(), groupRepository); +// } +} +/* + PermissionChecker.hasReadPermission(mechanizedIdUser,testInstanceGroup,groupRepository) + + PermissionChecker.hasPermission(mechanizedIdUser,testInstanceGroup,groupRepository, [READ, WRITE]) + PermissionsMAp = PermissionChecker.Build.hasRead + */ \ No newline at end of file