Buscar en este blog

jueves, 28 de febrero de 2013

Autenticación Automática contra el SII


Proceso de autenticación automática contra el SII

Recuerdo cuando comencé con mis desarrollos orientados a la facturación electrónica en Chile, que la experiencia que existía al respecto tenía sus bases en desarrollos efectuados en JAVA a los cuales debíamos ceñirnos para poder crear los nuestros. Esto significaba que o nos cambiábamos a plataformas JAVA o nos dábamos el trabajo de implementar las rutinas en lenguajes como VB 6.0.

De esta experiencia recuerdo varios dolores de cabeza e interminables horas de pruebas de firmas y envío. Gracias a la evolución de los lenguajes de desarrollo de Microsoft como en este caso C#, se ha podido simplificar mucho mas tales procesos. Sin embargo una cosa es saber cómo construir una clase orientada a la Facturación electrónica y otra muy distinta es como diseñar una aplicación que nos permita generar el flujo de la misma. Por esta razón escribo este blog, pues quisiera compartir algunos tips del proceso para que aquellos que inician en esto, pueda extraer algo de mi conocimiento del tema.


Bueno les dejo entonces algunas anotaciones separadas por conceptos, espero les sirvan y me puedan aportar algún comentario.

MODULO I: Como autenticarse contra el SII de forma automática.




martes, 26 de febrero de 2013

Como firmar la semilla del SII

Firma de semilla del SII

Una vez recupera la cadena que representa la semilla, debemos firmarla con nuestro certificado digital, de forma que el SII pueda cotejar quien firmo la semilla y si tiene permisos o no para entrar a los servicios disponibilizados por ellos. Sabemos que la consulta al SII utilizando el metodo maullin.getSeed() nos entregará una cadena string con la siguiente información:'1234567890123'.

Esta cadena debemos firmarla con el certificado digital del usuario registrado en el SII y que tenga los permisos de envío y consulta de documentos.Este certificado debería estar instalado en el servidor que realiza la consulta.


Expongo el codigo utilizado para preparar el valor de la semilla y luego firmarla.


/// 
/// Firma la semilla para poder validarla en el SII
/// 
private static string FirmarSemilla(string seed, string cn )
{

 ////
 //// Construya el cuerpo del documento en formato string.
 string resultado = string.Empty;
 string body = string.Format("{0}", double.Parse(seed).ToString());

 ////
 //// Recuperar el certificado para firmar el documento.
 //// utilizando el nombre del propietario del certificado o CN
 X509Certificate2 certificado = FuncionesComunes.obtenerCertificado(cn);

 ////
 //// Firme la semilla.
 try
 {
  resultado = Negocio.FirmarSemilla.firmarDocumentoSemilla(body, certificado);

 }
 catch (Exception)
 {
  resultado = string.Empty;
 }


 ////
 //// Regrese el valor de retorno
 return resultado;
 

}


/// 
/// Recupera un determinado certificado para poder firmar un documento
/// 
/// Nombre del certificado que se busca
/// X509Certificate2
public static X509Certificate2 obtenerCertificado(string CN)
{

   ////
   //// Respuesta
   X509Certificate2 certificado = null;

   ////
   //// Certificado que se esta buscando
   if (string.IsNullOrEmpty(CN) || CN.Length == 0)
      return certificado;

   ////
   //// Inicie la busqueda del certificado
   try
   {

      ////
      //// Abra el repositorio de certificados para buscar el indicado
      X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
      store.Open(OpenFlags.ReadOnly);
      X509Certificate2Collection Certificados1 = (X509Certificate2Collection)store.Certificates;
      X509Certificate2Collection Certificados2 = Certificados1.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
      X509Certificate2Collection Certificados3 = Certificados2.Find(X509FindType.FindBySubjectName, CN, false);

      ////
      //// Si hay certificado disponible envíe el primero
      if (Certificados3 != null && Certificados3.Count != 0)
         certificado = Certificados3[0];

      ////
      //// Cierre el almacen de sertificados
      store.Close();


   }
   catch (Exception)
   {
      certificado = null;
   }


   ////
   //// Regrese el valor de retorno 
   return certificado;

}








Expongo ademas la clase que realiza la firma de la semilla:


