I'm trying to send a POST request to an API controller that sets an authentication cookie. I need to retrieve that cookie, but I'm not sure how. What I have:
Sending, from a service:
public static Cookie Authenticate(string username, string url) {
using (var client = new WebClient()) {
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var data = "="+username;
var test = client.UploadString(url, "POST", data);
// get cookie here, converted from HttpCookie
return new Cookie();
}
}
Receiving, on API Controller:
[Route("api/auth")]
[System.Web.Http.AcceptVerbs("POST")]
public HttpCookie SetCookie([FromBody] string username) {
FormsAuthentication.SetAuthCookie(username, true);
return FormsAuthentication.GetAuthCookie(decrypted, true);
}
Currently, this returns what I believe is a string representation of the cookie, which doesn't do me much good. How can I capture the HttpCookie from the WebClient?
WebClient is a high level abstraction that doesn't expose cookies to the consumer.
You have two options:
You can derive your own class from WebClient, override the GetWebResponse method and read the cookies at that point
Or you can just use lower level classes like HttpWebRequest directly.
Related
I am creating an application for data retrieval from the web page. The page is password protected and when the user logs in the cookie is created.
In order to retrieve the data the application first has to log in: make web request with username and password and store the cookie. Then when the cookie is stored it has to be added into the headers of all requests.
Here is the method which makes requests and retrieves the content:
public void getAsyncDailyPDPContextActivationDeactivation()
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(dailyPDPContextActivationDeactivation);
IAsyncResult asyncResult = httpWebRequest.BeginGetResponse(null, null);
asyncResult.AsyncWaitHandle.WaitOne();
using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.EndGetResponse(asyncResult))
using (StreamReader responseStreamReader = new StreamReader(httpWebResponse.GetResponseStream()))
{
string responseText = responseStreamReader.ReadToEnd();
}
}
Does anyone know how to modify this method in order to add a cookie into the header?
I would be also thankful if anyone suggested a way to store cookie from the response (when the application makes a request http:xxx.xxx.xxx/login?username=xxx&password=xxx the cookie is created and has to be stored for future requests).
CookieContainer cookieContainer = new CookieContainer();
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(...);
httpWebRequest.CookieContainer = cookieContainer;
Then you reuse this CookieContainer in subsequent requests:
HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(...);
httpWebRequest2.CookieContainer = cookieContainer;
Use the CookieContainer or you could use a CookieAwareWebClient
My question is how can I do POST request, next get cookie from that request and set it to the next request for example GET type in C#? Please for example code.
I had tried a lot of times, for example by CookieAwareWebClient method but it not working:
public class CookieAwareWebClient : WebClient
{
public CookieContainer CookieContainer { get; set; }
public CookieAwareWebClient()
: base()
{
CookieContainer = new CookieContainer();
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null)
{
webRequest.CookieContainer = CookieContainer;
}
return request;
}
}
What I need? I need to login by POST requests and next do for example 10-20 request POST/GET by the authenticate cookie from first request (login)
I'm doing it by this:
//Create an instance of your new CookieAware Web Client
using (var client = new CookieAwareWebClient())
{
//Authenticate (username and password can be either hard-coded or pulled from a settings area)
var values = new NameValueCollection{{ "UserName", username },{ "Password", password }};
client.UploadValues(new Uri("http://www.yourdomain.com/Account/LogOn/"), "POST", values);
client.UploadString(new Uri("http://www.yourdomain.com/Secure/YourSecureMethod"),
"POST", "Example Message");
}
But I cant set this cookie to my next requests (next reauest creating thier own NEW non-authenticated cookies)
I am creating a proxy page in ASP .NET (I need to get around cross-site scripting limitations). I need the Page_Load handler to send out an HttpWebRequest based on the incoming request to this page.
var request = (HttpWebRequest)WebRequest.Create(urlToProxy);
request.Method = "GET";
request.GetResponse();
I'm running into some authentication problems (yes, I do set request.Credentials correctly, it's just not shown here), however, so I'd like to forward cookies from the incoming request (that hits my proxy page) to this outgoing request. You would think this would be straightforward:
request.CookieContiner = Request.Cookies;
However, this doesn't work. The outgoing HttpWebRequest uses HttpCookies and the incoming HttpRequest uses Cookies. These classes have no inheritance or interface relationship (indeed one is in System.Net, the other in System.Web.)
I've tried to copy the HttpCookies into Cookies and then add them to the CookieContainer, but I can't get this to work either.
public static IEnumerable<Cookie> ToCookies(this HttpCookie cookie)
{
var cookies = new List<Cookie>(cookie.Values.Count);
foreach (String key in cookie.Values)
{
cookies.Add(new Cookie()
{
Domain = cookie.Domain,
Expires = cookie.Expires,
HttpOnly = cookie.HttpOnly,
Name = cookie.Name,
Path = cookie.Path,
Secure = cookie.Secure,
Value = cookie.Values[key]
});
}
return cookies;
}
...
var cookieContainer = new CookieContainer();
foreach(var httpCookie in Request.Cookies)
{
foreach(var cookie in httpCookie.ToCookies())
{
cookieContainer.Add(cookie); //Exception thrown here
}
}
The exception being thrown says that a Cookie cannot be added that has a null "Domain". Apparently, some of the HttpCookies have null "Domain" properties.
Does anyone have any suggestions on the best way around this problem turning HttpCookie into Cookie? I'd like whatever solution I use with to be as general purpose as possible (and thus not involve hardcoding known domains into the new Cookies.)
Even better, is there an easier way to do what I want simply using the HttpRequest class rather than the HttpWebRequest class?
I am trying to access a webpage on a same domain / same asp.net application, that is password protected. Credentials are the same both for webpage firing this call and webpage being accessed.
Here is the code, and I don't know why I always end up with a login form html code?
using (WebClient client = new WebClient())
{
client.QueryString.Add("ID", "1040"); //add parameters
//client.Credentials = CredentialCache.DefaultCredentials;
//I tried to add credentials like this
client.Credentials = new NetworkCredential("username", "password");
string htmlCode = client.DownloadString("http://domain.loc/testpage.aspx");
}
I suspect that the web page that you are trying to access uses Forms Authentication. This means that you will have to provide a valid authentication cookie if you want to be able to access protected resources. And in order to obtain a valid authentication cookie you will have to first authenticate yourself by sending a POST request to the LogOn page which emits the cookie. Once you retrieve the cookie you will be able to send it along on subsequent requests on protected resources. You should also note that out of the box WebClient doesn't support cookies. For this reason you could write a custom cookie aware web client:
public class CookieAwareWebClient : WebClient
{
public CookieAwareWebClient()
{
CookieContainer = new CookieContainer();
}
public CookieContainer CookieContainer { get; private set; }
protected override WebRequest GetWebRequest(Uri address)
{
var request = (HttpWebRequest)base.GetWebRequest(address);
request.CookieContainer = CookieContainer;
return request;
}
}
Now you could use this client to fire off the 2 requests:
using (var client = new CookieAwareWebClient())
{
var values = new NameValueCollection
{
{ "username", "john" },
{ "password", "secret" },
};
client.UploadValues("http://domain.loc/logon.aspx", values);
// If the previous call succeeded we now have a valid authentication cookie
// so we could download the protected page
string result = client.DownloadString("http://domain.loc/testpage.aspx");
}
Obviously due to the ViewState crapiness of ASP.NET you might need to send a couple of other parameters along your logon request. Here's what you could do: authenticate in a web browser and look with FireBug the exact parameters and headers that need to be sent.
I am using a web service that requires authentication from .NET (Visual Studio 2010). According to the documentation, you first request a session identifier from the first web service. I can do that with no problem. Then you are supposed to call the second web service for actually performing your query, passing the session identifier in a cookie. Here is my sample code:
AuthenticateService authenticate_service = new AuthenticateService();
string session_identifier = authenticate_service.Authenticate();
SearchService search_service = new SearchService();
search_service.CookieContainer = new CookieContainer();
Cookie cookie = new Cookie("Cookie", "SID=" + session_identifier, null, search_service.Url);
search_service.CookieContainer.Add(cookie);
search_service.Test();
However, I am getting the following exception on the last line:
System.Web.Services.Protocols.SoapException was unhandled
Message=Session ID cookie value cannot be null or empty string - It is required that the high level Web service client program participate in the session initialized by the server.
Does anybody know how to properly send a cookie with a session ID to a web service?
Just figured it out...
It all had to do with the domain parameter of the Cookie constructor. I was passing search_service.Url because I wasn't sure what it was supposed to be. Apparently it should have been something like "search.google.com". When I passed that to the constructor instead, everything started working as expected.
I found this somewhere along the line. It is a cookie-aware web-client that I have been using. This allows me to have the ease of use of WebClient and pass cookies.
public class CookieAwareWebClient : WebClient
{
private CookieContainer m_container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = m_container;
}
return request;
}
}
Then you can just use the WebClient methods and the cookie is passed automatically after you authenticate.
Example code:
CookieAwareWebClient webClient = new CookieAwareWebClient();
NameValueCollection data = new System.Collections.Specialized.NameValueCollection();
data["user"] = "myusername"; //now holds a user=username map
byte[] response = webClient.UploadValues("http://localhost:8080/somewebservice/auth/","POST", data); //point to the webservice authentication URI
Now you can use webclient.UploadFile or UploadValues or whatever you want assuming that the previous authentication was OK.