Jakarta ee 如何在EJB/MDB调用期间更改用户主体?

Jakarta ee 如何在EJB/MDB调用期间更改用户主体?,jakarta-ee,authentication,ejb,jaas,Jakarta Ee,Authentication,Ejb,Jaas,我有一个应用程序,其中一些操作由MDB执行。这些MDB都使用@RunAs(SYSTEM)注释将它们标记为系统元素 其中一个MDB必须运行一些通过@RolesAllowed(WORKSPACE)保护的代码,系统角色显然没有这些代码,但启动该过程的用户(请注意,是人)有这些代码 所以,我的问题很简单:有没有办法(例如通过异步调用)让我的MDB将其主体更改为我的用户而不是系统?我假设系统是一个角色,而对于user,您真的是指发送JMS消息来表示MDB正在侦听的队列的用户吗 如果您想将主体设置为该用户的

我有一个应用程序,其中一些操作由MDB执行。这些MDB都使用
@RunAs(SYSTEM)
注释将它们标记为系统元素

其中一个MDB必须运行一些通过
@RolesAllowed(WORKSPACE)
保护的代码,
系统
角色显然没有这些代码,但启动该过程的
用户(请注意,是人)有这些代码

所以,我的问题很简单:有没有办法(例如通过异步调用)让我的MDB将其主体更改为我的
用户而不是
系统

我假设系统是一个角色,而对于user,您真的是指发送JMS消息来表示MDB正在侦听的队列的用户吗

如果您想将主体设置为该用户的确切角色(基本上传播用户的安全上下文或从MDB中进行容器登录),那么很遗憾,这是不可能的。有一个在EJB中标准化容器登录的请求(请参阅EJB规范JIRA),但现在这对您没有帮助

解决方法可以是JAX-RS资源,它可以使用ServletAPI触发任何给定用户的登录。在这里您必须小心,不要创建一个巨大的安全漏洞(例如只允许通过用户名登录),但这是一个选项


如果您只需要角色工作区,那么您不能简单地使用第二个@RunAs吗?

就像Mike Braun的回答所建议的那样,根据JavaEE规范,这是不可能的

这是不幸的。但是,有一点不那么不幸的是,在
@RunAs
的应用服务器实现中隐藏了一些代码来完成这类事情(特定于应用服务器)。在Glassfish中,该特定代码在类中,尤其是在其
LoginContextDriver#loginPrincipal
方法中

因此,为了让代码的一部分使用特定的主体,我定义了一个接口

public interface Sudoer {
    public <Result> Result sudo(String user, SudoOperation<Result> operation);
}
公共接口Sudoer{
公共结果sudo(字符串用户,SudoOperation操作);
}
我为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();
        }
    }
}
公共类GlassfishSudoer实现Sudoer{
@凌驾
公共结果sudo(字符串用户,SudoOperation操作){
试一试{
LoginContextDriver.loginPrincipal(用户,“autocat”);
返回操作。perform();
}捕获(例外e){
抛出新的UnableToSudoException(e);
}最后{
LoginContextDriver.logout();
}
}
}
当使用它时,想要有一些代码“sudoed”的部分只需要提供SudoOperation的实现,比如

    component.sudo(userLogin, new SudoOperation<Void>() {
        public Void perform() {
            /* do some sudoed code */
            return null;
        }
    });
component.sudo(用户登录,新的SudoOperation(){
公开执行{
/*做一些无用的代码*/
返回null;
}
});
这种方法的优点是,如果给定的应用程序服务器有一些代码来处理
@RunAs
,您可以使用这些代码来实现自己的sudoer(我正在考虑将其提取到sudo ejb库中…。

请看一下:


这是一种更通用的方法。为我在JBoss工作。

你能提供一个这种方法的例子吗?我知道jax rs,但如何通过servlet api登录?@dermoritz使用HttpServletRequest.authenticate()或HttpServletRequest.login()