Genivia Home Documentation
The gSOAP WS-Trust Extensible Framework

updated Tue Nov 23 2021 by Robert van Engelen
 
The gSOAP WS-Trust Extensible Framework

The gSOAP WS-Trust Extensible Framework

The material in this section relates to the WS-Trust specification.

The WS-Trust framework is extensible. New client-side and server-side WS-Trust operations can be added. Several predefined operations are included to get you started. The list of predefined operations will be expanded over time. Please inquire Genivia tech support services.

To use the WS-Trust framework, make sure that the wst.h specification is imported in the .h file for soapcpp2, e.g. after running wsdl2h check the generated .h file:

#import "wst.h"

If the import is not there, add it manually. Then run soapcpp2 as usual with option -Iimport to import wst.h from the import directory.

The wst.h and the WS-Trust-dependent wstx.h and other gSOAP-specific .h header files are located in the import directory of the gSOAP package. These files define the WS-Trust and other WS-* protocol header elements and types. The wstx.h header file defines the WS-Trust RequestSecurityTokenRequest and RequestSecurityTokenRequestCollection operations.

Compile your code with -DWITH_DOM and -DWITH_OPENSSL to enable WS-Security plugin API features.

Compile and link your code with wsseapi.c and wstapi.c, and include wsseapi.h and wstapi.h in your code.

Internally, the wstapi.c code enables SOAP 1.2 messaging. This will not affect your SOAP 1.1 messaging.

WS-Trust Bindings

The WS-Trust bindings in wst.h in the import directory were generated from the WS-Trust schema for you with the wsdl2h tool and WS/WS-typemap.dat as follows:

wsdl2h -cgyex -o wst.h -t WS/WS-typemap.dat WS/WS-Trust.xsd

The following modifications to wst.h are required to be made after generating wst.h with wsdl2h:

  • Remove //gsoapopt
  • Change http://docs.oasis-open.org/ws-sx/ws-trust/200512 to remove the trailing / (slash)
  • Change //gsoap wst schema namespace directive to //gsoap wst schema import directive
  • Add #import "wsp_appliesto.h"
  • Add #import "wstx.h" at the end of the definitions in wst.h

Expanding the Current WS-Trust Bindings

To expand or customize the WS-Trust bindings by adding (or removing) content model elements to the RequestSecurityToken and RequestSecurityTokenResponse, edit WS/WS-typemap.dat for the following two definition blocks:

wst__RequestSecurityTokenType = $\
    _wsp__AppliesTo_*                    wsp__AppliesTo;
wst__RequestSecurityTokenType = $\
    char*                                KeyType;
wst__RequestSecurityTokenType = $\
    char*                                RequestType;
wst__RequestSecurityTokenType = $\
    char*                                TokenType;
wst__RequestSecurityTokenType = $\
    wst__EntropyType*                    Entropy;
wst__RequestSecurityTokenType = $\
    char*                                ComputedKeyAlgorithm;
wst__RequestSecurityTokenType = $\
    unsigned int*                        KeySize;
wst__RequestSecurityTokenType = $\
    struct wst__BinaryExchangeType*      BinaryExchange;
wst__RequestSecurityTokenType = $\
    struct wst__AuthenticatorType*       Authenticator;

wst__RequestSecurityTokenResponseType = $\
    struct wst__RequestedSecurityTokenType* RequestedSecurityToken;
wst__RequestSecurityTokenResponseType = $\
    struct wst__RequestedReferenceType*  RequestedAttachedReference;
wst__RequestSecurityTokenResponseType = $\
    struct wst__RequestedReferenceType*  RequestedUnattachedReference;
wst__RequestSecurityTokenResponseType = $\
    struct wst__RequestedProofTokenType* RequestedProofToken;
wst__RequestSecurityTokenResponseType = $\
    struct wst__RequestedTokenCancelledType* RequestedTokenCancelled;
wst__RequestSecurityTokenResponseType = $\
    char*                                KeyType;
wst__RequestSecurityTokenResponseType = $\
    char*                                RequestType;
wst__RequestSecurityTokenResponseType = $\
    char*                                TokenType;
