9

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

根据这个论坛帖子,我希望它可以轻松地与 JBoss 一起使用。

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

Subject subject = new Subject();
Principal myPrincipal = new MyPrincipal("me I myself");
subject.getPrincipals().add(myPrincipal);

PrivilegedExceptionAction<String> action = new PrivilegedExceptionAction<String>() {
    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 中:

<security-identity>
   <use-caller-identity/>
</security-identity>

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

根据这个 IBM WebSphere 信息中心部分,我还启用了系统属性com.ibm.CSI.rmiOutboundPropagationEnabled=true

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

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

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

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

4

2 回答 2

3

我怀疑您没有在 WAS 服务器上启用安全性。因为没有启用安全性并且您没有向 WAS 进行身份验证,所以没有凭证。因此,您的呼叫getCallerPrincipal返回未经身份验证。

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

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

这是有趣的东西。祝你好运。

于 2012-09-12T04:15:04.770 回答
0

可能这将帮助您降低使用专有 websphere-classes 的价格。我记得,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<WSCredential> 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<WSCredential> iter= credSet.iterator();
        this.creds=(WSCredential) iter.next();
        this.publicCredentials=this.subject.getPublicCredentials();
    }
    public WSCredential getWSCredential() throws WSSecurityException
    {
        return this.creds;
    }
    public List<String> 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<String, Set<String>> getAttributes()
    {
        Map<String, Set<String>> attributes = null;
        Iterator<?> i = this.subject.getPublicCredentials().iterator();
        while (attributes == null && i.hasNext())
        {
            Map<String, Set<String>> 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<String, Set<String>>(); 
        }
        return attributes;
    }
    public Subject getSubject()
    {
        return this.subject;
    }
    protected Set getPublicCredentials() {
        return publicCredentials;
    }


}

另请参阅:从 JAAS 线程获取调用者主题和从线程获取RunAs 主题

于 2013-04-26T14:27:23.840 回答