Search in sources :

Example 1 with RoutingEntry

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

the class ProxyService method doCallSystemInterface.

/**
 * Actually make a request to a system interface, like _tenant. Assumes we are
 * operating as the correct tenant.
 */
private void doCallSystemInterface(String tenantId, String authToken, ModuleInstance inst, String modPerms, String request, ProxyContext pc, Handler<ExtendedAsyncResult<OkapiClient>> fut) {
    String curTenant = pc.getTenant();
    pc.debug("doCallSystemInterface on " + Json.encode(inst) + " for " + tenantId + " as " + curTenant + " with token " + authToken);
    discoveryManager.get(inst.getModuleDescriptor().getId(), gres -> {
        if (gres.failed()) {
            pc.warn("doCallSystemInterface on " + inst.getModuleDescriptor().getId() + " " + inst.getPath() + " failed. Could not find the module in discovery", gres.cause());
            fut.handle(new Failure<>(gres.getType(), gres.cause()));
            return;
        }
        DeploymentDescriptor instance = pickInstance(gres.result());
        if (instance == null) {
            fut.handle(new Failure<>(USER, "No running instances for module " + inst.getModuleDescriptor().getId() + ". Can not invoke " + inst.getPath()));
            return;
        }
        String baseurl = instance.getUrl();
        pc.debug("doCallSystemInterface Url: " + baseurl + " and " + inst.getPath());
        Map<String, String> headers = sysReqHeaders(pc.getCtx(), tenantId, authToken);
        if (modPerms != null) {
            // We are making an auth call
            RoutingEntry re = inst.getRoutingEntry();
            if (re != null) {
                headers.put(XOkapiHeaders.FILTER, re.getPhase());
            }
            if (!modPerms.isEmpty()) {
                headers.put(XOkapiHeaders.MODULE_PERMISSIONS, modPerms);
            }
            // Clear the permissions-required header that we inherited from the
            // original request (e.g. to tenant-enable), as we do not have those
            // perms set in the target tenant
            headers.put(XOkapiHeaders.PERMISSIONS_REQUIRED, "");
            headers.put(XOkapiHeaders.PERMISSIONS_DESIRED, "");
            logger.debug("Auth call, some tricks with permissions");
        }
        pc.debug("doCallSystemInterface: About to create OkapiClient with headers " + Json.encode(headers));
        OkapiClient cli = new OkapiClient(baseurl, vertx, headers);
        String reqId = inst.getPath().replaceFirst("^[/_]*([^/]+).*", "$1");
        // "tenant" or "tenantpermissions"
        cli.newReqId(reqId);
        cli.enableInfoLog();
        HttpMethod meth = HttpMethod.POST;
        if (request.isEmpty()) {
            pc.debug("doCallSystemInterface: No Req, making a HEAD req");
            meth = HttpMethod.HEAD;
        }
        HttpMethod finalMeth = meth;
        cli.request(meth, inst.getPath(), request, cres -> {
            cli.close();
            if (cres.failed()) {
                String msg = finalMeth + " request for " + inst.getModuleDescriptor().getId() + " " + inst.getPath() + " failed with " + cres.cause().getMessage();
                pc.warn(msg);
                fut.handle(new Failure<>(INTERNAL, msg));
                return;
            }
            // Pass response headers - needed for unit test, if nothing else
            String body = cres.result();
            pc.debug("doCallSystemInterface response: " + body);
            pc.debug("doCallSystemInterface ret " + " hdrs: " + Json.encode(cli.getRespHeaders().entries()));
            pc.passOkapiTraceHeaders(cli);
            fut.handle(new Success<>(cli));
        });
    });
}
Also used : RoutingEntry(org.folio.okapi.bean.RoutingEntry) OkapiClient(org.folio.okapi.common.OkapiClient) DeploymentDescriptor(org.folio.okapi.bean.DeploymentDescriptor) HttpMethod(io.vertx.core.http.HttpMethod)

Example 2 with RoutingEntry

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

the class ProxyService method authHeaders.

/**
 * Set up special auth headers. Get the auth bits from the module list into
 * X-Okapi-Permissions-Required and X-Okapi-Permissions-Desired headers. Also
 * X-Okapi-Module-Permissions for each module that has such.
 */
