当前位置: 首页 > 知识库问答 >
问题:

与自定义凭据提供程序的远程桌面连接

谈渊
2023-03-14

我已经使用VistacRedentialProviderSamples中的SampleWrapExistingCredentialProvider开发了一个自定义凭据提供程序。凭据提供程序实现了一个筛选器,用于筛选所有其他凭据提供程序,而我在登录时只看到我的凭据提供程序。问题是,如果我们使用远程桌面连接连接到它,用户名/密码不会从windows RDP客户端传递给凭据提供程序,当RDP会话打开时,我必须再次输入它(与默认提供程序的行为不同)

我已经为Credui返回了S_OK。我的SetUsageScenario如下:

HRESULT CSampleProvider::SetUsageScenario(
CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
DWORD dwFlags
)
{
    HRESULT hr;

// Create the password credential provider and query its interface for an
// ICredentialProvider we can use. Once it's up and running, ask it about the 
// usage scenario being provided.
IUnknown *pUnknown = NULL;
hr = ::CoCreateInstance(CLSID_PasswordCredentialProvider, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pUnknown));
if (SUCCEEDED(hr))
{
    hr = pUnknown->QueryInterface(IID_PPV_ARGS(&(_pWrappedProvider)));
    if (SUCCEEDED(hr))
    {
        hr = _pWrappedProvider->SetUsageScenario(cpus, dwFlags);
        switch (cpus)
        {
        case CPUS_LOGON:
        case CPUS_UNLOCK_WORKSTATION:
        case CPUS_CREDUI:
        {
            hr = S_OK;
            break;
        }
        case CPUS_CHANGE_PASSWORD:
        default:
            hr = E_INVALIDARG;
            break;
        }
    }
}
if (FAILED(hr))
{
    if (_pWrappedProvider != NULL)
    {
        _pWrappedProvider->Release();
        _pWrappedProvider = NULL;
    }
}

return hr;
}

共有1个答案

公孙弘图
2023-03-14

用户名/密码不会从windows RDP客户端传递给凭据提供程序,当RDP会话打开时,我必须再次输入它(与默认提供程序的行为不同)

通过RDP连接的客户端用户名/密码,windows无法通过某种魔术知道。

在客户端开始时,某个凭据提供程序必须创建credential_provider_credential_serialization并将其传递给服务器。在其内部clsidcredentialprovider说明哪个具体的提供程序收集这个序列化。

updateRemoteCredential方法中,如果声明为常量,则不能修改pcpcsIn。所以我们需要将我们的更新证书写入pcpcsout。因为系统无法知道RGBSerialization需要多少大小-我们需要自己分配。然后系统释放它。显然需要使用COTASKMEMALLOC来分配RGBSerialization

所以--所有这些都可以被理解,而不需要任何文档。然而,如果所有这些都被记录下来--也不会太糟。

因此UpdateRemoteCredential代码

