SOAP-запрос с заголовками безопасности (WSSE)

Я ссылаюсь на файл WSDL сторонних компаний, который мне нужно использовать для отправки запросов и получения информации через запросы SOAP.

Они предоставили файл WSDL, и я добавил его в качестве "справочной службы". Обычно этого достаточно, однако всякий раз, когда мы отправляем запрос, нам нужно прикрепить заголовок wsse и защиту. Нам удалось пробраться через добавление заголовка, однако есть некоторые проблемы с ним, которые я не совсем уверен, как обойти.

Запрос на мыло должен выглядеть так:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header>
        <wsse:Security
            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">
            <wsse:UsernameToken wsu:Id="UsernameToken-17A419BD1DC95B13F214417185709617">
                <wsse:Username>aUsername</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">##HashedPassword##</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">DUSgCUI8X3BJrVe8F+fGnQ==</wsse:Nonce>
                <wsu:Created>2015-09-08T13:22:50.961Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
                <stuffhere />
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Мой запрос в настоящее время выглядит так;

<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>
        <h:Security
        xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
        xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <h:UsernameToken u:Id="uuid-b9edaf83-70fb-4909-85eb-9773058c7001-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <h:Username>aUsername</h:Username>
                <h:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">##HashedPassword##</h:Password>
                <h:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">kRNsqdcQdv8T5y5rTv4O2WeidUM=</h:Nonce>
                <u:Created>2015-09-09T10:48:44.498Z</u:Created>
            </h:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body >
        <stuffhere />

    </s:Body>   
</s:Envelope>

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

В настоящее время мы перезаписываем заголовок, используя следующие классы (которые я получил из исследования);

Imports Microsoft.VisualBasic
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Channels
Imports System.ServiceModel
Imports System.Xml
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher.ClientRuntime
Imports System
Imports System.IdentityModel.Selectors.SecurityTokenSerializer
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Cryptography


Public Class CustomCredentials
    Inherits ClientCredentials
    Public Sub New()
    End Sub

    Protected Sub New(cc As CustomCredentials)
        MyBase.New(cc)
    End Sub

    Public Overrides Function CreateSecurityTokenManager() As System.IdentityModel.Selectors.SecurityTokenManager
        Return New CustomSecurityTokenManager(Me)
    End Function

    Protected Overrides Function CloneCore() As ClientCredentials
        Return New CustomCredentials(Me)
    End Function
End Class

Public Class CustomSecurityTokenManager
    Inherits ClientCredentialsSecurityTokenManager
    Public Sub New(cred As CustomCredentials)
        MyBase.New(cred)
    End Sub

    Public Overrides Function CreateSecurityTokenSerializer(version As System.IdentityModel.Selectors.SecurityTokenVersion) As System.IdentityModel.Selectors.SecurityTokenSerializer
        Return New CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity11)
    End Function
End Class

Public Class CustomTokenSerializer
    Inherits WSSecurityTokenSerializer
    Public Sub New(sv As SecurityVersion)
        MyBase.New(sv)
    End Sub

    'Protected Overrides Sub WriteKeyIdentifierClauseCore(writer As XmlWriter, keyIdentifierClause As SecurityKeyIdentifierClause)
    '    MyBase.WriteKeyIdentifierClauseCore(writer, keyIdentifierClause)

    '    writer.WriteRaw("TestClause")

    'End Sub

    Protected Overrides Sub WriteTokenCore(writer As System.Xml.XmlWriter, token As System.IdentityModel.Tokens.SecurityToken)
        Dim userToken As UserNameSecurityToken = TryCast(token, UserNameSecurityToken)

        Dim tokennamespace As String = "h"

        Dim created As DateTime = DateTime.Now
        Dim createdStr As String = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ")

        ' unique Nonce value - encode with SHA-1 for 'randomness'
        ' in theory the nonce could just be the GUID by itself
        Dim phrase As String = Guid.NewGuid().ToString()
        Dim nonce = GetSHA1String(phrase)

        ' in this case password is plain text
        ' for digest mode password needs to be encoded as:
        ' PasswordAsDigest = Base64(SHA-1(Nonce + Created + Password))
        ' and profile needs to change to
        'string password = GetSHA1String(nonce + createdStr + userToken.Password);

        Dim password As String = GetSHA1String(nonce + createdStr + GetSHA1String(userToken.Password))


        writer.WriteRaw(String.Format((Convert.ToString((Convert.ToString((Convert.ToString("<{0}:UsernameToken u:Id=""" + token.Id + """ xmlns:u=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">" + "<{0}:Username>" + userToken.UserName + "</{0}:Username>" + "<{0}:Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">") & password) + "</{0}:Password>" + "<{0}:Nonce EncodingType=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"">") & nonce) + "</{0}:Nonce>" + "<u:Created>") & createdStr) + "</u:Created></{0}:UsernameToken>", tokennamespace))


    End Sub

    Protected Function GetSHA1String(phrase As String) As String
        Dim sha1Hasher As New SHA1CryptoServiceProvider()
        Dim hashedDataBytes As Byte() = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase))
        Return Convert.ToBase64String(hashedDataBytes)
    End Function


End Class

Мой web.config в настоящее время настроен как;

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="shippingAPISoapBinding">
      <!--<security mode="TransportWithMessageCredential">-->
      <security mode="TransportWithMessageCredential">
        <message clientCredentialType="UserName" />
        <transport clientCredentialType="Certificate"></transport>
      </security>
    </binding>
    <binding name="shippingAPISoapBinding1"/>
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="https://www.anEndpoint.com/endpoint" binding="basicHttpBinding" bindingConfiguration="shippingAPISoapBinding" contract="RMailAPI.shippingAPIPortType" name="shippingAPISoapBinding" behaviorConfiguration="ClientCertificateBehavior"  >
  </endpoint>   
 </client>    
</system.serviceModel>

Как упоминалось ранее, мы отправляем запросы, используя их wsdl, что делается следующим образом;

    'The securityheader we have to attach to be able to call createshipmentrequest1
    'The only things i can access on this are .Any or .AnyAttr which are XML attributes
    Dim securityHeader As New RMailAPI.SecurityHeaderType


    'We declare our requests here
    Dim cs As RMailAPI.createShipmentRequest
    cs = New RMailAPI.createShipmentRequest

    'assign values to cs here
    'These come through into the XML just fine

    Dim cs1 As New RMailAPI.createShipmentRequest1(securityHeader, cs)

    Try
        shipResponse = serviceClient.createShipment(cs1)
    Catch ex As CommunicationException
        Response.Write("msg:" & ex.Message & "<br />")
    End Try

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

Я был бы рад предоставить больше информации.

* Редактировать 1;

Я попытался добавить свои заголовки в web.config, однако есть проблема с этим методом, так как мой пароль должен быть хеширован перед отправкой со случайной строкой ("nonce", через который я также должен пройти). Не уверен, смогу ли я изменить заголовки web.config перед отправкой.

* Редактировать 2;

Я пытался выяснить, есть ли какой-нибудь способ, которым я могу получить весь заголовок, или могу ли я перехватить его так же, как я делаю с функцией "WriteTokenCore". Но безрезультатно!

0 ответов

Другие вопросы по тегам