wst__RequestSecurityTokenResponseType = $\
    wst__EntropyType*                    Entropy;
wst__RequestSecurityTokenResponseType = $\
    struct wst__BinaryExchangeType*      BinaryExchange;
wst__RequestSecurityTokenResponseType = $\
    struct wst__AuthenticatorType*       Authenticator;

For example, to add the wst:Lifetime element to the RequestSecurityTokenResponse add the following two lines:

wst__RequestSecurityTokenResponseType = $\
    wst__LifetimeType*                   Lifetime;

where wst__LifetimeType is declared in wst.h. The pointer makes it optional.

Then follow the instructions in the previous section to regenerate wst.h.

Given the new Lifetime element, the wstapi.c framework can be extended to use this element information as follows:

time_t expires = 0; // no expiration
...
if (soap_call___wst__RequestSecurityToken(soap, endpoint, soap_wst_rst_action, &request, &response))
{
soap_set_namespaces(soap, saved_namespaces);
return soap->error;
}
soap_set_namespaces(soap, saved_namespaces);
if (response.Lifetime && response.Lifetime->wsu__Expires)
soap_s2dateTime(soap, response.Lifetime->wsu__Expires, &expires); // set expiration
"http://docs.oasis-open.org/ws-sx/ws-trust/200512/":RequestSecurityTokenResponseType is a complexType...
Definition: wst.h:313
const char * soap_wst_rst_action
Definition: wstapi.c:421
SOAP_FMAC5 int SOAP_FMAC6 soap_call___wst__RequestSecurityToken(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct wst__RequestSecurityTokenType *wst__RequestSecurityToken, struct wst__RequestSecurityTokenResponseType *wst__RequestSecurityTokenResponse)

Predefined WS-Trust Operations

This section lists the predefined WS-Trust operations implemented in wstapi.c.

wst_soap_wst_request_saml_token

int soap_wst_request_saml_token(struct soap *soap, const char *endpoint, int soapver, const char *applyto, const char *username, const char *password, saml1__AssertionType **saml1, saml2__AssertionType **saml2)
"urn:oasis:names:tc:SAML:1.0:assertion":AssertionType is a complexType.
Definition: saml1.h:173
"urn:oasis:names:tc:SAML:2.0:assertion":AssertionType is a complexType.
Definition: saml2.h:220
SOAP_FMAC1 int SOAP_FMAC2 soap_wst_request_saml_token(struct soap *soap, const char *endpoint, int soapver, const char *applyto, const char *username, const char *password, saml1__AssertionType **saml1, saml2__AssertionType **saml2)
Request SAML 1.0 or SAML 2.0 token. Verifies the SAML signature, which requires soap->cafile to be se...
Definition: wstapi.c:494

Request SAML 1.0 or SAML 2.0 token, with endpoint service endpoint URL (send to), soapver SOAP version with 1 = SOAP 1.1, 2 = SOAP 1.2 (SOAP 1.2 is recommended), applyto is your service domain, username to authenticate or NULL, password to authenticate or NULL, saml1 if non-NULL, requests SAML 1.0 and upon return points to a pointer that is set to the SAML 1.0 assertion received, saml2 if non-NULL, requests SAML 2.0 and upon return points to a pointer that is set to the SAML 2.0 assertion received.

Returns SOAP_OK on success when the assertion could be verified, with saml1 or saml2 set.

For example:

