Skip to content

Commit

Permalink
Merge pull request #110 from ananjaykumar2/fixes/acl-logic
Browse files Browse the repository at this point in the history
reractor access policy logic
  • Loading branch information
karun-singh authored Apr 3, 2024
2 parents 8fe8f93 + 026ccb4 commit b478d7a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 152 deletions.
14 changes: 7 additions & 7 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ consumes:

info:
title: "Data Exchange GIS Interface APIs"
version: 4.5.0
version: 5.5.0
description: |
# Introduction
Expand Down Expand Up @@ -98,7 +98,7 @@ paths:
- lang: 'cURL'
label: 'get latest data'
source: |
curl --location --request GET 'https://example-gis.com/ngsi-ld/v1/entities?id=iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR055' \
curl --location --request GET 'https://example-gis.com/ngsi-ld/v1/entities?id=d33533e6-ab10-4918-8ea1-4390c68fb464' \
--header 'token: <tokenValue>'
responses:
Expand Down Expand Up @@ -295,7 +295,7 @@ paths:
- lang: 'cURL'
label: 'delete GIS entry'
source: |
curl --location --request DELETE 'https://example-gis.com/admin/gis/serverInfo?id=iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR1059' \
curl --location --request DELETE 'https://example-gis.com/admin/gis/serverInfo?id=d33533e6-ab10-4918-8ea1-4390c68fb465' \
--header 'token: <tokenValue>'

