认为我在here的帮助下成功地为there提到的Credential API函数创建了一个托管的包装类。至少从这些函数返回的Win32-Errorcodes是零或其他但是预期的(即{来自CredDelete的{3}}如果调用它两次,并且相应的值存储在注册表中的正确位置(HKLM / Comm / Security / Credman / 1 ..)。
现在,我正在使用嵌入在PPC上的WindowsForm中的Webbrowser-Control来对使用NTLM身份验证的网站进行身份验证。我不想让popupdialog出现在用户必须输入其凭据的位置。相反,我给用户提供了将他的凭证存储在他首先在Optiondialog-Form中输入的设备的可能性(实习生调用CredWrite / CredUpdate)。
但PIE对我的API做了很多,但CredWrite,-Update或-Delete实际上都没有。那我在这里错过了什么?
CredWrite的示例代码:
[DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int CredWrite([In]IntPtr pCred, [In]CREDWRITE_FLAGS dwflags);
public enum CREDWRITE_FLAGS : int
{
CRED_FLAG_FAIL_IF_EXISTING = 0x00000400
}
public struct CRED
{
public int dwVersion;
public CRED_TYPE dwType;
[MarshalAs(UnmanagedType.LPWStr)]
public string wszUser;
public int dwUserLen;
[MarshalAs(UnmanagedType.LPWStr)]
public string wszTarget;
public int dwTargetLen;
public IntPtr pBlob;
public int dwBlobSize;
public CRED_FLAGS dwFlags;
}
public enum CRED_TYPE
{
CRED_TYPE_NTLM = 0x00010002,
CRED_TYPE_KERBEROS = 0x00010004,
CRED_TYPE_PLAINTEXT_PASSWORD = 0x00010006,
CRED_TYPE_CERTIFICATE = 0x00010008,
CRED_TYPE_GENERIC = 0x0001000a,
CRED_TYPE_DOMAIN_PASSWORD = 0x00010001,
}
public enum CRED_FLAGS : int
{
CRED_FLAG_PERSIST = 0x00000001,
CRED_FLAG_DEFAULT = 0x00000002,
CRED_FLAG_SENSITIVE = 0x00000008,
CRED_FLAG_TRUSTED = 0x00000010
}
public static void WriteCredentials(string target, string userName, string password)
{
CRED cred = new CRED();
cred.dwVersion = 1;
cred.dwType = CRED_TYPE.CRED_TYPE_NTLM;
cred.wszTarget = target;
cred.dwTargetLen = target.Length + 1;
cred.wszUser = userName;
cred.dwUserLen = userName.Length + 1;
cred.dwBlobSize = (Encoding.Unicode.GetBytes(password).Length + 1) * 2;
//cred.pBlob = Marshal.StringToCoTaskMemUni(password); //<--not in CF
//cred.pBlob = Marshal2.StringToHGlobalUni(password); //<--from OpenNETCF, the same?
cred.pBlob = Marshal.StringToBSTR(password); //<--not sure of that, but tried the other one also
cred.dwFlags = CRED_FLAGS.CRED_FLAG_PERSIST | CRED_FLAGS.CRED_FLAG_SENSITIVE | CRED_FLAGS.CRED_FLAG_TRUSTED; //<-- results in 25 which is also used in creds read which are stored by the IE-UI-CredMan-dialog
IntPtr credPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cred));
Marshal.StructureToPtr(cred, credPtr, true);
int ret = -1;
ret = CredWrite(credPtr, CREDWRITE_FLAGS.CRED_FLAG_FAIL_IF_EXISTING); //returns zero, unless called twice with the same target/username-tuple.
Marshal.FreeHGlobal(credPtr);
}
BTW所谓的“MS-Experts”提到PIE有自己的信用卡机制,这就是为什么PIE忽略了CredUpdate的变化。但是我怀疑这是100%正确的,因为当我在没有凭据的设备上调用CredWrite时,PIE也会忽略它们(弹出信号输入信号)。
有人可以帮助我吗?
答案 0 :(得分:0)
我要检查的事情是
之前我已经使用设备进行过NTLM身份验证,而不是使用浏览器控件,我使用了Authentication Services APIs。 Here's an example in native。我一直想将它移植到托管,只是没有找到时间。
编辑1 :在进一步查看代码时,我不喜欢这个blob。是什么让你认为它应该作为BSTR进入?这是一种COM类型,我非常怀疑它是你想要的。我倾向于只用密码发送一个字节数组。我首先尝试使用Unicode,因为CE严重偏向于Unicode,如果失败则为ASCII。
我也认为你对CRED结构的编组是可疑的,但这只是因为我从1.0天开始就使用CF而且我已经学会了“信任但验证”编组人所做的一切。我至少在内存视图中查看CRED实例,并确保这些字符串确实只是4字节的指针,并且它们指向的地址实际上包含您的字符串数据(没有更多,并且以null结尾)。