//// 
//// Firma el documento xml semilla
//// 
public static string firmarDocumentoSemilla(string documento, X509Certificate2 certificado)
{

 ////
 //// Cree un nuevo documento xml y defina sus caracteristicas
 XmlDocument doc = new XmlDocument();
 doc.PreserveWhitespace = false;
 doc.LoadXml(documento);

 ////
 //// Cree el objeto XMLSignature.
 SignedXml signedXml = new SignedXml(doc);
 
 ////
 //// Agregue la clave privada al objeto xmlSignature.
 signedXml.SigningKey = certificado.PrivateKey;
 
 ////
 //// Obtenga el objeto signature desde el objeto SignedXml.
 Signature XMLSignature = signedXml.Signature; 

 ////
 //// Cree una referencia al documento que va a firmarse
 //// si la referencia es "" se firmara todo el documento
 Reference reference = new Reference("");

 ////
 //// Representa la transformación de firma con doble cifrado para una firma XML  digital que define W3C.
 XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
 reference.AddTransform(env);
 
 ////
 //// Agregue el objeto referenciado al obeto firma.
 XMLSignature.SignedInfo.AddReference(reference);

 ////
 //// Agregue RSAKeyValue KeyInfo  ( requerido para el SII ).
 KeyInfo keyInfo = new KeyInfo();
 keyInfo.AddClause(new RSAKeyValue((RSA)certificado.PrivateKey));

 ////
 //// Agregar información del certificado x509
 keyInfo.AddClause(new KeyInfoX509Data(certificado));

 //// 
 //// Agregar KeyInfo al objeto Signature 
 XMLSignature.KeyInfo = keyInfo;

 ////
 //// Cree la firma
 signedXml.ComputeSignature();

 ////
 //// Recupere la representacion xml de la firma
 XmlElement xmlDigitalSignature = signedXml.GetXml();

 ////
 //// Agregue la representacion xml de la firma al documento xml
 doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));

 ////
 //// Limpie el documento xml de la declaracion xml ( Opcional, pera para nuestro proceso es valido  )
 if (doc.FirstChild is XmlDeclaration)
 {
  doc.RemoveChild(doc.FirstChild);
 }

 ////
 //// Regrese el valor de retorno
 return doc.InnerXml;




}



Lo que nos arrojara como resultado algo parecido a esto:



1234567890123










8slcL05kmrM8NGw4I9NSfRqYA9E=


jlbzatIIBLW8AjH++5uVTTrGIMVwGButuoAR88y/hvSc1+6/eW1K864fK3cKi76oArqk7lAM4pPokoXme0JT/hRXXGo6ecuKzO18z2WfPWwgnN0f3ac03TDu7PwfqiDG9mhQpYfIkNp6GNJIiqlg9PG2w1fOJ1QoypsrQmKq6YU=



2Pb4kEB19m7NmOUYew9f36325yrTLTPMU7qzYG2A0/BsubxDdgQw2Op0x6zXvOVX
sYI9KkPXtD5orKJMjwxYRv9wUWdyiE776Rv4ljfJO7EQhIK1fDQDnPt0HefBS06Xzg2QLBvLR+pe1vc6C02Dr99v+lnLA8mnZiJlRHndhNU=

AQAB



MIIF1DCCBLygAwIBAgIDAQNtMA0GCSqGSIb3DQEBBQUAMIHGMQswCQYDVQQG
EwJDTDEYMBYGA1UEChMPQWNlcHRhLmNvbSBTLkEuMTgwNgYDVQQLEy9BdXRv
cmlkYWQgY2VydGlmaWNhZG9yYSBDbGFzZSAzIHBlcnNvbmEgbmF0dXJhbDFD
MEEGA1UEAxM6QWNlcHRhLmNvbSBBdXRvcmlkYWQgY2VydGlmaWNhZG9yYSBD
bGFzZSAzIHBlcnNvbmEgbmF0dXJhbDEeMBwGCSqGSIb3DQEJARYPaW5mb0Bh
Y2VwdGEuY29tMB4XDTAxMDkyNTIxMDgxMloXDTAyMDkyNTIxMDgxMlowgZ8x
CzAJBgNVBAYTAkNMMRgwFgYDVQQKEw9BY2VwdGEuY29tIFMuQS4xLDAqBgNV
BAsTI0NlcnRpZmljYWRvIENsYXNlIDMgUGVyc29uYSBOYXR1cmFsMRwwGgYJ
KoZIhvcNAQkBFg1uY2hlbGVAc2lpLmNsMSowKAYDVQQDEyFOSUNPTEFTIFpB
UFJJQU4gQ0hFTEVCSUZTS0kgQkFFWkEwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBANj2+JBAdfZuzZjlGHsPX9+t9ucq0y0zzFO6s2BtgNPwbLm8Q3YE
MNjqdMes17zlV7GCPSpD17Q+aKyiTI8MWEb/cFFncohO++kb+JY3yTuxEISC
tXw0A5z7dB3nwUtOl84NkCwby0fqXtb3OgtNg6/fb/pZywPJp2YiZUR53YTV
AgMBAAGjggJyMIICbjAdBggrBgEEAbVrDwQRFg9BY2VwdGEuY29tIFMuQS4w
JQYDVR0RBB4wHKAaBggrBgEEAcEBAaAOFgwxMC40MTEuODcxLTIwDwYIKwYB
Jh0z1DR3Pl3xOiaFIjSXsQO2PSzcA3wZXYF+KDrMul8e5lAF2NNiLmMVtXEx
ZykMaTGGWS0ZETDhJmBwEZGpP4+lt/JhgwF1Sb6wdrXp7MFCJUc1Tj+/5JqH
1kP0E63/hVElrcP0g8Zn8Z+vr/PMGW1kKgE0IyS4iJ8eIhNSK5phFyKJUn0l
BmIZX7u89d5u7X8=




