Я использую Spring Security для аутентификации в своем приложении, и теперь я предоставляю доступ к веб-сервису с помощью cxf и хочу аутентифицировать текущий вызов веб-сервиса с использованием Spring Security. Но мне нужно получить доступ к сертификату в вызове веб-службы (я использую ws-security)
Это отрывок из моего объявления bean-компонента cxf:
<jaxws:endpoint id="service2" implementor="xxx.service2.CXFLibraryImpl" wsdlLocation="classpath:service2.wsdl" address="/service2"> <jaxws:inInterceptors> <bean class="com.kprtech.service.ws.service2.MyWSS4JInInterceptor"> </bean> </jaxws:endpoint>
Это wsdl, выставляющий ws-security:
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="CXFLibraryImplService" targetNamespace="http://service2.ws.service.kprtech.com/" xmlns:ns1="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service2.ws.service.kprtech.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <xs:schema elementFormDefault="unqualified" targetNamespace="http://service2.ws.service.kprtech.com/" version="1.0" xmlns:ns1="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service2.ws.service.kprtech.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xs:element name="sayHello" type="tns:sayHello" /> <xs:element name="sayHelloResponse" type="tns:sayHelloResponse" /> <xs:complexType name="sayHello"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:complexType name="sayHelloResponse"> <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="sayHello"> <wsdl:part element="tns:sayHello" name="parameters"> </wsdl:part> </wsdl:message> <wsdl:message name="sayHelloResponse"> <wsdl:part element="tns:sayHelloResponse" name="parameters"> </wsdl:part> </wsdl:message> <wsdl:portType name="Library"> <wsdl:operation name="sayHello"> <wsdl:input message="tns:sayHello" name="sayHello"> </wsdl:input> <wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CXFLibraryImplServiceSoapBinding" type="tns:Library"> <wsp:PolicyReference URI="#SignEncr" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" /> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="sayHello"> <soap:operation soapAction="" style="document" /> <wsdl:input name="sayHello"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="sayHelloResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CXFLibraryImplService"> <wsdl:port binding="tns:CXFLibraryImplServiceSoapBinding" name="CXFLibraryImplPort"> <soap:address location="http://localhost:8888/domicilios/services/service2" /> </wsdl:port> </wsdl:service> <wsp:Policy wsu:Id="SignEncr" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsp:ExactlyOne> <wsp:All> <sp:AsymmetricBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <wsp:Policy> <sp:InitiatorToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:RequireThumbprintReference /> <sp:WssX509V1Token10 /> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:InitiatorToken> <sp:RecipientToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"> <wsp:Policy> <sp:RequireThumbprintReference /> <sp:WssX509V3Token10 /> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:RecipientToken> <sp:AlgorithmSuite> <wsp:Policy> <sp:TripleDesRsa15 /> </wsp:Policy> </sp:AlgorithmSuite> <sp:Layout> <wsp:Policy> <sp:Strict /> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp /> <sp:OnlySignEntireHeadersAndBody /> </wsp:Policy> </sp:AsymmetricBinding> <sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"> <wsp:Policy> <sp:MustSupportRefKeyIdentifier /> <sp:MustSupportRefIssuerSerial /> </wsp:Policy> </sp:Wss10> <sp:SignedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <sp:Body /> </sp:SignedParts> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> </wsdl:definitions>
Проблема в том, что даже с моим пользовательским перехватчиком cxf использует org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor
и пытается проверить сертификаты и токены безопасности на крипто, и я хочу выполнить эту операцию самостоятельно в моем настраиваемом перехватчике com.kprtech.service.ws.service2.MyWSS4JInInterceptor
Я решил это некоторое время назад:
Вам нужна конфигурация CXF, подобная следующей:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-policy.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-ws-security.xml"/> <bean id="implementorBean" class="ws.Implementor"/> <jaxws:endpoint id="implementor" implementor="#implementorBean" wsdlLocation="/ws/server/service.wsdl" address="/service"> <jaxws:inInterceptors> <bean class="ws.SpringSecurityInterceptor"> </bean> </jaxws:inInterceptors> <jaxws:properties> <entry key="ws-security.signature.properties" value="/ws/security/server-crypto.properties"/> <entry key="ws-security.signature.username" value="serverkey"/> <entry key="ws-security.callback-handler" value="ws.ServerCallback"/> </jaxws:properties> </jaxws:endpoint> </beans>
И реализуйте перехватчик как этот:
public class SpringSecurityInterceptor extends AbstractWSS4JInterceptor { private ThreadLocal<Subject> currentSubject = new ThreadLocal<Subject>(); public SpringSecurityInterceptor() { super(); setPhase(Phase.PRE_PROTOCOL); getAfter().add(WSS4JInInterceptor.class.getName()); getAfter().add(PolicyBasedWSS4JInInterceptor.class.getName()); } public void handleMessage(SoapMessage message) throws Fault { try { Subject subject = (Subject) currentSubject.get(); if (subject == null) { subject = new Subject(); currentSubject.set(subject); } List<Object> results = (List<Object>)message.get(WSHandlerConstants.RECV_RESULTS); if (results == null) { return; } for (Iterator iter = results.iterator(); iter.hasNext();) { WSHandlerResult hr = (WSHandlerResult) iter.next(); if (hr == null || hr.getResults() == null) { return; } for (Iterator it = hr.getResults().iterator(); it.hasNext();) { WSSecurityEngineResult er = (WSSecurityEngineResult) it.next(); if (er != null && er.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE) instanceof X509Certificate) { X509Certificate cert = (X509Certificate)er.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE); // TODO do something with the certificate } } } message.put(Subject.class, subject); } catch (java.lang.reflect.UndeclaredThrowableException e) { Throwable undeclared = e.getUndeclaredThrowable(); if (undeclared != null && undeclared instanceof java.lang.reflect.InvocationTargetException) { throw new Fault( ((java.lang.reflect.InvocationTargetException) undeclared) .getTargetException()); } } finally { currentSubject.set(null); } } }