diff --git a/.classpath b/.classpath
index 4918979..5bbc871 100644
--- a/.classpath
+++ b/.classpath
@@ -1,5 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13,22 +36,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
index 4413d77..4a2bb6d 100644
--- a/.settings/org.eclipse.wst.common.component
+++ b/.settings/org.eclipse.wst.common.component
@@ -1,21 +1,50 @@
-
+
+
+
+
+
+
+
-
+
+
+
+
-
+
+
+
+
+
-
+
+
+
+
uses
+
-
+
+
+
+
-
+
+
+
+
-
-
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
index 71d64dd..c82abf3 100644
--- a/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -3,5 +3,5 @@
-
+
diff --git a/gcube/extra-resources/WEB-INF/web.xml b/gcube/extra-resources/WEB-INF/web.xml
index 9fd650f..2b62579 100644
--- a/gcube/extra-resources/WEB-INF/web.xml
+++ b/gcube/extra-resources/WEB-INF/web.xml
@@ -1,5 +1,9 @@
-
+
org.gcube.resourcemanagement.whnmanager.WHNManager
diff --git a/pom.xml b/pom.xml
index 97ea121..a2b12f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
org.gcube.distribution
gcube-smartgears-bom
- 3.0.0-SNAPSHOT
+ 3.0.1-SNAPSHOT
pom
import
@@ -39,30 +39,31 @@
org.gcube.core
common-smartgears-app
+
+
+
+ org.glassfish.jersey.inject
+ jersey-cdi2-se
+
-
- javax.ws.rs
- javax.ws.rs-api
-
org.glassfish.jersey.containers
jersey-container-servlet
-
-
- javax.servlet
- javax.servlet-api
- 3.0.1
-
-
- org.glassfish.jersey.media
- jersey-media-json-jackson
-
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
org.slf4j
slf4j-api
@@ -80,6 +81,27 @@
test
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ org.gcube.common
+ gxHTTP
+
+
+ org.gcube.common
+ event-publisher-library
+ [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)
+
diff --git a/src/main/java/org/gcube/resourcemanagement/whnmanager/ContextManager.java b/src/main/java/org/gcube/resourcemanagement/whnmanager/ContextManager.java
index 839f488..ec255d2 100644
--- a/src/main/java/org/gcube/resourcemanagement/whnmanager/ContextManager.java
+++ b/src/main/java/org/gcube/resourcemanagement/whnmanager/ContextManager.java
@@ -1,135 +1,182 @@
package org.gcube.resourcemanagement.whnmanager;
-import java.net.HttpURLConnection;
-import java.util.Map.Entry;
+import java.net.URL;
+import java.security.InvalidParameterException;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-
-import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
-import org.gcube.common.gxhttp.util.ContentUtils;
+import org.gcube.common.keycloak.KeycloakClient;
+import org.gcube.common.keycloak.KeycloakClientFactory;
+import org.gcube.common.keycloak.model.ModelUtils;
+import org.gcube.common.keycloak.model.TokenResponse;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
+import org.gcube.event.publisher.AbstractHTTPWithJWTTokenAuthEventSender;
+import org.gcube.event.publisher.Event;
+import org.gcube.event.publisher.EventStatus.Status;
+import org.gcube.oidc.rest.JWTToken;
+import org.gcube.oidc.rest.OpenIdConnectRESTHelperException;
import org.gcube.resourcemanagement.whnmanager.utils.ValidationUtils;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.managers.ContextEvents;
+import org.gcube.smartgears.security.AuthorizationProvider;
import org.gcube.smartgears.security.SimpleCredentials;
-import org.gcube.smartgears.security.defaults.DefaultAuthorizationProvider;
import org.gcube.smartgears.utils.InnerMethodName;
+import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+
@Path("/contexts")
public class ContextManager {
-
- private static Logger logger=LoggerFactory.getLogger(ContextManager.class);
-
+
+ private static Logger logger = LoggerFactory.getLogger(ContextManager.class);
+
+ private static final String CONDUCTOR_URI = "https://conductor.cloud-dev.d4science.org/api/workflow/";
+ // private static final String REQUEST_PATH ="workflow";
+
+ private static final String ADD_CONTEXT_TASK = "ghn_client_add_to_context";
+ private static final String REMOVE_CONTEXT_TASK = "ghn_client_remove_from_context";
+
+ private enum TaskType {
+ ADD(ADD_CONTEXT_TASK), REMOVE(REMOVE_CONTEXT_TASK);
+
+ private String taskName;
+
+ TaskType(String contextName) {
+ this.taskName = contextName;
+
+ }
+ }
+
+ private static final int READ_TIMEOUT = 40000;
+ private static final int CONNECTION_TIMEOUT = 40000;
+
@PUT
@Path("")
- public Response add(@FormParam("context") String context){
- InnerMethodName.instance.set("addContext");
- Secret secret = SecretManagerProvider.instance.get();
- logger.trace("WHNManager: addToContext method invokation with parameters context :{} and caller: {} curentContext: {}",context, secret.getOwner().getId(), secret.getContext() );
- ValidationUtils.valid("context", context);
- ApplicationContext appContext = ContextProvider.get();
- if(context!=null){
-
- GXHTTPStringRequest request = GXHTTPStringRequest.newRequest("https://conductor.dev.d4science.org/api");
- try {
-
- request = request.path("workflow");
- for(Entry entry : secret.getHTTPAuthorizationHeaders().entrySet())
- request = request.header(entry.getKey(), entry.getValue());
-
-
- SimpleCredentials credentials = ((DefaultAuthorizationProvider) appContext.container().authorizationProvider()).getCredentials();
-
- HttpURLConnection response = request.post(String.format(" \"name\": \"ghn_client_add_to_contexts\",\n" +
- " \"input\" : {\n" +
- " \"client_id\" : \"%s\",\n" +
- " \"context_list\" : [\"%s\"] }", credentials.getClientID(), context)) ;
-
- if(response.getResponseCode() == Status.CREATED.getStatusCode()) {
- String body = ContentUtils.toString(ContentUtils.toByteArray(response.getInputStream()));
- logger.info("Returned response for remove scope {} ",body);
- }
-
- appContext.container().events().fire(context, ContextEvents.ADD_CONTEXT_TO_CONTAINER);
- } catch (Exception e) {
- logger.error("error adding context {}", context, e);
- return Response.serverError().build();
- }
-
- }else{
- logger.error("context is null");
- return Response.status(Status.BAD_REQUEST).build();
+ public Response add(final @FormParam("context") String context) {
+ InnerMethodName.set("addContext");
+ Secret secret = SecretManagerProvider.get();
+ logger.debug(
+ "WHNManager: addToContext method invokation with parameters context :{} and caller: {} curentContext: {}",
+ context, secret.getOwner().getId(), secret.getContext());
+ try {
+ executeTask(l -> l.contains(context), TaskType.ADD, context);
+ ApplicationContext appContext = ContextProvider.get();
+ appContext.container().events().fire(context, ContextEvents.ADD_CONTEXT_TO_CONTAINER);
+ return Response.ok().build();
+ } catch (InvalidParameterException ip) {
+ logger.warn("clientId already contains {}", context);
+ return Response.noContent().build();
+ } catch (IllegalArgumentException ia) {
+ logger.warn("null context passed",ia);
+ return Response.status(400, "context parameter is null").build();
+ } catch (Throwable t) {
+ logger.error("error adding context", t);
+ throw new WebApplicationException(t);
}
- return Response.ok().build();
}
-
-
+
@DELETE
@Path("")
- public Response remove(@FormParam("context") String context){
- InnerMethodName.instance.set("removeContext");
- Secret secret = SecretManagerProvider.instance.get();
- logger.trace("WHNManager: removeFromContext method invokation with parameters context :{} and caller: {} curentContext: {}",context, secret.getOwner().getId(), secret.getContext());
- ValidationUtils.valid("context", context);
- ApplicationContext appContext = ContextProvider.get();
- if(context!=null){
- logger.trace("allowed container in context are {} ",appContext.container().authorizationProvider().getContexts());
-
- GXHTTPStringRequest request = GXHTTPStringRequest.newRequest("https://conductor.dev.d4science.org/api");
- try {
-
- request = request.path("workflow");
- for(Entry entry : secret.getHTTPAuthorizationHeaders().entrySet())
- request = request.header(entry.getKey(), entry.getValue());
-
-
- SimpleCredentials credentials = ((DefaultAuthorizationProvider) appContext.container().authorizationProvider()).getCredentials();
-
- HttpURLConnection response = request.post(String.format(" \"name\": \"ghn_client_remove_from_contexts\",\n" +
- " \"input\" : {\n" +
- " \"client_id\" : \"%s\",\n" +
- " \"context_list\" : [\"%s\"] }", credentials.getClientID(), context)) ;
-
- if(response.getResponseCode() == Status.CREATED.getStatusCode()) {
- String body = ContentUtils.toString(ContentUtils.toByteArray(response.getInputStream()));
- logger.info("Returned response for remove scope {} ",body);
- }
-
- appContext.container().events().fire(context, ContextEvents.REMOVE_CONTEXT_FROM_CONTAINER);
- } catch (Exception e) {
- logger.error("error removing context {}", context, e);
- return Response.serverError().build();
- }
-
-
- }else{
- logger.error("context is null");
- return Response.status(Status.BAD_REQUEST).build();
+ public Response remove(final @FormParam("context") String context) {
+ InnerMethodName.set("removeContext");
+ Secret secret = SecretManagerProvider.get();
+ logger.debug(
+ "WHNManager: removeFromContext method invokation with parameters context :{} and caller: {} curentContext: {}",
+ context, secret.getOwner().getId(), secret.getContext());
+ try {
+ executeTask(l -> !l.contains(context), TaskType.REMOVE, context);
+ ApplicationContext appContext = ContextProvider.get();
+ appContext.container().events().fire(context, ContextEvents.REMOVE_CONTEXT_FROM_CONTAINER);
+ return Response.ok().build();
+ } catch (Throwable t) {
+ logger.error("error removing context", t);
+ throw new WebApplicationException(t);
}
- return Response.ok().build();
}
-
+
+ private Status executeTask(Predicate> notModifiablePredicate, TaskType type, String inputContext ) throws Throwable {
+ ValidationUtils.valid("context", inputContext);
+ ApplicationContext appContext = ContextProvider.get();
+ AuthorizationProvider authProvider = appContext.container().authorizationProvider();
+
+ SimpleCredentials credentials = (SimpleCredentials) authProvider.getCredentials();
+
+ logger.debug("contexts already present in the container are {} executing task {}",authProvider.getContexts(), type.taskName);
+
+ if (notModifiablePredicate.test(authProvider.getContexts()))
+ throw new InvalidParameterException();
+
+ Map inputs = new HashMap();
+ inputs.put("client_id", credentials.getClientID());
+ inputs.put("context", inputContext);
+
+ Event event = new Event(type.taskName, type.taskName, appContext.name(), inputs);
+
+ Status result = checkEventResult(credentials, event);
+
+ logger.debug("{} exectured with result {}", type.taskName, result);
+ if (result != Status.COMPLETED) {
+ throw new Exception("error executing the workflow retuned with status " + result);
+ }
+ return result;
+ }
+
+ private Status checkEventResult(SimpleCredentials credentials, Event event) throws Throwable {
+ Secret secret = SecretManagerProvider.get();
+ AbstractHTTPWithJWTTokenAuthEventSender eventRequest = getAuthEventSender(credentials, secret);
+
+ String result = eventRequest.sendAndGetResult(event);
+
+ JSONObject eventResult;
+ do {
+ Thread.sleep(5000);
+ eventResult = eventRequest.retrive(result);
+ } while (Status.RUNNING == Status.valueOf((String) eventResult.get("status")));
+
+ return Status.valueOf((String) eventResult.get("status"));
+ }
+
@GET
@Path("")
@Produces(MediaType.APPLICATION_JSON)
- public String[] get(){
- InnerMethodName.instance.set("addContext");
+ public String[] get() {
+ InnerMethodName.set("getContext");
ApplicationContext appContext = ContextProvider.get();
Set contexts = appContext.authorizationProvider().getContexts();
return contexts.stream().toArray(String[]::new);
}
-
+
+ private AbstractHTTPWithJWTTokenAuthEventSender getAuthEventSender(SimpleCredentials credentials, Secret secret)
+ throws Throwable {
+ KeycloakClient client = KeycloakClientFactory.newInstance();
+ TokenResponse tokenResponse = client.queryOIDCToken(secret.getContext(), credentials.getClientID(),
+ credentials.getSecret());
+ AbstractHTTPWithJWTTokenAuthEventSender eventSender = new AbstractHTTPWithJWTTokenAuthEventSender(
+ new URL(CONDUCTOR_URI), credentials.getClientID(), credentials.getSecret(), null) {
+ protected JWTToken getAuthorizationToken() throws OpenIdConnectRESTHelperException {
+ return JWTToken.fromString(ModelUtils.toJSONString(tokenResponse));
+ }
+ };
+
+ eventSender.setConnectionTimeout(CONNECTION_TIMEOUT);
+ eventSender.setReadTimeout(READ_TIMEOUT);
+
+ return eventSender;
+ }
+
}
diff --git a/src/main/java/org/gcube/resourcemanagement/whnmanager/WHNManager.java b/src/main/java/org/gcube/resourcemanagement/whnmanager/WHNManager.java
index cb83098..bdb26f7 100644
--- a/src/main/java/org/gcube/resourcemanagement/whnmanager/WHNManager.java
+++ b/src/main/java/org/gcube/resourcemanagement/whnmanager/WHNManager.java
@@ -3,8 +3,8 @@ package org.gcube.resourcemanagement.whnmanager;
import java.util.HashSet;
import java.util.Set;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Application;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Application;
@Path("/")
public class WHNManager extends Application{
@@ -17,6 +17,4 @@ public class WHNManager extends Application{
return classes;
}
-
-
}
diff --git a/src/test/java/org/gcube/resourcemanagement/whnmanager/ContextManagerIntegrationTest.java b/src/test/java/org/gcube/resourcemanagement/whnmanager/ContextManagerIntegrationTest.java
index 5bc2d0a..2d10c9c 100644
--- a/src/test/java/org/gcube/resourcemanagement/whnmanager/ContextManagerIntegrationTest.java
+++ b/src/test/java/org/gcube/resourcemanagement/whnmanager/ContextManagerIntegrationTest.java
@@ -6,17 +6,16 @@ import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.Set;
-import javax.servlet.ServletContext;
-import javax.ws.rs.core.Application;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
+import jakarta.servlet.ServletContext;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
import org.gcube.common.events.Hub;
import org.gcube.common.security.credentials.Credentials;
import org.gcube.common.security.secrets.Secret;
-import org.gcube.resourcemanagement.whnmanager.ContextManager;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.configuration.application.ApplicationConfiguration;
import org.gcube.smartgears.context.Properties;