Вызов .NET Web Service (WSE 2/3, WS-Security) с Java
Мне нужно вызвать веб-службу, написанную на .NET с Java. Веб-сервис реализует стек WS-Security (либо WSE 2, либо WSE 3, он не ясен из информации, которую я имею).
Информация, полученная от поставщика услуг, включала WSDL, файл policyCache.config, некоторый пример кода С# и пример приложения, которое может успешно вызвать службу.
Это не так полезно, как кажется, потому что не ясно, как я должен использовать эту информацию для написания Java-клиента. Если запрос веб-службы не подписан в соответствии с политикой, он отклоняется службой. Я пытаюсь использовать Apache Axis2, и я не могу найти никаких инструкций о том, как я должен использовать файл policyCahce.config и WSDL для создания клиента.
Есть несколько примеров, которые я нашел в Интернете, но во всех случаях авторы примеров имели контроль над сервисом и клиентом, и поэтому смогли сработать с обеих сторон, чтобы заставить его работать. Я не в этом положении.
Кто-нибудь сделал это успешно?
Ответы
Ответ 1
Это, кажется, популярный вопрос, поэтому я предоставлю обзор того, что мы сделали в нашей ситуации.
Похоже, что службы, построенные в .NET, следуют старому стандарту ws-адресации (http://schemas.xmlsoap.org/ws/2004/03/addressing/), а axis2 понимает только новый стандарт (http://schemas.xmlsoap.org/ws/2004/08/addressing/).
Кроме того, файл policyCache.config предоставляется в форме, которую модуль оси axis2 не может понять.
Итак, шаги, которые мы должны были сделать, в двух словах:
- Прочитайте файл policyCache.config и попытайтесь его понять. Затем перепишите его в политику, которую может понять этот вал. (Некоторые обновленные документы помогли.)
- Настройте вал с этой политикой.
- Возьмите ключи, которые были предоставлены в файле .pfx, и преобразуйте их в хранилище ключей Java. Существует утилита, которая поставляется с Jetty, которая может это сделать.
- Настройте вал с этим хранилищем ключей.
- Напишите пользовательский обработчик axis2, который обратный преобразовывает новый материал ws-адресации, который выходит из оси2, в более старый материал, ожидаемый службой.
- Настройте ось 2, чтобы использовать обработчик исходящих сообщений.
В конце концов, было много конфигурации и кода для чего-то, что должно быть открытым стандартом, поддерживаемым поставщиками.
Хотя я не уверен, что альтернатива... можете ли вы ждать, пока поставщики (или в этом случае, один поставщик) будут уверены, что все будет взаимодействовать?
В качестве постскриптума я добавлю, что я не закончил работу, это был кто-то еще в моей команде, но я думаю, что я правильно понял детали. Другой вариант, который я рассматривал (до того, как мой товарищ по команде взял на себя ответственность), должен был вызвать API WSS4J напрямую, чтобы построить конверт SOAP, как ожидало его .NET-сервис. Я думаю, что это тоже сработало бы.
Ответ 2
Спецификации WS-Security обычно не содержатся в WSDL (никогда в WSDL WSE). Поэтому wsdl2java не знает, что WS-Security требуется даже для этой службы. Тот факт, что ограничения безопасности отсутствуют в WSDL WSE, является большим разочарованием для меня (WCF будет включать информацию WS-Trust в WSDL).
На стороне клиента вам нужно будет использовать Rampart, чтобы добавить необходимые заголовки WS-Security в сообщение исходящего клиента. Поскольку WSDL не сообщает, какие параметры WS-Security необходимы, вам лучше всего спросить у поставщика услуг, что требуется. Требования WS-Security могут быть простым открытым текстом или могут быть сертификатами X509 или могут быть зашифрованным сообщением..... Rampart должен иметь возможность обрабатывать большинство этих сценариев.
Apache Rampart включен, включив модуль в файл axis2.xml. Вам нужно будет загрузить модуль Rampart и поместить его в определенное место в вашем каталоге axis2, а затем изменить файл xml. Вы также можете запрограммировать Rampart (отредактируйте исходный вопрос, если это требование, и я отредактирую этот ответ).
В зависимости от того, как вы настраиваете вал (через другие файлы XML или программно), он будет перехватывать любые исходящие сообщения и добавлять к нему необходимую информацию WS-Security. Я лично использовал axis2 с валом для вызова службы WSE3, которая была защищена с помощью UsernameToken в обычном тексте, и она отлично работала. Аналогичные, но более сложные сценарии также должны работать. Более подробная информация о том, как настроить и начать работу с Rampart на сайте, указанном выше. Если у вас возникли проблемы с особенностями Rampart или с использованием Rampart с конкретной настройкой WSE, отредактируйте свой вопрос, и я постараюсь ответить на все ваши вопросы.
Ответ 3
@Mike
Недавно я сделал тест, и это тот код, который я использовал.
Я не использую материал политики, но я использовал WS-Security с простой текстовой аутентификацией.
CXF имеет действительно хорошую документацию о том, как это сделать.
Я использовал wsdl2java, а затем добавил этот код для использования веб-службы с ws-security.
Надеюсь, это поможет вам.
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.handler.WSHandlerConstants;
public class ServiceTest implements CallbackHandler
{
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword("buddah");
}
public static void main(String[] args){
PatientServiceImplService locator = new PatientServiceImplService();
PatientService service = locator.getPatientServiceImplPort();
org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(service);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN + " " + WSHandlerConstants.TIMESTAMP);
outProps.put(WSHandlerConstants.USER, "joe");
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
// Callback used to retrieve password for given user.
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServiceTest.class.getName());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
try
{
List list = service.getInpatientCensus();
for(Patient p : list){
System.out.println(p.getFirstName() + " " + p.getLastName());
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Ответ 4
Ответ 5
CXF - Я бы посмотрел на CXF. Я использовал его для создания веб-службы и клиента в java с помощью ws-secuirty. Я также подключил к нему веб-службу .net.
У них тоже неплохая документация. Мне больше повезло, чем оси.
Ответ 6
Я думаю, я должен быть более ясным - я использовал генераторы кода wsdl2java для генерации кода клиента для службы. Однако сгенерированный код не включает необходимые заголовки SOAP WS-Security, чтобы служба принимала запросы.