Basic Authentication via Angular, why is this throwing error 401 - c#

I have an Angular application that I'm trying to authenticate with Basic authentication to my REST service. I'm adding the authorization header with the corresponding "Base {username:password}" encoded in base64 and I'm calling my rest api but keep getting back a 401. I'm obviously missing a step here...
Here's the angular code:
angular
.module('myApp.services')
.factory('AuthenticationService', ['$http', '$q', '$location', 'Base64', 'SessionService', function ($http, $q, $location, encoder, session) {
return {
authenticate:
function (user, password) {
var deferred = $q.defer();
var url = "http://localhost:28924/api/login";
if (user && password) {
var encoded = encoder.encode(user + ':' + password);
$http.defaults.headers.common.Authorization = 'Basic ' + encoded;
console.log('here');
sessionStorage.setItem('Authorization', $http.defaults.headers.common.Authorization);
$http.get(url)
.success(function (data, status, headers, config) {
console.log('login Successful in Authentication service');
deferred.resolve(data);
session.setSession();
})
.error(function (data, status, headers, config) {
deferred.reject(status);
});
}
else {
deferred.reject(401);
}
return deferred.promise;
},
logout:
function () {
$http.defaults.headers.common.Authorization = null;
$http.defaults.headers.common.Impersonate = null;
$location.url('/login');
}
};
}
]
);
Here's my LoginController:
public class LoginController : ApiController
{
public LoginController()
{
}
[Authorize]
public HttpResponseMessage Get()
{
//return this.ControllerContext.Request.CreateResponse(HttpStatusCode.OK);
if (this.User.Identity.IsAuthenticated)
{
return this.ControllerContext.Request.CreateResponse(HttpStatusCode.OK);
}
return this.ControllerContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
And I've also set my IISExpress config file to "Allow" basic authentication, like described here: set basic authentication in IIS Express.
Does just adding the "Authorize" attribute to my Get method let the host know to check the credentials that were passed in the Authorization header? Or do I need to implement something extra, like in this SO post (the question part): basic authentication with custom message handler?
It seems to me that there needs to be more in my "Get" method, but I can't find any good examples to help walk me through this....(if you haven't figure it out, this is my first try with basic authentication AND REST api/services.
Edit: Aha! I'm getting closer. #Chandermani's response for some reason prompted me to check out my OWN web.config and I realized I didn't have this:
<security>
<authentication>
<basicAuthentication enabled="true"/>
</authentication>
</security>
Adding this now prompts me for my credentials when navigating to the .../api/login page.
Edit2: Checking to see what was sent across the wire via Chrome Dev tools shows that the authorization header is being sent, while specifying Basic authentication and my base64 encoded username and password. Here's what it looks like:
Request URL:http://localhost:28924/api/login
Request Method:GET
Status Code:401 Unauthorized
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Authorization:Basic YWblahblahblahDE=
Connection:keep-alive
Host:localhost:28924
Referer:http://localhost:28924/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Response Headersview source
Cache-Control:private
Content-Length:6333
Content-Type:text/html; charset=utf-8
Date:Wed, 08 Jan 2014 14:32:14 GMT
Server:Microsoft-IIS/8.0
WWW-Authenticate:Negotiate
WWW-Authenticate:NTLM
WWW-Authenticate:Basic realm="localhost"
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcU291cmNlQ29kZVxUcmlhbHNNb2JpbGVcVHJhaWxzTW9iaWxlLldlYlxhcGlcbG9naW4=?=
When the api/login page prompts me for my credentials it gets stuck in an infinite loop. I'll enter them, hit enter, then it asks for them again.
Edit3: Ok, I'm able to authenticate!!! I had to specify the domain in front of my username since I'm running localhost...
Thanks everyone for pointing me in the right direction!

A combination of changes led to fixing my problem:
1) I needed to allow basic authentication in my OWN web.config. I had only previously set it up in the IISExpress applicationhost.config (see Edit(1))
2) Showing the output from Chrome Dev tools proved that the Basic Authentication authorization header was, in fact, being sent across.
3) The last problem was since I'm running on localhost, I needed to specify the domain to authenticate against in my username. There's probably a cleaner way of doing this, but I just entered this in my username field: mydomain\ganders and it started working.

Related

Cookie for domain not being used for subdomains

