Search in sources :

Example 6 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method proxy.

public void proxy(RoutingContext ctx) {
    ctx.request().pause();
    ReadStream<Buffer> stream = ctx.request();
    // Pause the request data stream before doing any slow ops, otherwise
    // it will get read into a buffer somewhere.
    ProxyContext pc = new ProxyContext(ctx);
    // It would be nice to pass the request-id to the client, so it knows what
    // to look for in Okapi logs. But that breaks the schemas, and RMB-based
    // modules will not accept the response. Maybe later...
    String tenantId = tenantHeader(pc);
    if (tenantId == null) {
        stream.resume();
        // Error code already set in ctx
        return;
    }
    sanitizeAuthHeaders(ctx.request().headers());
    tenantManager.get(tenantId, gres -> {
        if (gres.failed()) {
            stream.resume();
            pc.responseText(400, "No such Tenant " + tenantId);
            return;
        }
        Tenant tenant = gres.result();
        moduleManager.getEnabledModules(tenant, mres -> {
            if (mres.failed()) {
                stream.resume();
                pc.responseError(mres.getType(), mres.cause());
                return;
            }
            List<ModuleDescriptor> enabledModules = mres.result();
            String metricKey = "proxy." + tenantId + "." + ctx.request().method() + "." + ctx.normalisedPath();
            DropwizardHelper.markEvent(metricKey);
            List<ModuleInstance> l = getModulesForRequest(pc, enabledModules);
            if (l == null) {
                stream.resume();
                // ctx already set up
                return;
            }
            pc.setModList(l);
            pc.logRequest(ctx, tenantId);
            ctx.request().headers().add(XOkapiHeaders.URL, okapiUrl);
            ctx.request().headers().remove(XOkapiHeaders.MODULE_ID);
            resolveUrls(l.iterator(), res -> {
                if (res.failed()) {
                    stream.resume();
                    pc.responseError(res.getType(), res.cause());
                } else {
                    proxyR(l.iterator(), pc, stream, null);
                }
            });
        });
    });
}
Also used : Buffer(io.vertx.core.buffer.Buffer) ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) Tenant(org.folio.okapi.bean.Tenant) ProxyContext(org.folio.okapi.util.ProxyContext) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 7 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class TenantManager method ead1TenantInterface.

/**
 * enableAndDisable helper 1: call the tenant interface.
 *
 * @param tenant
 * @param mdFrom
 * @param mdTo
 * @param fut
 */
private void ead1TenantInterface(Tenant tenant, ModuleDescriptor mdFrom, ModuleDescriptor mdTo, ProxyContext pc, Handler<ExtendedAsyncResult<Void>> fut) {
    if (mdTo == null) {
        // disable only
        ead5commit(tenant, mdFrom.getId(), null, pc, fut);
        return;
    }
    getTenantInterface(mdTo, ires -> {
        if (ires.failed()) {
            if (ires.getType() == NOT_FOUND) {
                logger.debug("eadTenantInterface: " + mdTo.getId() + " has no support for tenant init");
                ead2PermMod(tenant, mdFrom, mdTo, pc, fut);
            } else {
                fut.handle(new Failure<>(ires.getType(), ires.cause()));
            }
        } else {
            ModuleInstance tenInst = ires.result();
            logger.debug("eadTenantInterface: tenint=" + tenInst.getPath());
            JsonObject jo = new JsonObject();
            jo.put("module_to", mdTo.getId());
            if (mdFrom != null) {
                jo.put("module_from", mdFrom.getId());
            }
            String req = jo.encodePrettily();
            proxyService.callSystemInterface(tenant, tenInst, req, pc, cres -> {
                if (cres.failed()) {
                    fut.handle(new Failure<>(cres.getType(), cres.cause()));
                } else {
                    // We can ignore the result, the call went well.
                    ead2PermMod(tenant, mdFrom, mdTo, pc, fut);
                }
            });
        }
    });
}
Also used : JsonObject(io.vertx.core.json.JsonObject) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 8 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class TenantManager method tenantPerms.

/**
 * Helper to make the tenantPermissions call for one module. Used from
 * ead3RealoadPerms and ead4Permissions.
 */