HRESULT STDMETHODCALLTYPE CSampleProvider::UpdateRemoteCredential( 
    /* [annotation][in] */ 
    _In_  const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpcsIn,
    /* [annotation][out] */ 
    _Out_  CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpcsOut)
{

    if (pcpcsIn->clsidCredentialProvider != __uuidof(PasswordCredentialProvider) && 
        pcpcsIn->clsidCredentialProvider != __uuidof(V1PasswordCredentialProvider))
    {
        // we dont know format of serialization
        return E_UNEXPECTED;
    }

    ULONG cbSerialization = pcpcsIn->cbSerialization;

    if (pcpcsOut->rgbSerialization = (PBYTE)CoTaskMemAlloc(cbSerialization + sizeof(GUID)))
    {
        memcpy(pcpcsOut->rgbSerialization, pcpcsIn->rgbSerialization, cbSerialization);
        memcpy(pcpcsOut->rgbSerialization + cbSerialization, &pcpcsIn->clsidCredentialProvider, sizeof(GUID));

        pcpcsOut->cbSerialization = cbSerialization + sizeof(GUID);
        pcpcsOut->ulAuthenticationPackage = pcpcsIn->ulAuthenticationPackage;
        pcpcsOut->clsidCredentialProvider = __uuidof(CSampleProvider);

        return S_OK;
    }

    return E_OUTOFMEMORY;
}
HRESULT STDMETHODCALLTYPE CSampleProvider::SetSerialization(
    __in const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs
    )
{   
    if (pcpcs->clsidCredentialProvider == __uuidof(CSampleProvider))
    {
        // can not query WTSIsRemoteSession, small optimization
        _IsRemoteSession = true;

        // we got this via ICredentialProviderFilter::UpdateRemoteCredential
        ULONG cbSerialization = pcpcs->cbSerialization;

        if (cbSerialization >= sizeof(GUID))
        {
            // restore original clsidCredentialProvider
            cbSerialization -= sizeof(GUID);
            memcpy(const_cast<GUID*>(&pcpcs->clsidCredentialProvider), pcpcs->rgbSerialization + cbSerialization, sizeof(GUID));
            const_cast<CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION*>(pcpcs)->cbSerialization = cbSerialization;
        }
    }

    return _pWrappedProvider->SetSerialization(pcpcs);
}
HRESULT STDMETHODCALLTYPE CSampleProvider::GetCredentialCount(
    __out DWORD* pdwCount,
    __out_range(<,*pdwCount) DWORD* pdwDefault,
    __out BOOL* pbAutoLogonWithDefault
    )
{
    HRESULT hr = _pWrappedProvider->GetCredentialCount(pdwCount, pdwDefault, pbAutoLogonWithDefault);

    *pbAutoLogonWithDefault = FALSE;//!!!

    return hr;
}

注意非常重要的*PBAAutologonWithDefault=false;//!!!

 类似资料:
  • 因此,我开发了一个定制的身份验证提供商,(为了大大简化事情),它将当前用户的密码替换为他们不知道的、完全随机的密码。在身份验证过程中,使用一些wizzy加密,重新生成密码并通过Kerberos身份验证过程传递,以替换他们可能输入的任何密码(忽略)。我不能太详细地介绍它是如何工作的,但不管怎样,它确实在本地工作。我们的想法是在运行Windows Server 2012的云端机器上使用它,但我遇到了一

  • 这里怎么了?是否可以使用这样的PowerShell脚本? 我可以通过HTML页面调用此脚本吗(因为我将在网页上放置许多其他资源,这些资源将作为开发人员的一个链接,这样我们就不会在每次需要它们时浪费时间和精力去查找它们)?是否可以将应用程序注册到URI方案? 还有其他(标准)方法吗?

  • 我的Windows 10桌面上有两个远程桌面客户端应用程序。我想执行我的。带有Windows 10远程桌面APP的RDP文件。 这是带有红色边框的应用程序。 当我启动te. rdp文件时,它会提示我一个用户名和密码。但是没有保存它的选项。 提示用户名和密码 通常我打开。rdp文件和另一个远程桌面程序(并没有红色边框的那个)一起使用,它会提示我保存凭证一次。 在此处输入图像描述 是否可以使用te r

  • 我试图从Websphere Application Server连接到外部JMS提供者。我们可以不使用Websphere MQ从Websphere Application Server连接到远程JMS提供者吗?

  • 在我的firebase应用程序中,用户可以使用 Google(Firebase的联邦提供商)或 Slack(作为自定义身份验证提供程序实现) 我想给用户链接两个帐户的机会。所以我要开的案子是: 用户使用Google登录 用户转到“设置”并单击“使用松弛连接” 然后应该链接用户帐户,以便他下次可以使用Slack或Google登录 我现在想知道,我是否可以通过某种方式从我的自定义松弛身份验证获得一个A

  • 我将为我的网站创建自定义用户提供程序,对于用户来说,没有“用户名”和“密码”这样的概念(实际上有类似于密码的东西,但它的名称不同)。在文档中,用户实体必须实现来自安全包的UserInterface,该安全包具有诸如getUsername、getPassword之类的方法。我能用我自己的领域吗?或者我应该使用名称冲突(例如,getUsername将返回我的唯一字段)来实现我的行为吗?