I'm new to consuming webservices
, I have to send a file to a web service and receive a response, my problem is that I haven't been able to generate a SOAP Header
valid one.
The web service to consume is this:
https://facturaelectronica.dian.gov.co/habilitacion/B2BIntegrationEngine/FacturaElectronica/facturaElectronica.wsdl
the specifications in the document are that the header should look like this:
Request example using Base64
POST /B2BIntegrationEngine/FacturaElectronica HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Content-Length: 3342
Host: 192.168.250.65:9080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rep="http://www.dian.gov.co/servicios/facturaelectronica/ReportarFactura">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>8ac82326-3016-430f-8d69-9efc4bcefd8f</wsse:Username>
<wsse:Password>6361b7b5322acb07ced00a35a85a4cc5183da3a42ede0b07f578067a18425a55</wsse:Password>
<wsse:NonceEncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">FmbZRkx1jh2A+imgjD2fLQ==</wsse:Nonce>
<wsu:Created>2015-10-06T12:00:33.762Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
But as much as I try, the only thing I have been able to obtain is this:
<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>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken u:Id="uuid-c635f931-8274-4d3d-82a1-460a2f04af73-1">
<o:Username>22ffb485-64bc-4619-8a63-340de2dd7eec</o:Username>
<o:Password>+eho+ADhrJkwZtKGabXIZOEX/0YVa206TmKnQSwt+qE=</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
This is what I'm doing:
const string apiUrl = "https://facturaelectronica.dian.gov.co/habilitacion/B2BIntegrationEngine/FacturaElectronica",
apiUserName = "8ac82326-3016-430f-8d69-9efc4bcefd8f";
string apiPassword = "6361b7b5322acb07ced00a35a85a4cc5183da3a42ede0b07f578067a18425a55";
EndpointAddress endpointAddress = new EndpointAddress(new Uri(apiUrl));
SecurityBindingElement securityElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityElement.AllowInsecureTransport = false;
securityElement.EnableUnsecuredResponse = true;
securityElement.IncludeTimestamp = false;
TextMessageEncodingBindingElement encodingElement = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
HttpsTransportBindingElement transportElement = new HttpsTransportBindingElement();
CustomBinding binding = new CustomBinding(securityElement, encodingElement, transportElement);
//basic prueba
BasicHttpSecurityMode securityMode = new BasicHttpSecurityMode();
BasicHttpBinding binding2 = new BasicHttpBinding(securityMode);
// Then assign username and password based on the proxy. For example -
//var remoteAddress = new EndpointAddress("");
WSDian.facturaElectronicaPortNameClient service = new WSDian.facturaElectronicaPortNameClient(binding, endpointAddress);
//WSDian.facturaElectronicaPortNameClient service = new WSDian.facturaElectronicaPortNameClient(binding2, endpointAddress);
service.ClientCredentials.UserName.UserName = apiUserName;
service.ClientCredentials.UserName.Password = apiPassword;
var Obtnonce = GetNonce();
byte[] archivo = FileToByteArray(@"c:\temp\ws_f0816002834000000000A.zip");
service.Open();
WSDian.EnvioFacturaElectronica enviofactura = new WSDian.EnvioFacturaElectronica();
enviofactura.NIT = "816002834";
enviofactura.InvoiceNumber = "10";
enviofactura.IssueDate = Convert.ToDateTime("2018-01-01 05:00:00");
enviofactura.Document = archivo;
//temporal
WSDian.EnvioFacturaElectronicaPeticion envioFacturaElectronicaPeticion = new WSDian.EnvioFacturaElectronicaPeticion();
WSDian.EnvioFacturaElectronicaRespuesta envioFacturaElectronicaRespuesta = new WSDian.EnvioFacturaElectronicaRespuesta();
WSDian.AcuseRecibo acuseRecibo = new WSDian.AcuseRecibo();
WSDian.ReceivedInvoice receivedInvoice = new WSDian.ReceivedInvoice();
WSDian.facturaElectronicaPortNameClient facturaElectronicaPortNameClient = new WSDian.facturaElectronicaPortNameClient();
envioFacturaElectronicaPeticion.EnvioFacturaElectronicaPeticion1 = enviofactura;
var versionSoap = acuseRecibo.GetType();
acuseRecibo = service.EnvioFacturaElectronica(envioFacturaElectronicaPeticion.EnvioFacturaElectronicaPeticion1);
But I am getting the error:
The security token could not be authenticated or authorized; nested exception is org.apache.ws.security.WSSecurityException: The security token could not be authenticated or authorized
I don't understand how to generate the SOAP header as requested, shouldn't I wsdl
generate it automatically?
Thanks for your help.
I add, this is myWeb.config
?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net" >
<listeners>
<add name="MyTraceFile"/>
<add name="MyConsole"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add
name="MyTraceFile"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="System.Net.trace.log" />
<add name="MyConsole" type="System.Diagnostics.ConsoleTraceListener" />
</sharedListeners>
<switches>
<add name="System.Net" value="Verbose" />
</switches>
</system.diagnostics>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6" />
<httpRuntime targetFramework="4.6"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="facturaElectronicaPortNameSoap11">
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://facturaelectronica.dian.gov.co:80/habilitacion/B2BIntegrationEngine/FacturaElectronica"
binding="basicHttpBinding" bindingConfiguration="facturaElectronicaPortNameSoap11"
contract="WSDian.facturaElectronicaPortName" name="facturaElectronicaPortNameSoap11" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- Para evitar revelar información de los metadatos, establezca los valores siguientes en false antes de la implementación -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- Para recibir detalles de las excepciones en los fallos, con el fin de poder realizar la depuración, establezca el valor siguiente en true. Para no revelar información sobre las excepciones, establézcalo en false antes de la implementación -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
Para examinar el directorio raíz de la aplicación web durante la depuración, establezca el valor siguiente en true.
Establézcalo en false antes de la implementación para evitar revelar información sobre la carpeta de aplicación web.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Update:
I tested with SoapUI
it successfully and I realized that:
- The user is fine, it is the unique identifier of the software provided by the DIAN
- The password is the result of using
SHA-256
the password that was configured on the DIAN site.
Now, the biggest problem is to generate <soapenv:Header>
the <wsse:UsernameToken>
one that includes the <wsse:Nonce>
y<wsu:Created>
update
After much searching, I found this article with which I managed to get closer to the generation of <soapenv:Header>
:
https://weblog.west-wind.com/posts/2012/Nov/24/WCF-WSSecurity-and-WSE-Nonce-Authentication
Now my Header looks like this:
<s:Envelope xmln s: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>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken><wsse:Username><!--Removed--></wsse:Username>
<wsse:Password><!--Removed--></wsse:Password>
<wsse: Nonce>t21C05VjRqomc+OehZoSzwqhmaM=</wsse:Nonce>
<wsse:Created>2018-08-28T08:03:40.749Z</wsse:Created>
</wsse:UsernameToken>
</o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EnvioFacturaElectronicaPeticion xmlns="http://www.dian.gov.co/servicios/facturaelectronica/ReportarFactura">
<NIT><!--Removed--></NIT>
<InvoiceNumber>980000000</InvoiceNumber>
<IssueDate>2018-08-28T19:00:00</IssueDate>
<Document>UEsDBBQAAAAIAPBkHE3djKx2hwgAAEcdAAAeAAAAZmFjZV9mMDgxNjAwMjgzNDAwM0E2OTl.........
Now my problem is that it generates the following error:
System.Net Information: 0 : [11736] Connection#33583636 - Status line received: Version=1.1, StatusCode=400, StatusDescription=Bad Request.
System.Net Error: 0 : [11736] Exception at HttpWebRequest#36620214::GetResponse - Remote Server Error: (400) Bad Request..
any ideas?
Finally I managed to connect to the service
DIAN
and get the successful response:I found that:
SHA-256
nonce
The class to send is like this:
Sending can also be done using
MTOM
what the DIAN recommends, in that case the class looks like this:I
web.config
am like this:Finally:
WCF
usingC#
NuGet
The Microsoft.Web.Services3 package must be added per packageReferencia de servicio
( https://facturaelectronica.dian.gov.co/habilitacion/B2BIntegrationEngine/FacturaElectronica/facturaElectronica.wsdl )https
, the change must be made manually, since when adding the reference to the service it takes it ashttp
.That was it.
What remains is to process the response of the service that I have not yet achieved by any of the 2 methods that I exposed. But this answers the question I had asked.
I hope this information is helpful.
I am facing the same problem, I share the information that I have found so far
According to WSS standards the
password
is calculated as follows:In the code that you expose, although you specify the line
var Obtnonce = GetNonce();
, it is not clear if you are using thenonce
and thetimestamp
to calculate thepassword_digest
.Now, according to the technical annexes of the DIAN, a sha256
( password )
must be sent , it does not specify how to use thenonce
and thetimestamp
, and in fact in another webservice that exposes the called DIANConsulta_del_Resultado_de_Transacciones
it is not requested to send thenonce
and thecreatedtime
, as that part is not clear, You should try the different variants.My recommendation would be to change the code to calculate the
password
taking into account thenonce
and thetimestamp
:Take into account specifying the attribute
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" o Type="...#PasswordText"
depending on how you send thepassword
applying or notbase64
.I'm still researching on the subject if I find something else, I'll post it here, and also if you solve it, I'd appreciate it if you'd post it.