2014-02-05 53 views
4

我想編寫一個Web前端,希望將從瀏覽器接收到的HTTP認證「傳播」到暴露大量@Remote接口的JBoss AS 4.2.3。多個併發用戶對JBoss AS 4.2.3的RMI調用

考慮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 AS 7中,所以沒有運氣。

是否有任何其他RMI客戶端實現我可以使用或任何參數我可以通過在prop捆綁使InitialContexts不共享他們的登錄信息?另外,有人可以指向我需要被黑客入侵的代碼,以使其成爲可能嗎?

UPDATE:

根據要求:

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+"]"); 
} 
} 

與兩個工人產量運行:

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

Done [t=9, good=0] 
Done [t=10, good=100] 

用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毫秒,以獲得良好的重疊):

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] 

回答

2

docsorg.jboss.security.jndi.JndiLoginInitialContextFactory

在從JNDI命名的getInitialContext回調,層安全上下文身份填入用戶名... ...和憑據......還有就是這個沒有實際驗證信息。它只是提供給JBoss的傳輸層摻入後續調用

在這種情況下

,由你來調用你的bean時,user2是最後的主集,所以是要使用的一個可用由jboss傳輸層完成。

不過,從jboss4 source,它看起來像你可以作用域爲線程上下文的安全上下文,在這種情況下,你的線程測試應該工作,只需添加此屬性:

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

另一個解決方案是使用org.jboss.security.jndi.LoginInitialContextFactory而不是,與JndiLoginInitialContextFactory不同,LoginInitialContextFactory將嘗試在查找時進行身份驗證,而不是在調用EJB時​​嘗試,儘管在the docs中,他們建議在涉及EJB授權時使用JndiLoginInitialContextFactory遠程客戶端

+0

jnp.multi-threaded = true =>成功! – Bittrance

1

這裏的基本問題是,你還沒有關閉之前,第一環境信息你在同一個線程中使用第二個。我懷疑這是一個公平的考驗。通過在不同的線程中運行它們會讓兩者併發更有趣。

+0

這個例子的要點是要證明兩個上下文重用與JBoss相同的連接,儘管它們具有不同的憑證。正因爲沒有涉及到線程,我們可以確信這不是一個併發問題。 – Bittrance

+0

示例的要點是它在單線程中運行。當你在兩個線程中嘗試過它,並得到相同的結果時,它可能成爲一個有趣的討論。 – EJP

+0

增加了併發執行。 – Bittrance

1

當從JNDI調用getInitialContext()時,安全層調用包含憑據切片的包裝器;這實際上從來沒有用源驗證過,它只是爲了後續調用同一個實體模型而將JBOSS切片的虛擬表示類型。 就你而言,user2是JBOSS最後一個可用的。


  • 或者,您也可以通過使用ServiceBindingManager使用 同一臺機器上JBOSS的多個實例。這可以幫助你保持跟蹤你所做的所有RMI調用,並且 連接器對象的屬性也可以工作,因爲它本身是一個JMX Bean對象。
  • 你也可以使用一個線程模型可以通過 給你額外的安全性將屬性添加

    userN.setProperty(「jnp.multi線程」,「真」);

而只是作爲一個建議,我在網上找到使用JndiLoginInitialContextFactory對遠程客戶端EJB認證。

希望這會有所幫助!