/// <summary> /// Authenticates request. /// </summary> /// <param name="headers">Headers collection.</param> /// <param name="method">Http verb.</param> /// <returns>Authenticated <see cref="IPrincipal"/> instance or <c>null</c> otherwise.</returns> public IPrincipal AuthenticateRequest(NameValueCollection headers, string method) { if (!IsAuthorizationPresent(headers)) { return(null); } string authStr = headers["Authorization"]; authStr = authStr.Trim().Substring(7); string[] elems; // To avoid any issues when parsing CSV string, such as comas included in quoted fields, we use // TextFieldParser instead of String.Split here. using (StringReader reader = new StringReader(authStr)) { using (TextFieldParser parser = new TextFieldParser(reader)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(new string[] { ",", "=" }); parser.HasFieldsEnclosedInQuotes = true; parser.TrimWhiteSpace = true; elems = parser.ReadFields(); } } Dictionary <string, string> reqInfo = new Dictionary <string, string>(); for (int i = 0; i < elems.Length; i += 2) { reqInfo.Add(elems[i], elems[i + 1]); } string clientUsername = reqInfo.ContainsKey("username") ? reqInfo["username"] : string.Empty; // workaround for Windows Vista Digest Authorization. User name may be submitted in the following format: // Machine\\User. clientUsername = clientUsername.Replace("\\\\", "\\"); reqInfo["username"] = clientUsername; string username = clientUsername; int ind = username.LastIndexOf('\\'); if (ind > 0) { username = username.Remove(0, ind + 1); } PasswordAndRoles par = getPasswordAndRolesByUsernameFunction(username); if (par == null) { return(null); } string unhashedDigest = generateUnhashedDigest(par.Password, reqInfo, method); string hashedDigest = createMD5HashBinHex(unhashedDigest); isNonceStale = !isNonceValid(reqInfo["nonce"]); if ((reqInfo["response"] != hashedDigest) || isNonceStale) { return(null); } return(new GenericPrincipal(new GenericIdentity(clientUsername, "digest"), par.Roles)); }
/// <summary> /// Authenticates request. /// </summary> /// <param name="headers">Headers collection.</param> /// <param name="method">Http verb.</param> /// <returns>Authenticated <see cref="IPrincipal"/> instance or <c>null</c> otherwise.</returns> public IPrincipal AuthenticateRequest(NameValueCollection headers, string method) { if (!IsAuthorizationPresent(headers)) { return(null); } string authStr = headers["Authorization"]; authStr = authStr.Trim().Substring(7); //Filling header segments in dictionary. Dictionary <string, string> reqInfo = new Dictionary <string, string>(); MatchCollection matches = Regex.Matches(authStr, "([a-zA-Z0-9]+)=(([^\",]+)|(\\\"([^\"]*)\\\")),?"); // Group 1 - Param name // Group 2 - Whole value string // Group 3 - Value if not in "\"" e.g. alg=MD5 // Group 5 - Value if in "\"" e.g. name="name" foreach (Match match in matches) { string value = match.Groups[5].Value; if (value.Length == 0) { value = match.Groups[3].Value; } reqInfo.Add(match.Groups[1].Value, value); } string clientUsername = reqInfo.ContainsKey("username") ? reqInfo["username"] : string.Empty; // workaround for Windows Vista Digest Authorization. User name may be submitted in the following format: // Machine\\User. clientUsername = clientUsername.Replace("\\\\", "\\"); reqInfo["username"] = clientUsername; string username = clientUsername; int ind = username.LastIndexOf('\\'); if (ind > 0) { username = username.Remove(0, ind + 1); } PasswordAndRoles par = getPasswordAndRolesByUsernameFunction(username); if (par == null) { return(null); } string unhashedDigest = generateUnhashedDigest(par.Password, reqInfo, method); string hashedDigest = createMD5HashBinHex(unhashedDigest); isNonceStale = !isNonceValid(reqInfo["nonce"]); if ((reqInfo["response"] != hashedDigest) || isNonceStale) { return(null); } return(new GenericPrincipal(new GenericIdentity(clientUsername, "digest"), par.Roles)); }