C# WCF Клиентский интерфейс взаимодействия Blackboard Java WS-Security через транспорт HTTPS

У меня проблемы с получением привязки WCF для работы с Blackboard Java Web Services API.

(Простой ответ: если у кого-то есть такая работа, не могли бы вы опубликовать рабочую привязку для WCF на доске)

Я часами пробовал разные конфигурации и пользовательские закодированные привязки.

Некоторые неудачные попытки:

позвонив-а-WS-Security-ява-веб-сервис с-с-диез-клиент

wcf-client-with-ws-security 12-common-wcf-interop-confusions

Настройка-ФОС-для-WS-Security-с-именем-над-HTTPS

ФОС-клиент-подключения к Java-мыло-веб-сервис с использованием-WS-Security

ClearUsernameBinding

Есть еще много общего с JAVA и WS-Security с WCF, но я не буду продолжать.

Кажется, что каждый раз, когда я получаю одну работу, другая ломается. Теперь я чувствую, что хожу по кругу и просто запутываюсь.

В качестве первого теста я пытаюсь выполнить простую инициализацию объекта Context и войти в систему, используя тестовую учетную запись администратора с прокси WCF.

Доска Doc ContextWS

Чтобы убедиться, что все это работает, я сначала скачал пример кода для.Net WSE 2.0 и проверил, что он работает отлично.

Теперь, когда я использую WCF и привязку, я не могу получить то же самое поведение.

Сначала успешный обмен с очень старым WSE 2.0===================================

WSE 2.0 ContextWS Инициализация

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <soap:Header>
        <wsa:Action>initialize</wsa:Action>
        <wsa:MessageID>uuid:b975e989-a4ce-4e1e-abd6-500945346c40</wsa:MessageID>
        <wsa:ReplyTo>
            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
        </wsa:ReplyTo>
        <wsa:To>https://Blackboard.Server.Name/webapps/ws/services/Context.WS</wsa:To>
        <wsse:Security soap:mustUnderstand="1">
            <wsu:Timestamp wsu:Id="Timestamp-47d0d017-4fd1-46c2-b1b4-2431402cf847">
                <wsu:Created>2015-07-16T04:58:02Z</wsu:Created>
                <wsu:Expires>2015-07-16T05:03:02Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-1b71e23a-2d84-40a5-9509-b75902ec8b76">
                <wsse:Username>session</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">nosession</wsse:Password>
                <wsse:Nonce>lAW2qXrXZ1maNNkCEzlHGA==</wsse:Nonce>
                <wsu:Created>2015-07-16T04:58:02Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body />
</soap:Envelope>

WSE 2.0 ContextWS Успешный ответ инициализации

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <ns:initializeResponse xmlns:ns="http://context.ws.blackboard">
            <ns:return>c2762f357bbc42a4a88d33e4e42486b8</ns:return>
        </ns:initializeResponse>
    </soapenv:Body>
</soapenv:Envelope>

WSE 2.0 ContextWS Запрос на вход

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <soap:Header>
        <wsa:Action>login</wsa:Action>
        <wsa:MessageID>uuid:a823128b-efb4-49e1-87d9-fd35167f0bfc</wsa:MessageID>
        <wsa:ReplyTo>
            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
        </wsa:ReplyTo>
        <wsa:To>https://Blackboard.Server.Name/webapps/ws/services/Context.WS</wsa:To>
        <wsse:Security soap:mustUnderstand="1">
            <wsu:Timestamp wsu:Id="Timestamp-c38daf19-6b39-4391-a3f8-bcc030064a3e">
                <wsu:Created>2015-07-16T04:58:15Z</wsu:Created>
                <wsu:Expires>2015-07-16T05:03:15Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-65948746-e616-436a-85f4-d2e1023e39be">
                <wsse:Username>session</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">c2762f357bbc42a4a88d33e4e42486b8</wsse:Password>
                <wsse:Nonce>T0xs8aiaiODMK3sfKgDQtg==</wsse:Nonce>
                <wsu:Created>2015-07-16T04:58:15Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <login xmlns="http://context.ws.blackboard">
            <userid>test_admin</userid>
            <password>TestPassword</password>
            <clientVendorId>TestClient</clientVendorId>
            <clientProgramId>TestPOC</clientProgramId>
            <loginExtraInfo xsi:nil="true" />
            <expectedLifeSeconds>10000000</expectedLifeSeconds>
        </login>
    </soap:Body>
