Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed build.gradle
Empty file.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<parent>
<groupId>io.edifice</groupId>
<artifactId>edifice-parent</artifactId>
<version>1.0.1</version>
<version>1.1-SNAPSHOT</version>
</parent>

<groupId>fr.wseduc</groupId>
<artifactId>web-utils</artifactId>
<version>3.2-SNAPSHOT</version>
<version>3.2-zookeeper-SNAPSHOT</version>

<repositories>
<repository>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/fr/wseduc/bus/BusAddress.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@

String value();

boolean local() default true;
boolean local() default false;

}
17 changes: 8 additions & 9 deletions src/main/java/fr/wseduc/sms/Sms.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import fr.wseduc.webutils.Server;
import fr.wseduc.webutils.StringValidation;
import fr.wseduc.webutils.collections.SharedDataHelper;
import fr.wseduc.webutils.http.Renders;
import io.vertx.core.Future;
import io.vertx.core.Promise;
Expand All @@ -31,12 +32,12 @@
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.shareddata.LocalMap;
import io.vertx.core.shareddata.AsyncMap;
import org.apache.commons.lang3.StringUtils;

import static fr.wseduc.webutils.Utils.handlerToAsyncHandler;
import static fr.wseduc.webutils.Utils.isNotEmpty;

//-------------------
public class Sms {

private static final Logger log = LoggerFactory.getLogger(Sms.class);
Expand Down Expand Up @@ -64,14 +65,12 @@ public void init(Vertx vertx, JsonObject config) {
this.eb = Server.getEventBus(vertx);
this.vertx = vertx;
this.config = config;
LocalMap<Object, Object> server = vertx.sharedData().getLocalMap("server");
if(server != null && server.get("smsProvider") != null) {
smsProvider = (String) server.get("smsProvider");
final String node = (String) server.get("node");
smsAddress = (node != null ? node : "") + "entcore.sms";
} else {
SharedDataHelper.getInstance().<String, String>getLocal("server", "smsProvider").onSuccess(smsProvider -> {
if(isNotEmpty(smsProvider)) {
SmsFactory.this.smsProvider = smsProvider;
}
smsAddress = "entcore.sms";
}
}).onFailure(ex -> log.error("Error getting smsProvider configuration", ex));
}

public Sms newInstance( Renders render ) {
Expand Down
120 changes: 81 additions & 39 deletions src/main/java/fr/wseduc/webutils/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,35 @@

package fr.wseduc.webutils;

import java.io.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import fr.wseduc.webutils.http.Binding;
import fr.wseduc.webutils.http.HttpMethod;
import fr.wseduc.webutils.http.Renders;
import fr.wseduc.webutils.http.TraceIdContextHandler;
import fr.wseduc.webutils.request.AccessLogger;
import fr.wseduc.webutils.request.filter.SecurityHandler;
import fr.wseduc.webutils.request.filter.XSSHandler;
import fr.wseduc.webutils.security.ActionType;
import fr.wseduc.webutils.security.SecuredAction;
import io.vertx.core.Context;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonObject;

import fr.wseduc.webutils.http.Binding;
import fr.wseduc.webutils.http.HttpMethod;
import fr.wseduc.webutils.http.Renders;
import fr.wseduc.webutils.request.filter.SecurityHandler;
import fr.wseduc.webutils.security.ActionType;
import fr.wseduc.webutils.security.SecuredAction;
import org.apache.commons.lang3.time.StopWatch;
import org.vertx.java.core.http.RouteMatcher;

import java.io.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class Controller extends Renders {

private static final MethodHandles.Lookup lookup = MethodHandles.publicLookup();
Expand All @@ -56,6 +56,9 @@ public abstract class Controller extends Renders {
protected EventBus eb;
protected String busPrefix = "";
private AccessLogger accessLogger;
public static final String TRACE_ID = "X-Cloud-Trace-Context";
public static final String TRACE_MTTR = "Trace-MTTR";
private boolean logRestAccess = false;

public Controller(Vertx vertx, JsonObject config, RouteMatcher rm,
Map<String, SecuredAction> securedActions) {
Expand All @@ -79,6 +82,9 @@ protected void init(Vertx vertx, JsonObject config, RouteMatcher rm,
this.rm = rm;
this.securedActions = securedActions;
this.eb = Server.getEventBus(vertx);
if (config != null) {
logRestAccess = config.getBoolean("log-rest-access", false);
}
if (rm != null) {
loadRoutes();
} else {
Expand Down Expand Up @@ -162,13 +168,14 @@ private Handler<HttpServerRequest> execute(final String method) {
try {
final MethodHandle mh = lookup.bind(this, method,
MethodType.methodType(void.class, HttpServerRequest.class));
final String qualifiedName = this.getClass().getName() + "|" + method;
return new XSSHandler() {

@Override
public void filter(final HttpServerRequest request) {
accessLogger.log(request, v -> {
try {
mh.invokeExact(request);
doExecuteInvoke(mh, request, qualifiedName, false);
} catch (Throwable e) {
if (!(e instanceof IllegalStateException) ||
!"Response is closed".equals(e.getMessage())) {
Expand Down Expand Up @@ -196,12 +203,13 @@ private Handler<HttpServerRequest> executeSecure(final String method) {
try {
final MethodHandle mh = lookup.bind(this, method,
MethodType.methodType(void.class, HttpServerRequest.class));
final String qualifiedName = this.getClass().getName() + "|" + method;
return new SecurityHandler() {

@Override
public void filter(HttpServerRequest request) {
try {
mh.invokeExact(request);
doExecuteInvoke(mh, request, qualifiedName, true);
} catch (Throwable e) {
if (!(e instanceof IllegalStateException) ||
!"Response is closed".equals(e.getMessage())) {
Expand All @@ -224,24 +232,58 @@ public void filter(HttpServerRequest request) {
}
}

private void doExecuteInvoke(MethodHandle mh, HttpServerRequest request,
String qualifiedName, boolean secured) throws Throwable {
final Context ctx = Vertx.currentContext();
String traceId = TraceIdContextHandler.getTraceId(ctx, request);
//regex that transform full qualified class into short one: o.e.a.controllers.AdminController for ex
// capture all package name except the last one and replace them by the first letter
String shortQualifiedName = qualifiedName.replaceAll("\\B\\w+(\\.[a-z])","$1");
if(logRestAccess) {
if (secured) {
log.info(String.format("[%s] Begin secured method : %s", traceId, shortQualifiedName));
} else {
log.debug(String.format("[%s] Begin method : %s", traceId, shortQualifiedName));
}
}
request.response().putHeader(TRACE_ID, traceId);

// if call later and the http response implementation doesn't manage multiple end handler it will be
//erased, not a big deal
if(logRestAccess) {
request.response().endHandler(h -> {
StopWatch watch = TraceIdContextHandler.getTraceTime(ctx);
String mttr = "";
if (watch != null) {
watch.stop();
mttr = String.valueOf(watch.getTime(TimeUnit.MILLISECONDS));
Vertx.currentContext().putLocal(TRACE_MTTR, mttr);
}
if (secured) {
log.info(String.format("[%s] End of secured method : %s", traceId, shortQualifiedName));
} else {
log.debug(String.format("[%s] End of method : %s", traceId, shortQualifiedName));
}
});
}
//invoke the target method on the controller
mh.invokeExact(request);
}

public void registerMethod(String address, String method, boolean local)
throws NoSuchMethodException, IllegalAccessException {
final MethodHandle mh = lookup.bind(this, method,
MethodType.methodType(void.class, Message.class));
Handler<Message<JsonObject>> handler = new Handler<Message<JsonObject>>() {

@Override
public void handle(Message<JsonObject> message) {
try {
mh.invokeExact(message);
} catch (Throwable e) {
log.error(e.getMessage(), e);
JsonObject json = new JsonObject().put("status", "error")
.put("message", e.getMessage());
message.reply(json);
}
}
};
Handler<Message<JsonObject>> handler = message -> {
try {
mh.invokeExact(message);
} catch (Throwable e) {
log.error(e.getMessage(), e);
JsonObject json = new JsonObject().put("status", "error")
.put("message", e.getMessage());
message.reply(json);
}
};
if (local) {
Server.getEventBus(vertx).localConsumer(busPrefix + address, handler);
} else {
Expand All @@ -253,7 +295,7 @@ private Handler<HttpServerRequest> bindHandler(String method) {
if (method == null || method.trim().isEmpty()) {
throw new NullPointerException();
}
if (securedActions.containsKey(this.getClass().getName() + "|" + method)) {
if (securedActions!= null && securedActions.containsKey(this.getClass().getName() + "|" + method)) {
return executeSecure(method);
}
return execute(method);
Expand All @@ -277,7 +319,7 @@ public Map<String, Set<Binding>> getUriBinding() {
public Map<String, Set<Binding>> getSecuredUriBinding() {
Map<String, Set<Binding>> bindings = new HashMap<>();
for (Entry<String, Set<Binding>> e : this.uriBinding.entrySet()) {
if (securedActions.containsKey(e.getKey())) {
if (securedActions!= null && securedActions.containsKey(e.getKey())) {
bindings.put(e.getKey(), e.getValue());
}
}
Expand All @@ -287,7 +329,7 @@ public Map<String, Set<Binding>> getSecuredUriBinding() {
public Set<Binding> securedUriBinding() {
Set<Binding> bindings = new HashSet<>();
for (Entry<String, Set<Binding>> e : this.uriBinding.entrySet()) {
if (securedActions.containsKey(e.getKey())) {
if (securedActions != null && securedActions.containsKey(e.getKey())) {
bindings.addAll(e.getValue());
}
}
Expand Down Expand Up @@ -384,7 +426,7 @@ private void addRegEx(String input, HttpMethod httpMethod, String method) {
}

private String findOverride(String serviceMethod) {
if(!securedActions.containsKey(serviceMethod)) {
if(securedActions == null || !securedActions.containsKey(serviceMethod)) {
return null;
}
return securedActions.get(serviceMethod).getRight();
Expand Down
Loading