183 lines
6.8 KiB
Java
183 lines
6.8 KiB
Java
package org.gcube.resourcemanagement.whnmanager;
|
|
|
|
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 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.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 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(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);
|
|
}
|
|
}
|
|
|
|
@DELETE
|
|
@Path("")
|
|
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);
|
|
}
|
|
}
|
|
|
|
private Status executeTask(Predicate<Set<String>> 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<String, String> inputs = new HashMap<String, String>();
|
|
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.set("getContext");
|
|
ApplicationContext appContext = ContextProvider.get();
|
|
Set<String> 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;
|
|
}
|
|
|
|
}
|