使用Axis2 Java客户端访问.NET服务:SecurityContextToken缺少sp:IncludeToken属性
SecurityContextToken doesn't contain any sp:IncludeToken attribute异常 先给你拆解下这个问题的核心:你遇到的异常是因为Rampart在解析WS-SecureConversation的安全策略时,期望嵌套的SecurityContextToken(SCT)也带有sp:IncludeToken属性,但当前的WSDL或策略配置里没满足这个要求,或者Rampart版本存在解析bug。结合你的场景,给你几个可行的解决方案:
1. 检查WSDL的完整安全策略
你贴的WSDL片段只显示了sp:SecureConversationToken的IncludeToken属性,但需要确认这个节点下是否嵌套了sp:SecurityContextToken,并且这个SCT节点是否也带有sp:IncludeToken属性。如果WSDL里的SCT没有这个属性,Rampart 1.7.1的解析器会直接抛出这个异常。
如果有权限修改WSDL,可以补充这个属性,比如:
<sp:SecureConversationToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> <sp:SecurityContextToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> <wsc:SecurityContextTokenType xmlns:wsc="http://schemas.xmlsoap.org/ws/2005/02/sc"/> </sp:SecurityContextToken> <!-- 其他相关策略节点 --> </sp:SecureConversationToken>
2. 升级Rampart版本
你当前使用的是Rampart 1.7.1,这个版本对WS-SecureConversation的策略解析存在已知的兼容性问题。建议升级到Rampart 1.8.0(稳定版),新版本修复了不少策略解析的bug,大概率能解决这个属性缺失的报错。
3. 手动配置Rampart策略文件(绕过WSDL解析问题)
如果修改WSDL不可行,可以手动创建Rampart的配置文件,强制指定SCT的IncludeToken属性。步骤如下:
- 创建
rampart-config.xml文件,内容如下:
<rampart:RampartConfig xmlns:rampart="http://ws.apache.org/rampart/policy"> <rampart:passwordCallbackClass>com.yourpackage.ClientPasswordCallback</rampart:passwordCallbackClass> <rampart:policy> <wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <sp:SecureConversationToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy" sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> <sp:SecurityContextToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> <wsc:SecurityContextTokenType xmlns:wsc="http://schemas.xmlsoap.org/ws/2005/02/sc"/> </sp:SecurityContextToken> </sp:SecureConversationToken> <!-- 补充TransportWithMessageCredential相关的策略,比如HTTPS传输配置 --> <sp:TransportBinding> <wsp:Policy> <sp:TransportToken> <wsp:Policy> <sp:HttpsToken RequireClientCertificate="false"/> </wsp:Policy> </sp:TransportToken> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic256/> </wsp:Policy> </sp:AlgorithmSuite> <sp:Layout> <wsp:Policy> <sp:Lax/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> </wsp:Policy> </sp:TransportBinding> </wsp:Policy> </rampart:policy> </rampart:RampartConfig>
- 在客户端代码中加载这个配置,替换原来直接设置用户名密码的部分:
ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(ClientRepo, AxisConfig); IMSFeedManagerStub feed = new IMSFeedManagerStub(ctx, ServiceUrl); ServiceClient sc = feed._getServiceClient(); sc.engageModule("rampart"); Options options = sc.getOptions(); // 加载自定义Rampart配置 options.setProperty(RampartMessageData.KEY_RAMPART_CONFIG, new File("path/to/rampart-config.xml").getAbsolutePath());
4. 改用PasswordCallback处理凭证
直接在Options中设置用户名密码的方式,在SecureConversation场景下可能不生效,建议实现PasswordCallback类来处理凭证:
import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; import java.io.IOException; public class ClientPasswordCallback implements CallbackHandler { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback callback = (WSPasswordCallback) callbacks[0]; // 设置用户名和密码 callback.setIdentifier("apache"); callback.setPassword("password"); } }
然后在rampart-config.xml中指定这个类的全路径,如上面配置里的rampart:passwordCallbackClass节点。
5. 确认ClientRepo的模块配置
确保你的ClientRepo目录下的modules/rampart.xml配置文件存在且完整,没有缺失依赖。如果是从Axis2的分发包中复制的,一般没问题,但如果是自定义的,需要检查是否包含了SecureConversation相关的配置。
内容的提问来源于stack exchange,提问作者user2210276

