Security 多个并发用户对JBossAS 4.2.3的RMI调用

Security 多个并发用户对JBossAS 4.2.3的RMI调用,security,rmi,jboss-4.2.x,Security,Rmi,Jboss 4.2.x,我想编写一个web前端,它希望将从浏览器接收到的HTTP身份验证“传播”到JBoss AS 4.2.3,该JBoss AS 4.2.3公开了许多@Remote接口 考虑以下RMI调用并发性的简单模拟: Properties user1 = new Properties(); user1.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"

我想编写一个web前端,它希望将从浏览器接收到的HTTP身份验证“传播”到JBoss AS 4.2.3,该JBoss AS 4.2.3公开了许多@Remote接口

考虑以下RMI调用并发性的简单模拟:

Properties user1 = new Properties();
user1.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
    "org.jboss.security.jndi.JndiLoginInitialContextFactory");
user1.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming");
user1.setProperty(Context.PROVIDER_URL, "127.0.0.1:1099");
user1.setProperty(Context.SECURITY_PRINCIPAL, "user1");
user1.setProperty(Context.SECURITY_CREDENTIALS, "pass1");

Properties user2 = new Properties();
user2.setProperty(Context.INITIAL_CONTEXT_FACTORY,
   "org.jboss.security.jndi.JndiLoginInitialContextFactory");
user2.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming");
user2.setProperty(Context.PROVIDER_URL, "127.0.0.1:1099");
user2.setProperty(Context.SECURITY_PRINCIPAL, "user2");
user2.setProperty(Context.SECURITY_CREDENTIALS, "pass2");

InitialContext ctx1 = new InitialContext(user1);
Mine bean1 = (Mine) ctx1.lookup("myear/MyBean/remote");
InitialContext ctx2 = new InitialContext(user2);
Mine bean2 = (Mine) ctx2.lookup("myear/MyBean/remote");

System.out.println(bean1.whoami());
System.out.println(bean2.whoami());
调用使用jbossall客户端4.2.3并转到JBoss AS 4.2.3

.whoami()方法只是回显登录的用户名。当它转到我们的时,这导致两个调用都说它们是由“user2”发出的。据推测,底层连接是共享的,并且仅使用上次看到的属性包进行身份验证

简而言之,这太糟糕了。一些初步测试表明JBoss和7中仍然存在相同的问题,因此没有运气

我是否可以使用任何其他RMI客户端实现或在prop bundle中传递任何参数,以使InitialContext不共享其登录信息?或者,是否有人可以向我指出需要进行黑客攻击才能实现这一点的代码

更新:

根据要求:

public class Worker extends Thread {
private final String pass, user;
private int correct = 0;

public Worker(String user, String pass) { this.user = user; this.pass = pass; }

public void run() {
    Properties props = new Properties();
    props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
            "org.jboss.security.jndi.JndiLoginInitialContextFactory");
    props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming");
    props.setProperty(Context.PROVIDER_URL, "127.0.0.1:1099");
    props.setProperty(Context.SECURITY_PRINCIPAL, this.user);
    props.setProperty(Context.SECURITY_CREDENTIALS, this.pass);

    try {
        InitialContext ctx = new InitialContext(props);
        for(int i = 0; i < 100; i++) {
            Mine bean = (Mine) ctx.lookup("myear/MyBean/remote");
            if(bean.whoami().equals(this.user)) this.correct++;
            Thread.sleep(2); }
        ctx.close();
    } catch (Exception e) { throw new RuntimeException(e); }
    System.out.println("Done [id="+this.getId()+", good="+this.correct+"]"); 
}
}
使用5个线程运行会产生:

public static void main(String[] args) throws Exception {
    new Worker("user1", "pass1").start();
    new Worker("user2", "pass2").start();
    new Worker("user3", "pass3").start();
    new Worker("user4", "pass4").start();
    new Worker("user5", "pass5").start(); 
}

