diff --git a/Makefile b/Makefile
index 3cb23c34d..2ec5b92f0 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ build: java/registry/target/registry.jar
rm -rf java/claim/target/*.jar
cd target && rm -rf * && jar xvf ../java/registry/target/registry.jar && cp ../java/Dockerfile ./ && docker build -t dockerhub/sunbird-rc-core .
make -C java/claim
+ make -C java/consent
make -C services/certificate-api docker
make -C services/certificate-signer docker
make -C services/notification-service docker
diff --git a/docker-compose.yml b/docker-compose.yml
index 096b993f4..86148252b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -50,6 +50,7 @@ services:
- sunbird_sso_client_id=${KEYCLOAK_CLIENT_ID-registry-frontend}
- sunbird_sso_admin_client_secret=${KEYCLOAK_SECRET}
- claims_url=http://claim-ms:8082
+ - consent_url=http://consent-ms:8083
- sign_url=http://certificate-signer:8079/sign
- sign_health_check_url=http://certificate-signer:8079/health
- signature_enabled=true
@@ -132,6 +133,25 @@ services:
interval: 30s
timeout: 10s
retries: 4
+ consent-ms:
+ image: dockerhub/sunbird-rc-consent-ms:${RELEASE_VERSION}
+ environment:
+ - connectionInfo_uri=jdbc:postgresql://db:5432/registry
+ - connectionInfo_username=postgres
+ - connectionInfo_password=postgres
+ - sunbirdrc_url=http://registry:8081
+ ports:
+ - "8083:8083"
+ depends_on:
+ db:
+ condition: service_started
+ registry:
+ condition: service_started
+ healthcheck:
+ test: [ "CMD-SHELL", "wget -nv -t1 --spider http://localhost:8083/health || exit 1" ]
+ interval: 30s
+ timeout: 10s
+ retries: 4
certificate-signer:
image: dockerhub/sunbird-rc-certificate-signer:${RELEASE_VERSION}
environment:
diff --git a/java/apitest/src/test/java/e2e/registry/ConsentRequest.json b/java/apitest/src/test/java/e2e/registry/ConsentRequest.json
new file mode 100644
index 000000000..8b93a431d
--- /dev/null
+++ b/java/apitest/src/test/java/e2e/registry/ConsentRequest.json
@@ -0,0 +1,10 @@
+{
+ "entityName": "Place",
+ "entityId": "1-eab84a8b-72f2-448e-af65-d2082bee589d",
+ "requestorName": "Random",
+ "consentFieldsPath": {
+ "name": "$.name"
+ },
+ "osOwner": ["c8211527-9d2f-4e08-8d8a-b57ef8be6eba","anonymous"],
+ "consentExpiryTime": "1000"
+}
\ No newline at end of file
diff --git a/java/apitest/src/test/java/e2e/registry/FailingConsentRequest.json b/java/apitest/src/test/java/e2e/registry/FailingConsentRequest.json
new file mode 100644
index 000000000..325a4de19
--- /dev/null
+++ b/java/apitest/src/test/java/e2e/registry/FailingConsentRequest.json
@@ -0,0 +1,11 @@
+{
+ "entityName": "Place",
+ "entityId": "1-eab84a8b-72f2-448e-af65-d2082bee589d",
+ "requestorName": "Random",
+ "consentFieldsPath": {
+ "name": "$.name",
+ "country": ""
+ },
+ "osOwner": ["c8211527-9d2f-4e08-8d8a-b57ef8be6eba","anonymous"],
+ "consentExpiryTime": "1000"
+}
\ No newline at end of file
diff --git a/java/apitest/src/test/java/e2e/registry/GrantConsentRequest.json b/java/apitest/src/test/java/e2e/registry/GrantConsentRequest.json
new file mode 100644
index 000000000..3f36ce1ab
--- /dev/null
+++ b/java/apitest/src/test/java/e2e/registry/GrantConsentRequest.json
@@ -0,0 +1,3 @@
+{
+ "status": "GRANTED"
+}
\ No newline at end of file
diff --git a/java/apitest/src/test/java/e2e/registry/PlaceRequest.json b/java/apitest/src/test/java/e2e/registry/PlaceRequest.json
new file mode 100644
index 000000000..05639c69d
--- /dev/null
+++ b/java/apitest/src/test/java/e2e/registry/PlaceRequest.json
@@ -0,0 +1,8 @@
+{
+ "name": "Aurangabad",
+ "city": "Aurangabad",
+ "country": "India",
+ "email": "120@mail.com",
+ "contact": "1234567890",
+ "addressRegion": "Marathwada"
+}
\ No newline at end of file
diff --git a/java/apitest/src/test/java/e2e/registry/PlaceSchemaRequest.json b/java/apitest/src/test/java/e2e/registry/PlaceSchemaRequest.json
new file mode 100644
index 000000000..59ed95504
--- /dev/null
+++ b/java/apitest/src/test/java/e2e/registry/PlaceSchemaRequest.json
@@ -0,0 +1,6 @@
+{
+ "name": "place",
+ "schema": "{\"$schema\": \"http://json-schema.org/draft-07/schema\", \"type\": \"object\", \"properties\": { \"Place\": { \"$ref\": \"#/definitions/Place\" } }, \"required\": [ \"Place\" ], \"title\": \"Place\", \"definitions\": { \"Place\": { \"$id\": \"#/properties/Place\", \"type\": \"object\", \"title\": \"The Place Schema\", \"required\": [ \"name\", \"city\", \"addressRegion\", \"country\" ], \"properties\": { \"name\": { \"type\": \"string\" }, \"city\": { \"type\": \"string\" }, \"addressLocality\": { \"type\": \"string\" }, \"addressRegion\": { \"type\": \"string\" }, \"country\": { \"type\": \"string\" }, \"postalCode\": { \"type\": \"string\" }, \"contact\": { \"type\": \"string\" }, \"email\": { \"type\": \"string\" } } } }, \"_osConfig\": { \"privateFields\": [ \"name\" ], \"signedFields\": [ \"country\" ], \"roles\": [ ], \"inviteRoles\": [ \"anonymous\"], \"ownershipAttributes\": [{\n \"email\": \"/email\",\n \"mobile\": \"/email\",\n \"userId\": \"/email\"\n }], \"attestationPolicies\": [ { \"name\": \"schemaAttestation\", \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\", \"type\": \"AUTOMATED\", \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\", \"attestationProperties\": { \"country\": \"$.country\", \"contact\": \"$.contact\" } } ], \"credentialTemplate\": { \"@context\": [ \"https://www.w3.org/2018/credentials/v1\", \"https://gist.githubusercontent.com/varadeth/c781559f8d3954fda040d1be0fb2187d/raw/7e951447b3aaf670d407068274fe3ace814c55a4/gistfile1.json\" ], \"type\": [ \"VerifiableCredential\", \"AttestationCertificate\" ], \"issuer\": \"http://www.india.gov.in\", \"issuanceDate\": \"2022-08-08T12:00:00Z\", \"credentialSubject\": { \"type\": \"Place\", \"name\": \"{{name}}\", \"country\": \"{{country}}\" }, \"evidence\": { \"type\": \"Affiliation\", \"postalCode\": \"{{postalCode}}\", \"contact\": \"{{contact}}\" } } }}",
+ "status": "PUBLISHED"
+
+}
\ No newline at end of file
diff --git a/java/apitest/src/test/java/e2e/registry/registry.feature b/java/apitest/src/test/java/e2e/registry/registry.feature
index 72fcda46c..363a44b83 100644
--- a/java/apitest/src/test/java/e2e/registry/registry.feature
+++ b/java/apitest/src/test/java/e2e/registry/registry.feature
@@ -7,6 +7,8 @@ Feature: Registry api tests
* def admin_token = ""
* def client_secret = 'a52c5f4a-89fd-40b9-aea2-3f711f14c889'
* def sleep = function(millis){ java.lang.Thread.sleep(millis) }
+ * def placeOsid = ""
+ * def placeOwner = ""
Scenario: health check
Given path 'health'
@@ -191,6 +193,112 @@ Feature: Registry api tests
When method get
Then status 404
+ Scenario: Create consent and verify its apis
+ # get admin token
+ * url authUrl
+ * path 'auth/realms/sunbird-rc/protocol/openid-connect/token'
+ * header Content-Type = 'application/x-www-form-urlencoded; charset=utf-8'
+ * header Host = 'keycloak:8080'
+ * form field grant_type = 'client_credentials'
+ * form field client_id = 'admin-api'
+ * form field client_secret = 'a52c5f4a-89fd-40b9-aea2-3f711f14c889'
+ * method post
+ Then status 200
+ And print response.access_token
+ * def admin_token = 'Bearer ' + response.access_token
+
+ # create place schema
+ Given url registryUrl
+ And path 'api/v1/Schema'
+ And header Authorization = admin_token
+ And request read('PlaceSchemaRequest.json')
+ When method post
+ Then status 200
+ And response.params.status == "SUCCESSFUL"
+
+ # create entity for place
+ Given url registryUrl
+ And path 'api/v1/Place'
+ And header Authorization = admin_token
+ * def placeRequest = read('PlaceRequest.json')
+ And request placeRequest
+ When method post
+ Then status 200
+ And def placeOsid = response.result.Place.osid
+
+ # fetch token for place entity's owners token
+ * url authUrl
+ * path 'auth/realms/sunbird-rc/protocol/openid-connect/token'
+ * header Content-Type = 'application/x-www-form-urlencoded; charset=utf-8'
+ * header Host = 'keycloak:8080'
+ * form field grant_type = 'password'
+ * form field client_id = 'registry-frontend'
+ * form field username = placeRequest.email
+ * form field password = 'abcd@123'
+ * method post
+ Then status 200
+ And print response.access_token
+ * def place_token = 'Bearer ' + response.access_token
+ * sleep(3000)
+
+ # get entity by id
+ Given url registryUrl
+ And path 'api/v1/Place/' + placeOsid
+ And header Authorization = place_token
+ When method get
+ Then status 200
+ And def placeOwner = response.osOwner
+
+ # create consent for entity Place
+ Given url registryUrl
+ And path 'api/v1/consent'
+ And header Authorization = admin_token
+ * def consentRequest = read('ConsentRequest.json')
+ * consentRequest.entityId = placeOsid
+ * consentRequest.osOwner = placeOwner
+ And request consentRequest
+ When method post
+ Then status 200
+ * sleep(3000)
+
+# create consent for entity Place but without private fields
+ Given url registryUrl
+ And path 'api/v1/consent'
+ And header Authorization = admin_token
+ * def consentRequest = read('FailingConsentRequest.json')
+ * consentRequest.entityId = placeOsid
+ * consentRequest.osOwner = placeOwner
+ And request consentRequest
+ When method post
+ Then status 500
+ * sleep(3000)
+
+ # fetch consent by owner
+ Given url registryUrl
+ And path 'api/v1/consent/'
+ And header Authorization = place_token
+ When method get
+ Then status 200
+ And print response
+ And def consentId = response[0].id
+ And print consentId
+
+ # grant consent
+ Given url registryUrl
+ And path 'api/v1/consent/' + consentId
+ And header Authorization = place_token
+ * def grantConsentRequest = read('GrantConsentRequest.json')
+ And request grantConsentRequest
+ When method put
+ Then status 200
+ * sleep(3000)
+
+ # fetch consent by id
+ Given url registryUrl
+ And path 'api/v1/consent/' + consentId
+ And header Authorization = admin_token
+ When method get
+ Then status 200
@env=async
Scenario: Create a teacher schema and create teacher entity asynchronously
# get admin token
@@ -323,5 +431,4 @@ Feature: Registry api tests
And header Authorization = institute_token
When method get
Then status 200
- And response[0].osid.length > 0
-
+ And response[0].osid.length > 0
\ No newline at end of file
diff --git a/java/consent/Dockerfile b/java/consent/Dockerfile
new file mode 100644
index 000000000..4f1f5af6e
--- /dev/null
+++ b/java/consent/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:8-jdk-alpine
+ARG JAR_FILE=target/*.jar
+COPY ${JAR_FILE} app.jar
+ENTRYPOINT ["java","-jar","/app.jar"]
\ No newline at end of file
diff --git a/java/consent/HELP.md b/java/consent/HELP.md
new file mode 100644
index 000000000..06131a596
--- /dev/null
+++ b/java/consent/HELP.md
@@ -0,0 +1,9 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.4.5/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.4.5/maven-plugin/reference/html/#build-image)
+
diff --git a/java/consent/Makefile b/java/consent/Makefile
new file mode 100644
index 000000000..e4a6c3ce1
--- /dev/null
+++ b/java/consent/Makefile
@@ -0,0 +1,9 @@
+rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
+SOURCES := $(call rwildcard,java/,*.java)
+build: target/consent-0.0.1-SNAPSHOT.jar
+ echo ${SOURCES}
+ cd target && docker build -t dockerhub/sunbird-rc-consent-ms ..
+
+target/claim-0.0.1-SNAPSHOT.jar: $(SOURCES)
+ echo $(SOURCES)
+ ../mvnw -DskipTests clean install
\ No newline at end of file
diff --git a/java/consent/pom.xml b/java/consent/pom.xml
new file mode 100644
index 000000000..9abee7c09
--- /dev/null
+++ b/java/consent/pom.xml
@@ -0,0 +1,95 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.6
+
+
+ dev.sunbirdrc
+ consent
+ 0.0.1-SNAPSHOT
+ consent
+ Demo project for Spring Boot
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.70
+
+
+ dev.sunbirdrc
+ pojos
+ 2.0.3
+ compile
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.12.0
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
diff --git a/java/consent/src/main/java/dev/sunbirdrc/consent/ConsentApplication.java b/java/consent/src/main/java/dev/sunbirdrc/consent/ConsentApplication.java
new file mode 100644
index 000000000..19e07a263
--- /dev/null
+++ b/java/consent/src/main/java/dev/sunbirdrc/consent/ConsentApplication.java
@@ -0,0 +1,13 @@
+package dev.sunbirdrc.consent;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ConsentApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ConsentApplication.class, args);
+ }
+
+}
diff --git a/java/consent/src/main/java/dev/sunbirdrc/consent/constants/ConstentStatus.java b/java/consent/src/main/java/dev/sunbirdrc/consent/constants/ConstentStatus.java
new file mode 100644
index 000000000..cdfc033c6
--- /dev/null
+++ b/java/consent/src/main/java/dev/sunbirdrc/consent/constants/ConstentStatus.java
@@ -0,0 +1,5 @@
+package dev.sunbirdrc.consent.constants;
+
+public enum ConstentStatus {
+ GRANTED, DENIED
+}
diff --git a/java/consent/src/main/java/dev/sunbirdrc/consent/controller/ConsentController.java b/java/consent/src/main/java/dev/sunbirdrc/consent/controller/ConsentController.java
new file mode 100644
index 000000000..7ffc3849d
--- /dev/null
+++ b/java/consent/src/main/java/dev/sunbirdrc/consent/controller/ConsentController.java
@@ -0,0 +1,62 @@
+package dev.sunbirdrc.consent.controller;
+
+import dev.sunbirdrc.consent.entity.Consent;
+import dev.sunbirdrc.consent.exceptions.ConsentDefinitionNotFoundException;
+import dev.sunbirdrc.consent.exceptions.ConsentForbiddenException;
+import dev.sunbirdrc.consent.service.ConsentService;
+import dev.sunbirdrc.pojos.dto.ConsentDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Controller
+public class ConsentController {
+
+ private static final String STATUS = "status";
+ @Autowired
+ private ConsentService consentService;
+
+ @PostMapping("/api/v1/consent")
+ public ResponseEntity createConsent(@RequestBody ConsentDTO consentDTO) {
+ Consent consent = Consent.fromDTO(consentDTO);
+ Consent savedConsent = consentService.saveConsent(consent);
+ return new ResponseEntity<>(savedConsent, HttpStatus.CREATED);
+ }
+
+ @GetMapping(value = "/api/v1/consent/{id}/{requestorId}")
+ public ResponseEntity