So, there are two methods deals with credential dialog of IE
CredUIPromptForCredentials – for pop it up and CredUIConfirmCredentials for persist those settings in password manager (optional). So, in order to call it explicitly, you should implement them via P/Invoke like this
[DllImport("credui.dll", EntryPoint = "CredUIConfirmCredentialsW", CharSet = CharSet.Unicode)]
private static extern CredUIReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm);
[DllImport("credui.dll", EntryPoint = "CredUIPromptForCredentials", CharSet = CharSet.Ansi)]
private static extern CredUIReturnCodes CredUIPromptForCredentials(ref CREDUI_INFO creditUR,
string targetName,
IntPtr reserved1,
int iError,
StringBuilder userName,
int maxUserName,
StringBuilder password,
int maxPassword,
[MarshalAs(UnmanagedType.Bool)] ref bool pfSave,
CREDUI_FLAGS flags);
Please pay attention, that you’ll need CREDI_INFO structure and CREDI_FLAG and CredUIReturnCodes enums, that those function using
public struct CREDUI_INFO
{
public int cbSize;
public IntPtr hwndParent;
public string pszMessageText;
public string pszCaptionText;
public IntPtr hbmBanner;
}
[Flags]
enum CREDUI_FLAGS
{
INCORRECT_PASSWORD = 0x1,
DO_NOT_PERSIST = 0x2,
REQUEST_ADMINISTRATOR = 0x4,
EXCLUDE_CERTIFICATES = 0x8,
REQUIRE_CERTIFICATE = 0x10,
SHOW_SAVE_CHECK_BOX = 0x40,
ALWAYS_SHOW_UI = 0x80,
REQUIRE_SMARTCARD = 0x100,
PASSWORD_ONLY_OK = 0x200,
VALIDATE_USERNAME = 0x400,
COMPLETE_USERNAME = 0x800,
PERSIST = 0x1000,
SERVER_CREDENTIAL = 0x4000,
EXPECT_CONFIRMATION = 0x20000,
GENERIC_CREDENTIALS = 0x40000,
USERNAME_TARGET_CREDENTIALS = 0x80000,
KEEP_USERNAME = 0x100000,
}
public enum CredUIReturnCodes
{
NO_ERROR = 0,
ERROR_CANCELLED = 1223,
ERROR_NO_SUCH_LOGON_SESSION = 1312,
ERROR_NOT_FOUND = 1168,
ERROR_INVALID_ACCOUNT_NAME = 1315,
ERROR_INSUFFICIENT_BUFFER = 122,
ERROR_INVALID_PARAMETER = 87,
ERROR_INVALID_FLAGS = 1004,
}
Now, when you have those calls, you may want to make some wrappers (like those)
const int MAX_USER_NAME = 100;
const int MAX_PASSWORD = 100;
const int MAX_DOMAIN = 100;
static CredUIReturnCodes PromptForCredentials(ref CREDUI_INFO creditUI, string targetName, int netError, ref string userName, ref string password, ref bool save, CREDUI_FLAGS flags)
{
StringBuilder user = new StringBuilder(MAX_USER_NAME);
StringBuilder pwd = new StringBuilder(MAX_PASSWORD);
creditUI.cbSize = Marshal.SizeOf(creditUI);
CredUIReturnCodes result = CredUIPromptForCredentials(ref creditUI, targetName,IntPtr.Zero, netError,user, MAX_USER_NAME, pwd, MAX_PASSWORD, ref save, flags);
userName = user.ToString();
password = pwd.ToString();
return result;
}
CredUIReturnCodes AskCredit(ref string username, ref string password)
{
string host = url.Host;
CREDUI_INFO info = new CREDUI_INFO();
info.pszCaptionText = host;
info.pszMessageText = "The server "+host+" requires a username and password. \r\n\r\n\r\nWarning: This server is requesting that your username and password be sent in an insecure manner (basic authentication without a secure connection).";
CREDUI_FLAGS flags = CREDUI_FLAGS.GENERIC_CREDENTIALS |
CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX |
CREDUI_FLAGS.ALWAYS_SHOW_UI |
CREDUI_FLAGS.EXPECT_CONFIRMATION;
bool savePwd = false;
CredUIReturnCodes result = PromptForCredentials(ref info, host, 0, ref username,
ref password, ref savePwd, flags);
return result;
}
After it, you should call AskCredit to get the credit window pop up and get secured username and password from them. Something like this
CredUIReturnCodes code = AskCredit(ref user, ref pwd);
if (code == CredUIReturnCodes.NO_ERROR)
{
//Do something useful
}
The next part is to provide those credentials to your HTTPRequest. See the sample doing that
//create some string to get response into
string str = string.Empty;
HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest;
HttpWebResponse res = null;
//while you don’t OK keep trying
while (res == null || res.StatusCode != HttpStatusCode.OK)
{
try
{
//you are fine, do the rest
res = req.GetResponse() as HttpWebResponse;
using (Stream s = res.GetResponseStream())
{
using (StreamReader sr = new StreamReader(s))
{
str = sr.ReadToEnd();
sr.Close();
}
s.Close();
}
res.Close();
}
//You got an exception
catch (WebException e)
{
//If this exeption is not security one, you have nothing to do, the only thing is, maybe, check you network connection
if (e.Status == WebExceptionStatus.ProtocolError)
{
res = e.Response as HttpWebResponse;
//Now check what the problem and if it’s security, threat it
if (res.StatusCode == HttpStatusCode.Unauthorized)
{
string user = "";
string pwd = "";
//pop you window and get information
CredUIReturnCodes code = AskCredit(ref user, ref pwd);
if (code == CredUIReturnCodes.NO_ERROR)
{
//create new credential set and use it as required
CredentialCache creds = new CredentialCache();
creds.Add(url, "Basic", new NetworkCredential(user,pwd));
//creds.Add(url, "Digest", new NetworkCredential(user, pwd));
//creds.Add(url, "Negotiate", CredentialCache.DefaultNetworkCredentials);
req.Credentials = creds;
}
}
}
}
}
Well done. Now you have an application, that pops Internet Explorer authentication window and optionally saves your passwords into security password store within the browser
No comments:
Post a Comment