private void authHeaders(List<ModuleInstance> modlist, MultiMap requestHeaders, ProxyContext pc) {
    // Sanitize important headers from the incoming request
    sanitizeAuthHeaders(requestHeaders);
    Set<String> req = new HashSet<>();
    Set<String> want = new HashSet<>();
    Set<String> extraperms = new HashSet<>();
    // !!
    Map<String, String[]> modperms = new HashMap<>(modlist.size());
    for (ModuleInstance mod : modlist) {
        RoutingEntry re = mod.getRoutingEntry();
        String[] reqp = re.getPermissionsRequired();
        if (reqp != null) {
            req.addAll(Arrays.asList(reqp));
        }
        String[] wap = re.getPermissionsDesired();
        if (wap != null) {
            want.addAll(Arrays.asList(wap));
        }
        String[] modp = re.getModulePermissions();
        if (modp != null) {
            if (re.getProxyType() == ProxyType.REDIRECT) {
                extraperms.addAll(Arrays.asList(modp));
            } else {
                modperms.put(mod.getModuleDescriptor().getId(), modp);
            }
        }
    }
    // mod loop
    if (!req.isEmpty()) {
        pc.debug("authHeaders: " + XOkapiHeaders.PERMISSIONS_REQUIRED + " " + String.join(",", req));
        requestHeaders.add(XOkapiHeaders.PERMISSIONS_REQUIRED, String.join(",", req));
    }
    if (!want.isEmpty()) {
        pc.debug("authHeaders: " + XOkapiHeaders.PERMISSIONS_DESIRED + " " + String.join(",", want));
        requestHeaders.add(XOkapiHeaders.PERMISSIONS_DESIRED, String.join(",", want));
    }
    // Add the X-Okapi-Module-Permissions even if empty. That causes auth to return
    // an empty X-Okapi-Module-Token, which will tell us that we have done the mod
    // perms, and no other module should be allowed to do the same.
    String mpj = Json.encode(modperms);
    pc.debug("authHeaders: " + XOkapiHeaders.MODULE_PERMISSIONS + " " + mpj);
    requestHeaders.add(XOkapiHeaders.MODULE_PERMISSIONS, mpj);
    if (!extraperms.isEmpty()) {
        String epj = Json.encode(extraperms);
        pc.debug("authHeaders: " + XOkapiHeaders.EXTRA_PERMISSIONS + " " + epj);
        requestHeaders.add(XOkapiHeaders.EXTRA_PERMISSIONS, epj);
    }
}
Also used : RoutingEntry(org.folio.okapi.bean.RoutingEntry) HashMap(java.util.HashMap) ModuleInstance(org.folio.okapi.bean.ModuleInstance) HashSet(java.util.HashSet)

Example 3 with RoutingEntry

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

the class ProxyService method callSystemInterface.

/**
 * Make a request to a system interface, like _tenant. Part 1: Check that we
 * are working as the right tenant, and if not so, change identity to the
 * correct one.
 *
 * @param tenant to make the request for
 * @param inst carries the moduleDescriptor, RoutingEntry, and getPath to be
 * called
 * @param request body to send in the request
 * @param pc ProxyContext for logging, and returning resp headers
 * @param fut Callback with the OkapiClient that contains the body, headers,
 * and/or errors
 */
public void callSystemInterface(Tenant tenant, ModuleInstance inst, String request, ProxyContext pc, Handler<ExtendedAsyncResult<OkapiClient>> fut) {
    // the tenant we are about to enable
    String tenantId = tenant.getId();
    // is often the supertenant
    String curTenantId = pc.getTenant();
    String authToken = pc.getCtx().request().headers().get(XOkapiHeaders.TOKEN);
    pc.debug("callSystemInterface on " + Json.encode(inst) + " for " + tenantId + " as " + curTenantId + " with authToken " + authToken);
    if (tenantId.equals(curTenantId)) {
        pc.debug("callSystemInterface: Same tenant, no need for trickery");
        doCallSystemInterface(tenantId, authToken, inst, null, request, pc, fut);
        return;
    }
    // Check if the actual tenant has auth enabled. If yes, get a token for it.
    // If we have auth for current (super)tenant is irrelevant here!
    pc.debug("callSystemInterface: Checking if " + tenantId + " has auth");
    moduleManager.getEnabledModules(tenant, mres -> {
        if (mres.failed()) {
            // Should not happen
            pc.warn("callSystemInterface: getEnabledModules failed: ", mres.cause());
            fut.handle(new Failure<>(mres.getType(), mres.cause()));
            return;
        }
        List<ModuleDescriptor> enabledModules = mres.result();
        for (ModuleDescriptor md : enabledModules) {
            RoutingEntry[] filters = md.getFilters();
            if (filters != null) {
                for (RoutingEntry filt : filters) {
                    if ("auth".equals(filt.getPhase())) {
                        pc.debug("callSystemInterface: Found auth filter in " + md.getId());
                        authForSystemInterface(md, filt, tenantId, inst, request, pc, fut);
                        return;
                    }
                }
            }
        }
        pc.debug("callSystemInterface: No auth for " + tenantId + " calling with tenant header only");
        doCallSystemInterface(tenantId, null, inst, null, request, pc, fut);
    });
}
Also used : ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) RoutingEntry(org.folio.okapi.bean.RoutingEntry)

