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));
});
});
}
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);
}
}
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);
});
}
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);
});
}
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<>());
}
});
}
Aggregations