多平台架構:P1/P2/P3分別部署於不同服務器。用戶user1調用P1上的EJB,P1需以user2(配置文件指定)調用P2上的EJB。但控制台顯示P1仍使用user1身份調用P2。
<bean id="XXX" class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean" lazy-init="true">
<property name="jndiName"><value>XXX</value></property>
<property name="jndiTemplate"><ref local="XXXJndiTemplate"/></property>
<property name="businessInterface"><value>XXXXXX</value></property>
</bean>
<bean id="XXXJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url">${XX.url}</prop>
<prop key="java.naming.security.principal">${XX.username}</prop> <!-- user2 -->
<prop key="java.naming.security.credentials">${XX.password}</prop>
</props>
</property>
</bean>
WebLogic默認啟用安全上下文傳播:當客戶端(此處P1作為客戶端)已有認證上下文時,JNDI查找與EJB調用將忽略JndiTemplate中配置的principal/credentials,改用當前線程的安全上下文(user1)。
在P1調用P2前檢查線程上下文:
Subject subject = Subject.getSubject(AccessController.getContext());
// 或 WebLogic專用
weblogic.security.Security.getCurrentSubject();
若非null,說明存在傳播上下文。
在P1的weblogic.xml或啟動參數設置:
-Dweblogic.security.disableContextPropagation=true
或代碼級控制:
import weblogic.security.Security;
Security.runAs(subject, new PrivilegedAction() {
public Object run() {
// 此處調用P2 EJB,使用JndiTemplate配置的user2
return p2Service.doBusiness();
}
});
使用Spring的SimpleRemoteStatelessSessionProxyFactoryBean子類化,覆蓋create()方法:
public class CustomRemoteProxy extends SimpleRemoteStatelessSessionProxyFactoryBean {
protected Object create() throws NamingException {
// 構建帶user2憑證的Context
Hashtable env = new Hashtable();
env.put(Context.SECURITY_PRINCIPAL, "user2");
env.put(Context.SECURITY_CREDENTIALS, "pwd2");
Context ctx = new InitialContext(env);
return ctx.lookup(getJndiName());
}
}
配置P1為可信任域,P2接受P1的身份斷言:
Credential Mapper映射user1→user2Identity Asserter信任P1域令牌Spring配置正確但被WebLogic安全上下文傳播特性覆蓋。通過JVM參數關閉傳播或代碼級runAs隔離可強制使用配置身份user2。建議架構層面明確服務間身份傳播策略,避免隱式行為導致安全審計風險。