#include "wstapi.h"
#include "wsaapi.h"
#include "wsseapi.h"
#include "wst.nsmap"
static int ssl_verify(int ok, X509_STORE_CTX *store) { return 1; } // ignore all cert warnings (bad)
...
struct soap *soap = soap_new1(SOAP_XML_INDENT);
int soapver = 2; // SOAP 1.2
const char *to = "https://yourcompany.com/adfs/services/trust/13/UsernameMixed";
const char *applyto = "yourcompany.com";
const char *username = "yourusername";
const char *password = "yourpassword";
// register wsa plugin (optional, only if the client requires WS-Addressing rerouted messaging)
soap_register_plugin(soap, soap_wsa);
// register wsse plugin
soap_register_plugin(soap, soap_wsse);
// HTTPS settings
if (soap_ssl_client_context(soap, SOAP_SSL_DEFAULT, NULL, NULL, "cacerts.pem", NULL, NULL))
{
soap_print_fault(soap, stderr);
exit(1);
}
// HTTPS and SAML certificate verification callback
soap->fsslverify = ssl_verify;
// SAML 2.0 token request
if (soap_wst_request_saml_token(soap, to, soapver, applyto, username, password, NULL, &saml2))
{
soap_print_fault(soap, stderr);
}
else
{
// display subset of the assertion information
if (saml2)
{
int i;
for (i = 0; i < saml2->__size_AssertionType; i++)
{
{
// omitted from displaying
}
{
{
}
}
{
// omitted from displaying
}
{
int j;
{
{
int k;
}
}
}
}
if (saml2->saml2__Conditions)
{
printf("Not before %s\n", soap_dateTime2s(soap, *saml2->saml2__Conditions->NotBefore));
printf("Not on or after %s\n", soap_dateTime2s(soap, *saml2->saml2__Conditions->NotOnOrAfter));
}
}
else
{
printf("No SAML 2.0 statements!\n");
}
}
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
struct saml2__AuthnStatementType * saml2__AuthnStatement
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"AuthnStatement.
Definition: saml2.h:238
struct saml2__AttributeStatementType * saml2__AttributeStatement
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"AttributeStatement.
Definition: saml2.h:242
struct saml2__StatementAbstractType * saml2__Statement
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"Statement.
Definition: saml2.h:236
struct saml2__AuthzDecisionStatementType * saml2__AuthzDecisionStatement
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"AuthzDecisionStatement.
Definition: saml2.h:240
struct saml2__AssertionType::__saml2__union_AssertionType * __union_AssertionType
int __size_AssertionType
Definition: saml2.h:232
struct saml2__ConditionsType * saml2__Conditions
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"Conditions.
Definition: saml2.h:228
struct saml2__AttributeType * saml2__Attribute
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"Attribute.
Definition: saml2.h:731
struct saml2__AttributeStatementType::__saml2__union_AttributeStatementType * __union_AttributeStatementType
int __size_AttributeStatementType
INHERITED FROM saml2__StatementAbstractType:
Definition: saml2.h:727
_XML * saml2__AttributeValue
Array _XML* of size 0..unbounded.
Definition: saml2.h:506
char * Name
Attribute "Name" of type xs:string.
Definition: saml2.h:508
int __sizeAttributeValue
Size of the dynamic array of values of type _XML* is 0..unbounded.
Definition: saml2.h:504
char * saml2__AuthnContextClassRef
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"AuthnContextClassRef.
Definition: saml2.h:444
struct saml2__AuthnContextType * saml2__AuthnContext
Element reference "urn:oasis:names:tc:SAML:2.0:assertion:"AuthnContext.
Definition: saml2.h:660
xsd__dateTime * NotBefore
Attribute "NotBefore" of type xs:dateTime.
Definition: saml2.h:339
xsd__dateTime * NotOnOrAfter
Attribute "NotOnOrAfter" of type xs:dateTime.
Definition: saml2.h:341

This prints several of the assertion's properties, including the conditions under which the assertion is valid. The NotBefore and NotOnOrAfter conditions can be checked against the current time as follows:

time_t now = time(NULL);
... error // not valid yet
... error // expired

wst_soap_wst_request_psha1_token

int soap_wst_request_psha1_token(struct soap *soap, const char *endpoint, int soapver, const char *applyto, const char *username, const char *password, char *psha1, size_t psha1len)
SOAP_FMAC1 int SOAP_FMAC2 soap_wst_request_psha1_token(struct soap *soap, const char *endpoint, int soapver, const char *applyto, const char *username, const char *password, char *psha1, size_t psha1len)
Request PSHA1 token.
Definition: wstapi.c:581

Request P_SHA1 token with endpoint service endpoint URL (send to), soapver SOAP version with 1 = SOAP 1.1, 2 = SOAP 1.2 (SOAP 1.2 is recommended), applyto your service domain, username to authenticate or NULL, password to authenticate or NULL, psha1 is filled with the P_SHA1 result token of psa1len bytes.

