This document describes how to integrate custom credential providers with a Citrix XenApp or XenDesktop VDA. Credential providers can be used for customized logon options on a Microsoft Windows computer. For example, a deployment could require that a user enter a security PIN number in addition to the standard username and password combination when logging in
In general, Citrix XenApp and XenDesktop move user authentication stages to StoreFront, and users log into the actual Windows VDA automatically. The StoreFront authentication process itself can be customised using the AuthSDK, but that is outside the scope of this document. This document will concentrate on the customisation options available on the Windows VDA itself.
The XenDesktop single sign-on method is different for single-session Workstation and multi-session server versions of Windows.
On workstation editions of Windows (e.g., Windows 10), two credential providers are installed, one for username with password and one for smartcard with PIN:
PicaSSOnCredProv {5B340FA8-5C3F-45de-87C8-487ABE91013E}
Usually these credential providers are dormant, reporting no available credentials and showing no graphical user interface.
When the Citrix Desktop Service determines that single sign-on should occur, it will pass the logon information to the appropriate provider which will signal to the OS that logon should occur. Windows responds by initiating the usual logon process as if a user had entered credentials and clicked “OK”.
On server editions of Windows (e.g., Windows 2012 R2), authentication is initiated by the Microsoft RDP credential provider containing the opaque logon ticket sent by the HDX client.
An ICredentialsProviderFilter is registered (CtxWinlogonProv.dll) that implements the UpdateRemoteCredential() method. When an HDX connection occurs, this API is used to set the logon credentials (password, smart card, etc.) based on the logon ticket supplied.
In XenDesktop 7.8, Citrix introduced a separate COM-based single sign-on integration system called the HdxCredentialSelector SDK. This is a single API that integrates with both workstation and server editions of Windows. Classes registered with this SDK are invoked as part of the Citrix logon process.
A credential provider is a COM object implementing the ICredentialProvider interface. Refer to the Microsoft documentation of this API on MSDN.
When Windows needs to perform a logon, registered ICredentialProviders are instantiated and queried using::GetCredentialXXX() methods. The CredentialProvider can return a number of ICredentialProviderCredential COM objects that are displayed as tiles on the logon page.
An example credential provider is included in the ZIP file associated with this document. It implements a standard username/password prompt, adding an additional “Security PIN” field.
Credential providers are used in four basic modes:
Initial Logon [CPUS_LOGON]
Desktop unlock [CPUS_UNLOCK_WORKSTATION]
Change password [CPUS_CHANGE_PASSWORD.]
In-session credential prompts [CPUS_CREDUI]
This document concentrates on the initial logon and unlock scenarios, as the others modes are not affected by the HDX infrastructure in general.
Once built into a COM DLL, credential providers are registered with the following Microsoft registry key:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\
The Citrix logon system detects that a new provider has been registered here and automatically allows users to access the logon screen when HDX is launched if Citrix single sign-on is disabled.
When the user enters all the information required by a ICredentialProviderCredential and clicks “Submit”, the custom credential provider is called using the ::GetSerialization() method and must return a CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION structure which is sent to a registered AuthenticationPackage in the LSA.
In complex environments, the entire logon process can be customised at this stage, but in general it is easiest to reuse the existing LSA providers, passing KERB_INTERACTIVE_UNLOCK_LOGON (password logon) or KERB_SMART_CARD_UNLOCK_LOGON (X509 certificate logon) structures.
By default, users are prevented from interacting with the logon page when connecting via HDX. Installing a third-party credential provider automatically disables this functionality. Note however that it is not possible to logon with a different user account than the one that the Delivery Controller expects. Any attempt to do this results in a dropped HDX connection.
In some cases it may be useful to integrate with the Citrix single sign-on system. To do this, it is possible to register COM objects that implement the IHdxCredentialSelector interface by adding a REG_SZ value in:
HKLM\SOFTWARE\Citrix\Citrix Virtual Desktop Agent\HdxCredentialSelectorPlugins
Name: <CredentialType> Type of credentials to handle (e.g. “Password”)
Value: {<CLSID GUID>} ClassID of class implementing IHdxCredentialSelector
The “CredentialType” is a label applied to the username/password data by StoreFront. By default the CredentialType label is just “Password”; the VDA automatically interprets this as an Active Directory username/password if a plugin is not registered for it.
If StoreFront is modified to provide alternative CredentialType strings, a different HdxCredentialSelectorPlugin can be registered by name and invoked at the request of StoreFront. If the plugin is not registered, the launch fails before the HDX connection is initiated.
Note that it is not possible to intercept logons if Citrix Receiver is explicitly configured to log on with a smart card. It is possible, however, for an IHdxCredentialSelector plugin to request that a smart card logon be performed if the Receiver allows smart card access.
By default StoreFront specifies the CredentialType as “Password”, and supplies the clear-text Active Directory password as the credentials. By using the programmatic SDK, it is possible to specify different CredentialTypes at StoreFront to effectively select a particular HdxCredentialSelector plugin on the VDA.
If this is done, the Password field effectively becomes an opaque piece of data that the HdxCredentialSelector can interpret (however necessary).
The “CitrixIdentityAssertion” CredentialType references a Citrix provided plugin that centralises the authentication process at a server running the “Federated Authentication Service”. The StoreFront Authentication SDK can also be used to control this process, which may avoid the need to run custom code on the XenDesktop VDAs – the equivalent logic can simply be placed in StoreFront or NetScaler and evaluated before an HDX connection is initiated.
A plugin is invoked whenever an HDX logon is initiated with a CredentialType referenced in the HdxCredentialSelectorPlugins key.
The Initialize API will be called first, providing all the logon data provided by StoreFront.
/**************************************************************************
* Initialize
*
* The class is being initialized with the credentials passed to the Storefront SDK.
*
* It is important to validate the credentialData correctly as it is the equivalent
* of the user's password and will indicate that the caller is authorized to use this
* class' functionality. If the credentialData is incorrect, this method should
* throw an exception.
*
* The credentialUsageScenario describes the type of authentication (logon/unlock),
* its values are taken from the Microsoft CREDENTIAL_PROVIDER_USAGE_SCENARIO
* enumeration.
*
* If this call returns an error, the logon will fail.
*
* Parameters:
* Username: User name set by Storefront
* Domain: Domain name set by Storefront
* CredentialData: Secret set by Storefront (e.g. password)
* CredentialUsageScenario: Type of logon (logon/unlock)
*************************************************************************/
HRESULT __stdcall Initialize(
/*[in]*/ BSTR Username,
/*[in]*/ BSTR Domain,
/*[in]*/ BSTR CredentialData,
/*[in]*/ int CredentialUsageScenario);
Next the QueryLogonMethod API is called. On return, set the LogonModes variable to HdxLogonMethod.CustomLogon.
/**************************************************************************
* QueryLogonMethod
*
* This is the first method called on this class after initialization. On
* calling, the methods value is an or'ed list of logon mechanisms that the
* Citrix Signon service supports.
*
* This should be replaced with the (single) mechanism that this class wishes
* to use. Two special values are provided:
* HdxLogonMethod.AccessDenied - this user is not allowed to log in
* HdxLogonMethod.DefaultLogon - use the standard logon behaviour
*
* Other values will cause further methods on this class to be called.
*
* Parameters:
* LogonModes: Bitfield of supported and selected Logon
*************************************************************************/
HRESULT __stdcall QueryLogonMethod(
/*[in,out]*/ HdxLogonMethod * LogonModes);
Finally the GetRawCredentialSerialization API is called. This should return a SAFEARRAY for inclusion in a CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION structure.
/**************************************************************************
* GetRawCredentialSerialization
*
* This API is called when QueryLogonMethod specifies HdxLogonMethod.CustomLogon.
*
* The returned Array will be placed in the cbSerialization byte array of
* CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION.
*
* Parameters:
* CredentialGetSerializationResponse: Raw Credential Serialization
*************************************************************************/
HRESULT __stdcall GetRawCredentialSerialization(
/*[out]*/ SAFEARRAY ** CredentialGetSerializationResponse);
Other methods will not be called and should return E_NOTIMPL error codes.
A Windows computer can potentially have a number of different credential providers installed. The OS provides features that control which credential providers are activated and are available to users who log in.
Before initiating loading and displaying the credential providers, the operating system calls the registered ICredentialProviderFilters’ Filter(<List of GUIDs>) methods. Each filter is allowed to “veto” the use of a particular credential provider. If a filter vetos a credential provider, it will not be available for logon.
Windows allows credential providers to be disabled using registry keys. Identify the Credential Provider GUID to disable in:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\<GUID>
…and add a REG_DWORD value to disable it.
Disabled = 1
Similar functionality is available in Group Policy Computer Configuration > Administrative Templates > System > Logon
Enable the policy and include the GUIDs of the credential providers to disable.
The final option is to simply remove the entire credential provider registration from the HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\<GUID>
Registry Key. This option should be used with some care, but does work for disabling the Citrix credential providers.
If a credential provider class has been filtered out or disabled, it may still be possible to instantiate it as a standard COM object using CoCreateObjectEx(<GUID>). This approach is somewhat complicated to implement, and should only be used if absolutely necessary.
If a credential provider is wrapped in this way, it is possible to register and wait for the ICredentialProviderCredentialEvents::CredentialChanged() callback. The standard ICredentialProvider::GetSerialization() call can then be used to retrieve the CREDENTIAL_SERIALIZATION blob.
If this process is used with the Citrix single-sign on credential providers, it is possible to detect the single sign-on process occurring and to access the single sign-on a password or PIN.
In general, however, it is simpler to use the IHdxCredentialSelector COM object to integrate with the single sign-on process.
Credential providers: https://msdn.microsoft.com/en-us/library/windows/desktop/mt158211(v=vs.85).aspx
Credential provider filter: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776003(v=vs.85).aspx
KERB_CERTIFICATE_UNLOCK_LOGON: https://msdn.microsoft.com/en-us/library/windows/desktop/bb545681(v=vs.85).aspx