Unverified Commit a0203f94 authored by Tejash JL's avatar Tejash JL Committed by GitHub
Browse files

Merge pull request #6 from kesavanp123/open-saber-rc

Integrate condition resolver 
Showing with 474 additions and 53 deletions
+474 -53
......@@ -78,6 +78,12 @@
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.opensaber</groupId>
<artifactId>middleware-commons</artifactId>
<version>2.0.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
......
......@@ -3,12 +3,14 @@ package io.opensaber.claim;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@SpringBootApplication
@ComponentScan(basePackages = { "io.opensaber.registry.middleware", "io.opensaber.claim"})
public class ClaimsApplication {
public static void main(String[] args) {
SpringApplication.run(ClaimsApplication.class, args);
......
......@@ -8,6 +8,6 @@ public class AttributeNames {
public static final String PROPERTY = "PROPERTY";
public static final String ENTITY_ID = "ENTITY_ID";
public static final String ENTITY = "ENTITY";
public static final String ENTITY_HEADER = "entity";;
public static final String LOWERCASE_ENTITY = "entity";;
public static final String ATTESTOR_INFO = "attestorInfo";
}
......@@ -3,4 +3,5 @@ package io.opensaber.claim.contants;
public class OpensaberApiUrlPaths {
public static final String ATTESTATION_PROPERTIES = "/api/v1/ENTITY/ENTITY_ID/attestationProperties";
public static final String ATTEST = "/api/v1/ENTITY/ENTITY_ID/PROPERTY/PROPERTY_ID/attest";
public static final String USER_INFO = "/api/v1/ENTITY";
}
......@@ -10,7 +10,6 @@ import io.opensaber.claim.exception.InvalidInputException;
import io.opensaber.claim.model.AttestorActions;
import io.opensaber.claim.service.ClaimService;
import io.opensaber.pojos.dto.ClaimDTO;
import javassist.tools.web.BadHttpRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -21,10 +20,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import static io.opensaber.claim.contants.AttributeNames.*;
import static io.opensaber.claim.contants.ErrorMessages.ACCESS_TOKEN_IS_MISSING;
......@@ -40,10 +36,12 @@ public class ClaimsController {
this.claimService = claimService;
}
@RequestMapping(value = "/api/v1/claims", method = RequestMethod.GET)
public ResponseEntity<List<Claim>> getClaims(@RequestHeader HttpHeaders headers) throws IOException {
List<String> entities = getAccessToken(headers);
List<Claim> claims = claimService.findClaimsForAttestor(entities);
@RequestMapping(value = "/api/v1/getClaims", method = RequestMethod.POST)
public ResponseEntity<List<Claim>> getClaims(@RequestHeader HttpHeaders headers,
@RequestBody JsonNode requestBody) {
String entity = requestBody.get(LOWERCASE_ENTITY).asText();
JsonNode attestorNode = requestBody.get(ATTESTOR_INFO);
List<Claim> claims = claimService.findClaimsForAttestor(entity, attestorNode);
return new ResponseEntity<>(claims, HttpStatus.OK);
}
......@@ -58,14 +56,14 @@ public class ClaimsController {
String payloadStr = new String(decoder.decode(payloadPart));
ObjectMapper objectMapper = new ObjectMapper();
JsonNode payload = objectMapper.readTree(payloadStr);
ArrayNode node = (ArrayNode) payload.get(ENTITY_HEADER);
ArrayNode node = (ArrayNode) payload.get(LOWERCASE_ENTITY);
ObjectReader reader = objectMapper.readerFor(new TypeReference<List<String>>() {
});
return reader.readValue(node);
}
@RequestMapping(value = "/api/v1/claims", method = RequestMethod.POST)
public ResponseEntity<Claim> save(@RequestBody ClaimDTO claimDTO, @RequestHeader HttpHeaders headers) {
public ResponseEntity<Claim> save(@RequestBody ClaimDTO claimDTO) {
logger.info("Adding new claimDTO {} ", claimDTO.toString());
Claim savedClaim = claimService.save(Claim.fromDTO(claimDTO));
return new ResponseEntity<>(savedClaim, HttpStatus.OK);
......
......@@ -41,6 +41,8 @@ public class Claim {
private String status;
@Column
private String conditions;
@Column
private String attestorEntity;
@PrePersist
protected void onCreate() {
......@@ -142,6 +144,14 @@ public class Claim {
this.conditions = referenceId;
}
public String getAttestorEntity() {
return attestorEntity;
}
public void setAttestorEntity(String attestorEntity) {
this.attestorEntity = attestorEntity;
}
public static Claim fromDTO(ClaimDTO claimDTO) {
Claim claim = new Claim();
claim.setPropertyId(claimDTO.getPropertyId());
......@@ -150,6 +160,7 @@ public class Claim {
claim.setEntityId(claimDTO.getEntityId());
claim.setPropertyId(claimDTO.getPropertyId());
claim.setConditions(claimDTO.getConditions());
claim.setAttestorEntity(claimDTO.getAttestorEntity());
claim.setStatus(ClaimStatus.OPEN.name());
return claim;
}
......
......@@ -9,4 +9,6 @@ import java.util.List;
@Repository
public interface ClaimRepository extends JpaRepository<Claim, String> {
List<Claim> findByConditionsIn(List<String> conditions);
List<Claim> findByAttestorEntityIn(List<String> entities);
List<Claim> findByAttestorEntity(String entity);
}
......@@ -11,12 +11,14 @@ import io.opensaber.claim.exception.ResourceNotFoundException;
import io.opensaber.claim.model.ClaimStatus;
import io.opensaber.claim.repository.ClaimRepository;
import io.opensaber.pojos.attestation.AttestationPolicy;
import io.opensaber.registry.middleware.service.ConditionResolverService;
import net.minidev.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
......@@ -28,12 +30,14 @@ public class ClaimService {
private final ClaimRepository claimRepository;
private final OpenSaberClient openSaberClient;
private final ConditionResolverService conditionResolverService;
private static final Logger logger = LoggerFactory.getLogger(ClaimService.class);
@Autowired
public ClaimService(ClaimRepository claimRepository, OpenSaberClient openSaberClient) {
public ClaimService(ClaimRepository claimRepository, OpenSaberClient openSaberClient, ConditionResolverService conditionResolverService) {
this.claimRepository = claimRepository;
this.openSaberClient = openSaberClient;
this.conditionResolverService = conditionResolverService;
}
public Claim save(Claim claim) {
......@@ -48,9 +52,16 @@ public class ClaimService {
return claimRepository.findAll();
}
public List<Claim> findClaimsForAttestor(List<String> referenceId) {
return claimRepository.findByConditionsIn(referenceId);
public List<Claim> findClaimsForAttestor(String entity, JsonNode attestorNode) {
List<Claim> claims = claimRepository.findByAttestorEntity(entity);
return claims.stream().filter(claim -> {
String ATTESTOR = "ATTESTOR";
String resolvedCondition = conditionResolverService.resolve(attestorNode,
ATTESTOR, claim.getConditions(), Collections.emptyList());
return conditionResolverService.evaluate(resolvedCondition);
}).collect(Collectors.toList());
}
public void updateNotes(String claimId, Optional<String> notes, HttpHeaders headers, List<String> conditions) {
logger.info("Initiating denial action for claim with id{} ", claimId);
Claim claim = findById(claimId).orElseThrow(() -> new ResourceNotFoundException(CLAIM_NOT_FOUND));
......
package io.opensaber.claim.service;
import com.fasterxml.jackson.databind.JsonNode;
import io.opensaber.claim.contants.OpensaberApiUrlPaths;
import io.opensaber.claim.entity.Claim;
import io.opensaber.claim.exception.ResourceNotFoundException;
import io.opensaber.claim.model.AttestorActions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
......@@ -60,4 +64,14 @@ public class OpenSaberClient {
logger.info("Sending request to {}", url);
restTemplate.postForObject(url, entity, Void.class);
}
public JsonNode getEntity(String entity, HttpHeaders headers) {
String url = openSaberUrl + OpensaberApiUrlPaths.USER_INFO.replace(ENTITY, entity);
HttpEntity<JsonNode> httpEntity = new HttpEntity<>(headers);
ResponseEntity<JsonNode> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, JsonNode.class);
if(!responseEntity.getStatusCode().is2xxSuccessful()) {
throw new ResourceNotFoundException("Attestor info is not present in registry");
}
return responseEntity.getBody();
}
}
......@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.opensaber.claim.entity.Claim;
import io.opensaber.claim.repository.ClaimRepository;
import io.opensaber.pojos.attestation.AttestationPolicy;
import io.opensaber.registry.middleware.service.ConditionResolverService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -33,12 +34,14 @@ public class ClaimServiceTest {
ClaimRepository claimRepository;
@Mock
OpenSaberClient openSaberClient;
@Mock
ConditionResolverService conditionResolverService;
@Captor
ArgumentCaptor<Claim> argumentCaptor;
@Before
public void setUp() {
claimService = new ClaimService(claimRepository, openSaberClient);
claimService = new ClaimService(claimRepository, openSaberClient, conditionResolverService);
claim = new Claim();
claim.setId(claimId);
claim.setStatus(OPEN.name());
......
......@@ -53,5 +53,10 @@
<version>5.0.13.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package io.opensaber.registry.middleware.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ConditionResolverService {
/**
* @param entityNode subject node where we will apply the extract out the values for given json path
* @param matcher it accepts either ATTESTOR or REQUESTER
* @param condition this is the condition the system has to resolve which will be used for evaluation
* @param attributes contains pair[key, val] where key will be replaced with its value in the condition
* */
public String resolve(JsonNode entityNode, String matcher, String condition, List<String[]> attributes) {
String entity = entityNode.toString();
condition = replaceMultipleEntries(condition, attributes);
List<Integer> matchersIndices = findWordIndices(matcher, condition);
List<String[]> matchersValuesPair = new ArrayList<>();
for (int index : matchersIndices) {
String[] expressions = generateExpressionAndJsonPathPair(index, condition);
expressions[1] = replaceOriginalValueForGivenJsonPath(entity, expressions[1]);
matchersValuesPair.add(expressions);
}
for(String[] pair: matchersValuesPair) {
condition = replace(condition, pair);
}
return condition;
}
private String replaceOriginalValueForGivenJsonPath(String entity, String path) {
Configuration alwaysReturnListConfig = Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build();
List<String> read = JsonPath.using(alwaysReturnListConfig).parse(entity).read(path);
String s;
if(read.size() == 1) {
s = "\"" + read.get(0) + "\"";
} else {
s = read.toString();
}
return s.replace("[", "{").replace("]", "}");
}
private String[] generateExpressionAndJsonPathPair(int index, String condition) {
int hashCount = 0;
int indexAfterFirstHash = -1;
String[] ans = new String[2];
StringBuilder sb = new StringBuilder();
for (int i = index; i < condition.length(); i++) {
char val = condition.charAt(i);
sb.append(val);
if (val == '#') {
hashCount++;
}
if (hashCount == 1 && indexAfterFirstHash == -1) {
indexAfterFirstHash = i;
} else if(hashCount == 2){
ans[0] = sb.toString();
ans[1] = condition.substring(indexAfterFirstHash + 1, i);
break;
}
}
return ans;
}
private String replaceMultipleEntries(String condition, List<String[]> attributes) {
for (String[] entry : attributes) {
condition = replace(condition, entry);
}
return condition;
}
private String replace(String condition, String[] entry) {
return condition.replace(entry[0], entry[1]);
}
private List<Integer> findWordIndices(String matcher, String condition) {
int index = 0;
List<Integer> indices = new ArrayList<>();
while(index != -1) {
index = condition.indexOf(matcher, index);
if(index != -1) {
indices.add(index);
index++;
}
}
return indices;
}
public boolean evaluate(String s) {
ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression(s);
return expression.getValue(Boolean.class);
}
}
package io.opensaber.registry.middleware.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class ConditionResolverServiceTest {
ConditionResolverService conditionResolverService = new ConditionResolverService();
@Test
public void shouldAbleToResolveRequesterPaths() throws IOException {
String condition = "(ATTESTOR#$.experience.[*].institute#.contains('REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#') && (ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('bo') || ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('hod')))";
String matcher = "REQUESTER";
List<String[]> attributes = new ArrayList<String[]>(){{
add(new String[]{"REQUESTER_PROPERTY_ID", "4"});
}};
String expectedCondition = "(ATTESTOR#$.experience.[*].institute#.contains('Mary school') && (ATTESTOR#$.experience[?(@.institute == 'Mary school')]['role'][*]#.contains('bo') || ATTESTOR#$.experience[?(@.institute == 'Mary school')]['role'][*]#.contains('hod')))";
String resolve = conditionResolverService.resolve(getStudentJsonNode(), matcher, condition, attributes);
assertEquals(expectedCondition, resolve);
}
@Test
public void shouldAbleToResolveAttestorPaths() throws IOException {
String condition = "(ATTESTOR#$.experience.[*].institute#.contains('Mary school') && (ATTESTOR#$.experience[?(@.institute == 'Mary school')]['role'][*]#.contains('bo') || ATTESTOR#$.experience[?(@.institute == 'Mary school')]['role'][*]#.contains('hod')))";
String matcher = "ATTESTOR";
List<String[]> attributes = new ArrayList<String[]>();
String expectedCondition = "({\"Mary school\",\"ABC institute of school\"}.contains('Mary school') && ({\"hod\",\"admin\"}.contains('bo') || {\"hod\",\"admin\"}.contains('hod')))";
assertEquals(expectedCondition, conditionResolverService.resolve(getTeacherJsonNode(), matcher, condition, attributes));
}
@Test
public void shouldReturnTrueForValidExpression() throws IOException {
String condition = "(ATTESTOR#$.experience.[*].institute#.contains('REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#') && (ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('bo') || ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('hod')))";
List<String[]> attributes = new ArrayList<String[]>(){{
add(new String[]{"REQUESTER_PROPERTY_ID", "4"});
}};
String requester = "REQUESTER";
String resolve = null;
try {
resolve = conditionResolverService.resolve(getStudentJsonNode(), requester, condition, attributes);
} catch (IOException e) {
e.printStackTrace();
}
String attestor = "ATTESTOR";
resolve = conditionResolverService.resolve(getTeacherJsonNode(), attestor, resolve, attributes);
assertTrue(conditionResolverService.evaluate(resolve));
}
@Test
public void shouldReturnFalseForInvalidExpression() throws IOException {
String condition = "(ATTESTOR#$.experience.[*].institute#.contains('REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#') && (ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('boa') || ATTESTOR#$.experience[?(@.institute == 'REQUESTER#$.educationDetails[?(@.osid == 'REQUESTER_PROPERTY_ID')]['institute']#')]['role'][*]#.contains('hoda')))";
List<String[]> attributes = new ArrayList<String[]>(){{
add(new String[]{"REQUESTER_PROPERTY_ID", "4"});
}};
String requester = "REQUESTER";
String resolve = conditionResolverService.resolve(getStudentJsonNode(), requester, condition, attributes);
String attestor = "ATTESTOR";
resolve = conditionResolverService.resolve(getTeacherJsonNode(), attestor, resolve, attributes);
assertFalse(conditionResolverService.evaluate(resolve));
}
private JsonNode getTeacherJsonNode() throws IOException {
String nodeStr = "{\n" +
" \"identityDetails\":{\n" +
" \"fullName\":\"Omen\",\n" +
" \"gender\":\"Male\",\n" +
" \"dob\":\"2021-06-10\",\n" +
" \"identityType\":\"Aadhar\",\n" +
" \"identityValue\":\"1010101\"\n" +
" },\n" +
" \"academicQualifications\":[\n" +
" {\n" +
" \"institute\":\"ABC Institute\",\n" +
" \"qualification\":\"10\",\n" +
" \"program\":\"SSLC\",\n" +
" \"graduationYear\":\"1990\",\n" +
" \"marks\":\"80\"\n" +
" }\n" +
" ],\n" +
" \"experience\":[\n" +
" {\n" +
" \"role\":[\n" +
" \"hod\",\n" +
" \"admin\"\n" +
" ],\n" +
" \"institute\":\"Mary school\",\n" +
" \"employmentType\":\"Permanent\",\n" +
" \"start\":\"2021-06-10\",\n" +
" \"end\":\"2021-06-10\",\n" +
" \"teacherType\":\"Head teacher\",\n" +
" \"subjects\":[\n" +
" \"science\"\n" +
" ],\n" +
" \"grades\":[\n" +
" \"class 6th\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"role\":[\n" +
" \"secretary\"\n" +
" ],\n" +
" \"institute\":\"ABC institute of school\",\n" +
" \"employmentType\":\"Permanent\",\n" +
" \"start\":\"2021-06-10\",\n" +
" \"end\":\"2021-06-10\",\n" +
" \"teacherType\":\"Head teacher\",\n" +
" \"subjects\":[\n" +
" \"science\"\n" +
" ],\n" +
" \"grades\":[\n" +
" \"7th class\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}";
return new ObjectMapper().readTree(nodeStr);
}
JsonNode getStudentJsonNode() throws IOException {
String nodeStr = "{\n" +
" \"gender\":\"Male\",\n" +
" \"studentName\":\"Moorthy\",\n" +
" \"osid\":\"1-471bacc6-95ca-4cb6-b5db-8a308fdef263\",\n" +
" \"nationalIdentifier\":\"123456\",\n" +
" \"educationDetails\":[\n" +
" {\n" +
" \"degree\":\"HSC\",\n" +
" \"start\":\"04-05-2020\",\n" +
" \"end\":\"2014-09-12\",\n" +
" \"institute\":\"Mary school\",\n" +
" \"osid\":\"1-330cff35-65e6-4abd-9b0d-29fba5c97a93\",\n" +
" \"state\":\"DRAFT\"\n" +
" },\n" +
" {\n" +
" \"degree\":\"SSLC\",\n" +
" \"start\":\"04-05-2020\",\n" +
" \"end\":\"2014-09-12\",\n" +
" \"institute\":\"Mary school\",\n" +
" \"osid\":\"4\",\n" +
" \"state\":\"DRAFT\"\n" +
" }\n" +
" ],\n" +
" \"class\":\"8th\",\n" +
" \"principal\":\"Samarth\"\n" +
"}";
return new ObjectMapper().readTree(nodeStr);
}
}
......@@ -24,6 +24,10 @@ public class AttestationPolicy {
* Holds the expression to identify the attestor
* */
private String conditions;
/*
* It will be used as first filter for fetching claims
* */
private String attestorEntity;
public List<String> getPaths() {
return paths;
......@@ -69,4 +73,12 @@ public class AttestationPolicy {
public boolean hasProperty(String property) {
return getProperty().equals(property);
}
public String getAttestorEntity() {
return attestorEntity;
}
public void setAttestorEntity(String attestorEntity) {
this.attestorEntity = attestorEntity;
}
}
......@@ -9,6 +9,7 @@ public class ClaimDTO {
private String notes;
private String status;
private String conditions;
private String attestorEntity;
public String getEntity() {
return entity;
}
......@@ -64,4 +65,12 @@ public class ClaimDTO {
public void setConditions(String conditions) {
this.conditions = conditions;
}
public String getAttestorEntity() {
return attestorEntity;
}
public void setAttestorEntity(String attestorEntity) {
this.attestorEntity = attestorEntity;
}
}
package io.opensaber.registry.controller;
import com.fasterxml.jackson.databind.JsonNode;
import io.opensaber.registry.helper.RegistryHelper;
import io.opensaber.registry.util.ClaimRequestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
@RestController
public class RegistryClaimsController {
private static Logger logger = LoggerFactory.getLogger(RegistryClaimsController.class);
private final ClaimRequestClient claimRequestClient;
private final RegistryHelper registryHelper;
public RegistryClaimsController(ClaimRequestClient claimRequestClient, RegistryHelper registryHelper) {
this.registryHelper = registryHelper;
this.claimRequestClient = claimRequestClient;
}
@RequestMapping(value = "/api/v1/{entityName}/claims", method = RequestMethod.GET)
public ResponseEntity<Object> getAllClaims(@PathVariable String entityName,
HttpServletRequest request) {
try {
JsonNode result = registryHelper.getRequestedUserDetails(request, entityName);
JsonNode claims = claimRequestClient.getClaims(result.get(entityName).get(0), entityName);
logger.info("Received {} claims", claims.size());
return new ResponseEntity<>(claims, HttpStatus.OK);
} catch (Exception e) {
logger.error("Fetching claims failed {}", e.getMessage());
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
......@@ -8,12 +8,13 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.opensaber.pojos.*;
import io.opensaber.pojos.attestation.AttestationPolicy;
import io.opensaber.pojos.dto.ClaimDTO;
import io.opensaber.registry.dao.NotFoundException;
import io.opensaber.registry.helper.RegistryHelper;
import io.opensaber.registry.middleware.MiddlewareHaltException;
import io.opensaber.registry.middleware.service.ConditionResolverService;
import io.opensaber.registry.middleware.util.Constants;
import io.opensaber.registry.middleware.util.JSONUtil;
import io.opensaber.registry.middleware.util.OSSystemFields;
import io.opensaber.registry.model.DBConnectionInfoMgr;
import io.opensaber.registry.model.state.StateContext;
import io.opensaber.registry.service.*;
......@@ -22,7 +23,6 @@ import io.opensaber.registry.sink.shard.ShardManager;
import io.opensaber.registry.transform.*;
import io.opensaber.registry.util.*;
import io.opensaber.validators.ValidationException;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -41,6 +41,8 @@ import java.util.*;
public class RegistryController {
private static Logger logger = LoggerFactory.getLogger(RegistryController.class);
@Autowired
ConditionResolverService conditionResolverService;
@Autowired
Transformer transformer;
@Autowired
private ConfigurationHelper configurationHelper;
......@@ -386,7 +388,7 @@ public class RegistryController {
@RequestHeader HttpHeaders header,
@RequestBody JsonNode rootNode,
String userId
) throws JsonProcessingException {
) {
logger.info("Adding entity {}", rootNode);
ResponseParams responseParams = new ResponseParams();
Response response = new Response(Response.API_ID.CREATE, "OK", responseParams);
......@@ -480,8 +482,7 @@ public class RegistryController {
StateContext stateContext = new StateContext(existingNode, requestBody, "student");
ruleEngineService.doTransition(stateContext);
if (stateContext.isAttestationRequested()) {
String conditions = definitionsManager.getDefinition(entityName).getOsSchemaConfiguration().getConditions(property);
HashMap<String, Object> claimResponse = claimRequestClient.riseClaimRequest(entityName, entityId, property, propertyId, conditions);
HashMap<String, Object> claimResponse = createClaimHelper(entityName, entityId, property, propertyId, stateContext);
stateContext.setOSProperty("_osClaimId", claimResponse.get("id").toString());
}
ObjectNode newRootNode = objectMapper.createObjectNode();
......@@ -501,6 +502,22 @@ public class RegistryController {
}
}
private HashMap<String, Object> createClaimHelper(String entityName, String entityId, String property, String propertyId, StateContext stateContext) {
OSSchemaConfiguration osSchemaConfiguration = definitionsManager.getDefinition(entityName).getOsSchemaConfiguration();
String conditions = osSchemaConfiguration.getConditions(property);
String attestorEntity = osSchemaConfiguration.getAttestorEntity(property);
String resolvedConditions = conditionResolverService.resolve(stateContext.getResult(), "REQUESTER", conditions, Collections.emptyList());
ClaimDTO claimDTO = new ClaimDTO();
claimDTO.setEntity(entityName);
claimDTO.setEntityId(entityId);
claimDTO.setProperty(property);
claimDTO.setPropertyId(propertyId);
claimDTO.setConditions(resolvedConditions);
claimDTO.setAttestorEntity(attestorEntity);
return claimRequestClient.riseClaimRequest(claimDTO);
}
@Deprecated
@RequestMapping(value = "/api/v1/{entityName}/{entityId}/{property}/{propertyId}/send", method = RequestMethod.POST)
public ResponseEntity<Object> sendForVerification(
@PathVariable String entityName,
......@@ -520,13 +537,14 @@ public class RegistryController {
.get(property);
StateContext stateContext = new StateContext(existingNode, currentRole);
ruleEngineService.doTransition(stateContext);
HashMap<String, Object> claimResponse = createClaimHelper(entityName, entityId, property, propertyId, stateContext);
stateContext.setOSProperty("_osClaimId", claimResponse.get("id").toString());
ObjectNode newRootNode = objectMapper.createObjectNode();
newRootNode.set(property, stateContext.getResult());
String tag = "RegistryController.update " + entityName;
watch.start(tag);
registryHelper.updateEntity(newRootNode, userId);
registryHelper.updateEntityInEs(entityName, entityId);
claimRequestClient.riseClaimRequest(entityName, entityId, property, propertyId, existingNode.get("institute").asText());
responseParams.setErrmsg(userId);
responseParams.setStatus(Response.Status.SUCCESSFUL);
watch.stop(tag);
......@@ -594,8 +612,7 @@ public class RegistryController {
ResponseParams responseParams = new ResponseParams();
Response response = new Response(Response.API_ID.READ, "OK", responseParams);
try {
String userId = getKeycloakUserId(request);
String userId = registryHelper.getKeycloakUserId(request);
JsonNode resultNode = registryHelper.readEntity(userId, entityName, entityId, false, null, false);
// Transformation based on the mediaType
Data<Object> data = new Data<>(resultNode);
......@@ -628,16 +645,7 @@ public class RegistryController {
ResponseParams responseParams = new ResponseParams();
Response response = new Response(Response.API_ID.SEARCH, "OK", responseParams);
try {
String userId = getKeycloakUserId(request);
ObjectNode payload = JsonNodeFactory.instance.objectNode();
payload.set("entityType", JsonNodeFactory.instance.arrayNode().add(entityName));
ObjectNode filters = JsonNodeFactory.instance.objectNode();
filters.set(OSSystemFields.osOwner.toString(), JsonNodeFactory.instance.objectNode().put("eq", userId));
payload.set("filters", filters);
watch.start("RegistryController.searchEntity");
JsonNode result = registryHelper.searchEntity(payload);
watch.stop("RegistryController.searchEntity");
JsonNode result = registryHelper.getRequestedUserDetails(request, entityName);
if (result.get(entityName).size() > 0) {
return new ResponseEntity<>(result.get(entityName), HttpStatus.OK);
} else {
......@@ -655,14 +663,6 @@ public class RegistryController {
return new ResponseEntity<>(response, HttpStatus.OK);
}
private String getKeycloakUserId(HttpServletRequest request) throws Exception {
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
if (principal != null) {
return principal.getAccount().getPrincipal().getName();
}
throw new Exception("Forbidden");
}
@GetMapping(value = "/api/v1/{entity}/{entityId}/attestationProperties")
public ResponseEntity<Object> getEntityForAttestation(
@PathVariable String entity,
......@@ -684,7 +684,6 @@ public class RegistryController {
}
@RequestMapping(value = "/api/v1/{entityName}/{entityId}", method = RequestMethod.PATCH)
public ResponseEntity<Object> attestEntity(
@PathVariable String entityName,
......
......@@ -5,10 +5,12 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.flipkart.zjsonpatch.JsonPatch;
import io.opensaber.pojos.OpenSaberInstrumentation;
import io.opensaber.registry.controller.RegistryController;
import io.opensaber.registry.middleware.util.JSONUtil;
import io.opensaber.registry.middleware.util.OSSystemFields;
import io.opensaber.registry.model.DBConnectionInfoMgr;
......@@ -24,11 +26,14 @@ import io.opensaber.validators.ValidationException;
import io.opensaber.views.ViewTemplate;
import io.opensaber.views.ViewTransformer;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
......@@ -296,4 +301,43 @@ public class RegistryHelper {
return resultNode;
}
public JsonNode getRequestedUser(String entityName, String userId) throws Exception {
ObjectNode payload = JsonNodeFactory.instance.objectNode();
payload.set("entityType", JsonNodeFactory.instance.arrayNode().add(entityName));
ObjectNode filters = JsonNodeFactory.instance.objectNode();
filters.set(OSSystemFields.osOwner.toString(), JsonNodeFactory.instance.objectNode().put("eq", userId));
payload.set("filters", filters);
watch.start("RegistryController.searchEntity");
JsonNode result = searchEntity(payload);
watch.stop("RegistryController.searchEntity");
return result;
}
public String getKeycloakUserId(HttpServletRequest request) throws Exception {
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
if (principal != null) {
return principal.getAccount().getPrincipal().getName();
}
throw new Exception("Forbidden");
}
public JsonNode getRequestedUserDetails(HttpServletRequest request, String entityName) throws Exception {
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
if (principal != null) {
String userId = principal.getAccount().getPrincipal().getName();
ObjectNode payload = JsonNodeFactory.instance.objectNode();
payload.set("entityType", JsonNodeFactory.instance.arrayNode().add(entityName));
ObjectNode filters = JsonNodeFactory.instance.objectNode();
filters.set(OSSystemFields.osOwner.toString(), JsonNodeFactory.instance.objectNode().put("eq", userId));
payload.set("filters", filters);
watch.start("RegistryController.searchEntity");
JsonNode result = searchEntity(payload);
watch.stop("RegistryController.searchEntity");
return result;
}
throw new Exception("Forbidden");
}
}
package io.opensaber.registry.util;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.opensaber.pojos.dto.ClaimDTO;
import io.opensaber.registry.controller.RegistryController;
import org.slf4j.Logger;
......@@ -8,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.json.Json;
import java.util.HashMap;
@Component
......@@ -15,23 +19,24 @@ public class ClaimRequestClient {
private static Logger logger = LoggerFactory.getLogger(RegistryController.class);
private final String claimRequestUrl;
private final RestTemplate restTemplate;
private static final String CLAIMS_PATH = "/api/v1/claims";
private static final String FETCH_CLAIMS_PATH = "/api/v1/getClaims";
ClaimRequestClient(@Value("${claims.url}") String claimRequestUrl, RestTemplate restTemplate) {
this.claimRequestUrl = claimRequestUrl;
this.restTemplate = restTemplate;
}
public HashMap<String, Object> riseClaimRequest(String entityName, String entityId, String property, String propertyId, String conditions) throws Exception {
ClaimDTO claimDTO = new ClaimDTO();
claimDTO.setEntity(entityName);
claimDTO.setEntityId(entityId);
claimDTO.setProperty(property);
claimDTO.setPropertyId(propertyId);
claimDTO.setConditions(conditions);
String claimsPath = "/api/v1/claims";
HashMap<String, Object> hashMap = restTemplate.postForObject(claimRequestUrl + claimsPath, claimDTO, HashMap.class);
public HashMap<String, Object> riseClaimRequest(ClaimDTO claimDTO) {
HashMap<String, Object> hashMap = restTemplate.postForObject(claimRequestUrl + CLAIMS_PATH, claimDTO, HashMap.class);
logger.info("Claim has successfully risen {}", hashMap.toString());
return hashMap;
}
public JsonNode getClaims(JsonNode jsonNode, String entityName) {
ObjectNode requestBody = JsonNodeFactory.instance.objectNode();
requestBody.set("attestorInfo", jsonNode);
requestBody.put("entity" ,entityName);
return restTemplate.postForObject(claimRequestUrl + FETCH_CLAIMS_PATH, requestBody,JsonNode.class);
}
}
......@@ -139,4 +139,8 @@ public class OSSchemaConfiguration {
.filter(policy -> policy.hasProperty(property))
.findFirst().orElse(new AttestationPolicy());
}
public String getAttestorEntity(String property) {
return getAttestationPolicy(property).getAttestorEntity();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment