using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Configuration; using System.Net.Http.Headers; using System.Windows; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text.RegularExpressions; using System.Security.Cryptography; using System.Net; using System.Globalization; using System.IO; namespace _01555951_Bachelorarbeit { public static class HttpHelper { //performs a PUT method public static async Task Put(string baseUri, string requestUri, string bearerToken, string contentValue) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); var content = new StringContent(contentValue, Encoding.UTF8, "application/json"); var result = await client.PutAsync(requestUri, content); try { result.EnsureSuccessStatusCode(); return 200; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: "+httpRE.Message); return -1; } } } //performs a POST method public static async Task Post(string baseUri, string requestUri, string bearerToken, string contentValue) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); var content = new StringContent(contentValue, Encoding.UTF8, "application/json"); var result = await client.PostAsync(requestUri, content); var json = await result.Content.ReadAsStringAsync(); try { result.EnsureSuccessStatusCode(); return 200; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: " + httpRE.Message); return -1; } } } public static async Task Post(string baseUri, string requestUri, string contentValue) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); var content = new StringContent(contentValue, Encoding.UTF8, "application/json"); dynamic result = await client.PostAsync(requestUri, content); try { result.EnsureSuccessStatusCode(); return result; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: " + httpRE.Message); return -1; } } } //performs a GET method public static async Task Get(string baseUri, string requestUri, string bearerToken) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); var result = await client.GetAsync(requestUri); try { result.EnsureSuccessStatusCode(); string resultContentString = await result.Content.ReadAsStringAsync(); dynamic resultContent = JObject.Parse(resultContentString); return resultContent; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: " + httpRE.Message); return default(T); } } } //performs a GET method public static async Task Get(string baseUri, string requestUri) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); var result = await client.GetAsync(requestUri); try { result.EnsureSuccessStatusCode(); string resultContentString = await result.Content.ReadAsStringAsync(); dynamic resultContent = JObject.Parse(resultContentString); return resultContent; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: " + httpRE.Message); return default(T); } } } //performs a DELETE method public static async Task Delete(string baseUri, string requestUri, string bearerToken) { using (var client = new HttpClient()) { client.BaseAddress = new Uri(baseUri); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); var result = await client.DeleteAsync(requestUri); try { result.EnsureSuccessStatusCode(); return 200; } catch (HttpRequestException httpRE) { Console.WriteLine("ERROR: " + httpRE.Message); return -1; } } } public static async Task GetDigest(string baseUri, string requestUri, string contentValue, string username, string password) { Uri myUri = new Uri(baseUri+requestUri); WebRequest myWebRequest = HttpWebRequest.Create(myUri); HttpWebRequest myHttpWebRequest = (HttpWebRequest)myWebRequest; NetworkCredential myNetworkCredential = new NetworkCredential(username, password); CredentialCache myCredentialCache = new CredentialCache(); myCredentialCache.Add(myUri, "Digest", myNetworkCredential); myHttpWebRequest.PreAuthenticate = true; myHttpWebRequest.Credentials = myCredentialCache; WebResponse myWebResponse = myWebRequest.GetResponse(); Stream responseStream = myWebResponse.GetResponseStream(); StreamReader myStreamReader = new StreamReader(responseStream, Encoding.Default); string pageContent = myStreamReader.ReadToEnd(); responseStream.Close(); myWebResponse.Close(); return pageContent; } public static async Task PostDigest(string baseUri, string requestUri, string contentValue, string username, string password) { DigestHttpWebRequest request = new DigestHttpWebRequest(username, password); request.Method = WebRequestMethods.Http.Post; request.ContentType = "text/plain; charset=utf-8"; request.PostData = Encoding.ASCII.GetBytes(contentValue); HttpWebResponse result = request.GetResponse(new Uri(baseUri + requestUri)); Console.WriteLine(result.ToString()); } public static async Task PutDigest(string baseUri, string requestUri, string contentValue, string username, string password) { DigestHttpWebRequest request = new DigestHttpWebRequest(username, password); request.Method = WebRequestMethods.Http.Put; request.ContentType = "text/plain; charset=utf-8"; request.PostData = Encoding.ASCII.GetBytes(contentValue); HttpWebResponse result = request.GetResponse(new Uri(baseUri + requestUri)); Console.WriteLine(result.ToString()); } // DigestHttpWebRequest class was copied from https://blogs.msdn.microsoft.com/daniem/2013/02/27/digest-authentication-in-system-net-classes-dont-fully-comply-with-rfc2617/ public class DigestHttpWebRequest { private string _user; private string _password; private string _realm; private string _nonce; private string _qop; private string _cnonce; private Algorithm _md5; private DateTime _cnonceDate; private int _nc; private string _requestMethod = WebRequestMethods.Http.Get; private string _contentType; private byte[] _postData; public DigestHttpWebRequest(string user, string password) { _user = user; _password = password; } public string Method { get { return _requestMethod; } set { _requestMethod = value; } } public string ContentType { get { return _contentType; } set { _contentType = value; } } public byte[] PostData { get { return _postData; } set { _postData = value; } } public HttpWebResponse GetResponse(Uri uri) { HttpWebResponse response = null; int infiniteLoopCounter = 0; int maxNumberAttempts = 2; while ((response == null || response.StatusCode != HttpStatusCode.Accepted) && infiniteLoopCounter < maxNumberAttempts) { try { var request = CreateHttpWebRequestObject(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", ComputeDigestHeader(uri)); } try { response = (HttpWebResponse)request.GetResponse(); } catch (WebException webException) { // Try to fix a 401 exception by adding a Authorization header if (webException.Response != null && ((HttpWebResponse)webException.Response).StatusCode == HttpStatusCode.Unauthorized) { var wwwAuthenticateHeader = webException.Response.Headers["WWW-Authenticate"]; _realm = GetDigestHeaderAttribute("realm", wwwAuthenticateHeader); _nonce = GetDigestHeaderAttribute("nonce", wwwAuthenticateHeader); _qop = GetDigestHeaderAttribute("qop", wwwAuthenticateHeader); _md5 = GetMD5Algorithm(wwwAuthenticateHeader); _nc = 0; _cnonce = new Random().Next(123400, 9999999).ToString(); _cnonceDate = DateTime.Now; request = CreateHttpWebRequestObject(uri, true); infiniteLoopCounter++; response = (HttpWebResponse)request.GetResponse(); } else { throw webException; } } switch (response.StatusCode) { case HttpStatusCode.OK: case HttpStatusCode.Accepted: return response; case HttpStatusCode.Redirect: case HttpStatusCode.Moved: uri = new Uri(response.Headers["Location"]); // We decrement the loop counter, as there might be a variable number of redirections which we should follow infiniteLoopCounter--; break; } } catch (WebException ex) { throw ex; } } throw new Exception("Error: Either authentication failed, authorization failed or the resource doesn't exist"); } private HttpWebRequest CreateHttpWebRequestObject(Uri uri, bool addAuthenticationHeader) { var request = (HttpWebRequest)WebRequest.Create(uri); request.AllowAutoRedirect = false; request.Method = this.Method; if (!String.IsNullOrEmpty(this.ContentType)) { request.ContentType = this.ContentType; } if (addAuthenticationHeader) { request.Headers.Add("Authorization", ComputeDigestHeader(uri)); } if (this.PostData != null && this.PostData.Length > 0) { request.ContentLength = this.PostData.Length; Stream postDataStream = request.GetRequestStream(); //open connection postDataStream.Write(this.PostData, 0, this.PostData.Length); // Send the data. postDataStream.Close(); } else if(this.Method == WebRequestMethods.Http.Post && (this.PostData == null || this.PostData.Length == 0)) { request.ContentLength = 0; } return request; } private HttpWebRequest CreateHttpWebRequestObject(Uri uri) { return CreateHttpWebRequestObject(uri, false); } private string ComputeDigestHeader(Uri uri) { _nc = _nc + 1; string ha1, ha2; switch (_md5) { case Algorithm.MD5sess: var secret = ComputeMd5Hash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", _user, _realm, _password)); ha1 = ComputeMd5Hash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", secret, _nonce, _cnonce)); ha2 = ComputeMd5Hash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}", this.Method, uri.PathAndQuery)); var data = string.Format(CultureInfo.InvariantCulture, "{0}:{1:00000000}:{2}:{3}:{4}", _nonce, _nc, _cnonce, _qop, ha2); var kd = ComputeMd5Hash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}", ha1, data)); return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\"," + "algorithm =MD5-sess, response=\"{4}\", qop={5}, nc={6:00000000}, cnonce=\"{7}\"", _user, _realm, _nonce, uri.PathAndQuery, kd, _qop, _nc, _cnonce); case Algorithm.MD5: ha1 = ComputeMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password)); ha2 = ComputeMd5Hash(string.Format("{0}:{1}", this.Method, uri.PathAndQuery)); var digestResponse = ComputeMd5Hash(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, uri.PathAndQuery, digestResponse, _qop, _nc, _cnonce); } throw new Exception("The digest header could not be generated"); } private string GetDigestHeaderAttribute(string attributeName, string digestAuthHeader) { var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", attributeName)); var matchHeader = regHeader.Match(digestAuthHeader); if (matchHeader.Success) return matchHeader.Groups[1].Value; throw new ApplicationException(string.Format("Header {0} not found", attributeName)); } private Algorithm GetMD5Algorithm(string digestAuthHeader) { var md5Regex = new Regex(@"algorithm=(?.*)[,]", RegexOptions.IgnoreCase); var md5Attribute = md5Regex.Match(digestAuthHeader); if (md5Attribute.Success) { char[] charSeparator = new char[] { ',' }; string algorithm = md5Attribute.Result("${algo}").ToLower().Split(charSeparator)[0]; switch (algorithm) { case "md5-sess": case "\"md5-sess\"": return Algorithm.MD5sess; case "md5": case "\"md5\"": default: return Algorithm.MD5; } } throw new ApplicationException("Could not determine Digest algorithm to be used from the server response."); } private string ComputeMd5Hash(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(); } public enum Algorithm { MD5 = 0, // Apache Default MD5sess = 1 //IIS Default } } } }