Caused by: javax.ejb.EJBAccessException: Authentication failure
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.handleGeneralSecurityException(Ejb3AuthenticationInterceptor.java:68)
at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:70)
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:110)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:304)
at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:106)
at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:809)
at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:608)
at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:406)
at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:173)
at org.jboss.remoting.MicroRemoteClientInvoker.invoke(MicroRemoteClientInvoker.java:163)
at org.jboss.remoting.Client.invoke(Client.java:1634)
at org.jboss.remoting.Client.invoke(Client.java:548)
at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:62)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:53)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:74)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:107)
at $Proxy0.whoami(Unknown Source)
at net.windwards.Worker.run(TestRMIClient.java:31)
at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:74)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:53)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:74)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:107)
at $Proxy0.whoami(Unknown Source)
at net.windwards.Worker.run(TestRMIClient.java:31)
建立初始连接大约需要100毫秒,因此我尝试了以下方法(在两次呼叫之间睡眠10毫秒以获得良好的重叠):


这里的基本问题是,在同一线程中使用第二个上下文之前,没有关闭第一个上下文。我怀疑这是一个公平的测试。更有趣的是,通过在单独的线程中运行这两个线程,实际上使它们并发。

来自for
org.jboss.security.jndi.JndiLoginInitialContextFactory

在JNDI命名的getInitialContext回调期间,层安全上下文标识将填充用户名。。。还有证书。。。此信息没有实际的身份验证。它只提供给jboss传输层,以便合并到后续调用中

在本例中,当您调用bean时,
user2
是最后一个主体集,jboss传输层也可以使用这个主体集

但是,从中可以看出,您可以将安全上下文的作用域设置为线程上下文,在这种情况下,您的线程测试应该可以工作,只需添加以下属性:

userN.setProperty("jnp.multi-threaded", "true");

另一种解决方案是使用
org.jboss.security.jndi.LoginInitialContextFactory
而不是
org.jboss.security.jndi.JndiLoginInitialContextFactory
,与
JndiLoginInitialContextFactory
不同,
LoginInitialContextFactory
将在查找时尝试进行身份验证,而不是在调用EJB时,您可以尝试一下,即使在中,当涉及到远程客户端上的EJB授权时,他们建议使用JndiLoginInitialContextFactory

当从JNDI调用
getInitialContext()
时,安全层使用凭证分幅调用包装器;事实上,它从未经过源代码验证,它只是JBOSS的一种虚拟表示,用于后续调用同一实体模型。 在您的情况下,user2是JBOSS最后一个可用的


  • 或者,您也可以在服务器上使用JBOSS的多个实例 通过使用
    ServiceBindingManager
    使用同一台机器。这可以帮助你 跟踪您进行的所有RMI调用,以及 连接器对象可以工作,因为它本身是一个JMXbean对象
  • 您还可以使用线程模型,通过 添加属性

    setProperty(“jnp.multi-threaded”、“true”)

正如一项建议,我发现在远程客户端上使用
JndiLoginInitialContextFactory
进行EJB身份验证


希望这有帮助

该示例的要点是显示这两个上下文重用到JBoss的相同连接,尽管它们具有不同的凭据。正是因为不涉及线程,所以我们可以相当肯定这不是并发性问题。当您在两个线程中尝试了它,并且得到了相同的结果时,它可能会成为一个有趣的讨论。添加了并发执行。
public static void main(String[] args) throws Exception {
    new Worker("user1", "pass1").start();
    Thread.sleep(200);
    new Worker("user2", "pass2").start();
    Thread.sleep(200);
    new Worker("user3", "pass3").start();
    Thread.sleep(200);
    new Worker("user4", "pass4").start();
    Thread.sleep(200);
    new Worker("user5", "pass5").start();
}

Done [t=9, good=1]
Done [t=14, good=12]
Done [t=15, good=14]
Done [t=16, good=15]
Done [t=17, good=100]
userN.setProperty("jnp.multi-threaded", "true");