我有一个tomcat Web服务,它接受 opentravel.org OTA XML请求并做出相应的响应。 它使用 JibX OTA 类。
到目前为止,该服务的用户已经使用了 POX,并且效果非常好,但是新用户希望使用 SOAP 并像这样将安全凭据添加到 SOAP 标头中(而不是将它们放入 POS xml 片段(...
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org /wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-username-token-profile-1.0#PasswordText">SECRET</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
因此,要对请求进行身份验证,我认为我需要从服务实现类中访问标头。
我查看了 SOAP 标头示例,我认为它告诉我可以通过包含 inContext 来访问标头,例如
public RoomListRS list(RoomListRQ roomListRQ, InContext inCtx){
....
}
所以在这种方法中我可以做到这一点...
Security security = (Security ) inCtx.getAttribute("security");
所以我可以访问其中的用户名令牌,
。在服务中指定了这一点...
<service name="OTAService">
<service-class>com.xx.webservice.ota.HotelServiceImpl</service-class>
<operation method="list"/>
<handler-class class="org.jibx.ws.io.handler.ContextAttributeUnmarshallingInHandler">
<constructor-arg value="com.xx.shared.soap.security.Security"/>
<constructor-arg value="security"/>
</handler-class>
</service>
我说得对吗?
所以我创建了 Security 类,但省略了所有命名空间的内容,只是为了开始并证明我可以访问标头中的某些内容。 基于这样的片段...
<Security>
<UsernameToken>
<Username>USERNAME</Username>
<Password>SECRET</Password>
</UsernameToken>
</Security>
所以我用bindgen创建了绑定,然后编译,然后用soapUI调用它
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.opentravel.org/OTA/2003/05">
<soapenv:Header>
<Security>
<UsernameToken>
<Username>USERNAME</Username>
<Password>SECRET</Password>
</UsernameToken>
</Security>
</soapenv:Header>
<soapenv:Body>
<OTA_HotelRoomListRQ xmlns="http://www.opentravel.org/OTA/2003/05" Version="2.0">
....
</OTA_HotelRoomListRQ>
</soapenv:Body>
</soapenv:Envelope>
但是当我尝试从上下文中获取安全对象时,它是空的。
我弄错了棍子的一端吗?
我是否应该使用更 SOAP 的东西创建另一个具有不同端点的服务?
我试图用 JibX WS 和 inHandler 做不到吗?
欢迎任何评论。
非常感谢您不厌其烦地回答我的问题。
我正在尝试浏览您添加的内容。 我使用您的自定义和 xsd 来创建 java 源代码和绑定.xml。
我已经编译了这些类,现在正在尝试绑定它们,但是我收到此错误:
C:Javawsse>java org.jibx.binding.generator.BindGen org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType
Exception in thread "main" java.lang.IllegalStateException: No way to handle type java.lang.Object, referenced from org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType
at org.jibx.binding.generator.BindGen.expandReferences(BindGen.java:227)
at org.jibx.binding.generator.BindGen.findReferences(BindGen.java:1010)
at org.jibx.binding.generator.BindGen.generate(BindGen.java:1124)
at org.jibx.binding.generator.BindGen.main(BindGen.java:1302)
我将看看bindgen定制,看看这是否提供了任何启示,因为这是回应这个问题的唯一线索。 你能告诉我你是怎么解决这个问题的吗?
再次感谢。
我可以分享一些用于WS-Security用户名/密码标头的生产代码。 我不明白为什么你的代码不起作用,但也许这会有所帮助。
我们从 oasis-200401-wss-wssecurity-secext-1.0.xsd 架构生成了 WS-Security 代码和绑定,并具有以下自定义:
<!-- Contains customization elements for code generation from WS Security schema -->
<schema-set show-schema="false" generate-all="false" xmlns:xs="http://www.w3.org/2001/XMLSchema" line-width="120">
<schema name="oasis-200401-wss-wssecurity-secext-1.0.xsd" generate-all="true" prefer-inline="true" any-handling="mapped">
<class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator" />
</schema>
</schema-set>
然后用:
<target name="codegen-wss" description="Regenerate JiBX bindings and generated code for WS-Security schema">
<echo message="Running code generation from schema" />
<mkdir dir="${gen.src.dir}" />
<java classname="org.jibx.schema.codegen.CodeGen" fork="yes" classpathref="build.classpath" failonerror="true">
<arg value="-c" />
<arg value="custom_jibx_gen_wssec.xml" />
<arg value="-t" />
<arg value="${gen.src.dir}" />
<arg value="wsdl/wssec/oasis-200401-wss-wssecurity-secext-1.0.xsd" />
</java>
<move file="${gen.src.dir}/binding.xml" tofile="${wssec.binding.file}" failonerror="true" />
</target>
并绑定:
<target name="compile" depends="init" description="Compile the source code and run JiBX binding compiler">
<mkdir dir="${dest.dir}" />
<javac srcdir="${src.dir}:${gen.src.dir}" destdir="${dest.dir}" deprecation="on">
<classpath refid="build.classpath" />
</javac>
<bind binding="${gen.src.dir}/xxx-binding.xml">
<classpath path="${dest.dir}" />
</bind>
<bind binding="${wssec.binding.file}">
<classpath path="${dest.dir}" />
</bind>
</target>
servlet 的 Spring 配置定义了 InHandler:
<property name="handlerDefinitions">
<list>
<bean class="org.jibx.ws.server.HandlerDefinition" >
<description>Handler for inbound WS/Security header</description>
<property name="className" value="org.jibx.ws.io.handler.ContextAttributeUnmarshallingInHandler" />
<property name="args">
<list>
<value>org.oasisopen.docs.wss.oasis200401wsswssecuritysecext1.SecurityHeaderType</value>
<value>wssecurity.header</value>
</list>
</property>
</bean>
端点使用以下方法检索标头:
public ServiceRequestReceipt processRequest(ServiceRequest request, InContext inCtx, OutContext outCtx)
throws WsException {
SecurityHeaderType securityHeader = (SecurityHeaderType) inCtx.getAttribute("wssecurity.header");
我们使用 securityHeader 的代码如下所示:
if (securityHeader == null) {
throw new AuthenticationException("No WS-Security header found");
}
List<Object> securityHeaderTypes = securityHeader.getSecurityHeaderTypes();
if (securityHeaderTypes == null || securityHeaderTypes.size() == 0) {
throw new AuthenticationException("WS-Security header appears to be empty");
}
UsernameTokenType usernameToken = null;
try {
usernameToken = (UsernameTokenType) securityHeaderTypes.get(0);
} catch (ClassCastException e) {
throw new AuthenticationException("Expected UsernameToken in WS-Security header");
}
AttributedString usernameAttStr = usernameToken.getUsername();
if (usernameAttStr == null) {
throw new AuthenticationException("Expected Username in WS-Security header");
}
String username = usernameAttStr.getString();
if (!username.equals(retailer.getRetailerUsername())) {
throw new AuthenticationException("Invalid username in WS-SecurityHeader");
}
List<Object> any = usernameToken.getAny();
if (any == null) {
throw new AuthenticationException("Expected Password element in WS-Security header");
}
PasswordString passwordString = null;
for (Iterator iterator = any.iterator(); iterator.hasNext();) {
try {
passwordString = (PasswordString) iterator.next();
} catch (ClassCastException ignore) {
logger.debug("Found non password string object");
}
}
if (passwordString == null) {
throw new AuthenticationException("Expected Password in WS-Security header");
}
if (passwordString.getAttributedString() == null) {
throw new AuthenticationException("Expected Password AttributedString in WS-Security header");
}
String password = passwordString.getAttributedString().getString();
if (!password.equals(retailer.getRetailerPassword())) {
throw new AuthenticationException("Invalid password in WS-SecurityHeader");
}
我希望这有所帮助!