I use HttpClient in my app to send my user/password to a service that returns some cookies that I can later use for all my other requests. The service is located at https://accounts.dev.example.com/login and returns two cookies that have Domain=.dev.example.com. The issue I'm finding is that, in some machines (Windows Domain Controllers), these cookies are not being used when I request resources in subdomains like https://accounts.dev.example.com/health-check, but according to the MDN docs a cookie for a domain can be used for requesting resources to subdomains:
Domain= Optional
Specifies those hosts to which the cookie will be sent. If not specified, defaults to the host portion of the current document location (but not including subdomains). Contrary to earlier specifications, leading dots in domain names are ignored. If a domain is specified, subdomains are always included.
Do you know how to properly configure HttpClient to pass the domain cookies to subdomain requests?
A bit more of details:
The cookies returned by my authentication service at https://accounts.dev.example.com/login look like this in the HTTP headers:
Set-Cookie: AK=112233;Version=1;Domain=.dev.example.com;Path=/;Max-Age=5400;Secure;HttpOnly,
Set-Cookie: AS=445566;Version=1;Domain=.dev.example.com;Path=/;Max-Age=5400;Secure;HttpOnly,
Then I can query C#'s CookieContainer with either of these calls in normal workstations:
cookies.GetCookies("https://accounts.dev.example.com")
cookies.GetCookies("https://dev.example.com")
Both of which will return the 2 cookies like:
$Version=1; AK=112233; $Path=/; $Domain=.dev.example.com
$Version=1; AS=445566; $Path=/; $Domain=.dev.example.com
But in the other machines (the Domain Controller's) the first call will return an empty list, while the second will return the 2 cookies.
Why this difference on the behaviour of CookieContainer.GetCookies depending on which machine is running the code?
My workstations are using Microsoft Windows 10 Home Single Language (.Net 4.0.30319.42000) and the DCs are using Microsoft Windows Server 2012 R2 Datacenter (.Net 4.0.30319.36399).
The code
This is a modified version of my code:
public static async Task<string> DoAuth(CookieContainer cookies,
Dictionary<string, string> postHeaders,
StringContent postBody)
{
try
{
using (var handler = new HttpClientHandler())
{
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler, true))
{
foreach (var key in postHeaders.Keys)
client.DefaultRequestHeaders.Add(key, postHeaders[key]);
var response = await client.PostAsync("https://accounts.dev.example.com/login", postBody);
response.EnsureSuccessStatusCode();
// This line returns 0 in Domain Controllers, and 2 in all other machines
Console.Write(cookies.GetCookies("https://accounts.dev.example.com").Count);
return await response.Content.ReadAsStringAsync();
}
}
}
catch (HttpRequestException e)
{
...
throw;
}
}
As I couldn't find an answer to this (not in TechNet either), I decided to go with the following solution, which works, but not sure if there is a proper way of solving the issue:
foreach (Cookie cookie in cookies.GetCookies(new Uri("https://dev.example.com")))
{
cookies.Add(new Uri("https://accounts.dev.example.com"), new Cookie(cookie.Name, cookie.Value, cookie.Path, ".accounts.dev.example.com"));
}
So, I'm duplicating the cookie for each one of the subdomains that my app should send these cookies to.
The underlying issue seems to be a bug in the Set-Cookie header. It seems the cause of the issue is the Version= component in the Set-Cookie header. This makes the CookieContainer fall on its face and results in the strange $Version and $Domain cookies then being sent in subsequent client requests. As far as I can tell there is no way to remove these broken cookies either. Iterating GetCookies() with the originating domain does not reveal the erroneous cookies.

Multi-language Google Translate API is returing (503) Server Unavailable

