Credential provider not displayed for all users (Other user included)

牧云@^-^@ 提交于 2020-05-28 04:57:27

问题


I am trying to show credential provider for all local and for other user(Domain users) in signing options but I am not able to. I developed this credential provider taking reference from here. I made following changes in _EnumerateCredentials and GetCredentialCount functions of CSampleprovider.cpp file.

GetCredentialCount()

HRESULT GetCredentialCount([out] DWORD* pdwCount,
                           [out] DWORD* pdwDefault,
                           [out] BOOL* pbAutoLogonWithDefault)
{
    *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
    *pbAutoLogonWithDefault = FALSE;

    if (_fRecreateEnumeratedCredentials)
    {
        _fRecreateEnumeratedCredentials = false;
        _ReleaseEnumeratedCredentials();
        _CreateEnumeratedCredentials();
    }
    DWORD dwUserCount;
    HRESULT hr;

    if (_pCredProviderUserArray != nullptr) {
        hr = _pCredProviderUserArray->GetCount(&dwUserCount);
    }

    if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
        dwUserCount += 1;//display additional empty tile
    }
    *pdwCount = dwUserCount;
    return S_OK;
}

_EnumerateCredentials()

HRESULT CSampleProvider::_EnumerateCredentials()
{
    HRESULT hr = E_UNEXPECTED;


    DWORD dwUserCount;
    if (_pCredProviderUserArray != nullptr)
    {
        //DWORD dwUserCount = 0;
        _pCredProviderUserArray->GetCount(&dwUserCount);
        if (dwUserCount > 0)
        {
            //_pCredential = new CSampleCredential*[dwUserCount];
            for (DWORD i = 0; i < dwUserCount; i++) {
                ICredentialProviderUser* pCredUser;
                hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
                if (SUCCEEDED(hr))
                {
                    //_pCredential[i] = new(std::nothrow) CSampleCredential();
                    _pCredential.push_back(new(std::nothrow) CSampleCredential());
                    if (_pCredential[i] != nullptr)
                    {
                        //logfile << "new CSampleCredential()\n";

                        hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);

                        if (FAILED(hr))
                        {
                            _pCredential[i]->Release();
                            _pCredential[i] = nullptr;

                        }
                    }
                    else
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    pCredUser->Release();
                }
            }
        }
        //if you are in a domain or have no users on the list you have to show "Other user tile"
        if (DEVELOPING) PrintLn(L"IsOS(OS_DOMAINMEMBER): %d", IsOS(OS_DOMAINMEMBER));
        if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
            if (DEVELOPING) PrintLn(L"Adding empty user tile");
            _pCredential.push_back(new(std::nothrow) CSampleCredential());
            if (_pCredential[_pCredential.size() - 1] != nullptr) {
                hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
            }
            else {
                if (DEVELOPING) PrintLn(L"Error adding user: %d", _pCredential.size());
            }
        }

        return hr;
    }
}

And I have changed a private header of type CSampleCredential to

std::vector<CSampleCredential> _pCredentialVector; 
// SampleV2CredentialCSampleProvider.h

in CSampleProvider.h file.

When I tested this Credential provider of mine it is working fine i.e it is displaying for all local users in sign in options when no domain is added (No other user) but when domain is added(other user enabled) then I am being stuck at the welcome wallpaper and screen keeps on flickering.

So, How do I display my Credential provider for all local and domain users (Other user) in sign in options and over come that flickering of screen. I am new to this VC++ please help me out.


回答1:


While I was trying to enable the custom credential provider to all the tiles including the other user tile I made few changes in GetCredentialCount() method and _EnumerateCredentials() method in SampleProvider.cpp file in Credential provider Sample given by Microsoft. The changes I made are:

HRESULT CServiceProvider::GetCredentialCount(
_Out_ DWORD *pdwCount,
_Out_ DWORD *pdwDefault,
_Out_ BOOL *pbAutoLogonWithDefault){

*pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
*pbAutoLogonWithDefault = FALSE;

if (_fRecreateEnumeratedCredentials)
{
    _fRecreateEnumeratedCredentials = false;
    _ReleaseEnumeratedCredentials();
    _CreateEnumeratedCredentials();
}
DWORD dwUserCount;
HRESULT hr;

if (_pCredProviderUserArray != nullptr) {
    hr = _pCredProviderUserArray->GetCount(&dwUserCount);
}

if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
    dwUserCount += 1;//display additional empty tile
}
*pdwCount = dwUserCount;
return S_OK;}