</soap:Envelope>

WSE 2.0 ContextWS Ответ на вход в систему

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <ns:loginResponse xmlns:ns="http://context.ws.blackboard">
            <ns:return>true</ns:return>
        </ns:loginResponse>
    </soapenv:Body>
</soapenv:Envelope>

===================================

Итак, я знаю, что это работает в нашей среде, и я знаю, что пользователь может войти в систему.

Используя WCF, я могу заставить инициализацию работать, но тогда она теряет сессию. Он не помещает идентификатор возвращенного сеанса в поле пароля для следующего сообщения. Я пытался сделать это вручную, конечно; но я получаю сообщение о том, что поле "Пароль" доступно только для чтения.

Теперь для моей Конфигурации WCF и кода, который дал мне самое близкое к вышеупомянутому сообщению.

WCF App.Config Binding

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    </system.serviceModel>
        <bindings>
          <customBinding>
                <binding name="WCFSoapInteropJavaWS"  closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"  >
                  <textMessageEncoding messageVersion="Soap11" writeEncoding="utf-8" />
                  <security authenticationMode="UserNameOverTransport" enableUnsecuredResponse="true" allowSerializedSigningTokenOnReply="true"
                            messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                            includeTimestamp="true" allowInsecureTransport="true" canRenewSecurityContextToken="false" >
                  </security>
                  <httpsTransport  authenticationScheme="Anonymous"  />
                </binding>

              </customBinding>
         </bindings>

        <client>

            <endpoint 
                address="https://Blackboard.Server.Name:443/webapps/ws/services/Context.WS"
                binding="customBinding" bindingConfiguration="WCFSoapInteropJavaWS"
                contract="ContextWS.ContextWSPortType" name="Context.WCFSoapInteropJavaWS" />

        </client>

    </system.serviceModel>
</configuration>

Код WCF C#

 public bool testWrapper(String userId, String userPassword){


             try
             {
                 context = new ContextWrapper("Context.WCFSoapInteropJavaWS");

                 context.ClientCredentials.UserName.UserName = "session";
                 context.ClientCredentials.UserName.Password = "nosession";

                 context.initialize();

                 //context.ClientCredentials.UserName.Password = "886d935527944f94a3526288e39a555e";  // SessionGUID_HERE Throws a Read Only Error for Pasword

                 bool retval = context.login(userId, userPassword, vendorId, programId, null, expectedLife);

                 return retval;
             }
             catch (System.Exception e)
             {
                 lastError = e;
                 return false;
             }
        }

Вот как выглядит SOAP-связь.

WCF ContextWS Запрос инициализации

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo+FmveflwUtMgSATRu3Ht9EAAAAAmYVJsX+bhUeYcTDsFqFktkqe8xmMiA1MpXouaouXgJwACQAA</VsDebuggerCausalityData>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2015-07-16T07:15:05.109Z</u:Created>
                <u:Expires>2015-07-16T07:20:05.109Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken u:Id="uuid-1237f56c-7c68-4d40-a756-7ff2c19a3235-1">
                <o:Username>session</o:Username>
                <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">nosession</o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
</s:Envelope>

WCF ContextWS Ответ успешного инициализации

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <ns:initializeResponse xmlns:ns="http://context.ws.blackboard">
            <ns:return>886d935527944f94a3526288e39a555e</ns:return>
        </ns:initializeResponse>
    </soapenv:Body>
