如何在Apache Sling的OSGI服务调用中告诉用户身份?

问题描述

在Apache Sling中:如果您具有多租户设置或用户可以部署自己的代码的环境(例如JSP或实际的Java / Groovy代码或其他),是否可以确定具有以下身份的用户的身份:从一个称为Osgi服务的内部发送当前请求?它必须安全防范恶意代码

背景:通常,依靠JCR permissions来保护用户不应该看到的东西就足够了。但是有时您希望Osgi服务使用service user来访问内部内容,以获取该服务实现所需的JCR资源,但是您不希望用户对其进行访问。在这里,您可能会采用某种防篡改的方式来识别用户,以便检查其对服务的权限。

有些事情显然不起作用。

  • 您可以将用户ResourceResolver作为参数传递给Osgi服务中的调用,并检查ResourceResolver.getUserId()返回什么。可以通过传入一个委派给原始ResourceResolver的包装器,但在此为getUserId()返回任意值的方法来轻松地颠覆这一点。
  • 可以将用户ResourceResolver作为服务的参数传递,并检查用户对资源树中某个路径的访问权限,并设置JCR权限以保护该路径。不幸的是,这并不像听起来那样简单:恶意代码可能再次在此处传递包装器,该包装器返回此路径的模拟资源,以模拟访问。我认为这可行的唯一方法用户必须对该路径进行写访问,并且使用服务用户来检查该路径是否确实被修改。但是由于性能和其他原因,这不是一个方法

您还有其他可行的想法吗?非常感谢!

注意:我知道这里还需要阻止其他攻击(例如the use of reflection to intrude into the OSGI services,但我至少要使其平凡。

解决方法

这是一个多租户系统,因此每个用户都将属于某个租户。根据租户上下文,您可以使用RequestContext对象,该对象实际上使用SecurityManager检查该租户的用户是否具有适当的访问权限,并允许特定用户使用。

,

好吧,我至少发现了一些东西:ResourceResolverFactory.getThreadResourceResolver返回请求对其进行身份验证的最后一个ResourceResolver。因此,如果将ResourceResolverFactory注入服务中,则由此返回的ResourceResolver的getUserId似乎至少会提供用户可以模拟的用户ID。

(请注意,这不一定是用户本身的原始ID,因为如果代码使用ResourceResolverFactory.getResourceResolver,则会更改结果。但这至少意味着用户可以模拟返回的用户ID。)

另一件事是采用像Composum的PlatformAccessFilter这样的ServletFilter,它将原始SlingHttpRequest使用的ResourceResolver保留在ThreadLocal中。 (如果恶意代码能够以更高的优先级部署ServletFilter,那么该方案就会失效,但是我们必须停在某个地方。)

不幸的是,由于ResourceResolverFactory.getServiceResolver不会设置esourceResolverFactory.getThreadResourceResolver,因此这两种想法都不适用于服务解析器。