HRESULT CServiceProvider::_EnumerateCredentials(){
HRESULT hr = E_UNEXPECTED;
DWORD dwUserCount;
if (_pCredProviderUserArray != nullptr)
{
    _pCredProviderUserArray->GetCount(&dwUserCount);
    if (dwUserCount > 0)
    {   
        //You need to initialize all the fields in LogonUI for each and every user 
        for (DWORD i = 0; i < dwUserCount; i++) {
            ICredentialProviderUser* pCredUser;
            hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
            if (SUCCEEDED(hr))
            {
                _pCredential.push_back(new(std::nothrow) CUserCredential());
                if (_pCredential[i] != nullptr)
                {
                    hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);

                    if (FAILED(hr))
                    {
                        _pCredential[i]->Release();
                        _pCredential[i] = nullptr;
                    }
                }
                else
                {
                    hr = E_OUTOFMEMORY;
                }
                pCredUser->Release();
            }
        }
    }
    //if you are in a domain or have no users on the list you have to show "Other user tile"
    if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
        _pCredential.push_back(new(std::nothrow) CUserCredential());
        if (_pCredential[_pCredential.size() - 1] != nullptr) {
            hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
        }
    }
    return hr;
}
return hr;

}

Now as you see we are sending nullptr as one of the argument while calling Initialize() method after checking if system is connected to domain, we need to handle that nullptr in Initialize() method by checking with if condition in SampleCredential.cpp file.

HRESULT CUserCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
_In_ CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR const* rgcpfd,
_In_ FIELD_STATE_PAIR const* rgfsp,
_In_ ICredentialProviderUser* pcpUser){
HRESULT hr = S_OK;
_cpus = cpus;
_nNextScreenID = e_ARSNone;

GUID guidProvider;
LPOLESTR clsid;

if (pcpUser != nullptr) {
    pcpUser->GetProviderID(&guidProvider);
    StringFromCLSID(guidProvider, &clsid);
    CoTaskMemFree(clsid);
    _fIsLocalUser = (guidProvider == Identity_LocalUserProvider);
}
else {
    _fIsLocalUser = true;//CP V1 or Domain
}

// Copy the field descriptors for each field. This is useful if you want to vary the field
// descriptors based on what Usage scenario the credential was created for.
for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(_rgCredProvFieldDescriptors); i++)
{
    _rgFieldStatePairs[i] = rgfsp[i];
    hr = FieldDescriptorCopy(rgcpfd[i], &_rgCredProvFieldDescriptors[i]);
}

// Initialize the String value of all the fields.
if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"SomeLable1", &_rgFieldStrings[SFI_LABEL]);
}

if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"SomeLable2", &_rgFieldStrings[SFI_LARGE_TEXT]);
}


if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"", &_rgFieldStrings[SFI_PASSWORD]);
}

if (SUCCEEDED(hr))
{
    hr = SHStrDupW(L"Somelabel4", &_rgFieldStrings[SFI_SUBMIT_BUTTON]);
}


hr = S_OK;
if (SUCCEEDED(hr))
{
    if (pcpUser != nullptr) {
        hr = pcpUser->GetStringValue(PKEY_Identity_QualifiedUserName, &_pszQualifiedUserName);//get username from the LogonUI user object
        PWSTR pszUserName1;
        pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName1);
        if (_fIsLocalUser) {
            PWSTR pszUserName;
            pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName);
            if (pszUserName != nullptr)
            {
                wchar_t szString[256];
                StringCchPrintf(szString, ARRAYSIZE(szString), L"User Name: %s", pszUserName);
                if (DEVELOPING) PrintLn(szString);
                hr = SHStrDupW(pszUserName, &_rgFieldStrings[SFI_LARGE_TEXT]);
                CoTaskMemFree(pszUserName);
            }
            else
            {
                hr = SHStrDupW(L"User Name is NULL", &_rgFieldStrings[SFI_LARGE_TEXT]);
            }
        }
        else {
            if (DEVELOPING) PrintLn(L"Domain user, skip SFI_LARGE_TEXT");
        }
    }
    else {
        PWSTR connectedDomainName = getNetworkName();
        wchar_t szString[256];
        StringCchPrintf(szString, ARRAYSIZE(szString), L"Sign in to: %s", connectedDomainName);
        hr = SHStrDupW(szString, &_rgFieldStrings[SFI_DOMAIN_NAME_TEXT]);

        if (DEVELOPING) PrintLn("Unknown user -> display LoginName");
        hr = SHStrDupW(L"", &_pszQualifiedUserName);
        _fUserNameVisible = true;
        _rgFieldStatePairs[SFI_LOGIN_NAME].cpfs = CPFS_DISPLAY_IN_SELECTED_TILE;//unhide login name
        //switch focus to login
        _rgFieldStatePairs[SFI_LOGIN_NAME].cpfis = CPFIS_FOCUSED;
        _rgFieldStatePairs[SFI_PASSWORD].cpfis = CPFIS_NONE;
        //Don't panic!!!
    }
}
if (pcpUser != nullptr)
{
    hr = pcpUser->GetSid(&_pszUserSid);
}
return hr;}

Using above code you can solve flickering (which is crashing of CP) as well as enable Credential provider for all user tiles.



来源:https://stackoverflow.com/questions/55967533/credential-provider-not-displayed-for-all-users-other-user-included

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!