</soapenv:Envelope>

WCF ContextWS Запрос на вход

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo+JmveflwUtMgSATRu3Ht9EAAAAAmYVJsX+bhUeYcTDsFqFktkqe8xmMiA1MpXouaouXgJwACQAA</VsDebuggerCausalityData>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2015-07-16T07:15:14.033Z</u:Created>
                <u:Expires>2015-07-16T07:20:14.033Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken u:Id="uuid-1237f56c-7c68-4d40-a756-7ff2c19a3235-1">
                <o:Username>session</o:Username>
                <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">nosession</o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <login xmlns="http://context.ws.blackboard">
            <userid>Test_admin</userid>
            <password>TestPassword</password>
            <clientVendorId>TestClient</clientVendorId>
            <clientProgramId>TestPOC</clientProgramId>
            <loginExtraInfo xsi:nil="true"/>
            <expectedLifeSeconds>10000000</expectedLifeSeconds>
        </login>
    </s:Body>
</s:Envelope>

WCF ContextWS Ошибка входа в систему

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>soapenv:Server</faultcode>
            <faultstring>[WSFW001]Invalid session</faultstring>
            <detail />
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>

Как вы можете видеть, идентификатор возврата сеанса не был добавлен в поле пароля в запросе на вход в систему, поэтому существует "Недопустимый сеанс:

Казалось, все идет хорошо.

Короче говоря, если кто-то знает, как добиться привязки клиента WCF к API Blackboard Java Webservice, и пример будет фантастическим. С другой стороны, я надеюсь, что кто-то еще, кто знает больше о привязках WCF к Java, чем я, мог бы взглянуть на вышеприведенное, чтобы увидеть, где я иду не так.

Любая помощь, которую кто-либо может дать мне, чтобы получить эту работу, была бы очень признательна, так что спасибо. Я действительно надеюсь, что это просто глупость, которую мне не хватает.

Извините за такой длинный подробный вопрос.

1 ответ

Благодаря куче чтения и некоторым полезным образцам я смог заставить это работать. Доска с WCF.

Спасибо обоим: Аджадекс Лопес

http://www.isyourcode.com/2010/08/attaching-oasis-username-tokens-headers.html

Джонни Локхарт "Входящее сообщение не содержит требуемого заголовка безопасности"

BB - багги, так что вы можете сделать все возможное, чтобы найти на форуме WCF, чтобы найти сообщение

Образец класса

using System;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
using System.Xml;
using System.Security.Cryptography;
using System.Text;


namespace BBWcfWrapper
{


    /// <summary>
    /// Coupled with the additional classes below, allows for injecting the WS-Security header into a WCF Service call without requiring SSL on the server.
    /// </summary>
    /// <remarks>http://isyourcode.blogspot.com/2010/08/attaching-oasis-username-tokens-headers.html</remarks>
    public class BBWSSecurityBehavior : IEndpointBehavior
    {
        public MessageInspector MessageInspector { get; set; }

        public BBWSSecurityBehavior(MessageInspector messageInspector)
        {
            MessageInspector = messageInspector;
        }

