Hola amigos..Estoy desarrollando un sistema para coenctarme al web service de facturacion electronica de AFIP.
Esta es la unidad de Autenticacion, a la cual llamo como parametro "wsfe":
unit UAutenticacion; interface uses XMLIntf, XMLDoc,Winapi.shellAPI, dialogs,Classes,SOAPHTTPClient,sysutils,DateUtils; type TLogin = class private Fservicio: string; Fsign: string; Ftoken: string; Fexpiration: TDateTime; procedure Setservicio(const Value: string); procedure Setsign(const Value: string); procedure Settoken(const Value: string); procedure Setexpiration(const Value: TDateTime); public property expiration:TDateTime read Fexpiration write Setexpiration; property token:string read Ftoken write Settoken; property sign:string read Fsign write Setsign; property servicio:string read Fservicio write Setservicio; destructor destroy; function guardarXML():IXMLDocument; function armarsource:string; function generarCMS(const xml1:IXMLDocument):WideString; procedure respuestaXML(const s:string); function expiro():boolean; class function unicoLogin:TLogin; procedure actualizarsigntoken; constructor Loguearse(s:string); end; var login:TLogin; implementation { TLogin } uses tra,IniFiles,Forms, LoginCms1,loginresponse, string64, NuevoTicket; procedure TLogin.actualizarsigntoken; var xml1:IXMLDocument; cms:string; begin xml1:=NewXMLDocument(); xml1:=login.guardarXML(); cms:=login.generarCMS(xml1); login.respuestaXML(cms); end; function TLogin.armarsource: string; var archivoini:TIniFile; source,o,serialNumber,C,cn:string; begin archivoini:=TIniFile.Create(ExtractFilePath(Application.ExeName)+ 'caja.ini'); o:=archivoini.ReadString('EMPRESA','O',''); serialNumber:=archivoini.ReadString('EMPRESA','CUIT',''); cn:=archivoini.ReadString('EMPRESA','cn',''); C:=archivoini.ReadString('EMPRESA','C',''); source:='C='+C+',o='+o+',serialNumber='+serialNumber+',cn='+cn; Result:=source; end; destructor TLogin.destroy; begin inherited; end; function TLogin.expiro: boolean; var time:string; diferencia:int64; begin diferencia:=2; time:=FormatDateTime('hh:mm:ss',Now); if (MinuteSpan(StrToDateTime(time),login.expiration)<2) then begin result:=True; end else begin result:=False; end; end; function TLogin.generarCMS(const xml1:IXMLDocument):WideString; var rutabat,linea:string; archivoCMS:TStringList; textocms:WideString; archivoplano:TextFile; nombrearchivo:string; begin rutabat:=ExtractFilePath(Application.ExeName)+'certificado\'+'cms.bat'; ShellExecute(0,'open',PWideChar(rutabat),nil, nil,0); archivoCMS:=TStringList.Create; archivoCMS.LoadFromFile(ExtractFilePath(Application.ExeName) + 'loginticketrequest.xml.cms'); result:=archivoCMS.Text; end; function TLogin.guardarXML():IXMLDocument; var loginticketrequest:IXMLLoginTicketRequestType; loginheader:IXMLHeaderType; archivoini:TIniFile; diai,diaf,horai,time,horaf,horae,expiration:string; XML1:IXMLDocument; XMLanterior:IXMLDocument; startnode,nodohijo,nodoexp:IXMLNode; begin time:=FormatDateTime('hh:mm:ss',now); //crear archivo xml XML1 := NewXMLDocument; XML1.FileName:='loginticketrequest.xml'; loginticketrequest:=NewloginTicketRequest; //asginar valores para loginticketrequest.xml // version loginticketrequest.Version:='1.0'; //header // uniqueid son constantes loginticketrequest.header.UniqueId:=4325399; //hora del pedido.. es ahora diai:=FormatDateTime('yyyy-mm-dd',Now); diaf:=FormatDateTime('yyyy-mm-dd',IncHour(Now,12)); horai:=FormatDateTime('hh:mm:ss',now); horaf:=FormatDateTime('hh:mm:ss',IncHour(Now,12)); loginticketrequest.header.GenerationTime:=diai+ 'T' + horai + '-03:00'; //hora de finalizacion (1 dia es el maximo); loginticketrequest.header.ExpirationTime:=diaf+'T'+horaf + '-03:00'; //servicio a acceder loginticketrequest.Service:=Fservicio; XML1.XML.Add(loginticketrequest.XML); XML1.Active:=True; XML1.SaveToFile(ExtractFilePath(Application.ExeName) + 'loginticketrequest.xml'); Result:=XML1; end; constructor TLogin.Loguearse(s:string); var XML1:IXMLDocument; CMS:WideString; CMS64:WideString; TRA:TXMLDocument; begin self.Fservicio:=s; XML1:=self.guardarXML; CMS:=self.generarCMS(XML1); ShowMessage(CMS); CMS64:=Base64Encode(CMS); ShowMessage(CMS64); self.respuestaXML(CMS64); end; procedure TLogin.respuestaXML(const s:string); var RIOLogin:THTTPRIO; xml3:IXMLDocument; content,expira,nodo:string; nodohijo,nodohijosign,startnode,startnodesign:IXMLNode; begin RIOLogin:=THTTPRIO.Create(nil); with RIOLogin do begin WSDLLocation:='https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl'; Port:='LoginCms'; Service:='LoginCMSService'; end; xml3:=NewXMLDocument; content:=(RIOLogin as LoginCms).loginCms(s); xml3.XML.Text:=content; xml3.Active:=True; xml3.SaveToFile(ExtractFilePath(Application.ExeName) + 'respuestaxml.xml'); startnode:=xml3.ChildNodes[1]; nodohijo:=startnode.ChildNodes[0]; nodo:=nodohijo.ChildNodes['expirationTime'].Text; expira:=Copy(nodo,12,8); Setexpiration(StrToDateTime(expira)); //setear sign y token startNodesign := xml3.ChildNodes[1]; nodohijosign:=startnodesign.ChildNodes[1]; Setsign(nodohijosign.ChildNodes['sign'].Text); Settoken(nodohijosign.ChildNodes['token'].Text); end; procedure TLogin.Setexpiration(const Value: TDateTime); begin Fexpiration := Value; end; procedure TLogin.Setservicio(const Value: string); begin Fservicio := Value; end; procedure TLogin.Setsign(const Value: string); begin Fsign := Value; end; procedure TLogin.Settoken(const Value: string); begin Ftoken := Value; end; class function TLogin.unicoLogin:TLogin; begin if login<>nil then begin if login.expiro=False then begin Result:=login; end else begin login.actualizarsigntoken; Result:=login; end; end else begin login:=Tlogin.Loguearse('padron-puc-ws-consulta-nivel3'); login.respuestaXML(login.generarCMS(login.guardarXML())); end; end; end.
Y obtengo No se puede decodificar el BASE64.
Como veran en el constructor sigo los pasos de las especificaciones tecnicas de AFIP:
1- Creo el xml con tiempo de expiracion
2-Genero el CMS en un archivo, para lo mismo ejecuto un archivo BAT (Codigo DOS digamos):