我正在测试JAAS Subject与custom Principal从在原始Java运行时上运行的独立EJB客户端到JavaEE服务器的传播。我的目标是JBoss和WebSphere实现。
根据this forum thread我预计它可以轻松地与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不受任何角色的保护。
根据this IBM WebSphere infocenter section,我还启用了系统属性com.ibm.CSI.rmiOutboundPropagationEnabled=true
。
从技术上讲,服务调用在JBoss或WebSphere上都能正常工作。但是包含我在客户端上创建的自定义主体的JAAS主题不会传播到服务器。或者,在JNDI上下文创建和EJB调用之前转储的Subject
是正常的。
我为服务器和客户端(IBM Java6 SR9 FP2 ...)运行相同的Java运行时版本,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
当然,我错过了某种魔法咒语。你知道哪一个吗?
答案 0 :(得分:3)
我怀疑您没有在WAS服务器上启用安全性。由于未启用安全性且您未对WAS进行身份验证,因此没有凭据。因此,您对getCallerPrincipal
的调用将返回UNAUTHENTICATED。
如果您在WAS中打开应用程序安全性,则必须通过CSIv2 protocol进行身份验证。在独立客户端中创建自己的JAAS主题将不会这样做。如果可以,那么任何人都可以创建一个“嘿,它是我”的凭证并登录到他们想要的任何远程EJB。
通过将主题附加到正在运行的执行线程,您的代码将在服务器上运行。通过线路流动的主体/凭证需要协议来实现主题信息的序列化并确保在凭证中声明身份的一方的信任。从独立客户端,WAS以基本授权,LTPA和kerberos的形式接受用户信息。这可以在管理控制台中的入站CSIv2配置上配置。它在我之前引用的信息中心链接中有记录。
这很有趣。祝你好运。
答案 1 :(得分:0)
这可能会帮助您降低使用专有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<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;
}
}
另请参阅:Getting the caller subject from the thread for JAAS和Getting the RunAs subject from the thread