Подавить Диалог проверки подлинности NTLM
Код
Я создал страницу входа, которая сочетает проверку подлинности форм с встроенной проверкой подлинности Windows.
public partial class Login : System.Web.UI.Page
{
// http://www.innovation.ch/personal/ronald/ntlm.html
// http://curl.cofman.dk/rfc/ntlm.html
// http://blogs.msdn.com/b/chiranth/archive/2013/09/21/ntlm-want-to-know-how-it-works.aspx
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Request.Headers["Authorization"].IsNullOrEmpty())
{
Response.StatusCode = 401;
Response.AddHeader("WWW-Authenticate", "NTLM");
Email.SendMailToDebugger("Auth", "No Auth");
//Response.End();
}
else if (Request.Headers["Authorization"].StartsWith("Negotiate"))
{
Response.StatusCode = 401;
Response.AddHeader("WWW-Authenticate", "NTLM");
Email.SendMailToDebugger("Auth", "Negotiate Auth");
Response.End();
}
else if (Request.Headers["Authorization"].StartsWith("NTLM"))
{
string base64text = Request.Headers["Authorization"].Remove(0, 5); //Remove NTLM<space>
byte[] bytes = Convert.FromBase64String(base64text);
byte typebyte = bytes[8];
if (typebyte.ToString("X2") == "01") //type 1 message received
{
//send type 2 message
List<byte> responsebytes = new List<byte> { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
string type2message = Convert.ToBase64String(responsebytes.ToArray());
Response.StatusCode = 401;
Response.AddHeader("WWW-Authenticate", "NTLM " + type2message);
Email.SendMailToDebugger("Auth", "Type 1 Received, Type 2 Sent");
Response.End();
}
else if (typebyte.ToString("X2") == "03") //type3 message received
{
var dv = Database.GetDataView("select UPPER('termana'||REPLACE(P.EMAIL,'@termana.com','')||p.init) displayname, 'termana\'||REPLACE(P.EMAIL,'@termana.com','') username from tercons.phonebook p where P.COMPANY_ID=40");
string username = ""; //magic to get the username from the type3 response
Email.SendMailToDebugger("Auth", "Type 3 Received, logging in: " + username);
FormsAuthentication.RedirectFromLoginPage(username, false);
}
else
{
Email.SendMailToDebugger("Auth", "Unknown Type Received");
}
}
else
{
Email.SendMailToDebugger("Auth", "Unknown Authentication Received: " + Request.Headers["Authorization"]);
}
}
}
}
Вопрос
Это, кажется, работает довольно хорошо до сих пор. Он правильно входит в систему пользователя, если они поддерживают IWA. Если их браузер не настроен для приема IWA,я хочу вернуться к проверке подлинности форм. К сожалению, я вижу, что происходит, если браузер не настроен на прием IWA, он всплывает в уродливом диалоге аутентификации NTLM (выглядит так основной диалог). Как мне сделать так, чтобы это не появилось?
Фон
Основная причина, по которой я это делаю, заключается в том, что один и тот же сайт может быть доступен через пользователей настольных компьютеров (в домене) или мобильных устройств (iPhone/Windows Phone). И iPhone не поддерживает сохранение паролей для аутентификации NTLM, что является проблемой для моих пользователей.
Для Проверки
Если вы хотите протестировать этот код в своей собственной среде, настройте сайт для проверки подлинности форм, убедитесь, что анонимная проверка подлинности проверил в службах IIS, а не МВА.
Также
Этот код не полностью протестирован / конкретизирован. Если вы случайный человек, который натыкается на мой вопрос, не думайте, что это совершенно безопасно, а затем идите и реализуйте его на своем сайте. Этот код находится на ранних стадиях разработки. Тем не менее, если вы хотите оставить комментарий о том, как его улучшить, не стесняйтесь.
Обновление
Я обновил свой код и вопрос, чтобы отразить тот факт, что мне удалось получить его так, что когда пользователь отменяет уродливый диалог проверки подлинности они могут войти в систему с помощью проверки подлинности форм. Но я все еще хочу, чтобы этот уродливый диалог был подавлен.
2 ответов:
Я подозреваю, что нежелательное всплывающее окно происходит из первоначального запроса, не содержащего Заголовок
Authorization, пока браузер не получит 401. Вместо этого вам нужно выбрать, чтобы избежать выдачи 401, если вы прогнозируете, что требуется авторизация форм.Рассмотрим такой подход:
- включить аутентификацию форм в качестве режима по умолчанию (не NTLM) и
- Изменить Глобальный.asax для имитации аутентификации NTLM, если ваш агент пользователя не является мобильным агентом (или любой комбинацией IP / user ограничение агента просмотре в качестве браузера по протоколу NTLM).
Код в глобальном формате.аскс будет действовать в этом направлении.
Обработайте Application_AuthenticateRequest явно:
protected void Application_AuthenticateRequest(object sender, EventArgs e) { try { if (IsAutomation() && Request.Headers["Authorization"] != null) { // Your NTML handling code here; below is what I use for Basic auth string[] parts = Request.Headers["Authorization"].Split(' '); string credentials = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(parts[1])); string[] auth = credentials.Split(':'); if (Membership.ValidateUser(auth[0], auth[1])) { Context.User = Membership.GetUser(auth[0]); } else { Response.Clear(); Response.StatusCode = 401; Response.StatusDescription = "Access Denied"; Response.RedirectLocation = null; // Switch to NTLM as you see fit; just my sample code here Response.AddHeader("WWW-Authenticate", "Basic realm={my realm}"); Response.ContentType = "text/html"; Response.Write(@" <html> <head> <title>401 Access Denied</title> </head> <body> <h1>Access Denied</h1> <p>The credentials supplied are invalid.</p> </body> </html>"); } } } catch (System.Exception ex) { throw ex; } }, где IsAutomation определяет, требуется ли проверка подлинности на основе форм или нет.
В моем случае IsAutomation выглядит так:
protected bool IsAutomation() { // In your case, I'd config-drive your desktop user agent strings if (!string.IsNullOrEmpty(Properties.Settings.Default.BasicAuthenticationUserAgents)) { string[] agents = Properties.Settings.Default.BasicAuthenticationUserAgents.Split(';'); foreach (string agent in agents) if (Context.Request.Headers["User-Agent"].Contains(agent)) return true; } return false; }Наконец, вам нужно перехватить перенаправление 302 и выполнить вызов NTLM:
protected void Application_EndRequest(object sender, EventArgs e) { if (IsAutomation() && Context.Response.StatusCode == 302) { Response.Clear(); Response.StatusCode = 401; Response.StatusDescription = "Access Denied"; Response.RedirectLocation = null; // Switch to NTLM as you see fit; just my sample code here Response.AddHeader("WWW-Authenticate", "Basic realm={your realm}"); Response.ContentType = "text/html"; Response.Write(@" <html> <head> <title>401 Authorization Required</title> </head> <body> <h1>Authorization Required</h1> <p>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.</p> </body> </html>"); } }
Я думаю, что вы путаетесь между понятиями аутентификации NTLM/IWA и тонкостями автоматического входа браузера на доверенный сайт. Если я перефразирую этот вопрос, вы на самом деле спрашиваете, Может ли сервер определить, будет ли браузер автоматически входить в систему, не запрашивая учетные данные, используя IWA, , Прежде чем вы предложите IWA в качестве метода аутентификации. Ответом на это будет звучное "нет."Зоны и параметры безопасности, которые контролируют это поведение полностью зависит от машины пользователя.
Теперь, если вы находитесь в среде интрасети и можете распознать определенные диапазоны IP-адресов как принадлежащие машинам, которые, как вы уже знаете, будут выполнять автоматическое IWA, то, конечно, это работает. Мне кажется, что вы пытаетесь обобщить, и для этого вы не можете заставить это работать.
Comments