Finalmente este es el documento xml firmado que se envía al SII.

viernes, 22 de febrero de 2013

Solicitar Semilla al SII


Obtener semilla del SII

Una vez creado nuestro proxy de comunicación al SII debemos empesar a utilizarlo para autenticarnos. Para tales efectos debemos contar con el certificado digital del usuario registrado en el SII el cual puede realizar los envios y consultas de los documentos DTE o IECV exigidos por la entidad publica. 

Sí Ud. No cuenta con la clases para realizar la comunicación y autenticación con el SII puede revisar estas urls para copiar el código y pegarlos en sus clases .Net.

Ver archivo con descripción de GetSeed

Ver archivo con descripción de GetTokenFromSeed

Para tales efectos el SII diseño un pequeño algoritmo para realizar el proceso de autentificación, el cual yo extraje desde su 'Manual de Desarrollador Autenticación Automática' que explica como realizar la operación. No quice darle muchas vueltas al asunto pues la figura es bastante expllicativa, por esta razón solo realice una copia del diagrama. En todo caso siempre es bueno que lean lo dispuesto por el SII asi que les dejo el link para que descarguen el manual.


Vision general del sistema


















Ahora visto esto y tomando en consideración que ya contamos con nuestro proxy que nos conecta al SII, les presento un pequeño metodo que nos permitira recuperar la semilla del SII. Esta piesa de caracteres se denomina semilla, la cual no es otra cosa que una cadena de caracteres la cual debemos firmar  y luego enviarla al SII para que ellos determinen que quien firmo la semilla es un usuario registrado en el SII.


Metodo para extraer la semilla.
Este metodo administra el modo de operación de la consulta de la semilla, es decir si lo hace en ambiente deproducción ( Palena ) o en el de certificación ( Maullin ). En todo caso se expone aqui el metodo completo para efectos nuestros solo estamos interesados en solo en un par de lineas.


  
#region CrSeedService 

   ////
   //// Crear instancia  
   CrSeedService maullin = new CrSeedService();
   string respuesta = maullin.getSeed();


#endregion


El resultado de esta operación regresa el siguiente documento xml en formato string desde el SII. En el mejor de los casos. pero puede darse el caso que el estado del documento xml cambie por diversas razones. Así que cuando el desarrollador implemente este metodo, debera agregar las rutinas necesarias para capturar las excepciones que el webservices retorne en su nodo estado.


  

 
  00
 
 
  000000000078
 
 


Una vez que se obtiene la semilla el desarrollador debéra extraer el valor de la misma y agregarla al documento xml necesario para ser firmado y posteriormente enviado al SII.

jueves, 21 de febrero de 2013

Clase Proxy para conectarse al SII

Cómo construir clase proxy para obtener semilla del SII
Bueno unos de los problemas más frecuentes para el proceso de conexión y autentificación contra el SII es que muchos de los programas que hoy realizan esta tarea se comunican de forma nativa a través de JAVA. Generalmente los desarrolladores como yo tenemos muchos problemas para hacerlo pues necesitamos algún conector ( proxy ) que nos ayude con la comunicación a servicios del tipo java. Para solucionar esto les dejo un pequeño tutorial para generar su clase proxy y también el cómo pueden acceder a el para utilizarlo.

Definición según el SII
Según la definición formal del SII ( Servicio de Impuestos Internos ), el proceso de autenticación automatica corresponde a: "Es un chequeo del uso de la llave privada del certificado del cliente, mediante el uso de Web Services (WS).". En donde el certificado del cliente es aquel que utiliza el usuario registrado en el SII para acceder a los servicios del portal del SII.

