I am trying to consume WCF webserice which is siteminder protected. The issue is when I am trying to browse the webservice URL in browser it is working fine with the credential that I have supplied.
But when I am trying to do the same programmatically, it's throwing an error -
error #401 unauthorized.
for reference -
http://www.codeproject.com/Articles/80314/How-to-Connect-to-a-SiteMinder-Protected-Resource
CookieContainer cookies = null;
HttpWebRequest request = null;
HttpWebResponse response = null;
string responseString = null;
NameValueCollection tags = null;
string url = null;
url = PROTECTED_URL;
Debug.WriteLine("Step 1: Requesting page #" + url);
request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = false;
response = (HttpWebResponse)request.GetResponse();
ShowResponse(response);
// Step 2: Get the redirection location
// make sure we have a valid response
if (response.StatusCode != HttpStatusCode.Found)
{
throw new ApplicationException();
}
url = response.Headers["Location"];
// Step 3: Open a connection to the redirect and load the login form,
// from this screen we will capture the required form fields.
Debug.WriteLine("Step 3: Requesting page #" + url);
request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = false;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
string str = ex.Message.ToString();
}
It's my HtTpClient to call WCF.
public async Task<string> webClient(string method, string uri)
{
try
{
var client = new HttpClient();
client.Timeout =new TimeSpan(0,0,0,10);
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(method).Result;
string content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
return "Error";
}
}
Uri is base adress, method is your method name.
string response = webClient(uri + "/GetSomething/", uri).Result;
Related
I'm trying to manage the redirect on this site: https://uk.soccerway.com, so I wrote this code:
public static string GetHtml(string url)
{
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url);
try
{
webReq.AllowAutoRedirect = false;
HttpWebResponse response = webReq.GetResponse() as HttpWebResponse;
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
url = (response.Headers["Location"] != null) ? response.Headers["Location"] : url;
return client.DownloadString(url);
}
catch (WebException)
{
throw;
}
}
this will return an Exception, in particular:
'The remote server returned an error: (302) Moved Temporarily.'
what I did wrong?
I can see this being a useful answer for many other users so reading this article helped me arrive with the code below. It recursively handles the redirects in case there are more than 1 redirects. Finally it returns the response:
public static HttpResponseMessage MakeRequest(string url)
{
using (var client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
};
HttpResponseMessage response = client.SendAsync(request).Result;
var statusCode = (int)response.StatusCode;
// We want to handle redirects ourselves so that we can
// determine the final redirect Location (via header)
if (statusCode >= 300 && statusCode <= 399)
{
var redirectUri = response.Headers.Location;
if (!redirectUri.IsAbsoluteUri)
{
redirectUri = new Uri(request.RequestUri.
GetLeftPart(UriPartial.Authority) + redirectUri);
}
return MakeRequest(redirectUri.AbsoluteUri);
}
return response;
}
}
Usage
HttpResponseMessage response = MakeRequest("https://uk.soccerway.com");
if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
}
I am trying to make a web API call by using HttpClient but getting Not authorized error. I am passing key in the header but still, it gives me this error. I can see my key in fiddler trace.
If I use WebClient then I am getting a successful response. request is same in both methods.
Using HttpClient:
#region HttpClient
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("apiKey", "MyKey");
var content = JsonConvert.SerializeObject(request);
var response = await client.PostAsJsonAsync("https://MyUrl", content);
if (response.IsSuccessStatusCode)
{
deliveryManagerQuoteResponse = await response.Content.ReadAsAsync<DeliveryManagerQuoteResponse>();
}
else
{
var reasonPhrase = response.ReasonPhrase;
if (reasonPhrase.ToUpper() == "NOT AUTHORIZED")
{
throw new KeyNotFoundException("Not authorized");
}
}
}
#endregion
Using WebClient:
#region WebClient
// Create string to hold JSON response
string jsonResponse = string.Empty;
using (var client = new WebClient())
{
try
{
client.UseDefaultCredentials = true;
client.Headers.Add("Content-Type:application/json");
client.Headers.Add("Accept:application/json");
client.Headers.Add("apiKey", "MyKey");
var uri = new Uri("https://MyUrl");
var content = JsonConvert.SerializeObject(request);
var response = client.UploadString(uri, "POST", content);
jsonResponse = response;
}
catch (WebException ex)
{
// Http Error
if (ex.Status == WebExceptionStatus.ProtocolError)
{
var webResponse = (HttpWebResponse)ex.Response;
var statusCode = (int)webResponse.StatusCode;
var msg = webResponse.StatusDescription;
throw new HttpException(statusCode, msg);
}
else
{
throw new HttpException(500, ex.Message);
}
}
}
#endregion
First things first, you are using HttpClient wrong.
Secondly, are you using fiddler to see what both requests look like? You should be able to see that the headers will look different. Right now you are using the Authorization Headers which will actually do something different than you want. All you need to do is simply add a regular 'ol header:
client.DefaultRequestHeaders.Add("apiKey", "MyKey");
I'm working on a C# Windows Form application and I would like to have the ability to test a users' credentials against Jira. Basically the user would input their username and password, click OK and the program will tell them if their credentials are accepted or not.
I already have working code (see below) that uses basic authentication via HttpWebRequest to create new tickets (aka issues), close tickets, add watchers, etc - so I figured this would be easy but I'm struggling with it.
As an analog, you can do a credentials check against Active Directory very easily using the System.DirectoryServices.AccountManagement namespace. Basically the method authenticateAD() will simply return true or false:
private bool authenticateAD(string username, string password)
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "example.com");
bool isValid = pc.ValidateCredentials(username,password);
return isValid;
}
This is exactly the kind of thing I want to do with Jira.
For reference, here's the code I'm using to add/close/update tickets in jira - maybe it can be modified to do what I want?
private Dictionary<string, string> sendHTTPtoREST(string json, string restURL)
{
HttpWebRequest request = WebRequest.Create(restURL) as HttpWebRequest;
request.Method = "POST";
request.Accept = "application/json";
request.ContentType = "application/json";
string mergedCreds = string.Format("{0}:{1}", username, password);
byte[] byteCreds = UTF8Encoding.UTF8.GetBytes(mergedCreds);
request.Headers.Add("Authorization", "Basic " + byteCreds);
byte[] data = Encoding.UTF8.GetBytes(json);
try
{
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
requestStream.Close();
}
}
catch(Exception ex)
{
displayMessages(string.Format("Error creating Jira: {0}",ex.Message.ToString()), "red", "white");
Dictionary<string, string> excepHTTP = new Dictionary<string, string>();
excepHTTP.Add("error", ex.Message.ToString());
return excepHTTP;
}
response = (HttpWebResponse)request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var sData = jss.Deserialize<Dictionary<string, string>>(str);
if(response.StatusCode.ToString()=="NoContent")
{
sData.Add("code", "NoContent");
request.Abort();
return sData;
}
else
{
sData.Add("code", response.StatusCode.ToString());
request.Abort();
return sData;
}
}
Thanks!
How about attempting to access the root page of JIRA and see if you get an HTTP 403 error?
try
{
// access JIRA using (parts of) your existing code
}
catch (WebException we)
{
var response = we.Response as HttpWebResponse;
if (response != null && response.StatusCode == HttpStatusCode.Forbidden)
{
// JIRA doesn't like your credentials
}
}
The HttpClient would be simple and best to use check credentials with GetAsync.
The sample code is below
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(JiraPath);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string mergedCreds = string.Format("{0}:{1}", username, password);
byte[] byteCreds = UTF8Encoding.UTF8.GetBytes(mergedCreds);
var authHeader = new AuthenticationHeaderValue("Basic", byteCreds);
client.DefaultRequestHeaders.Authorization = authHeader;
HttpResponseMessage response = client.GetAsync(restURL).Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
strJSON = response.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(strJSON))
return strJSON;
}
else
{
exceptionOccured = true;
// Use "response.ReasonPhrase" to return error message
}
}
I'm coding a Xamarin cross-platform mobile app. The server is a SpringMVC server which uses JWT Tokens to authenticate against each of the endpoints/webservices. So basically when I'm doing a request to a webservice for first time, before I need to hit a /authorize POST endpoint sending my email and password, the endpoint response will contain in the "Cookie" header an authenticaton token which comes as "AUTH_TOKEN={MD5-String}". Once I got the token I send the request to the endpoint, let's say /feed. But my problem is that I cannot figure out the way of setting the "Cookie" header in the C# HttpClient. I tried everything but the endpoing just keeps responding with the login screen html instead of the actual JSON response. I tried the same steps in Postman and other REST clients and It worked. So It means that I'm doing something wrong. Here's my code:
public class RestService : IRestService
{
HttpClient client;
HttpClientHandler handler;
CookieContainer cookies;
string authToken;
public List<Feed> FeedItems { get; private set; }
public RestService()
{
cookies = new CookieContainer();
handler = new HttpClientHandler();
handler.UseCookies = true; //Otherwise It'll not use the cookies container!!
handler.CookieContainer = cookies;
client = new HttpClient(handler);
client.MaxResponseContentBufferSize = 256000;
}
public async Task<List<Role>> GetFeedDataAsync()
{
//Request credentials
//Credentials validation
var credentials = new HalliganCredential()
{
email = Constants.Username,
password = Constants.Password
};
var jsonCredentials = JsonConvert.SerializeObject(credentials);
var jsonCredentialsContent = new StringContent(jsonCredentials, Encoding.UTF8, "application/json");
var authorizeUri = new Uri(Constants.AuthorizeEndpoint);
var authorizeResponse = await client.PostAsync(authorizeUri, jsonCredentialsContent);
if (authorizeResponse.IsSuccessStatusCode)
{
//If authentication went OK
IEnumerable<Cookie> responseCookies = cookies.GetCookies(authorizeUri).Cast<Cookie>();
foreach (Cookie cookie in responseCookies)
{
if (cookie.Name.Equals("AUTH-TOKEN"))
{
authToken = cookie.Value;
}
}
}
else
{
//Authentication failed throw error
throw new HttpRequestException("Authentication failed");
}
FeedItems = new List<Feed>();
//Making the GET request
var uri = new Uri(string.Format(Constants.FeedEnpoint, string.Empty));
try
{
cookies.Add(uri, new Cookie("Cookie", string.Format("AUTH_TOKEN={0}", authToken)));
client.DefaultRequestHeaders.Add("Cookie", string.Format("AUTH_TOKEN={0}", authToken));
handler.CookieContainer.Add(uri, new Cookie("Cookie", string.Format("AUTH_TOKEN={0}", authToken)));
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
//Credentials validation
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
FeedItems = JsonConvert.DeserializeObject<List<Feed>>(content);
}
}
catch (Exception ex)
{
Debug.WriteLine(#"ERROR {0}", ex.Message);
}
return FeedItems;
}
}
When I reach the line var content = await response.Content.ReadAsStringAsync(); the response is an HTML string instead of the actual JSON response.
I tried with several other key values for the header, although "Cookie" is the one that worked on Postman.
I tried with "Set-Cookie", "set-cookie", "Set-Cookie", setting the header as "AUTH_TOKEN". I tried all this convinations in different places like adding them in the cookie CookieContainer, in the handler CookieContainer and in the client.DefaultRequestHeaders.
I tried setting on and off the handler.UseCookies = true; //Otherwise It'll not use the cookies container!! line.
Any help will be welcome!
UPDATE
I tried with one of the suggested solutions but didn't work I tried either with UseCookies in true and false.
//Making the GET request
var baseAddress = new Uri("http://app.******.io");
using (var handler = new HttpClientHandler { UseCookies = true })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var message = new HttpRequestMessage(HttpMethod.Get, "/api/v1/feed?api_key=sarasa");
message.Headers.Add("Cookie", string.Format("AUTH_TOKEN={0}", authToken));
message.Headers.Add("Cookie", string.Format("AUTH_TOKEN={0};", authToken));
message.Headers.Add("Set-Cookie", string.Format("AUTH_TOKEN={0}", authToken));
message.Headers.Add("AUTH_TOKEN", authToken);
var result = await client.SendAsync(message);
result.EnsureSuccessStatusCode();
if (result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync();
FeedItems= JsonConvert.DeserializeObject<List<Feed>>(content);
}
}
return FeedItems;
UPDATE
I tried with the another solution, same results.
var baseAddress = new Uri("http://app.*****.io");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
cookieContainer.Add(baseAddress, new Cookie("Cookie", string.Format("AUTH_TOKEN={0}", authToken)));
cookieContainer.Add(baseAddress, new Cookie("Set-Cookie", string.Format("AUTH_TOKEN={0}", authToken)));
var result = client.GetAsync("/api/v1/roles?api_key=sarasa").Result;
result.EnsureSuccessStatusCode();
if (result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync();
RolesItems = JsonConvert.DeserializeObject<List<Role>>(content);
}
}
Is there an alternative to HttpClient?
I finally could set the Cookie header parameter, but I change HttpClient by HttpWebRequest
Getting the Cookies
//Credentials validation
var credentials = new CompanyCredential()
{
Email = Constants.Username,
Password = Constants.Password
};
var jsonCredentials = JsonConvert.SerializeObject(credentials);
var request = (HttpWebRequest) WebRequest.Create(new Uri(baseAddress, Constants.AuthorizeEndpoint));
request.ContentType = "application/json";
request.Method = "POST";
var requestStream = request.GetRequestStreamAsync().Result;
var streamWriter = new StreamWriter(requestStream);
streamWriter.Write(jsonCredentials);
streamWriter.Flush();
try
{
HttpWebResponse response = (HttpWebResponse) request.GetResponseAsync().Result;
if (response.StatusCode.Equals(HttpStatusCode.OK))
{
authToken = response.Headers["Set-Cookie"];
tokenExpireDate = DateTime.ParseExact(response.Headers["Expires"], "yyyy-MM-dd HH:mm:ss,fff",
System.Globalization.CultureInfo.InvariantCulture);
}
else
{
//Authentication failed throw error
throw new HttpRequestException("Authentication failed");
}
} catch (Exception e)
{
Debug.WriteLine(string.Format("Warning: {0}", e.Message));
}
Setting the Cookies
var request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress, endpoint));
SetHeaders(request);
if (string.IsNullOrEmpty(authToken))
{
throw new AuthTokenNullException();
}
request.Headers["Cookie"] = authToken;
request.Method = "GET";
HttpWebResponse response = request.GetResponseAsync().Result as HttpWebResponse;
if (!response.StatusCode.Equals(HttpStatusCode.OK))
{
throw new HttpRequestException(string.Format("Warning expected response as 200 and got {0}", Convert.ToString(response.StatusCode)));
}
var reader = new StreamReader(response.GetResponseStream());
string stringResponse = reader.ReadToEnd();
return JsonConvert.DeserializeObject<T>(stringResponse);
Does anyone know how to get the WebResponse ?? the method GetResponse() is obsolet, btw it's windows universal app.
Uri uri = new Uri("myuri");
HttpClient httpclient = new HttpClient();
HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(uri);
httpclient.DefaultRequestHeaders.Add("name", "value");
httpclient.DefaultRequestHeaders.Accept.TryParseAdd("application/json");
webrequest.Method = "GET";
HttpWebResponse response = webrequest.GetResponseAsync();
StreamReader streamReader1 = new StreamReader(response.GetResponseStream());
solved:
solved with this: private async void Start_Click(object sender, RoutedEventArgs e)
{
response = new HttpResponseMessage();
outputView.Text = "";
httpClient.DefaultRequestHeaders.Add("name", "value");
// The value of 'InputAddress' is set by the user and is therefore untrusted input.
// If we can't create a valid URI,
// We notify the user about the incorrect input.
Uri resourceUri = new Uri("myuri")
string responseBodyAsText;
try
{
response = await httpClient.GetAsync(resourceUri);
response.EnsureSuccessStatusCode();
responseBodyAsText = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
// Need to convert int HResult to hex string
statusText.Text = "Error = " + ex.HResult.ToString("X") +
" Message: " + ex.Message;
responseBodyAsText = "";
}
// Format the HTTP response to display better
responseBodyAsText = responseBodyAsText.Replace("<br>", Environment.NewLine);
outputView.Text = responseBodyAsText;
You need to include the await keyword.
HttpWebResponse response = await webrequest.GetResponseAsync();