HttpWebRequests sends parameterless URI in Authorization header

后端 未结 3 1578
没有蜡笔的小新
没有蜡笔的小新 2020-12-06 03:09

I\'m connecting to a web service from .NET, like:

var request = (HttpWebRequest) WebRequest.Create(uri);
request.Credentials = new NetworkCredential(\"usr\",         


        
相关标签:
3条回答
  • 2020-12-06 03:45

    It looks like you need to install this hotfix might help you out:

    http://support.microsoft.com/?kbid=924638

    Your problem was probably happening because you weren't able to set the KeepAlive property to false when you're using the HTTP adapter to post a message

    Also ensure PreAuthenticate is set to true.

    0 讨论(0)
  • 2020-12-06 03:51

    It turns out that Digest authentication is fairly easy to implement. With our own implementation, we were able to use the full URI (including parameters) to generate the MD5 hash. That fixed the problem.

    In case someone hits this problem in the future, you can call the workaround like:

    var resultText = DigestAuthFixer.GrabResponse("/dir/index.html");
    

    The code for the DigestAuthFixer class:

    public static class DigestAuthFixer
    {
        private static string _host = "http://localhost";
        private static string _user = "Mufasa";
        private static string _password = "Circle Of Life";
        private static string _realm;
        private static string _nonce;
        private static string _qop;
        private static string _cnonce;
        private static DateTime _cnonceDate;
        private static int _nc;
    
        private static string CalculateMd5Hash(
            string input)
        {
            var inputBytes = Encoding.ASCII.GetBytes(input);
            var hash = MD5.Create().ComputeHash(inputBytes);
            var sb = new StringBuilder();
            foreach (var b in hash)
                sb.Append(b.ToString("x2"));
            return sb.ToString();
        }
    
        private static string GrabHeaderVar(
            string varName,
            string header)
        {
            var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", varName));
            var matchHeader = regHeader.Match(header);
            if (matchHeader.Success)
                return matchHeader.Groups[1].Value;
            throw new ApplicationException(string.Format("Header {0} not found", varName));
        }
    
        // http://en.wikipedia.org/wiki/Digest_access_authentication
        private static string GetDigestHeader(
            string dir)
        {
            _nc = _nc + 1;
    
            var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
            var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", "GET", dir));
            var digestResponse =
                CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2));
    
            return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " +
                "algorithm=MD5, response=\"{4}\", qop={5}, nc={6:00000000}, cnonce=\"{7}\"",
                _user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce);
        }
    
        public static string GrabResponse(
            string dir)
        {
            var url = _host + dir;
            var uri = new Uri(url);
    
            var request = (HttpWebRequest)WebRequest.Create(uri);
    
            // If we've got a recent Auth header, re-use it!
            if (!string.IsNullOrEmpty(_cnonce) &&
                DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0)
            {
                request.Headers.Add("Authorization", GetDigestHeader(dir));
            }
    
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                // Try to fix a 401 exception by adding a Authorization header
                if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized)
                    throw;
    
                var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"];
                _realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
                _nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
                _qop = GrabHeaderVar("qop", wwwAuthenticateHeader);
    
                _nc = 0;
                _cnonce = new Random().Next(123400, 9999999).ToString();
                _cnonceDate = DateTime.Now;
    
                var request2 = (HttpWebRequest)WebRequest.Create(uri);
                request2.Headers.Add("Authorization", GetDigestHeader(dir));
                response = (HttpWebResponse)request2.GetResponse();
            }
            var reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
        }
    }
    
    0 讨论(0)
  • 2020-12-06 03:55

    I ran into this issue recently. I couldn't get the workaround from Andomar to work either without some minor adjustments. I submitted the changes as a suggestion to Andomar's answer, but they were unceremoniously rejected by TheTinMan and Lucifer. Since it took me and some collegues hours to figure these out and I'm sure someone else will need this I'm posting the code as an answer to make it available.

    Here's the adjusted code. Basically an "opaque" header variable was needed, and some quotes needed fixing in GetDigestHeader.

    public static class DigestAuthFixer
    {
        private static string _host = "http://localhost";
        private static string _user = "Mufasa";
        private static string _password = "Circle Of Life";
        private static string _realm;
        private static string _nonce;
        private static string _qop;
        private static string _cnonce;
        private static string _opaque;
        private static DateTime _cnonceDate;
        private static int _nc = 0;
    
        private static string CalculateMd5Hash(
            string input)
        {
            var inputBytes = Encoding.ASCII.GetBytes(input);
            var hash = MD5.Create().ComputeHash(inputBytes);
            var sb = new StringBuilder();
            foreach (var b in hash)
                sb.Append(b.ToString("x2"));
            return sb.ToString();
        }
    
        private static string GrabHeaderVar(
            string varName,
            string header)
        {
            var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", varName));
            var matchHeader = regHeader.Match(header);
            if (matchHeader.Success)
                return matchHeader.Groups[1].Value;
            throw new ApplicationException(string.Format("Header {0} not found", varName));
        }
    
        // http://en.wikipedia.org/wiki/Digest_access_authentication
        private static string GetDigestHeader(
            string dir)
        {
            _nc = _nc + 1;
    
            var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
            var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", "GET", dir));
            var digestResponse =
                CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2));
    
            return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " +
            "algorithm=MD5, response=\"{4}\", qop=\"{5}\", nc=\"{6:00000000}\", cnonce=\"{7}\", opaque=\"{8}\"",
            _user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce, _opaque);
        }
    
        public static string GrabResponse(
            string dir)
        {
            var url = _host + dir;
            var uri = new Uri(url);
    
            var request = (HttpWebRequest)WebRequest.Create(uri);
    
            // If we've got a recent Auth header, re-use it!
            if (!string.IsNullOrEmpty(_cnonce) &&
                DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0)
            {
                request.Headers.Add("Authorization", GetDigestHeader(dir));
            }
    
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                // Try to fix a 401 exception by adding a Authorization header
                if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized)
                    throw;
    
                var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"];
                _realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
                _nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
                _qop = GrabHeaderVar("qop", wwwAuthenticateHeader);
                _opaque = GrabHeaderVar("opaque", wwwAuthenticateHeader);
                _nc = 0;
                _cnonce = new Random().Next(123400, 9999999).ToString();
                _cnonceDate = DateTime.Now;
    
                var request2 = (HttpWebRequest)WebRequest.Create(uri);
                request2.Headers.Add("Authorization", GetDigestHeader(dir));
                response = (HttpWebResponse)request2.GetResponse();
            }
            var reader = new StreamReader(response.GetResponseStream());
            return reader.ReadToEnd();
        }
    }
    
    0 讨论(0)
提交回复
热议问题