如何从自定义凭据提供程序

时间:2015-08-15 12:11:59

标签: windows authentication visual-c++ change-password credential-providers

我正在做一个自定义包装的凭据提供程序。因为我需要获得新密码'更改密码方案的字段字符串。据我所知,用户从更改密码方案提交后,我的凭证提供程序中的GetSerialization函数被调用,我应该能够获得用户提交的字段的值。但我不确切知道如何得到它。我经历了整个谷歌和堆栈溢出但不能得到我需要的确切。任何帮助将不胜感激。

HRESULT CSampleCredential::GetSerialization(
    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, 
    PWSTR* ppwszOptionalStatusText, 
    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
    )
 {
HRESULT hr = E_UNEXPECTED;


if (_pWrappedCredential != NULL)
{
    hr = _pWrappedCredential->GetSerialization(pcpgsr, pcpcs,         ppwszOptionalStatusText, pcpsiOptionalStatusIcon);
}

logger->log(NORMAL,L"****************GetSerialisation**************\n");

 return hr;
}

我正在获取日志" *******获取序列化数据"每当用户提交登录/解锁表单或更改密码表单时。应该有一些方法,我可以得到字段的值(我对新密码字段感兴趣)。要么应该有一些字段ID(到目前为止我找不到),我可以访问这些值,或者这些值应该存储在我应该访问的某个缓冲区中,并获取值或其他类似的东西。

2 个答案:

答案 0 :(得分:0)

包装的Credential将新密码序列化为CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION结构,准备返回到Winlogon以呈现给LSA。您可以使用CredUnPackAuthenticationBuffer函数反序列化此结构 - 这将显示新密码的内容。

答案 1 :(得分:0)

如果将来对任何人有帮助;这是我的方法。这是我想出的解决方案,其中包含我正在工作的V1(而不是V2)包装的凭据提供程序(CP)中的适当代码段-在64位Windows 7和8.1上进行了测试。 (尽管不能保证它可以在Windows 7和8的所有安装中正常工作)。成功使用VS 2013和VS 2010构建代码。

在更改密码(CTRL-ALT-DEL)方案中,这是确定新密码输入的一种不太常规的方法。但是,由于我的客户希望跟踪并检查新密码的复杂性,因此在用户输入/键入新密码时,它对我来说确实非常有效-但仅在Windows 7和8 / 8.1上有效;而不是Windows 10上-恰恰是实施自定义“更改密码”凭据提供程序的噩梦。

我这样做的方式是: a)检查CredentialProvider.cpp中SetUsageScenario()中的“ cpus”变量是否等于CPUS_CHANGE_PASSWORD,然后将全局布尔标志设置为TRUE。

b),这是关键部分,在函数SetStringValue()中,我使用fieldID(在所有标准Windows 7/8中都相同)跟踪了新密码字段中输入的每个字符。 MS提供的安装和默认CP)-像这样:

CSampleCredential::SetStringValue(
    DWORD dwFieldID,
    PCWSTR pwz
    )
{
    string strCurrentFieldData = ws2s(pwz);// this contains the current data , as typed by the user. SO, as the user keeps typing the password, this field will get longer and longer. Perfect!


    FILE_LOG(logINFO) << "in SetStringValue() FieldID = " << dwFieldID << "   Field value = " << strCurrentFieldData.c_str() ;
eWinVersion ver;
    char szVer[64] = { "" };
    WCHAR wszFullVersion[255] = { L"" };
    bool bSuccess = GetOSVersionString(wszFullVersion, 255, ver, szVer, 64);
    if (bSuccess)
    {
        if (ver == VER_WIN8 || ver == VER_WIN81  )
        {
            switch (dwFieldID)
            {
            case PFID_OLDPWD: csOldPassword = strCurrentFieldData;
                break;

            case PFID_NEWPWD: csNewPassword = strCurrentFieldData;
                break;

            case PFID_NEWPWDCONF: csNewPasswordConfirmation = strCurrentFieldData;
                break;
            default:
                break;
            }
        }else
            if (ver == VER_WIN7)
            {
                switch (dwFieldID)
                {
                case PFID_OLDPWD+1: csOldPassword = strCurrentFieldData;
                    break;

                case PFID_NEWPWD+1: csNewPassword = strCurrentFieldData;
                    break;

                case PFID_NEWPWDCONF+1: csNewPasswordConfirmation = strCurrentFieldData;
                    break;
                default:
                    break;
                }
            }
    }
    }
// and so on...
}

c),最后,在Get CSampleCredential :: Serialization()中,我检查了密码的复杂性,并根据需要返回了正确的CP值-如下:

//
// Collect the username and password into a serialized credential for the correct usage scenario 
// (logon/unlock is what's demonstrated in this sample).  LogonUI then passes these credentials 
// back to the system to log on.
//
HRESULT CSampleCredential::GetSerialization(
    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, 
    PWSTR* ppwszOptionalStatusText, 
    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
    )
{
    FILE_LOG(logINFO) << "In CSampleCredential::GetSerialization";

    HRESULT hr = E_UNEXPECTED;

    if (_pWrappedCredential != NULL)
    {
        hr = _pWrappedCredential->GetSerialization(pcpgsr, pcpcs, ppwszOptionalStatusText, pcpsiOptionalStatusIcon);
        if (g_bIsChangingPassword)
        {
            FILE_LOG(logINFO) << "********** In GetSerialization()..... Scenario = Change Password! ";
            char buf[256] = { "" };
            sprintf_s(buf, 256, "Old password Input = [%s] New password input = [%s]  New pwd confirmation inpot = [%s]",
                csOldPassword.c_str(), csNewPassword.c_str(), csNewPasswordConfirmation.c_str());
            FILE_LOG(logINFO) << buf;

            //******************************************
            // ************ IMPORTANT*****
            // If new password input by user doens't fulfil our complexity requirements, we don't allow password chnge to compelte, by CP
            if (!IsPasswordStrong(csNewPassword))
            {
                HWND hwndOwner = nullptr;
                _pCredProvCredentialEvents->OnCreatingWindow(&hwndOwner);

                *pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
                ::MessageBox(hwndOwner, 
"The new password you have chosen is not secure enough.\n\rPlease try a more complex password that is:\n\ra) At least 8 characters long\r\nb)contains Upper case AND lower letters\n\rc)and numbers", 
"Insufficient Password Strength", 0);
            }
            //******************************************
        }
    }
    return hr;
}

这是为了帮助可能需要帮助的任何人在WRAPPED自定义凭据提供程序中跟踪新密码字段。