I try to implement a soap client, that should call a service like this:
Request-XML:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="wsse:Base64Binary" ValueType="bipro:VDGTicket">ABCDEFG</wsse:BinarySecurityToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
<TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
<RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</RequestType>
</RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>
Response:
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<wst:RequestSecurityTokenResponse xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>
<wst:Lifetime>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-03-22T13:11:53.053Z</wsu:Created>
<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-03-22T17:11:53.053Z</wsu:Expires>
</wst:Lifetime>
<wst:RequestedSecurityToken>
<wsc:SecurityContextToken xmlns:wsc="http://schemas.xmlsoap.org/ws/2005/02/sc">
<wsc:Identifier>bipro:1438029780641932842</wsc:Identifier>
</wsc:SecurityContextToken>
</wst:RequestedSecurityToken>
<allgemein:BiPROVersion xmlns:allgemein="http://www.bipro.net/namespace/allgemein">2.1.0.1.0</allgemein:BiPROVersion>
</wst:RequestSecurityTokenResponse>
</soapenv:Body>
</soapenv:Envelope>
Yes, there is also a WSDL file, but the code generator of Delphi does not generate code for everything in it... The generated code is missing two relevant type definitions... and there is no possibility to get a correct wsdl... so I decided to code the interface-unit on my own:
BinarySecurityToken = class(TRemotable)
private
FEncodingType: string;
FValueType: string;
FVDGTicket: string;
public
published
property EncodingType: string Index (IS_ATTR) read FEncodingType write FEncodingType;
property ValueType: string Index (IS_ATTR) read FValueType write FValueType;
property VDGTicket: string Index (IS_TEXT) read FVDGTicket write FVDGTicket;
end;
Security = class(TSoapHeader)
private
FBinarySecurityToken: BinarySecurityToken;
public
destructor Destroy; override;
published
property BinarySecurityToken: BinarySecurityToken Index (IS_REF) read FBinarySecurityToken write FBinarySecurityToken;
end;
TokenType = class(TRemotable)
private
FTokenType: string;
public
published
property TokenType: string Index (IS_TEXT) read FTokenType write FTokenType;
end;
RequestType = class(TRemotable)
private
FRequestType: string;
published
property RequestType: string Index (IS_TEXT) read FRequestType write FRequestType;
end;
RequestSecurityToken = class(TRemotable)
private
FTokenType: TokenType;
FRequestType: RequestType;
public
destructor Destroy; override;
published
property TokenType: TokenType Index (IS_REF) read FTokenType write FTokenType;
property RequestType: RequestType Index (IS_REF) read FRequestType write FRequestType;
end;
Created = class(TRemotable)
private
FDate: TXSDateTime;
public
destructor Destroy; override;
published
property Date: TXSDateTime Index (IS_TEXT) read FDate write FDate;
end;
Expires = class(TRemotable)
private
FDate: TXSDateTime;
public
destructor Destroy; override;
published
property Date: TXSDateTime Index (IS_TEXT) read FDate write FDate;
end;
Lifetime = class(TRemotable)
private
FCreated: Created;
FExpires: Expires;
public
destructor Destroy; override;
published
property Created: Created Index (IS_REF) read FCreated write FCreated;
property Expires: Expires Index (IS_REF) read FExpires write FExpires;
end;
Identifier = class(TRemotable)
private
FSCTToken: string;
public
published
property SCTToken: string Index (IS_TEXT) read FSCTToken write FSCTToken;
end;
SecurityContextToken = class(TRemotable)
private
FIdentifier: Identifier;
public
destructor Destroy; override;
published
property Identifier: Identifier Index (IS_REF) read FIdentifier write FIdentifier;
end;
RequestedSecurityToken = class(TRemotable)
private
FSecurityContextToken: SecurityContextToken;
public
destructor Destroy; override;
published
property SecurityContextToken: SecurityContextToken Index (IS_REF) read FSecurityContextToken write FSecurityContextToken;
end;
BiPROVersion = class(TRemotable)
private
FVersion: string;
public
published
property Version: string Index (IS_TEXT) read FVersion write FVersion;
end;
RequestSecurityTokenResponse = class(TRemotable)
private
FTokenType: TokenType;
FLifetime: Lifetime;
FRequestedSecurityToken: RequestedSecurityToken;
FBiPROVersion: BiPROVersion;
public
destructor Destroy; override;
published
property TokenType: TokenType Index (IS_REF) read FTokenType write FTokenType;
property Lifetime: Lifetime Index (IS_REF) read FLifetime write FLifetime;
property RequestedSecurityToken: RequestedSecurityToken Index (IS_REF) read FRequestedSecurityToken write FRequestedSecurityToken;
property BiPROVersion: BiPROVersion Index (IS_REF) read FBiPROVersion write FBiPROVersion;
end;
SecurityTokenServicePortType = interface(IInvokable)
['{FE7EBD83-56D0-4542-5A4D-662805285ED8}']
function RequestSecurityToken(const TokenType: TokenType; RequestType: RequestType): RequestSecurityTokenResponse; stdcall;
end;
initialization
{ SecurityTokenServicePortType }
InvRegistry.RegisterInterface(TypeInfo(SecurityTokenServicePortType), 'http://schemas.xmlsoap.org/ws/2005/02/trust', 'UTF-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(SecurityTokenServicePortType), '');
InvRegistry.RegisterInvokeOptions(TypeInfo(SecurityTokenServicePortType), ioDocument);
// InvRegistry.RegisterInvokeOptions(TypeInfo(SecurityTokenServicePortType), ioLiteral);
{ SecurityTokenServicePortType.RequestSecurityToken }
// InvRegistry.RegisterMethodInfo(TypeInfo(SecurityTokenServicePortType), 'RequestSecurityToken', '',
// '[RequestNS="http://schemas.xmlsoap.org/ws/2005/02/trust", ResponseNS="http://schemas.xmlsoap.org/ws/2005/02/trust"]');
// InvRegistry.RegisterParamInfo(TypeInfo(SecurityTokenServicePortType), 'RequestSecurityToken', 'RequestSecurityToken', '',
// '[Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"]', IS_REF);
// InvRegistry.RegisterParamInfo(TypeInfo(SecurityTokenServicePortType), 'RequestSecurityToken', 'RequestSecurityTokenResponse', '',
// '[Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"]', IS_REF);
InvRegistry.RegisterMethodInfo(TypeInfo(SecurityTokenServicePortType), 'RequestSecurityToken', '',
'[ReturnName="RequestSecurityTokenResponse", Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"]');
InvRegistry.RegisterParamInfo(TypeInfo(SecurityTokenServicePortType), 'RequestSecurityToken', 'RequestSecurityTokenResponse', '',
'[Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"]');
RemClassRegistry.RegisterXSClass(BiPROVersion,
'http://www.bipro.net/namespace/allgemein', 'BiPROVersion');
RemClassRegistry.RegisterXSClass(Identifier,
'http://schemas.xmlsoap.org/ws/2005/02/sc', 'Identifier');
RemClassRegistry.RegisterXSClass(SecurityContextToken,
'http://schemas.xmlsoap.org/ws/2005/02/sc', 'SecurityContextToken');
RemClassRegistry.RegisterXSClass(RequestedSecurityToken,
'http://schemas.xmlsoap.org/ws/2005/02/trust', 'RequestedSecurityToken');
RemClassRegistry.RegisterXSClass(Created,
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Created');
RemClassRegistry.RegisterXSClass(Expires,
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Expires');
RemClassRegistry.RegisterXSClass(Lifetime,
'http://schemas.xmlsoap.org/ws/2005/02/trust', 'Lifetime');
RemClassRegistry.RegisterXSClass(RequestSecurityToken,
'http://schemas.xmlsoap.org/ws/2005/02/trust', 'RequestSecurityToken');
RemClassRegistry.RegisterXSClass(RequestSecurityTokenResponse,
'http://schemas.xmlsoap.org/ws/2005/02/trust', 'RequestSecurityTokenResponse');
RemClassRegistry.RegisterXSClass(RequestType,
'', 'RequestType');
RemClassRegistry.RegisterXSClass(TokenType,
'', 'TokenType');
RemClassRegistry.RegisterXSClass(BinarySecurityToken,
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'BinarySecurityToken');
RemClassRegistry.RegisterXSClass(Security,
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', 'Security');
InvRegistry.RegisterHeaderClass(TypeInfo(SecurityTokenServicePortType),
Security, 'Security',
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd');
end.
Now... that seems to work... delphi soap generates the above request, sends it to the webservice and receives a response... which I already have checked (saved it to a file in the RIO.OnAfterExecute() event). The response is ok.
but I got a problem: the result of the method RequestSecureToken (aTokenOut) is a nil value.
procedure TMainForm.btnGetTheTicket2Click(Sender: TObject);
var
aBean: SecurityTokenServicePortType;
aTokenOut: RequestSecurityTokenResponse;
aSCTHeader: SecurityTokenService_2.Security;
aCreated: TDateTime;
aExpires: TDateTime;
aTicket: string;
aTokenType: TokenType;
aRequestType: RequestType;
begin
aBean := SecurityTokenService_2.GetSecurityTokenServicePortType;
aSCTHeader := SecurityTokenService_2.Security.Create;
try
aSCTHeader.BinarySecurityToken := SecurityTokenService_2.BinarySecurityToken.Create;
aSCTHeader.BinarySecurityToken.EncodingType := 'NS1:Base64Binary';
aSCTHeader.BinarySecurityToken.ValueType := 'bipro:VDGTicket';
aSCTHeader.BinarySecurityToken.VDGTicket := edVDGTicket.Text;
(aBean as ISOAPHeaders).Send(aSCTHeader);
aTokenType := TokenType.Create;
try
aTokenType.TokenType := 'http://schemas.xmlsoap.org/ws/2005/02/sc/sct';
aRequestType := RequestType.Create;
try
aRequestType.RequestType := 'http://schemas.xmlsoap.org/ws/2005/02/trust/Issue';
aTokenOut := aBean.RequestSecurityToken(aTokenType, aRequestType);
try
// place a breakpoint here
aCreated := aTokenOut.Lifetime.Created.Date.AsDateTime;
aExpires := aTokenOut.Lifetime.Expires.Date.AsDateTime;
aTicket := aTokenOut.RequestedSecurityToken.SecurityContextToken.Identifier.SCTToken;
finally
FreeAndnil(aTokenOut);
end;
finally
FreeAndNil(aRequestType);
end;
finally
FreeAndNil(aTokenType);
end;
finally
FreeAndNil(aSCTHeader);
end;
end;
Did I forget to register anything? Do I do something wrong?
Fallback: is there a possibility to generate a wsdl file from request-xml and response-xml?
The problem was the interface of the method RequestSecurityToken...
SecurityTokenServicePortType = interface(IInvokable)
['{FE7EBD83-56D0-4542-5A4D-662805285ED8}']
function RequestSecurityToken(const TokenType: TokenType; RequestType: RequestType): RequestSecurityTokenResponse; stdcall;
end;
With that kind of SOAP-Response, it has to be like this:
SecurityTokenServicePortType = interface(IInvokable)
['{FE7EBD83-56D0-4542-5A4D-662805285ED8}']
procedure RequestSecurityToken(TokenType: TokenType; RequestType: RequestType;
out Lifetime: Lifetime;
out RequestedSecurityToken: RequestedSecurityToken;
out BiPROVersion: BiPROVersion); stdcall;
end;