Example 4 with RoutingEntry

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

the class ProxyService method authForSystemInterface.

/**
 * Helper to get a new authtoken before invoking doCallSystemInterface.
 */
private void authForSystemInterface(ModuleDescriptor authMod, RoutingEntry filt, String tenantId, ModuleInstance inst, String request, ProxyContext pc, Handler<ExtendedAsyncResult<OkapiClient>> fut) {
    pc.debug("Calling doCallSystemInterface to get auth token");
    RoutingEntry re = inst.getRoutingEntry();
    String modPerms = "";
    if (re != null) {
        String[] modulePermissions = re.getModulePermissions();
        Map<String, String[]> mpMap = new HashMap<>();
        if (modulePermissions != null) {
            mpMap.put(inst.getModuleDescriptor().getId(), modulePermissions);
            logger.debug("authForSystemInterface: Found modPerms:" + modPerms);
        } else {
            logger.debug("authForSystemInterface: Got RoutingEntry, but null modulePermissions");
        }
        modPerms = Json.encode(mpMap);
    } else {
        logger.debug("authForSystemInterface: re is null, can't find modPerms");
    }
    ModuleInstance authInst = new ModuleInstance(authMod, filt, inst.getPath());
    doCallSystemInterface(tenantId, null, authInst, modPerms, "", pc, res -> {
        if (res.failed()) {
            pc.warn("Auth check for systemInterface failed!");
            fut.handle(new Failure<>(res.getType(), res.cause()));
            return;
        }
        OkapiClient cli = res.result();
        String deftok = cli.getRespHeaders().get(XOkapiHeaders.TOKEN);
        logger.debug("authForSystemInterface:" + Json.encode(cli.getRespHeaders().entries()));
        String modTok = cli.getRespHeaders().get(XOkapiHeaders.MODULE_TOKENS);
        JsonObject jo = new JsonObject(modTok);
        String token = jo.getString(inst.getModuleDescriptor().getId(), deftok);
        logger.debug("authForSystemInterface: Got token " + token);
        doCallSystemInterface(tenantId, token, inst, null, request, pc, fut);
    });
}
Also used : RoutingEntry(org.folio.okapi.bean.RoutingEntry) OkapiClient(org.folio.okapi.common.OkapiClient) HashMap(java.util.HashMap) JsonObject(io.vertx.core.json.JsonObject) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 5 with RoutingEntry

use of org.folio.okapi.bean.RoutingEntry 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)

Aggregations

RoutingEntry (org.folio.okapi.bean.RoutingEntry)10 ModuleInstance (org.folio.okapi.bean.ModuleInstance)6 ModuleDescriptor (org.folio.okapi.bean.ModuleDescriptor)3 HashMap (java.util.HashMap)2 OkapiClient (org.folio.okapi.common.OkapiClient)2 Test (org.junit.Test)2 HttpMethod (io.vertx.core.http.HttpMethod)1 HttpServerRequest (io.vertx.core.http.HttpServerRequest)1 DecodeException (io.vertx.core.json.DecodeException)1 JsonObject (io.vertx.core.json.JsonObject)1 RoutingContext (io.vertx.ext.web.RoutingContext)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 DeploymentDescriptor (org.folio.okapi.bean.DeploymentDescriptor)1 InterfaceDescriptor (org.folio.okapi.bean.InterfaceDescriptor)1 PermissionList (org.folio.okapi.bean.PermissionList)1