Ik verstuur met Delphi 10.2 xml pensioenaangiften aan verschillende pensioenuitvoerders. Deze berichten worden verpakt in een soap envelop. Dat doe ik tot nog toe door de soap envelop met header en body handmatig aan te maken (zonder een XML engine als (T|I)XMLDocument te gebruiken). De soap envelop verstuur ik met behulp van idHTTP. Dat werkt allemaal prima.
Nu moet ik voor het eerst een soap envelop produceren met een header gebaseerd op WS Security UsernameToken Profile 1.1. De betreffende pensioenuitvoerder heeft me de volgende voorbeelden van een soap envelop toegestuurd die voldoen aan de eisen.
De basisstructuur van het bericht moet zijn:
Code:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>Gebruikersnaam</wsse:Username>
<wsse:Password>}wachtwoord</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ws:ZendBerichtAlsZIP>
<ws:idLcr>idLcr</ws:idLcr>
<ws:idBer>idBer</ws:idBer>
<ws:berichtZip>BerichtZipData</ws:berichtZip>
</ws:ZendBerichtAlsZIP>
</soapenv:Body>
</soapenv:Envelope>
Daarnaast stuurde ze een door hun testomgeving geaccepteerd testbericht:
Code:
<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">
<u:Timestamp u:Id="_0">
<u:Created>2017-10-05T11:27:05.742Z</u:Created>
<u:Expires>2017-10-05T11:32:05.742Z</u:Expires>
</u:Timestamp>
<o:UsernameToken u:Id="uuid-075a8197-9c2c-43c9-a2cf-3fa6515044e7-1">
<o:Username>XXXXXXXXXXXX</o:Username>
<o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">XXXXXXXX</o:Password>
</o:UsernameToken>
</o:Security>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://localhost:44300/UPAWebService.svc</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS/UPAWebService/ZendBerichtAlsZIP</Action>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ZendBerichtAlsZIP xmlns="http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS">
<idLcr>XXXXXXXX</idLcr>
<idBer>XXXXXXXXXXXXXX</idBer>
<berichtZIP>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</berichtZIP>
</ZendBerichtAlsZIP>
</s:Body>
</s:Envelope>
Op basis daarvan ben ik aan de slag gegaan en nu produceert mijn programma het volgende bericht:
Code:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsu:Timestamp wsu:Id="_67">
<wsu:Created>2017-10-27T08:58:28Z</wsu:Created>
<wsu:Expires>2017-10-27T09:03:28Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken wsu:Id="DCADF9E6-67C6-4BD3-9777-5B9E4AD97839">
<wsse:Username>UserName</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">W242TDJLUUpeeTg1dmcoJQ0K</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<To soapenv:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://localhost:44300/UPAWebService.svc</To>
<Action soapenv:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS/UPAWebService/ZendBerichtAlsZIP</Action>
</soapenv:Header>
<soapenv:Body>
<ws:ZendBerichtAlsZIP>
<ws:idLcr>XXXXXXXX</ws:idLcr>
<ws:idBer>SLAGER-PA-01A-20171027105827</ws:idBer>
<ws:berichtZIP>XXXXXXXX</ws:berichtZIP>
</ws:ZendBerichtAlsZIP>
</soapenv:Body>
</soapenv:Envelope>
Helaas levert dit bij verzending de volgende foutcode op:
Code:
Recv 27-10-2017 11:18:31: HTTP/1.1 400 Bad Request<EOL>
Cache-Control: private,no-cache, no-store, must-revalidate<EOL>
Server: Microsoft-IIS/8.5<EOL>X-AspNet-Version: 4.0.30319<EOL>
Strict-Transport-Security: max-age=31536000<EOL>
X-FRAME-OPTIONS: SAMEORIGIN<EOL>
X-Content-Type-Options: nosniff<EOL>
Date: Fri, 27 Oct 2017 09:18:27 GMT<EOL>
Content-Length: 0<EOL><EOL>
Als ik de betrokken pensioenuitvoerder om ondersteuning vraag melden ze dat ze zelfs geen inlogpoging zien, zelfs geen foutieve. Verder geven ze aan dat het SOAP bericht als WS Security UsernameToken Profile 1.1, WS-I Basic Profile 1.1 standaard moet worden verstuurd. In .Net moeten de Credentials aan de verbinding gehangen worden zodat deze in het SOAP verkeer worden gebruikt.
Nu is dit nieuw voor mij, maar als ik mijn bericht vergelijk met het testvoorbeeld bericht zie ik toch grote overeenkomsten (Timestamp, UsernameToken). Evengoed zijn er zaken niet in orde, maar wat dan precies is de vraag?
Nu zag ik in http://www.codenewsfast.com/cnf/arti...okmark.7398716 een op zich duidelijk voorbeeld hoe je met de WSDL importer een Delphi unit kunt laten samenstellen met de vereiste SOAPHeader. Deze kun je dan in je overige code aanroepen om de juiste SOAPHeader samen te stellen. En met een HTTPRIO1BeforeExecute kun je de soapenveloppe dan weer bekijken alvorens deze daadwerkelijk te verzenden.
Als ik de WSDL (https://Pensioenaangifte.AGH.nl/acct...ngifteWs/?wsdl) importeer dan krijg ik deze unit:
Code:
// ************************************************************************ //
// The types declared in this file were generated from data read from the
// WSDL File described below:
// WSDL : https://Pensioenaangifte.AGH.nl/acctest/ws/PensioenaangifteWs/?wsdl
// >Import : https://pensioenaangifte.agh.nl/acctest/ws/PensioenaangifteWs/UPAWebService.svc?wsdl=wsdl0
// >Import : https://pensioenaangifte.agh.nl/acctest/ws/PensioenaangifteWs/UPAWebService.svc?wsdl=wsdl0>0
// >Import : https://pensioenaangifte.agh.nl/acctest/ws/PensioenaangifteWs/UPAWebService.svc?xsd=xsd0
// Encoding : utf-8
// Version : 1.0
// (10-11-2017 08:55:20 - - $Rev: 90173 $)
// ************************************************************************ //
unit WSDL_UPA;
interface
uses Soap.InvokeRegistry, Soap.SOAPHTTPClient, System.Types, Soap.XSBuiltIns;
const
IS_OPTN = $0001;
IS_REF = $0080;
type
// ************************************************************************ //
// The following types, referred to in the WSDL document are not being represented
// in this file. They are either aliases[@] of other types represented or were referred
// to but never[!] declared in the document. The types from the latter category
// typically map to predefined/known XML or Embarcadero types; however, they could also
// indicate incorrect WSDL documents that failed to declare or import a schema type.
// ************************************************************************ //
// !:string - "http://www.w3.org/2001/XMLSchema"[Gbl]
ZendBerichtAlsZIPResponse = class; { "http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS"[GblCplx] }
OntvangBerichtAlsZIPResponse = class; { "http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS"[GblCplx] }
// ************************************************************************ //
// XML : ZendBerichtAlsZIPResponse, global, <complexType>
// Namespace : http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS
// ************************************************************************ //
ZendBerichtAlsZIPResponse = class(TRemotable)
private
FStatus: string;
FStatus_Specified: boolean;
FFoutmelding: string;
FFoutmelding_Specified: boolean;
procedure SetStatus(Index: Integer; const Astring: string);
function Status_Specified(Index: Integer): boolean;
procedure SetFoutmelding(Index: Integer; const Astring: string);
function Foutmelding_Specified(Index: Integer): boolean;
published
property Status: string Index (IS_OPTN) read FStatus write SetStatus stored Status_Specified;
property Foutmelding: string Index (IS_OPTN) read FFoutmelding write SetFoutmelding stored Foutmelding_Specified;
end;
// ************************************************************************ //
// XML : OntvangBerichtAlsZIPResponse, global, <complexType>
// Namespace : http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS
// ************************************************************************ //
OntvangBerichtAlsZIPResponse = class(TRemotable)
private
FOntvangBerichtAlsZIPResult: string;
FOntvangBerichtAlsZIPResult_Specified: boolean;
procedure SetOntvangBerichtAlsZIPResult(Index: Integer; const Astring: string);
function OntvangBerichtAlsZIPResult_Specified(Index: Integer): boolean;
published
property OntvangBerichtAlsZIPResult: string Index (IS_OPTN) read FOntvangBerichtAlsZIPResult write SetOntvangBerichtAlsZIPResult stored OntvangBerichtAlsZIPResult_Specified;
end;
// ************************************************************************ //
// Namespace : http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS
// soapAction: http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS/UPAWebService/%operationName%
// transport : http://schemas.xmlsoap.org/soap/http
// style : document
// use : literal
// binding : BasicHttpBinding_UPAWebService
// service : UPA
// port : BasicHttpBinding_UPAWebService
// URL : https://pensioenaangifte.agh.nl/acctest/ws/PensioenaangifteWs/UPAWebService.svc
// ************************************************************************ //
UPAWebService = interface(IInvokable)
['{8898E84C-AFA7-1928-4B19-AB1D27995D31}']
function ZendBerichtAlsZIP(const idLcr: string; const idBer: string; const berichtZIP: string): ZendBerichtAlsZIPResponse; stdcall;
function OntvangBerichtAlsZIP(const idLcr: string; const idber: string): OntvangBerichtAlsZIPResponse; stdcall;
end;
function GetUPAWebService(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): UPAWebService;
implementation
uses System.SysUtils;
function GetUPAWebService(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): UPAWebService;
const
defWSDL = 'https://Pensioenaangifte.AGH.nl/acctest/ws/PensioenaangifteWs/?wsdl';
defURL = 'https://pensioenaangifte.agh.nl/acctest/ws/PensioenaangifteWs/UPAWebService.svc';
defSvc = 'UPA';
defPrt = 'BasicHttpBinding_UPAWebService';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as UPAWebService);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
procedure ZendBerichtAlsZIPResponse.SetStatus(Index: Integer; const Astring: string);
begin
FStatus := Astring;
FStatus_Specified := True;
end;
function ZendBerichtAlsZIPResponse.Status_Specified(Index: Integer): boolean;
begin
Result := FStatus_Specified;
end;
procedure ZendBerichtAlsZIPResponse.SetFoutmelding(Index: Integer; const Astring: string);
begin
FFoutmelding := Astring;
FFoutmelding_Specified := True;
end;
function ZendBerichtAlsZIPResponse.Foutmelding_Specified(Index: Integer): boolean;
begin
Result := FFoutmelding_Specified;
end;
procedure OntvangBerichtAlsZIPResponse.SetOntvangBerichtAlsZIPResult(Index: Integer; const Astring: string);
begin
FOntvangBerichtAlsZIPResult := Astring;
FOntvangBerichtAlsZIPResult_Specified := True;
end;
function OntvangBerichtAlsZIPResponse.OntvangBerichtAlsZIPResult_Specified(Index: Integer): boolean;
begin
Result := FOntvangBerichtAlsZIPResult_Specified;
end;
initialization
{ UPAWebService }
InvRegistry.RegisterInterface(TypeInfo(UPAWebService), 'http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS', 'utf-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(UPAWebService), 'http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS/UPAWebService/%operationName%');
InvRegistry.RegisterInvokeOptions(TypeInfo(UPAWebService), ioDocument);
{ UPAWebService.ZendBerichtAlsZIP }
InvRegistry.RegisterMethodInfo(TypeInfo(UPAWebService), 'ZendBerichtAlsZIP', '',
'[ReturnName="ZendBerichtAlsZIPResult"]', IS_OPTN);
{ UPAWebService.OntvangBerichtAlsZIP }
InvRegistry.RegisterMethodInfo(TypeInfo(UPAWebService), 'OntvangBerichtAlsZIP', '',
'[ReturnName="OntvangBerichtAlsZIPResult"]', IS_OPTN);
RemClassRegistry.RegisterXSClass(ZendBerichtAlsZIPResponse, 'http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS', 'ZendBerichtAlsZIPResponse');
RemClassRegistry.RegisterXSClass(OntvangBerichtAlsZIPResponse, 'http://www.pensioenfederatie.nl/uniformePensioenAangifte/2015/05/WS', 'OntvangBerichtAlsZIPResponse');
end.
Daarin zie ik helemaal niets staan over een Header, laat staan over Timestamp, UsernameToken, Password of UserName. Kortom, hoe moet ik verder?
Bookmarks