赞
踩
I've implemented a Credential Provider based on the MS samples, and I would
like it to filter out the default MS password provider. To keep things
simple, I decided to implement the ICredentialProviderFilter interface on my
main Credential Provider class (which works fine). To do that, I updated the
class to implement ICredentialProviderFilter, implemented the Filter and
UpdateRemoteCredential methods, and registered the assembly in the registry
as a Credential Provider filter.
Unfortunately, something isn't working. As far as I can tell the Filter
method is never getting called, and I'm wondering what I've missed. I've
included the relevant sections of code (and registry entries):
--CLMSProvider.h--
class CLMSProvider : public ICredentialProvider, public
ICredentialProviderFilter
{
//***SNIP***
public:
//***SNIP: ICredentialProvider methods ***
IFACEMETHODIMP Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD
dwFlags, GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders);
IFACEMETHODIMP UpdateRemoteCredential(const
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsIn,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsOut);
//***SNIP***
--CLMSProvider.cpp--
//***SNIP***
//Function to filter out other credential providers
HRESULT CLMSProvider::Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD
dwFlags, GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders)
{
//DEBUG
MessageBox(NULL, "Filter!", "Trace", NULL);
switch (cpus)
{
case CPUS_LOGON:
case CPUS_UNLOCK_WORKSTATION:
//Filters out the default Windows provider (only for Logon and
Unlock scenarios)
//TODO: This isn't working
for (int i = 0; i < cProviders; i++)
{
if (IsEqualGUID(rgclsidProviders[i], CLSID_PasswordCredentialProvider))
rgbAllow[i] = FALSE;
}
return S_OK;
case CPUS_CREDUI:
case CPUS_CHANGE_PASSWORD:
return E_NOTIMPL;
default:
return E_INVALIDARG;
}
--Register.reg--
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{3E340420-5103-11DC-99F1-DB9156D89593}]
@="LMSCredentialProvider"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters\{3E340420-5103-11DC-99F1-DB9156D89593}]
@="LMSCredentialProvider"
[HKEY_CLASSES_ROOT\CLSID\{3E340420-5103-11DC-99F1-DB9156D89593}]
@="LMSCredentialProvider"
[HKEY_CLASSES_ROOT\CLSID\{3E340420-5103-11DC-99F1-DB9156D89593}\InprocServer32]
@="LMSCredentialProvider.dll"
"ThreadingModel"="Apartment"
-------------------
So, what did I miss? Any help would be appreciated. Thanks!
You shouldn't need to manually instantiate the filter. You just register it,
and code enough of the COM boilerplate that when Windows asks your DLL for an
instance, it can be generated. From your post, I'm not sure if you're doing
that or not, so I'll go ahead and post some code samples for you and anyone
else who comes looking.
Here's a snippet from my "register.reg":
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{<LMSCredentialProvider GUID Snipped>}]
@="LMSCredentialProvider"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters\{<LMSCredentialProvider GUID Snipped>}]
@="LMSCredentialProvider"
[HKEY_CLASSES_ROOT\CLSID\{<LMSCredentialProvider GUID Snipped>}]
@="LMSCredentialProvider"
[HKEY_CLASSES_ROOT\CLSID\{<LMSCredentialProvider GUID
Snipped>}\InprocServer32]
@="LMSCredentialProvider.dll"
"ThreadingModel"="Apartment"
As mentioned in the other thread, I have a separate class for the filter in
the same DLL.
Here is CLMSFilter.h:
#pragma once
#include "credentialprovider.h"
#include <windows.h>
#include <strsafe.h>
#include "dll.h"
//This class implements ICredentialProviderFilter, which is responsible for
filtering out other credential providers.
//The LMS Credential Provider uses this to mask out the default Windows
provider.
class CLMSFilter : public ICredentialProviderFilter
{
public:
//This section contains some COM boilerplate code
// IUnknown
STDMETHOD_(ULONG, AddRef)()
{
return _cRef++;
}
STDMETHOD_(ULONG, Release)()
{
LONG cRef = _cRef--;
if (!cRef)
{
delete this;
}
return cRef;
}
STDMETHOD (QueryInterface)(REFIID riid, void** ppv)
{
HRESULT hr;
if (IID_IUnknown == riid ||
IID_ICredentialProviderFilter == riid)
{
*ppv = this;
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
hr = S_OK;
}
else
{
*ppv = NULL;
hr = E_NOINTERFACE;
}
return hr;
}
public:
friend HRESULT CLMSFilter_CreateInstance(REFIID riid, __deref_out void**
ppv);
//Implementation of ICredentialProviderFilter
IFACEMETHODIMP Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD
dwFlags, GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders);
IFACEMETHODIMP UpdateRemoteCredential(const
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsIn,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsOut);
protected:
CLMSFilter();
__override ~CLMSFilter();
private:
LONG _cRef;
You shouldn't need to do anything special with your CredentialProvider class.
You will also need to modify dll.cpp to know about your Credential Provider
filter class. I believe the only changes I made to the basic MS sample were:
1. add "extern HRESULT CLMSFilter_CreateInstance(REFIID riid, void** ppv);"
towards the top of the file.
2. Modify the function with signature "STDMETHOD (CreateInstance)(IUnknown*
pUnkOuter, REFIID riid, void** ppv)" to be as follows:
STDMETHOD (CreateInstance)(IUnknown* pUnkOuter, REFIID riid, void** ppv)
{
HRESULT hr;
if (!pUnkOuter)
{
if (IID_ICredentialProvider == riid)
hr = CLMSProvider_CreateInstance(riid, ppv);
else if (IID_ICredentialProviderFilter == riid)
hr = CLMSFilter_CreateInstance(riid, ppv);
}
else
{
hr = CLASS_E_NOAGGREGATION;
}
return hr;
}
I think that's everything. Go ahead and check your code against what I've
posted: hopefully, there's something there that will help you out.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。