如何从纯客户端调用远程EJB(基于IIOP的RMI)时传播JAAS主题

我正在使用从原始Java运行时上运行的独立EJB客户端到JavaEE服务器的自定义Principal测试JAAS Subject的传播。 我的目标是JBoss和WebSphere实现。

根据这个论坛post,我预计它可以轻松地与JBoss一起使用。

这是我的EJB客户端代码代码段:

Subject subject = new Subject(); Principal myPrincipal = new MyPrincipal("me I myself"); subject.getPrincipals().add(myPrincipal); PrivilegedExceptionAction action = new PrivilegedExceptionAction() { public String run() throws Exception { String result; System.out.println("Current Subject: " + Subject.getSubject(AccessController.getContext())); InitialContext ic = new InitialContext(); Business1 b = (Business1) ic.lookup("StatelessBusiness1"); result = b.getNewMessage("Hello World"); return result; } }; result = subject.doAs(subject, action); System.out.println("result "+result); 

服务器端代码是:

 public String getNewMessage(String msg) { System.out.println("getNewMessage principal: " + sessionContext.getCallerPrincipal()); System.out.println("Current Subject: " + Subject.getSubject(AccessController.getContext())); return "getNewMessage: " + msg; } 

可以肯定的是,即使它是默认行为,我也已将此部分添加到我的ejb-jar.xml会话bean中:

    

我的会话bean不受任何角色的保护。

根据此IBM WebSphere infocenter部分 ,我还启用了系统属性com.ibm.CSI.rmiOutboundPropagationEnabled=true

从技术上讲,服务调用在JBoss或WebSphere上都能正常工作。 但是包含我在客户端上创建的自定义主体的JAAS主题不会传播到服务器。 或者, Subject在JNDI上下文创建和EJB调用之前转储。

我为服务器和客户端运行相同的Java运行时版本(IBM Java6 SR9 FP2 …), MyPrincipal序列化类在服务器ClassPath中可用(WebSphere的AppServer/lib/ext ,JBoss的server/default/lib

WebSphere转储:

 [8/31/12 11:56:26:514 CEST] 00000024 SystemOut O getNewMessage principal: UNAUTHENTICATED [8/31/12 11:56:26:515 CEST] 00000024 SystemOut O Current Subject: null 

JBoss转储:

  12:30:20,540 INFO [STDOUT] getNewMessage principal: anonymous 12:30:20,540 INFO [STDOUT] Current Subject: null 

当然,我错过了某种魔法咒语。 你知道哪一个吗?

我怀疑您没有在WAS服务器上启用安全性。 由于未启用安全性且您未对WAS进行身份validation,因此没有凭据。 因此,您对getCallerPrincipal的调用将返回UNAUTHENTICATED。

如果在WAS中打开应用程序安全性,则必须通过CSIv2协议进行身份validation。 在独立客户端中创建自己的JAAS主题将不会这样做。 如果可以,那么任何人都可以创建一个“嘿,它是我”凭证并登录到他们想要的任何远程EJB。

通过将主题附加到正在运行的执行线程,您的代码将在服务器上运行。 通过线路流动的主体/凭证需要协议来实现主题信息的序列化并确保在凭证中声明身份的一方的信任。 从独立客户端,WAS以基本授权,LTPA和kerberos的forms接受用户信息。 这可以在管理控制台中的入站CSIv2配置上配置。 它在我之前引用的信息中心链接中有记录。

这很有趣。 祝你好运。

这可能会帮助您降低使用专有websphere类的价格。 我记得,websphere不会传播jaas来电主题,这对于ibm来说是典型的

  package foo.bar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.login.CredentialExpiredException; import org.apache.log4j.Logger; import com.ibm.websphere.security.WSSecurityException; import com.ibm.websphere.security.auth.CredentialDestroyedException; import com.ibm.websphere.security.auth.WSSubject; import com.ibm.websphere.security.cred.WSCredential; public class IdentityHelper { private static final Logger log = Logger.getLogger(IdentityHelper.class); private static final String CLASS_OBJECT = "java.util.HashMap"; private static final String KEY_OBJECT = "java.lang.String"; private static final String VALUE_OBJECT = "java.util.HashSet"; private Subject subject=null; private WSCredential creds; private Set publicCredentials=null; public IdentityHelper(Subject _subject) throws WSSecurityException { if(_subject==null) { IdentityHelper.log.warn("given subject was null, using Caller-Subject or the RunAs-Subject!"); this.subject = WSSubject.getCallerSubject(); if(this.subject==null)this.subject=WSSubject.getRunAsSubject(); } else { this.subject=_subject; } init(); } public IdentityHelper() throws WSSecurityException { this.subject=WSSubject.getRunAsSubject(); if(this.subject==null) { IdentityHelper.log.warn("using Caller-Subject NOT the RunAs-Subject!"); this.subject = WSSubject.getCallerSubject(); } init(); } private void init() throws WSSecurityException { Set credSet= this.subject.getPublicCredentials(WSCredential.class); //set should contain exactly one WSCredential if(credSet.size() > 1) throw new WSSecurityException("Expected one WSCredential, found " + credSet.size()); if(credSet.isEmpty()) { throw new WSSecurityException("Found no credentials"); } Iterator iter= credSet.iterator(); this.creds=(WSCredential) iter.next(); this.publicCredentials=this.subject.getPublicCredentials(); } public WSCredential getWSCredential() throws WSSecurityException { return this.creds; } public List getGroups() throws WSSecurityException,CredentialDestroyedException,CredentialExpiredException { WSCredential c = this.getWSCredential(); return c.getGroupIds(); } /** * helper method for obtaining user attributes from Subject objects. * @param subject * @return */ @SuppressWarnings("unchecked") public Map> getAttributes() { Map> attributes = null; Iterator i = this.subject.getPublicCredentials().iterator(); while (attributes == null && i.hasNext()) { Map> tmp = null; Object o = i.next(); if(IdentityHelper.log.isDebugEnabled()) { IdentityHelper.log.debug("checking for attributes (class name): " + o.getClass().getName()); } if(!o.getClass().getName().equals(CLASS_OBJECT)) continue;//loop through tmp = (Map) o; Object tObject = null; Iterator t = null; t = tmp.keySet().iterator(); tObject = t.next(); if(IdentityHelper.log.isDebugEnabled()) { IdentityHelper.log.debug("checking for attributes (key object name): " + tObject.getClass().getName()); } if(!tObject.getClass().getName().equals(KEY_OBJECT)) continue;//loop through t = tmp.values().iterator(); tObject = t.next(); if(IdentityHelper.log.isDebugEnabled()) { IdentityHelper.log.debug("checking for attributes (value object name): " + tObject.getClass().getName()); } if(!tObject.getClass().getName().equals(VALUE_OBJECT)) continue;//loop through attributes = (Map) o; } if (attributes == null) { attributes = new HashMap>(); } return attributes; } public Subject getSubject() { return this.subject; } protected Set getPublicCredentials() { return publicCredentials; } } 

另请参阅: 从线程中获取调用者主题以获取JAAS并从该线程 获取RunAs主题