I am trying to use the SOAP API defined by the Alfresco CMS. According to the
Alfresco documentation I am supposed to include a ticket received after an
initial login as header to every request like so:
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-070e548d-5a45-48d7-acf3-c2c4d0b7b506">
<wsu:Created>2006-02-22T09:56:27Z</wsu:Created>
<wsu:Expires>2006-02-22T10:01:27Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>admin</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">TICKET_7c6a9e2b-a389-11da-983b-911c53c687cc</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
In <46e04cdc$1...@newsgroups.borland.com> I found help for creating definitions
for such a header. I followed those instructions and fiddled around with the
code. The result of my effort can be found in:
http://www.marian-aldenhoevel.de/tmp/WSSE.pas
The important part, or so I believe, of it is the registration:
const
NS_SECEXT='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
NS_UTILITY='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
RemClassRegistry.RegisterXSClass(Security, NS_SECEXT, 'Security');
RemClassRegistry.RegisterXSClass(Timestamp, NS_UTILITY,'Timestamp');
RemClassRegistry.RegisterXSClass(Created, NS_UTILITY,'Created');
RemClassRegistry.RegisterXSClass(Expires, NS_UTILITY,'Expires');
RemClassRegistry.RegisterXSClass(UsernameToken,NS_SECEXT, 'UsernameToken');
RemClassRegistry.RegisterXSClass(Password, NS_SECEXT, 'Password');
If I then create a Security Header and use RIO.Send() with it I get the
following in my SOAP-Message:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Header>
<Security
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Timestamp>
<Created
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2007-10-12T08:18:36Z</Created>
<Expires
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2007-10-13T08:18:36Z</Expires>
</Timestamp>
<UsernameToken>
<Username>admin</Username>
<Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">TICKET_d5bb7ce2ec39daabb0612de46c92e27cf670cf46</Password>
</UsernameToken>
</Security>
</SOAP-ENV:Header>
Which does not work.
I think it does not work because the <Timestamp>-Element is missing the
namespace-declaration for "http://docs.oasis-..wssecurity-utility-1.0.xsd".
I do not claim to fully understand the issue, though.
I have managed to create a working version of my client by handling
RIO.OnBeforeRequest and fiddling in a string-version of the headers as per
the documentation. But I would really like to understand what is going on
here.
How is the creating of the namespace-attributes controlled in the Delphi 2007
SOAP implementation?
Ciao, MM
I grabbed a copy of the WSSE.pas you posted and did notice that the
serialization logic produces a different namespace for the 'Timestamp'
element. Ultimately, it's the schema that dictates what it should be. I
suspect that the Alfresco documentation is correct and that the Delphi
importer failed to properly interpret the schema. I'll know more once I put
together a WebService that users that schema.
BTW, I had to do a little tweak to WSSE.PAS. The version I downloaded had
the following:
destructor UsernameToken.Destroy;
begin
FreeAndNil(FUsername);
inherited Destroy;
end;
I believe it's FPassword, not FUsername, that should be the argument to
FreeAndNil.
I'll post more once I've investigated the schema.
Cheers,
Bruneau.
I looked at the schema for Security and (as I should have expected), it's a
very generic definition that basically allows any elements from any schema
to be included:
<xsd:complexType name="SecurityHeaderType">
<xsd:sequence>
<xsd:any processContents="lax" minOccurs="0"
maxOccurs="unbounded"></xsd:any>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax" />
</xsd:complexType>
<xsd:element name="Security" type="wsse:SecurityHeaderType">
The Delphi binding class Security...
Security=class(TSOAPHeader)
published
property Timestamp:TimeStamp read FTimestamp write FTimestamp;
property UsernameToken:UsernameToken read FUserNameToken write
FUserNameToken;
end;
... is an incorrect mapping of the schema type. The above would work if
SecurityHeaderType were defined as:
<xsd:complexType name="SecurityHeaderType">
<xsd:sequence>
<xsd:element name="Timestamp" type="wssu:TimeStampType"/>
<xsd:element name="UsernameToken" type="wsse:UsernameTokenType"/>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax" />
</xsd:complexType>
The reason is that (unfortunately) the delphi runtime assumes that any
published property maps to an <xsd:element ...> at the schema level unless
specified otherwise. For example, in the case of attributes, the Delphi
property declaration reads "Index (IS_ATTR)".
This issue cannot be elegantly resolved without an additional attribute that
would inform the runtime no to assume that the property was an element. Once
this attribute is in place, the runtime would then know not to pass on the
namespace of the (outer) complextype to the property as it was not an
element.
If time allows, would you mind opening a QC report for this? It's very
related to something we started addressing in the latest rev: i.e. qualified
vs. unqualified elements: Unqualified elements don't inherit the outer's
namespace; qualified ones do; we need a third attribute that specifies that
the property uses the namespace of its type.
Cheers,
Bruneau.
> I am trying to use the SOAP API defined by the Alfresco CMS. According
> to the
> Alfresco documentation I am supposed to include a ticket received after an
> initial login as header to every request like so:
I have the same problem and some questions ...
I need to obtain a kerberos service token and then include it in a header.
1. How do you obtain the ticket ?
2. What are disadvantages of using the OnBeforeRequest ?
3. Can you please post your example ?
TIA
Sergio Sette
I investigated the issue Marian reported and we need to have a tweak in the
runtime to get this to work properly. Basically the runtime's assumption
that 'property' maps to 'xsd:element' unless told otherwise is incorrect.
While such a tweak is easy at the runtime level no importer would emit it...
hence all bindings generated by the WSDL importer would have to be manually
modified. In that light, I agree that using OnBeforeRequest is preferable in
this case. In the event handler you're basically looking for a string
pattern in the request and replacing with another.
Cheers,
Bruneau.