private void tenantPerms(Tenant tenant, ModuleDescriptor mdTo, ModuleDescriptor permsModule, ProxyContext pc, Handler<ExtendedAsyncResult<Void>> fut) {
    pc.debug("Loading permissions for " + mdTo.getName() + " (using " + permsModule.getName() + ")");
    String moduleTo = mdTo.getId();
    PermissionList pl = new PermissionList(moduleTo, mdTo.getPermissionSets());
    String pljson = Json.encodePrettily(pl);
    pc.debug("tenantPerms Req: " + pljson);
    InterfaceDescriptor permInt = permsModule.getSystemInterface("_tenantPermissions");
    String permPath = "";
    List<RoutingEntry> routingEntries = permInt.getAllRoutingEntries();
    ModuleInstance permInst = null;
    if (!routingEntries.isEmpty()) {
        for (RoutingEntry re : routingEntries) {
            if (re.match(null, "POST")) {
                permPath = re.getPath();
                if (permPath == null || permPath.isEmpty()) {
                    permPath = re.getPathPattern();
                }
                permInst = new ModuleInstance(permsModule, re, permPath);
            }
        }
    }
    if (permInst == null) {
        fut.handle(new Failure<>(USER, "Bad _tenantPermissions interface in module " + permsModule.getId() + ". No path to POST to"));
        return;
    }
    pc.debug("tenantPerms: " + permsModule.getId() + " and " + permPath);
    proxyService.callSystemInterface(tenant, permInst, pljson, pc, cres -> {
        if (cres.failed()) {
            fut.handle(new Failure<>(cres.getType(), cres.cause()));
        } else {
            pc.debug("tenantPerms request to " + permsModule.getName() + " succeeded for module " + moduleTo + " and tenant " + tenant.getId());
            fut.handle(new Success<>());
        }
    });
}
Also used : RoutingEntry(org.folio.okapi.bean.RoutingEntry) PermissionList(org.folio.okapi.bean.PermissionList) ModuleInstance(org.folio.okapi.bean.ModuleInstance) InterfaceDescriptor(org.folio.okapi.bean.InterfaceDescriptor)

Example 9 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class TenantManager method getTenantInterface1.

private void getTenantInterface1(InterfaceDescriptor pi, ModuleDescriptor md, Handler<ExtendedAsyncResult<ModuleInstance>> fut) {
    if (!"1.0".equals(pi.getVersion())) {
        fut.handle(new Failure<>(USER, "Interface _tenant must be version 1.0 "));
        return;
    }
    if ("system".equals(pi.getInterfaceType())) {
        // looks like a new type
        List<RoutingEntry> res = pi.getAllRoutingEntries();
        if (!res.isEmpty()) {
            for (RoutingEntry re : res) {
                if (re.match(null, "POST")) {
                    if (re.getPath() != null) {
                        logger.debug("findTenantInterface: found path " + re.getPath());
                        fut.handle(new Success<>(new ModuleInstance(md, re, re.getPath())));
                        return;
                    }
                    if (re.getPathPattern() != null) {
                        logger.debug("findTenantInterface: found pattern " + re.getPathPattern());
                        fut.handle(new Success<>(new ModuleInstance(md, re, re.getPathPattern())));
                        return;
                    }
                }
            }
        }
    }
    logger.warn("Module '" + md.getId() + "' uses old-fashioned tenant " + "interface. Define InterfaceType=system, and add a RoutingEntry." + " Falling back to calling /_/tenant.");
    fut.handle(new Success<>(new ModuleInstance(md, null, "/_/tenant")));
}
Also used : RoutingEntry(org.folio.okapi.bean.RoutingEntry) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 10 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method getModulesForRequest.

/**
 * Builds the pipeline of modules to be invoked for a request.
 * Sets the
 * default authToken for each ModuleInstance. Later, these can be overwritten
 * by the ModuleTokens from the auth, if needed.
 *
 * @param pc
 * @param enabledModules modules enabled for the current tenant
 * @return a list of ModuleInstances. In case of error, sets up ctx and
 * returns null.
 */