        public void Validate(ServiceEndpoint endpoint)
        { }
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        { }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            if (this.MessageInspector == null) throw new InvalidOperationException("Caller must supply ClientInspector.");
            clientRuntime.MessageInspectors.Add(MessageInspector);
        }

    }

    public class MessageInspector : IClientMessageInspector
    {
        public MessageHeader[] Headers { get; set; }
        public MessageInspector(params MessageHeader[] headers)
        {
            Headers = headers;
        }
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            if (Headers != null)
            {
                for (int i = Headers.Length - 1; i >= 0; i--)
                {
                    request.Headers.Insert(0, Headers[i]);
                }
            }

            return request;
        }
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }
    }


    public class SecurityHeader : MessageHeader
    {

        public string SystemUser { get; set; }
        public string SystemPassword { get; set; }
        public SecurityHeader(string systemUser, string systemPassword)
        {
            SystemUser = systemUser;
            SystemPassword = systemPassword;
        }
        public override string Name
        {
            get { return "Security"; }
        }
        public override string Namespace
        {
            get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
        }

        protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteStartElement("wsse", Name, Namespace);
            writer.WriteXmlnsAttribute("wsse", Namespace);
            writer.WriteAttributeString("soap", "mustUnderstand", Namespace, "1");
        }

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            WriteHeader(writer);
        }

        private void WriteHeader(XmlDictionaryWriter writer)
        {
            var createDate = DateTime.Now;

            //Start Parent Elements 
            writer.WriteStartElement("wsu","Timestamp","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            writer.WriteAttributeString("wsu","id","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd","Timestamp-6557466");

            #region Start Child Elements

            writer.WriteStartElement("wsu", "Created", XmlConvert.ToString(createDate, "yyyy-MM-ddTHH:mm:sszzzzzz"));
            writer.WriteEndElement();   //End Created

            writer.WriteStartElement("wsu", "Expires", XmlConvert.ToString(createDate.AddDays(1), "yyyy-MM-ddTHH:mm:sszzzzzz"));
            writer.WriteEndElement();   //End Expires

            #endregion

            writer.WriteEndElement();   //End Timestamp

            //Start Parent Elements 
            writer.WriteStartElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            writer.WriteXmlnsAttribute("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

            #region Start Child Elements

            writer.WriteStartElement("wsse", "Username", null);
            writer.WriteString(SystemUser);
            writer.WriteEndElement();//End Username 

            writer.WriteStartElement("wsse", "Password", null);
            writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
            writer.WriteString(SystemPassword);
            writer.WriteEndElement();//End Password 

            // unique Nonce value - encode with SHA-1 for 'randomness'
            // in theory the nonce could just be the GUID by itself
            // This is used to stop Replay attacks 
            writer.WriteStartElement("wsse", "Nonce", null);
            writer.WriteString(GetSHA1String(Guid.NewGuid().ToString()));
            writer.WriteEndElement();//Nonce 

            writer.WriteStartElement("wsu", "Created", null);
            writer.WriteString(XmlConvert.ToString(createDate, "yyyy-MM-ddTHH:mm:sszzzzzz"));
            writer.WriteEndElement();   //End Created

            #endregion

            writer.WriteEndElement();//End UsernameToken
            writer.Flush(); 

        }

        protected string GetSHA1String(string phrase)
        {
            SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
            byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
            return Convert.ToBase64String(hashedDataBytes);
        }

    }

}

Пример использования

  calendar = new CalendarWrapper("Calendar.BB_WSSecurity_Binding");

        //This adds a custom security Headder for WCF and Java WS-Security Interop
        calendar.Endpoint.Behaviors.Add(new BBWSSecurityBehavior(new MessageInspector(BbWsAuth.SecurityHeader)));

        calendar.initializeCalendarWS(false);

Простой класс Wrapper

    public class CalendarWrapper : CalendarWSPortTypeClient
{
    public CalendarWrapper() : base() { }

    public CalendarWrapper(string endpointConfigurationName) : base(endpointConfigurationName) { }
    public CalendarWrapper(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) { }
}

конфиг

 <bindings>

    <basicHttpsBinding>
      <binding name="BB_WSSecurity_Binding" messageEncoding="Text" textEncoding="utf-8" maxReceivedMessageSize="4000000" >
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
          maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      </binding>
    </basicHttpsBinding>

  </bindings>

  <client>

  <endpoint address="https://xxxxxxxxxx/webapps/ws/services/Calendar.WS"
           binding="basicHttpsBinding" bindingConfiguration="BB_WSSecurity_Binding"
            contract="CalendarWS.CalendarWSPortType" name="Calendar.BB_WSSecurity_Binding"  />
Другие вопросы по тегам