Creating a Client in C++ Using WWSAPI
This section explains how to create a WWSAPI web service client for the AAA Server 6.8 SKI Connector service.
Generate the Web Service Client Files
Use the following command line to run wsutil.exe and generate the required web service client files:
-
A header with the necessary structures and declarations.
-
A .c file with the definitions of the client functions.
Wsutil.exe <wsdl_path>\ActivCardSKIConnectorV2.wsdl /out:<output_path>
Where:
-
<output_path> points to the folder where the generated files are to be stored.
-
<wsdl_path> points to the folder of the .wsdl file.
Configure the Web Service Client
-
Include the following files in the project:
- WebServices.h header
- WebServices.lib library
- The generated .c and .h
Change the .c file extension to .cpp.
Deactivate the precompiled headers for this file.
-
Create the following elements in the given order:
- WS_ERROR* error with WsCreateError()
- WS_HEAP* heap with WsCreateHeap()
- WS_SERVICE_PROXY* proxy with WsCreateServiceProxy()
-
Open the web service proxy with the function WsOpenServiceProxy().
For further information about the web service configuration, refer to Microsoft WWSAPI function documentation.
-
Configure the service endpoint URI as a WS_STRING and register it in a WS_ENDPOINT_ADDRESS.
This WS_ENDPOINT_ADDRESS is used as a parameter when opening the web service proxy with the WsOpenServiceProxy() function.
For AAA Server 6.8, the service endpoint URL must be as follows:
http://<hostname>:<port>/ws/ActivCardSKIConnectorV2
-
To test the client configuration and connection, it is recommended that you use a simple function such as getVersion().
If getVersion() returns nothing or indicates an error, the endpoint URL might be wrong or using an invalid format.
Use the ActivID SKI Connector Functions
-
To use the ActivID SKI Connector functions, call the corresponding methods of the client with the required variables.
For further information about the method names and input/output variables, see ActivID SKI Connector Service API Functions.
-
Name the methods using the following format:
ActivCardSKIConnectorV2Soap_<function_name>
-
In addition to the output and input variables, pass the created WS_ERROR, WS_HEAP and WS_SERVICE_PROXY elements to the function as arguments.
-
As most functions can only be used with a valid login handle, retrieve it using the ActivCardSKIConnectorV2Soap_Login function before performing any other operation.
-
Instantiate and fill a single structure parameter for the inputs.
These structures are declared in the generated header file and should be named _<function_name>In.
-
If the function has an output value, pass a reference or pointer to a relevant variable to retrieve it.
If the returned value is a structure, it should be one that is defined in the generated header file.
Close the Service
-
Before closing the service, it is recommended that you use the Logout() function to invalidate the login handle.
If you do not, it is only invalidated after a defined time (10 minutes).
-
Use WsCloseServiceProxy() to close the web service proxy.
-
Free the allocated WS_ERROR, WS_HEAP and WS_SERVICE_PROXY with WsFreeError(), WsFreeHeap() and WsFreeServiceProxy() respectively.
Configure the Sample for SSL
This section explains how to configure the sample for SSL if the ActivID SKI Connector is using a secured connection.
To use SSL with the ActivID SKI Connector, you must import a client certificate into the certificate store of the local machine.
During the AAA Server setup, you can generate two certificates used for the AAA SKI Connector service (SKIConnector.p12) and client (WHD.p12). These certificates are generated in the AAA Server <installdir>\Certificates directory.
Modify the endpoint URL to use HTTPS instead of HTTP.
-
In the sample, create the following elements:
- WS_SSL_TRANSPORT_SECURITY_BINDING to define the binding.
- One of the following certificate credentials:
- WS_THUMBPRINT_CERT_CREDENTIAL to use the certificate thumbprint.
- WS_SUBJECT_NAME_CERT_CREDENTIAL to use the certificate name.
- WS_CUSTOM_CERT_CREDENTIAL to use a custom method.
- WS_SECURITY_BINDING attached to the SSL binding and containing the security binding properties.
- WS_SECURITY_DESCRIPTION to be passed to the created proxy and containing the SSL binding.
-
Add additional WS_SECURITY_BINDING_PROPERTY elements to configure the binding.
In the example below, the WS_CERT_FAILURE_CN_MISMATCH security property of WS_SECURITY_BINDING_PROPERTY_CERT_FAILURES_TO_IGNORE is used to verify compatibility with the ActivID SKI Connector certificates generated by the AAA Server setup.
-
Create the proxy using WS_SECURITY_DESCRIPTION as an argument of the WsCreateServiceProxy() function (see Configure the Web Service Client).
For example:
// SSL binding
WS_SSL_TRANSPORT_SECURITY_BINDING sslBinding = {}; // SSL binding
sslBinding.binding.bindingType = WS_SSL_TRANSPORT_SECURITY_BINDING_TYPE;
// Certificate credentials
WS_THUMBPRINT_CERT_CREDENTIAL thumbprint_cert_credential = {};
thumbprint_cert_credential.credential.credentialType = WS_THUMBPRINT_CERT_CREDENTIAL_TYPE;
thumbprint_cert_credential.storeLocation = CERT_SYSTEM_STORE_LOCAL_MACHINE;
thumbprint_cert_credential.storeName = WS_STRING_VALUE(L"MY"); //Personal store
thumbprint_cert_credential.thumbprint = WS_STRING_VALUE(L"<certificate_thumbprint>");
sslBinding.localCertCredential = &thumbprint_cert_credential.credential;
// Security properties
ULONG failuresIgnored = 0;
WS_SECURITY_BINDING_PROPERTY securityProperty = {};
WS_SECURITY_BINDING_PROPERTY* securityProperties[1] = { &securityProperty };
// Array of all security bindings
WS_SECURITY_BINDING* securityBindings[1] = { &sslBinding.binding };
failuresIgnored = WS_CERT_FAILURE_CN_MISMATCH; // discarding CN mismatch
securityProperty = { WS_SECURITY_BINDING_PROPERTY_CERT_FAILURES_TO_IGNORE, (void*)&failuresIgnored, sizeof(ULONG) };
sslBinding.binding.properties = securityProperties[0];
sslBinding.binding.propertyCount = WsCountOf(securityProperties);
WS_SECURITY_DESCRIPTION securityDescription = {}; // zero out the struct securityDescription.securityBindings = securityBindings;
securityDescription.securityBindingCount = WsCountOf(securityBindings);
[…]
hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST,
WS_HTTP_CHANNEL_BINDING,
&securityDescription,
NULL,
0,
NULL,
0,
&proxy,
error);
Error Cases
With the WWSAPI, all client function calls return an HRESULT indicating if the web service call performed correctly.
In addition, most functions have a returned value (often a boolean) indicating if the operation was successful.
Implementation Example
int nTimeout = 10 * 60 * 1000; /* setting a 10 minutes timeout */
HRESULT hRes = S_FALSE;
long long hLogin = -1;
loginInParameters.LoginInUid = SysAllocString("<admin_uid>");
loginInParameters.LoginInPwd = SysAllocString("<admin_pwd>");
loginInParameters.LoginInTimeout = nTimeout;
hRes = ActivCardSKIConnectorV2Soap_Login(proxy,
&loginInParameters,
&hLogin,
heap,
NULL,
0,
NULL, error);
SysFreeString(loginInParameters.LoginInUid);
SysFreeString(loginInParameters.LoginInPwd);
if (SUCCEEDED(hRes))
{
if (hLogin>0) cout << "Login succeeded."<< endl;
else
{
cout << "ERROR: invalid credentials." << endl;
// Handle error case
}
}
else
{
cout << "ERROR: Login webservice call failed" << endl;
// Handle error case
}