Expand Down Expand Up @@ -355,7 +355,7 @@ components:
type: boolean
example:
id:
"iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR059"
"d33533e6-ab10-4918-8ea1-4390c68fb464"
server: "https://example-gis.com/apis"
server-port: 1234
isSecure: false
Expand Down Expand Up @@ -392,7 +392,7 @@ components:
- password
- tokenURL
example:
"id": "iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR1059"
"id": "d33533e6-ab10-4918-8ea1-4390c68fb465"
"server-url": "https://example-gis.com/apis"
"server-port": 1234
"isSecure": true
Expand Down Expand Up @@ -421,7 +421,7 @@ components:
title: Successful Operation
results: [
{
"iudx_resource_id": "iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR055",
"iudx_resource_id": "d33533e6-ab10-4918-8ea1-4390c68fb464",
"url": "https://map.varanasismartcity.gov.in/varanasismartcity",
"isopen": true,
"port": 123,
Expand Down Expand Up @@ -492,7 +492,7 @@ components:
example:
type: urn:dx:rs:invalidPayloadFormat
title: Bad Request
detail: provided string should respect pattern ^[a-zA-Z0-9.]{4,100}/{1}[a-zA-Z0-9.]{4,100}/{1}[a-zA-Z.]{4,100}/{1}[a-zA-Z-_.]{4,100}/{1}[a-zA-Z0-9-_.]{4,100}$
detail: "Validation error : Invalid id"

InvalidResourceIdErrorResponse:
title: InvalidResourceIdErrorResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ public class JwtAuthenticationServiceImpl implements AuthenticationService {
.maximumSize(1000)
.expireAfterAccess(CACHE_TIMEOUT_AMOUNT, TimeUnit.MINUTES)
.build();
// resourceGroupCache will contain ACL info about all resource group in a resource server
Cache<String, String> resourceGroupCache =
CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(CACHE_TIMEOUT_AMOUNT, TimeUnit.MINUTES)
.build();

public JwtAuthenticationServiceImpl(
Vertx vertx,
Expand Down Expand Up @@ -187,34 +181,19 @@ private Future<String> isOpenResource(String id) {
Promise<String> promise = Promise.promise();
String acl = resourceIdCache.getIfPresent(id);
if (acl != null) {
LOGGER.debug("Cache Hit");
LOGGER.info("Cache Hit");
promise.complete(acl);
} else {
// cache miss
LOGGER.debug("Cache miss calling cat server");
// 1. check group accessPolicy.
// 2. check resource exist, if exist set accessPolicy to group accessPolicy. else fail
getGrupId(id)
LOGGER.info("Cache miss calling cat server");
Future<String> aclFuture = getAccessPolicy(id);
aclFuture
.onSuccess(
groupId -> {
Future<String> groupAclFuture = getGroupAccessPolicy(groupId);
groupAclFuture
.compose(
groupACLResult -> {
String groupPolicy = groupACLResult;
return isResourceExist(id, groupPolicy);
})
.onSuccess(
handler -> {
promise.complete(resourceIdCache.getIfPresent(id));
})
.onFailure(
handler -> {
LOGGER.error(
"cat response failed for Id : (" + id + ")" + handler.getCause());
promise.fail("Not Found " + id);
});

accessPolicy -> {
promise.complete(accessPolicy);
})
.onFailure(
failure -> {
promise.fail(failure.getMessage());
});
}
return promise.future();
Expand Down Expand Up @@ -347,46 +326,6 @@ public Future<Boolean> isValidId(JwtData jwtData, String id) {
return promise.future();
}

public Future<Boolean> isResourceExist(String id, String groupAcl) {
LOGGER.trace("isResourceExist() started");
Promise<Boolean> promise = Promise.promise();
String resourceExist = resourceIdCache.getIfPresent(id);
if (resourceExist != null) {
LOGGER.debug("Info : cache Hit");
promise.complete(true);
} else {
LOGGER.debug("Info : Cache miss : call cat server");
catWebClient
.get(port, host, path)
.addQueryParam("property", "[id]")
.addQueryParam("value", "[[" + id + "]]")
.addQueryParam("filter", "[id]")
.expect(ResponsePredicate.JSON)
.send(
responseHandler -> {
if (responseHandler.failed()) {
promise.fail("false");
}
HttpResponse<Buffer> response = responseHandler.result();
JsonObject responseBody = response.bodyAsJsonObject();
if (response.statusCode() != HttpStatus.SC_OK) {
promise.fail("false");
} else if (!responseBody.getString("type").equals("urn:dx:cat:Success")) {
promise.fail("Not Found");
return;
} else if (responseBody.getInteger("totalHits") == 0) {
LOGGER.debug("Info: Resource ID invalid : Catalogue item Not Found");
promise.fail("Not Found");
} else {
LOGGER.debug("is Exist response : " + responseBody);
resourceIdCache.put(id, groupAcl);
promise.complete(true);
}
});
}
return promise.future();
}

Future<Boolean> isRevokedClientToken(JwtData jwtData) {
LOGGER.trace("isRevokedClientToken started param : ");
Promise<Boolean> promise = Promise.promise();
Expand Down Expand Up @@ -423,92 +362,53 @@ Future<Boolean> isRevokedClientToken(JwtData jwtData) {
return promise.future();
}

public Future<String> getGroupAccessPolicy(String groupId) {
public Future<String> getAccessPolicy(String id) {
LOGGER.trace("getGroupAccessPolicy() started");
Promise<String> promise = Promise.promise();
String groupAcl = resourceGroupCache.getIfPresent(groupId);
if (groupAcl != null) {
LOGGER.debug("Info : cache Hit");
promise.complete(groupAcl);
} else {
LOGGER.debug("Info : cache miss");
catWebClient
.get(port, host, path)
.addQueryParam("property", "[id]")
.addQueryParam("value", "[[" + groupId + "]]")
.addQueryParam("filter", "[accessPolicy]")
.expect(ResponsePredicate.JSON)
.send(
httpResponseAsyncResult -> {
if (httpResponseAsyncResult.failed()) {
LOGGER.error(httpResponseAsyncResult.cause());
promise.fail("Resource not found");
return;
}
HttpResponse<Buffer> response = httpResponseAsyncResult.result();
if (response.statusCode() != HttpStatus.SC_OK) {
promise.fail("Resource not found");
return;
}
JsonObject responseBody = response.bodyAsJsonObject();
if (!responseBody.getString("type").equals("urn:dx:cat:Success")) {
promise.fail("Resource not found");
return;
}
String resourceAcl = "SECURE";
try {
resourceAcl =
responseBody
.getJsonArray("results")
.getJsonObject(0)
.getString("accessPolicy");
resourceGroupCache.put(groupId, resourceAcl);
LOGGER.debug("Info: Group ID valid : Catalogue item Found");
promise.complete(resourceAcl);
} catch (Exception ignored) {
LOGGER.error(ignored.getMessage());
LOGGER.error("Info: Group ID invalid : Empty response in results from Catalogue");
promise.fail("Resource not found");
}
});
}
return promise.future();
}

// class to contain intermediate data for token interospection
final class ResultContainer {
JwtData jwtData;
boolean isOpen;
}

public Future<String> getGrupId(String id) {
LOGGER.debug("get item for id: {} ", id);
Promise<String> promise = Promise.promise();

catWebClient
.get(port, host, path)
.addQueryParam("property", "[id]")
.addQueryParam("value", "[[" + id + "]]")
.addQueryParam("filter", "[id,resourceGroup]")
.addQueryParam("filter", "[accessPolicy]")
.expect(ResponsePredicate.JSON)
.send(
relHandler -> {
if (relHandler.succeeded()
&& relHandler.result().bodyAsJsonObject().getInteger("totalHits") > 0) {
JsonArray resultArray =
relHandler.result().bodyAsJsonObject().getJsonArray("results");
JsonObject response = resultArray.getJsonObject(0);
String groupId =
response.containsKey("resourceGroup") ? response.getString("resourceGroup") :
response.getString("id");
promise.complete(groupId);
} else {
LOGGER.error("catalogue call search api failed: " + relHandler.cause());
promise.fail("catalogue call search api failed");
httpResponseAsyncResult -> {
if (httpResponseAsyncResult.failed()) {
LOGGER.error(httpResponseAsyncResult.cause());
promise.fail("Resource not found");
return;
}
HttpResponse<Buffer> response = httpResponseAsyncResult.result();
if (response.statusCode() != HttpStatus.SC_OK) {
promise.fail("Resource not found");
return;
}
JsonObject responseBody = response.bodyAsJsonObject();
if (!responseBody.getString("type").equals("urn:dx:cat:Success")) {
promise.fail("Resource not found");
return;
}
String resourceAcl = "SECURE";
try {
resourceAcl =
responseBody.getJsonArray("results").getJsonObject(0).getString("accessPolicy");
resourceIdCache.put(id, resourceAcl);
LOGGER.debug("Info: Resource ID is valid : Catalogue item Found");
promise.complete(resourceAcl);
} catch (Exception ignored) {
LOGGER.error(ignored.getMessage());
LOGGER.error(
"Info: Resource ID is invalid : Empty response in results from Catalogue");
promise.fail("Resource not found");
}
});

return promise.future();
}

// class to contain intermediate data for token interospection
final class ResultContainer {
JwtData jwtData;
boolean isOpen;
}
}

0 comments on commit b478d7a

Please sign in to comment.