This tutorial shows how to make a remote procedure call to a REST service with WS-Security data protection and x509 digital signatures. The given example connects to a REST service, which is written using C# WCF. The service implements a simple algorithm, which converts Celsius to Fahrenheit, and vice versa. Both SOAP requests and responses are digitally signed and encrypted using x509 cryptographic keys. Delphi client utilizes the TclHttpRio component from the Clever Internet Suite library.
procedure TForm1.btnC2FClick(Sender: TObject);
begin
if (edtCelsius.Text = '') then Exit;
case cbSecurity.ItemIndex of
0 : ConvertC2F();
1 : ConvertC2FSign();
2 : ConvertC2FSignEncrypt();
end;
end;
procedure TForm1.btnF2CClick(Sender: TObject);
begin
if (edtFahrenheit.Text = '') then Exit;
case cbSecurity.ItemIndex of
0 : ConvertF2C();
1 : ConvertF2CSign();
2 : ConvertF2CSignEncrypt();
end;
end;
After WSDL import, Delphi automatically creates the .pas unit with declared data and service types.
...
procedure TForm1.ConvertC2FSign;
var
service: IRestSoapSign;
celsius, fahrenheit: RestSoapSign.Temperature2;
begin
service := clHttpRioSign as IRestSoapSign;
celsius := nil;
fahrenheit := nil;
try
celsius := RestSoapSign.Temperature2.Create();
celsius.Value := StrToFloat(edtCelsius.Text);
celsius.Units := 'C';
fahrenheit := service.Celsius2Fahrenheit(celsius);
edtFahrenheit.Text := FloatToStr(fahrenheit.Value);
finally
fahrenheit.Free();
celsius.Free();
end;
end;
procedure TForm1.ConvertC2FSignEncrypt;
var
service: IRestSoapSignEncrypt;
celsius, fahrenheit: RestSoapSignEncrypt.Temperature2;
begin
service := clHttpRioEncrypt as IRestSoapSignEncrypt;
celsius := nil;
fahrenheit := nil;
try
celsius := RestSoapSignEncrypt.Temperature2.Create();
celsius.Value := StrToFloat(edtCelsius.Text);
celsius.Units := 'C';
fahrenheit := service.Celsius2Fahrenheit(celsius);
edtFahrenheit.Text := FloatToStr(fahrenheit.Value);
finally
fahrenheit.Free();
celsius.Free();
end;
end;
...
Add a TclSoapMessage.OnGetEncryptionCertificate event handler for the Request object. You need to provide a public-key service certificate here. All used certificates must be installed in Windows.
This example looks for a signing certificate using its fingerprint parameter.
procedure TForm1.RequestGetEncryptionCertificate(Sender: TObject;
AKeyInfo: TclXmlKeyInfo; var ACertificate: TclCertificate;
AExtraCerts: TclCertificateList; var AStoreName: string;
var AStoreLocation: TclCertificateStoreLocation; var Handled: Boolean);
begin
if (clCertificateStore1.Items.Count = 0) then
begin
clCertificateStore1.Open('MY');
end;
ACertificate :=
clCertificateStore1.FindByThumbprint('d47ec78db75e82832a5c7fc91895b55fad1de81e', True);
AStoreName := 'MY';
AStoreLocation := slCurrentUser;
Handled := True;
end;
procedure TForm1.RequestGetSigningCertificate(Sender: TObject;
AKeyInfo: TclXmlKeyInfo; var ACertificate: TclCertificate;
AExtraCerts: TclCertificateList; var Handled: Boolean);
begin
if (clCertificateStore1.Items.Count = 0) then
begin
clCertificateStore1.Open('MY');
end;
ACertificate :=
clCertificateStore1.FindByThumbprint('4ea0ea7560685b381f729f7a855451ced26a297d', True);
Handled := True;
end;
The Response object requires certificates, as well. You need to add both the TclSoapMessage.OnGetSigningCertificateEx and the OnGetEncryptionCertificate event handlers. By default, the component looks for a server certificate in the Addressbook folder of the CurrentUser storage.
A handler for the OnGetEncryptionCertificate event of the Response requires your personal private-key certificate.
procedure TForm1.ResponseGetEncryptionCertificate(Sender: TObject;
AKeyInfo: TclXmlKeyInfo; var ACertificate: TclCertificate;
AExtraCerts: TclCertificateList; var AStoreName: string;
var AStoreLocation: TclCertificateStoreLocation; var Handled: Boolean);
begin
AStoreName := 'MY';
AStoreLocation := slCurrentUser;
Handled := True;
end;
procedure TForm1.ResponseGetSigningCertificateEx(Sender: TObject;
AKeyInfo: TclXmlKeyInfo; var ACertificate: TclCertificate;
AExtraCerts: TclCertificateList; var AStoreName: string;
var AStoreLocation: TclCertificateStoreLocation; var Handled: Boolean);
begin
AStoreName := 'MY';
AStoreLocation := slCurrentUser;
Handled := True;
end;
Article ID: 157, Created: March 10, 2020 at 11:46 PM, Modified: June 5, 2020 at 7:14 PM