Les dejo el link del archivo Manual de Desarrollador Autenticación Autemática SII para que tengan mas información técnica del proceso.

Como crear el proxy
Primero que nada debemos saber que el SII tiene dos formas de trabajo disponibles para los usuarios registrados en su portal. Un ambiente de pruebas denominado ‘Certificación’ y otro en donde aquellos postulantes de la factura electrónica ya pasaron todos los test del SII para incorporarse completamente al ambiente de ‘Producción ‘ del SII.
Para tales efectos los dejo las direcciones de donde obtener los manifiestos de los servicios disponibles del SII.


Para el ambiente de certificación es la siguiente dirección:
https://maullin.sii.cl/DTEWS/CrSeed.jws?WSDL
https://maullin.sii.cl/DTEWS/GetTokenFromSeed.jws?WSDL

Para el ambiente de Producción es la siguiente dirección:
https://palena.sii.cl/DTEWS/CrSeed.jws?WSDL
https://palena.sii.cl/DTEWS/GetTokenFromSeed.jws?WSDL

Nota:
Donde CrSeed.jws permite recuperar la semilla del SII y GetTokenFromSeed representa el método a consultar cuando ya firmamos la semilla, el último método regresa una respuesta en formato xml que nos indica si la autenticación fue posible o no.

Lo primero que debe hacer es intentar conectarse en su explorador a estas urls, de tal forma que sepamos que el servicio esta operativo. En el caso que Ud. Sea un desarrollador .Net debe tener presente que para poder generar la conexión al SII es necesario tener activado de forma predeterminada el IExplorer de Microsoft en su equipo o servidor.

Nota:
Recuerde que al momento de generar la conexión debe saber claramente a donde lo esta haciendo, el SII asume gracias al certificado digital que tiene asignado el usuario del portal, que él sabe lo que esta haciendo y todas las responsabilidades que tiene por utilizar este servicio.


Una vez que ya sabe que puede llegar al servicio ( Conectarse ), podemos iniciar el proceso de construcción del proxy. Para tales efectos utilizaremos herramientas de Microsoft que nos ayudarán a realizar el proceso casi sin necesidad de escribir una línea de código. Para algunos esto resulta muy bueno, pero para desarrolladores como yo muchas veces se transforma en armas de doble filo, que funcionan correctamente en ambientes controlados, pero que dan muchos dolores de cabeza cuando no se comprende la lógica detrás de ellas.

Visual Studio 2011 tiene un gran número de herramientas disponibles que están disponibles a nivel de línea de comandos, las cuales deberás utilizar para generar el proxy.

Les dejo aquí la url de Microsoft para que lean detalladamente las características de la herramienta.
Web Services Description Language Tool ( WSDL.EXE )



Procedimiento
Bueno en el caso mío, fueron varias horas de trabajo hasta conseguir lo que necesitaba, pero al final logré construir el conector (Proxy) utilizando la siguiente sintaxis. Primero, cree el archivo de contrato el cual almacenara la descripción de los servicios a los cuales quiere acceder, en mi caso cree un archivo plano denominado Contrato.wsdl donde deposite el contrato de servicios extraído de la URL de Producción. Lo cual me quedo algo como esto:

Ver archivo con descripción de GetSeed

Ver archivo con descripción de GetTokenFromSeed

Nota:
Los archivos creados apuntan al servidor de producción del SII, para crear los archivos de certificación, deberá editar los archivos y cambiar la referencia 'palena' por 'maullin'.


Una vez creado el archivo wsdl es necesario indicarle al ejecutable que es lo que se necesita hacer con el. En mi caso yo necesitaba que a partir de este archivo generará una clase del tipo librería que me permitiera acceder a los servicios del SII. Así que aplique esta sintaxis:

Wsdl /out:myProxyClass.cs Contrato.wsdl

Donde el primer parámetro corresponde al archivo de salida tipo clase c# y el segundo parámetro corresponde a nuestro archivo de contrato wsdl generado en el paso anterior. La nueva clase generada ahora puede ser insertada en nuestro proyecto .NET para ser consumida. El resultado de la conversión es algo como esto:

El resultado de la operacion arroja los siguientes archivos. En este caso les dejo una url de donde verlos utilizando Google Drive.

Ver clase proxy GetSeed

Proxy GetSeed












Ver clase proxy GetTokenFromSeedService













Con estas dos clases ya se encuentra listo para incluirlas en su proyecto y de esta forma iniciar el proceso de autenticación sobre el SII.