private List<ModuleInstance> getModulesForRequest(ProxyContext pc, List<ModuleDescriptor> enabledModules) {
    List<ModuleInstance> mods = new ArrayList<>();
    HttpServerRequest req = pc.getCtx().request();
    final String id = req.getHeader(XOkapiHeaders.MODULE_ID);
    pc.debug("getMods: Matching " + req.method() + " " + req.absoluteURI());
    for (ModuleDescriptor md : enabledModules) {
        pc.debug("getMods:  looking at " + md.getId());
        List<RoutingEntry> rr = null;
        if (id == null) {
            rr = md.getProxyRoutingEntries();
        } else if (id.equals(md.getId())) {
            rr = md.getMultiRoutingEntries();
        }
        if (rr != null) {
            for (RoutingEntry re : rr) {
                if (match(re, req)) {
                    ModuleInstance mi = new ModuleInstance(md, re, req.uri());
                    mi.setAuthToken(pc.getCtx().request().headers().get(XOkapiHeaders.TOKEN));
                    mods.add(mi);
                    if (!resolveRedirects(pc, mods, re, enabledModules, "", req.uri(), "")) {
                        return null;
                    }
                    pc.debug("getMods:   Added " + md.getId() + " " + re.getPathPattern() + " " + re.getPath() + " " + re.getPhase() + "/" + re.getLevel());
                }
            }
        }
    }
    Comparator<ModuleInstance> cmp = (ModuleInstance a, ModuleInstance b) -> a.getRoutingEntry().getPhaseLevel().compareTo(b.getRoutingEntry().getPhaseLevel());
    mods.sort(cmp);
    // Check that our pipeline has a real module in it, not just filters,
    // so that we can return a proper 404 for requests that only hit auth
    pc.debug("Checking filters for " + req.absoluteURI());
    boolean found = false;
    for (ModuleInstance inst : mods) {
        pc.debug("getMods: Checking " + inst.getRoutingEntry().getPathPattern() + " " + "'" + inst.getRoutingEntry().getPhase() + "' " + "'" + inst.getRoutingEntry().getLevel() + "' ");
        if (inst.getRoutingEntry().getPhase() == null) {
            // No real handler should have a phase any more.
            found = true;
        // It has been deprecated for a long time, and never made any sense anyway.
        // The auth filter, the only one we have, uses phase 'auth'
        }
    }
    if (!found) {
        if (// If we defaulted to supertenant,
        "-".equals(pc.getTenant()) && !req.path().startsWith("/_/")) {
            // and not wrong okapi request
            // The /_/ test is to make sure we report same errors as before internalModule stuff
            pc.responseText(403, "Missing Tenant");
            return null;
        } else {
            pc.responseError(404, "No suitable module found for path " + req.path());
            return null;
        }
    }
    return mods;
}
Also used : ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) RoutingEntry(org.folio.okapi.bean.RoutingEntry) HttpServerRequest(io.vertx.core.http.HttpServerRequest) ArrayList(java.util.ArrayList) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Aggregations

ModuleInstance (org.folio.okapi.bean.ModuleInstance)14 RoutingEntry (org.folio.okapi.bean.RoutingEntry)8 JsonObject (io.vertx.core.json.JsonObject)5 ModuleDescriptor (org.folio.okapi.bean.ModuleDescriptor)5 RoutingContext (io.vertx.ext.web.RoutingContext)4 HashMap (java.util.HashMap)4 Buffer (io.vertx.core.buffer.Buffer)3 HttpServerRequest (io.vertx.core.http.HttpServerRequest)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 DeploymentDescriptor (org.folio.okapi.bean.DeploymentDescriptor)3 ProxyType (org.folio.okapi.bean.RoutingEntry.ProxyType)3 Tenant (org.folio.okapi.bean.Tenant)3 OkapiClient (org.folio.okapi.common.OkapiClient)3 Handler (io.vertx.core.Handler)2 MultiMap (io.vertx.core.MultiMap)2 Vertx (io.vertx.core.Vertx)2 HttpClient (io.vertx.core.http.HttpClient)2 HttpClientOptions (io.vertx.core.http.HttpClientOptions)2 HttpClientRequest (io.vertx.core.http.HttpClientRequest)2