Returns SOAP_OK on success.

#include "wsaapi.h"
#include "wstapi.h"
#include "wsseapi.h"
#include "wst.nsmap"
static int ssl_verify(int ok, X509_STORE_CTX *store) { return 1; } // ignore all cert warnings (bad)
...
struct soap *soap = soap_new1(SOAP_XML_INDENT);
int soapver = 2; // SOAP 1.2
const char *to = "https://yourcompany.com/adfs/services/trust/13/UsernameMixed";
const char *applyto = "yourcompany.com";
const char *username = "yourusername";
const char *password = "yourpassword";
char psha1[256];
// register wsa plugin (optional, only if the client requires WS-Addressing rerouted messaging)
soap_register_plugin(soap, soap_wsa);
// register wsse plugin
soap_register_plugin(soap, soap_wsse);
// HTTPS settings
if (soap_ssl_client_context(soap, SOAP_SSL_DEFAULT, NULL, NULL, "cacerts.pem", NULL, NULL))
{
soap_print_fault(soap, stderr);
exit(1);
}
// HTTPS certificate verification callback
soap->fsslverify = ssl_verify;
// PSHA1 token request
if (soap_wst_request_psha1_token(soap, to, soapver, applyto, username, password, psha1, 256))
{
soap_print_fault(soap, stderr);
}
else
{
// use psha1[0..255]
}
soap_destroy(soap);
soap_end(soap);
soap_free(soap);

wst_soap_wst_request_psha256_token

Similar to the previous section, request a P_SHA256 token with:

int soap_wst_request_psha256_token(struct soap *soap, const char *endpoint, int soapver, const char *applyto, const char *username, const char *password, char *psha256, size_t psha256len)

Using the wst Plugin for Servers

To implement a WS-Trust server in C, run soapcpp2 as follows:

soapcpp2 -c -L file.h

where file.h has an #import "wst.h". This generates the soapServer.c and soapC.c code you need to compile with wstapi.c, wsaapi.c, wsseapi.c, smdevp.c, and mecevp.c. Link with libgsoapssl.a (or stdsoap2.c and dom.c). Use -DWITH_OPENSSL and -DWITH_DOM to compile the source code.

For C++, use:

soapcpp2 -L file.h

This generates the soapServer.cpp and soapC.cpp code you need to compile with wstapi.c, wsaapi.c, wsseapi.c, smdevp.c, and mecevp.c. Link with libgsoapssl++.a (or stdsoap2.cpp and dom.cpp). Use -DWITH_OPENSSL and -DWITH_DOM to compile the source code.

If you prefer to use soapcpp2 option -j (or -i) to generate C++ server objects, please run soacpp2 again as follows:

soapcpp2 -j -L file.h
soapcpp2 -CL -pwst import/wst.h

This generates wstClient.cpp, which should be compiled together with the rest of your project code.

You should define the following service operations:

int wstService::RequestSecurityToken(wst__RequestSecurityTokenType *request, wst__RequestSecurityTokenResponseType *response)
{
...
}
int wstService::RequestSecurityTokenCollection(struct wst__RequestSecurityTokenCollectionType *request, struct wst__RequestSecurityTokenResponseCollectionType *response)
{
...
}
"http://docs.oasis-open.org/ws-sx/ws-trust/200512/":RequestSecurityTokenCollectionType is a complexTy...
Definition: wst.h:411
"http://docs.oasis-open.org/ws-sx/ws-trust/200512/":RequestSecurityTokenResponseCollectionType is a c...
Definition: wst.h:431
Imported simpleType "http://docs.oasis-open.org/ws-sx/ws-trust/200512/":RequestTypeOpenEnum from type...
Definition: wst.h:232

If you are combinding WS-Trust with other service operations, then you must also chain the service operations at the server side as follows:

if (soap_begin_serve(service.soap) == SOAP_OK)
if (service.dispatch() == SOAP_NO_METHOD)
soap_serve_request(service.soap);

where the service object is an instance of the application services generated by soapcpp2 -j.