我有一个应用程序,其中一些操作由 MDB 执行。这些MDB 都使用@RunAs(SYSTEM)
注解将它们标记为系统元素。
其中一个 MDB 必须运行一些受保护的代码,显然@RolesAllowed(WORKSPACE)
,SYSTEM
角色没有这些代码,但是user
启动该过程的(人类,请注意)具有这些代码。
所以,我的问题很简单:有什么方法(例如通过异步调用)让我的 MDB 将其主体更改为 myuser
而不是SYSTEM
?
我有一个应用程序,其中一些操作由 MDB 执行。这些MDB 都使用@RunAs(SYSTEM)
注解将它们标记为系统元素。
其中一个 MDB 必须运行一些受保护的代码,显然@RolesAllowed(WORKSPACE)
,SYSTEM
角色没有这些代码,但是user
启动该过程的(人类,请注意)具有这些代码。
所以,我的问题很简单:有什么方法(例如通过异步调用)让我的 MDB 将其主体更改为 myuser
而不是SYSTEM
?
我假设SYSTEM是一个角色,而对于用户,您真的是指发送例如 JMS 消息来表示 MDB 正在侦听的队列的用户?
如果您想设置具有与该用户完全相同的角色的 Principal(基本上是传播用户的安全上下文或从 MDB 中进行容器登录),那么很遗憾,这是不可能的。有一个要求标准化 EJB 中的容器登录(请参阅 EJB 规范 JIRA),但现在这对您没有帮助。
一种解决方法可能是使用 JAX-RS 资源,它可以使用 Servlet API 来触发任何给定用户的登录。您必须在这里小心,不要造成巨大的安全漏洞(例如,仅允许通过用户名登录),但这是一种选择。
如果您只需要角色WORKSPACE,那么您不能简单地使用第二个@RunAs 吗?
就像 Mike Braun 回答建议的那样,根据 JavaEE 规范这是不可能的。
这是不幸的。但是,不那么不幸的是,有一些代码可以做这种事情(特定于应用程序服务器),隐藏在@RunAs
. 在 Glassfish 中,该特定代码在com.sun.enterprise.security.auth.login.LoginContextDriver
类中,尤其是在其LoginContextDriver#loginPrincipal
方法中。
所以,为了让一部分代码使用特定的主体,我定义了一个接口
public interface Sudoer {
public <Result> Result sudo(String user, SudoOperation<Result> operation);
}
我为 Glassfish 实现的如下:
public class GlassfishSudoer implements Sudoer {
@Override
public <Result> Result sudo(String user, SudoOperation<Result> operation) {
try {
LoginContextDriver.loginPrincipal(user, "autocat");
return operation.perform();
} catch (Exception e) {
throw new UnableToSudoException(e);
} finally {
LoginContextDriver.logout();
}
}
}
并且在使用它时,想要有一些代码“sudoed”的部分只需要提供 SudoOperation 的实现,比如
component.sudo(userLogin, new SudoOperation<Void>() {
public Void perform() {
/* do some sudoed code */
return null;
}
});
这种方法的优点是,如果给定的应用程序服务器有一些代码要处理@RunAs
,您可以使用该代码来实现您自己的 sudoer(我正在考虑将其提取到 sudo-ejb 库中......)。
看看: 这里的一个最近的问题
它是一种更通用的方法。为我在 JBoss 工作。