I am trying to use Google Translate to translate but it gives error Server Unavailable. What my guess is that when I try to put same thing in the address bar we receive a captcha to fill in. If we get thru the captcha than only it downloads a txt file. I am thinking this might be the issue of captcha page and not the Server Unavailable.
Calling Function.
string result = TranslateGoogle("Life is great and one is spoiled when it goes on and on and on", "en", "hi");
Console.WriteLine(result);
TranslateGoogle Function
public string TranslateGoogle(string text, string fromCulture, string toCulture)
{
fromCulture = fromCulture.ToLower();
toCulture = toCulture.ToLower();
string[] tokens = fromCulture.Split('-');
if(tokens.Length > 1)
fromCulture = tokens[0];
tokens = toCulture.Split('-');
if(tokens.Length > 1)
toCulture = tokens[0];
string url = string.Format(#"http://translate.google.com/translate_a/t?client=j&text={0}&hl=en&sl={1}&tl={2}", System.Uri.EscapeDataString(text), fromCulture, toCulture);
string html = null;
try
{
WebClient web = new WebClient();
web.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0");
web.Headers.Add(HttpRequestHeader.AcceptCharset, "UTF-8");
web.Encoding = Encoding.UTF8;
html = web.DownloadString(url);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
string result = Regex.Match(html, "trans\":(\".*?\"),\"", RegexOptions.IgnoreCase).Groups[1].Value;
return result;
}
Expected Output
{
"sentences":
[
{
"trans":"जीवन महान है और इस पर और पर और पर चला जाता है जब एक खराब है",
"orig":"Life is great and one is spoiled when it goes on and on and on",
"translit":"Jīvana mahāna hai aura isa para aura para aura para calā jātā hai jaba ēka kharāba hai",
"src_translit":"",
"backend":0
}
],
"src":"en",
"server_time":85
}
This is what I am getting.
"The remote server returned an error: (503) Server Unavailable."
What should I be doing to get the expected output for the program.
Sorry, this is not an answer(but maybe the community can help and let this become a real answer), but I need to post here because in comment I can't format well.
I tried your example and it seems that google thinks that you are trying to abuse their services, here is what client sends:
GET http://translate.google.com/translate_a/t?client=j&text=Life%20is%20great%20and%20one%20is%20spoiled%20when%20it%20goes%20on%20and%20on%20and%20on&hl=en&sl=en&tl=hi HTTP/1.1
Accept-Charset: UTF-8
User-Agent: Mozilla/5.0
Host: translate.google.com
Proxy-Connection: Keep-Alive
Google sends this request to http://ipv4.google.com/sorry/IndexRedirect?continue=http://translate.google.com/translate_a/t%3Fclient%3Dj%26text%3DLife%2520is%2520great%2520and%2520one%2520is%2520spoiled%2520when%2520it%2520goes%2520on%2520and%2520on%2520and%2520on%26hl%3Den%26sl%3Den%26tl%3Dhi&q=CGMSBFgz6X4YkI3frwUiGQDxp4NLo-2RV2k8i7UPzIRYKSuT5usFkUU
here, if navigated from browser it shows captcha, so I tried navigating the url generated by the program using web browser (Firefox).
That's what it shows:
Sorry for the italian, it says that an unusual traffic is coming from the PC.
Once you prompt the captcha correctly your browser saves a cookie for the next requests(so you won't get the captcha again) and you are redirected to the translated sentence.
Here is an example of the browser requests on next navigations:
GET http://translate.google.com/translate_a/t?client=j&text=Life%20is%20great%20and%20one%20is%20spoiled%20when%20it%20goes%20on%20and%20on%20and%20on&hl=en&sl=en&tl=hi HTTP/1.1
Host: translate.google.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: NID=71=a__xJqNU4C1oQTkLrMCSL4CLdR_nelc5kbjcUwgvJUBILn2SOHrfUeIg-9vWfy6tRHVh9Z4yXT1dpwnnHIXf5i2NLlCuDn-joB1tpYo_9JM4_zQnaaYO7UCsFoFILogS8G4XTt1M8esMgUnG_JzoMWSG81Q-JfGk1_IQsb5gIHyHcKroJeNEUp4bnMkiOvZgj1Sk; SID=DQAAAP8AAADnhNjYLtZUYSPbm-V_62WNnlSj8pUKPRnUfLR-Fp18gYeyWsC93YgLn5yoy0L3FLPb2_yNM7ysBQPCnqJGCy6Or6i2WLHicMaVFr0_0LT4xM2KECq3F6Nczc6V7RO8G5VYnHNLXjZ4ZqVMRTfG3E-Ljrgq_0zg_bhi1DT2CeWoBgBFSVTh_cyMjjYdCRiPpyEFRAtUp_48EKmd62YzJHyPeD-JfXTvVlyacDavPzl4L5yf1KmJ37c-j_Px8dYVKHn5tE_jAKHcFjJ717mY85bjyyUasTKoPc_w9AhnVQXE-v-jBsT4rvbJ3khIqiddjagnQ6LpVCMrRwZ9OwU2uubG; HSID=AX4zDBkEvzB-ZdrnV; APISID=ZMLtLIl8PnW6C6X2/A20GPxC9NiRmY3t1T; _ga=GA1.3.1956353841.1435321193; PREF=ID=1111111111111111:FF=0:LD=it:TM=1436338644:LM=1437143045:V=1:S=me455Y_9_LyG2PFU; GOOGLE_ABUSE_EXEMPTION=ID=52cecb7a44e552cc:TM=1442301156:C=c:IP=88.51.233.126-:S=APGng0tXDRxFvrRNJHu-uk3IRqKVpJAIIQ
Connection: keep-alive
As a proof if I add this line to the C# code:
web.Headers.Add(HttpRequestHeader.Cookie, "NID=71=a__xJqNU4C1oQTkLrMCSL4CLdR_nelc5kbjcUwgvJUBILn2SOHrfUeIg-9vWfy6tRHVh9Z4yXT1dpwnnHIXf5i2NLlCuDn-joB1tpYo_9JM4_zQnaaYO7UCsFoFILogS8G4XTt1M8esMgUnG_JzoMWSG81Q-JfGk1_IQsb5gIHyHcKroJeNEUp4bnMkiOvZgj1Sk; SID=DQAAAP8AAADnhNjYLtZUYSPbm-V_62WNnlSj8pUKPRnUfLR-Fp18gYeyWsC93YgLn5yoy0L3FLPb2_yNM7ysBQPCnqJGCy6Or6i2WLHicMaVFr0_0LT4xM2KECq3F6Nczc6V7RO8G5VYnHNLXjZ4ZqVMRTfG3E-Ljrgq_0zg_bhi1DT2CeWoBgBFSVTh_cyMjjYdCRiPpyEFRAtUp_48EKmd62YzJHyPeD-JfXTvVlyacDavPzl4L5yf1KmJ37c-j_Px8dYVKHn5tE_jAKHcFjJ717mY85bjyyUasTKoPc_w9AhnVQXE-v-jBsT4rvbJ3khIqiddjagnQ6LpVCMrRwZ9OwU2uubG; HSID=AX4zDBkEvzB-ZdrnV; APISID=ZMLtLIl8PnW6C6X2/A20GPxC9NiRmY3t1T; _ga=GA1.3.1956353841.1435321193; PREF=ID=1111111111111111:FF=0:LD=it:TM=1436338644:LM=1437143045:V=1:S=me455Y_9_LyG2PFU; GOOGLE_ABUSE_EXEMPTION=ID=52cecb7a44e552cc:TM=1442301156:C=c:IP=88.51.233.126-:S=APGng0tXDRxFvrRNJHu-uk3IRqKVpJAIIQ"); //This is the cookie of the request of Firefox
Google sends the translated sentence "जीवन महान है और इस पर और पर और पर चला जाता है जब एक खराब है"
Here is a project that seems to work, it basically add different parameters in the url.
GoogleTranslator works by directly invoking Google's translation API
called by its online translation form and parsing the results.
I have been trying to use the Google TTS as well, but it doesn't work anymore. The Google Translate v2 doesn't support TTS anymore (see here)
Since you are using C# you could better use the speechsynthesis with System.Speech.Synthesis
public static void TextToSpeech (string utterance)
{
SpeechSynthesizer speaker = new SpeechSynthesizer();
speaker.Speak(utterance);
return;
}
Hope this answers a bit of your question. There are no workarounds for the captcha as of yet.

HTTP Post to Web API 2 - Options request received and handled no further request received

I have a web application using MVC and AngularJS, which connects to a Web API 2 api, that I have set up in a separate project.
Currently I am able to retrieve information from the Api with no problems.
However when I try to do a HTTP Post I am getting no response, originally I was getting a problem with the pre-flight request failing, I have now handled this in my controller, however it does not send the proper request after it has got an OK message back.
I have included my code for the Angular Factory and the C# Controller in the API.
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class RegisterController : ApiController
{
public string Post()
{
return "success";
}
public HttpResponseMessage Options()
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
}
var RegistrationFactory = function($http, $q, ApiAddress) {
return function(model) {
// $http.post(ApiAddress.getApiAddress() + '/Register/Post', model.ToString());
$http({
method: "POST",
url: ApiAddress.getApiAddress() + '/Register/Post',
data: model,
headers: { 'Content-Type': 'application/json; charset=utf-8' }
}).success(function(data) {
$location.path("/");
});
}
};
RegistrationFactory.$inject = ['$http', '$q', 'ApiAddress'];
Edit:
I am still not having any joy with this, however I tested in Internet Explorer and it works with no problems at all.
I have got it working in chrome by starting with web security disabled, however obviously this is not ideal as it will not work on a user PC with security enabled.
I see that you have done adaptation for CORS on the server side. But I cannot see any client side (javascript) adaptation. May be you should add the code below before calling the service.
$http.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
Let me know if this fixes the issue. Worked for me in all scenarios :)
It's strange that your GETs work, but your POSTs don't.
I would recommend running the code in Google Chrome with web security enabled (so we can watch it go wrong) and with the F12 Developer Options shown.
Select the Network tab, run your code, and watch what happens when the POST is called.
Does your service return a "200 OK" status, or some other value ?
Does any kind of Response get returned ?
It might be worth trying this, and appending a screenshot of the results in your original question. It might help to identify the cause.
I am still not having any joy with this, however I tested in Internet
Explorer and it works with no problems at all.
Btw, you don't have any single sign-on stuff setup in your company, do you ? We've had issues where IE works fine, but other browsers don't allow single sign-on. Just a thought...
CORS requires a OPTIONS-preflight which has HTTP headers in its response that tell the browser whether it is allowed to access the resource.
E.g. HTTP Response Headers:
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Origin: *
Because you have a custom Options handler in your C# controller, it seems those HTTP headers are not returned, stopping the browser to make the call after the preflight.
Avoid the Options method, and you should be good.

Digest Authentication Token Invalid after some time

i am just working on my first Windows Phone 8.1 app (Universal if this matters, but only Windows Phone implemented at the moment). And at first all is working very smooth but as soon as my app is running for about 25-30 Minutes I can no longer use my HttpClient. I use the Windows.Web.Http.HttpClient.
In my first trys I used a singleHttpClientand reused it all the time. As I became aware that this is not working I started using a newHttpClient` for each request. But still no luck.
This is my method to get a new HttpClient:
private HttpClient GetClient()
{
var filter = new HttpBaseProtocolFilter
{
AllowUI = false,
CacheControl = { WriteBehavior = HttpCacheWriteBehavior.NoCache },
ServerCredential =
new PasswordCredential(
BaseApiUri.ToString(),
credentials.UserName,
credentials.Password),
};
var httpClient = new HttpClient(filter);
var headers = httpClient.DefaultRequestHeaders;
var httpConnectionOptionHeaderValueCollection = headers.Connection;
httpConnectionOptionHeaderValueCollection.Clear();
headers.Accept.TryParseAdd("application/json");
headers.CacheControl.TryParseAdd("no-cache");
headers.Add("Pragma", "no-cache");
headers.Add("Keep-Alive", "false");
headers.Cookie.Clear();
return httpClient;
}
The extra code setting the headers and clearing cookies are my attempts to stop some kind of caching of connections under the surface that might happen. But still no luck.
My method to make requests my API is like the following:
private async Task<bool> PostNoResponseRequestTo(string relativeUri, object requestContent, CancellationToken cancellationToken)
{
var targetUri = new Uri(BaseApiUri, relativeUri);
var requestJson = JsonConvert.SerializeObject(requestContent);
var content = new HttpStringContent(requestJson, UnicodeEncoding.Utf8, "application/json");
try
{
using (var httpClient = this.GetClient())
{
var post =
await httpClient.PostAsync(targetUri, content).AsTask(cancellationToken).ContinueWith(
async request =>
{
using (var response = await request)
{
return response.IsSuccessStatusCode;
}
},
cancellationToken);
return await post;
}
}
catch (Exception)
{
return false;
}
}
This works fine for about 25-30 Minutes after which the calls to the api suddenly start to fail. I start getting a 401 but as you can see i have specified credentials and because those are working and do not change (hardcoded them to test this) i start believing that the problem is on the API side.
This is the response I get:
StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 2, Content: Windows.Web.Http.HttpStreamContent, Headers:
{
Server: Microsoft-IIS/8.5
Date: Fri, 20 Mar 2015 14:25:06 GMT
WWW-Authenticate: Digest qop="auth",algorithm=MD5-sess,nonce="+Upgraded+NounceRemoved",charset=utf-8,realm="Digest", Negotiate, NTLM
X-Powered-By: ASP.NET
}
{
Content-Length: 1344
Content-Type: text/html
}
My API consists of a Asp.Net project with ServiceStack for its API functionality.
This is running on an IIS with activated digest authentication (all other are disabled).
By inspecting the logs i became aware of a failing API call in front of each successful call. But if i'm right this is by design of digest auth because i have not found a way to tell the client that the other side is using digest auth. I was able to specify this kind of information in my other .Net projects but for some reason Microsoft changed the code (and namespace) for the HttpClient. I am also aware of the HttpClient in the original namespace that you can get through nuget but this is not working for me as i get an error in my output window as soon as i make any call. This closes my app without any kind of information.
Back to the log i was able to get some information with the help of the extended logging and the tool to analyze them. The error is something like (can't access it right now will edit it later):'Invalid token passed to function/method'.
I really hope that someone can help me to solve this problem as it makes the app nearly unusable. My users have to restart the app every 15 Minutes to be on the save site.
Thanks for all advices that help me.
Try Checking the Machine Key setting in IIS. Automatically generate at runtime if tick will generate a new key every time the app pool is restarted. This might be causing your issue. The Machine Key can be set on the server, website or application level. As activated digest authentication is encrypted this might be the issue.
Managing Websites with IIS Manager (part 6) - The Machine Key and Windows Authentication

How to authenticate before a post in C#?

I have a local website (not mine) that requires authentication before doing some queries. The authentication header looks like this:
Host: 192.168.7.9
Connection: keep-alive
Content-Length: 185
Origin: http://192.168.7.9
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/27.0.1453.3 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: */*
DNT: 1
Referer: http://192.168.7.9/signin
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: _FProEnterprise_session=BAh7CzoVbmVlZF93ZWxjb21lX21zZ1Q6D3Nlc3Npb25faWQiJTUxNjI5OGRiMDNmNjU4ZDg4ODE3NmFiZjhmMDU3YTI2OglzaXRlSSIKc2l0ZTAGOgZFRjoObGFuZ19wYXRoSSIHZW4GOwhUOg5vbmVfY2xpY2tGOgx1c2VyX2lkaRE%3D--0c6634a714baa7f0e4795aee89b31f9b7ec0565e
And the request body looks like this:
username=myusername&password=mypassword
I'm not super great with how authentication works. So first, is this forms authentication? I'm guessing it is, since I have to enter my username and password on the site then submit to get in.
Second, why is there a Cookie already there? Is it from a previous session perhaps, and I can ignore it?
My goal is to reproduce this in C#, so that I can authenticate, get the cookie and then post data and retrieve results from this site. At least thats what I think I need to do. Links and code would be super helpful. If it's helpful I need to make this request from my web.api app controller.
You use asp.net membership provider and do the authentication like Membership.ValidateUser() and that will authenticate the formsauthentication also. Check if it is authenticated if (Context.User.Identity.IsAuthenticated) - FormsAuthentication.SignOut();
You need sql server or some kind of authentication mechanism first to save the username and password.
This seems to be an AJAX request (X-Requested-With: XMLHttpRequest). Therefore the user has to be on the web page first, which is when the session started. That is when the user gets the session cookie, which is sent every time to keep track of the session. This session is also kept on the server, where login information is stored - whether or not you're logged in, and who you are.
The contents seem to be a simple HTTP form, but since it came from an XMLHttpRequest it could just as well be created using Javascript. This is at least the standard way to send POST data through HTTP.
That is using plain HTTP authentication and the cookies are from an old session.
http://en.wikipedia.org/wiki/Basic_access_authentication
This link solved it for me:
HERE
My final code (in my web.api controller looked like this):
public static string JsonWithAuth( string url, string data )
{
var bytes = Encoding.Default.GetBytes( data );
using ( var client = new WebClientEx() )
{
var values = new NameValueCollection
{
{ "username", "myUsername" },
{ "password", "myPassword" },
};
// Authenticate
client.UploadValues( "http://192.168.7.9/main/signin", values );
// Post data
var response = client.UploadData( url, "POST", bytes );
return Encoding.Default.GetString( response );
}
}
And this was the class that made it work (from the linked answer):
/// <summary>
/// A custom WebClient featuring a cookie container
/// </summary>
public class WebClientEx : WebClient
{
public CookieContainer CookieContainer { get; private set; }
public WebClientEx()
{
CookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest( Uri address )
{
var request = base.GetWebRequest( address );
if ( request is HttpWebRequest )
{
( request as HttpWebRequest ).CookieContainer = CookieContainer;
}
return request;
}
}
So my final call was like this:
string sampleInfo = JsonWithAuth(
"http://192.168.7.9/samples/sample_locations_list",
"sort=position&dir=ASC&box_id=");
Hope that helps someone else!

Categories

Resources