views:

258

answers:

5

I am trying to login to this website https://www.virginmobile.com.au programatically (on the right there is a Member Login form).

That form works. But when I do a POST request to the form action (https://www.virginmobile.com.au/selfcare/MyAccount/LogoutLoginPre.jsp) it failed.

It returns a 302, then following up to the new location, it returns 405.

This is my code test1.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.Text;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net;


public partial class test1 : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    string uri = "https://www.virginmobile.com.au/selfcare/MyAccount/LogoutLoginPre.jsp";
    string parameters = "username=0411222333&password=123";

    System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    //req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.0.4506.2152)";
    //req.Referer = "http://www.virginmobile.com.au/";
    //req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    req.AllowAutoRedirect = false;

    // Send the Post
    byte[] paramBytes = Encoding.ASCII.GetBytes(parameters);
    req.ContentLength = paramBytes.Length;
    Stream reqStream = req.GetRequestStream();
    reqStream.Write(paramBytes, 0, paramBytes.Length);   //Send it
    reqStream.Close();

    // Get the response
    HttpWebResponse response = (HttpWebResponse)req.GetResponse();
    if (response == null) throw new Exception("Response is null");

    if (!string.IsNullOrEmpty(response.Headers["Location"]))
    {
      string newLocation = response.Headers["Location"];

      // Request the new location
      req = (HttpWebRequest)WebRequest.Create(newLocation);
      req.Method = "POST";
      req.ContentType = "application/x-www-form-urlencoded";
      //req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.0.4506.2152)";
      //req.Referer = "http://www.virginmobile.com.au/";
      //req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
      req.AllowAutoRedirect = false;
      req.CookieContainer = new CookieContainer();
      req.CookieContainer.Add(response.Cookies);

      // Send the Post
      paramBytes = Encoding.ASCII.GetBytes(parameters);
      req.ContentLength = paramBytes.Length;
      reqStream = req.GetRequestStream();
      reqStream.Write(paramBytes, 0, paramBytes.Length);   //Send it
      reqStream.Close();

      // Get the response
      response = (HttpWebResponse)req.GetResponse(); //**** 405 Method Not Allowed here
    }

    StreamReader sr = new StreamReader(response.GetResponseStream());
    string responseHtml = sr.ReadToEnd().Trim();

    Response.Write(responseHtml);
  }
}

public class MyPolicy : ICertificatePolicy
{
  public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem)
  {
    return true; // Return true to force the certificate to be accepted.
  }
}

Could anyone help me? Thanks in advance!

+1  A: 

The 302 response is trying to redirect you to another page, so the problem might be that your POST data isn't being sent to the redirected page.

Maybe try setting HttpWebRequest.AllowAutoRedirect = false and catch the exception that you get back. Then create another request to the redirected URL (specified in the Location response header) and then issue the request again with the same POST data.

cxfx
Using TamperData, I found out that the real form on virginmobile.com.au also redirects... but I'll try that. Thanks!
It seems to set a cookie. How do you get the "Location" using C#?
You can find the response headers in the WebResponse.Headers property after calling GetResponse(). You can use `request.CookieContainer = new CookieContainer();` to capture to cookie.
cxfx
I am not sure if I passed the cookie correctly<br><code>req.CookieContainer.Add(response.Cookies);</code>But now the second request throws a 405 Method Not Allowed. I updated the code above with my current code.
oops... how do you format this thing
+1  A: 

You are sending pretty few headers with your request. It is very possible that they wrote their script so that it expects certain headers to be present. Headers that I can think of off the top of my head are:

  • User-Agent (identifies your browser and version; you can pretend to be Firefox, for example)
  • Referer (identifies the URL you came from; put the homepage URL in here)
  • Accept-Charset, Accept-Encoding, Accept-Language

but there may be others. You can probably use the Fiddler tool you mentioned to find out what headers Firefox (or whatever browser you’re using) sends with normal (non-HTTPS) requests and then add some of them to your request and see whether that makes it work. (Personally, I use TamperData for this purpose, which is a Firefox plugin.)

Timwi
Thanks Timwi, TamperData is pretty good. It seems to set a cookie. Any idea how I catch the cookie programatically and pass it on to the next request (specified in Location)?
LOL! I honestly didn’t expect that you didn’t take care of the most obvious header, the Cookie. How did you think logins work? :) — I suspect that all you need to do is instantiate a `CookieContainer` and assign it to `req.CookieContainer` for every request. I haven’t tried it, but I expect that the first request will store the cookie in there, and the second request will read it from it.
Timwi
lol I didn't think of that. Thanks you're probably right I'll try it!
Hi Timwi I updated my code above, now got a 405. Any idea? This is how I tried passing the cookie: req.CookieContainer.Add(response.Cookies);
Btw I tried using TamperData and deleted all the request headers except the cookie, and it still worked. That's why I commented out the request headers on my code.
A: 

Resolved: 405 was because I was sending a POST instead of a GET

A: 

Hi,

I'm having the same problem as you were previously having accessing virginmobile and I can't seem to have any luck getting it working. I've changed the Post to a GET but still I'm having no luck, maybe it's something that I've changed wrongly when changing from a POST to a GET. Any chance you could post your working code so I can see where I'm going wrong.

Thanks.

Andy Elks
I don't have the code anymore sorry, what error are you getting?
A: 

I'm getting a 404 error - The remote server returned an error: (404) Not Found. Below is the code I'm getting the error at the same line of code as you were getting the 405 error. If I replace the code with your previous version no 404 is returned but the 405 error is returned.

Thanks

string uri = "https://www.virginmobile.com.au/selfcare/MyAccount/LogoutLoginPre.jsp?username=0466651800&amp;password=160392";
string parameters = "username=0411223344&password=123456";

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "GET";
req.ContentType = "application/x-www-form-urlencoded";
//req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.2)     Gecko/20100316 Firefox/3.6.2 ( .NET CLR 3.0.4506.2152)";
//req.Referer = "http://www.virginmobile.com.au/";
//req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
req.AllowAutoRedirect = false;

// Send the Post
byte[] paramBytes = Encoding.ASCII.GetBytes(parameters);
//req.ContentLength = paramBytes.Length
//Dim reqStream As Stream = req.GetRequestStream()
//reqStream.Write(paramBytes, 0, paramBytes.Length)
//Send it
//reqStream.Close()

// Get the response
HttpWebResponse response__1 = (HttpWebResponse)req.GetResponse();
if (response__1 == null) {
throw new Exception("Response is null");
}

if (!string.IsNullOrEmpty(response__1.Headers("Location"))) {
string newLocation = response__1.Headers("Location");

// Request the new location
req = (HttpWebRequest)WebRequest.Create(newLocation + "?" + parameters);
req.Method = "GET";
req.ContentType = "application/x-www-form-urlencoded";
req.AllowAutoRedirect = false;
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(response__1.Cookies);

// Send the Post
//paramBytes = Encoding.ASCII.GetBytes(parameters)
//req.ContentLength = paramBytes.Length
//Dim reqStream As Stream = req.GetRequestStream()
//reqStream.Write(paramBytes, 0, paramBytes.Length)
//Send it
//reqStream.Close()

// Get the response
//**** The remote server returned an error: (404) Not Found.
response__1 = (HttpWebResponse)req.GetResponse();
}

StreamReader sr = new StreamReader(response__1.GetResponseStream());
string responseHtml = sr.ReadToEnd().Trim();
Andy Elks