14 Replies - 1227 Views - Last Post: 03 October 2013 - 05:50 AM Rate Topic: -----

#1 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Automatic Web Interface Login

Posted 26 September 2013 - 10:46 AM

I have a WPF window with a browser in it. I have login data in a database. The user selects a device from the database, then clicks a button to view the device. The application then passes the device data (IPAddress, hostname, login name, password, ect) to a DeviceViewer class, when then opens a new browser control to display the web based device interface. The goal here is to make the login process invisible, using the device credentials stored in the database.

The process to get to and show the interface is working properly, but is stopping at the login screen.

I *think* I need to form some sort of HTTP header? There is a piece of knowledge I am missing here.. what step I need to take to login automatically. I know it can be done, since I have seen examples using the HTTPWebRequest class, but I don't understand the examples I am seeing.

Below are a couple of code examples, of the DeviceViewer class and the Browser class:


Please note on Line 17 where I am trying to develop a working URI to login. I haven't been able to get it to work yet.
class DeviceViewer
    {
        Device targetDevice = new Device();
           
        public DeviceViewer(Device targetDeviceIn)
        {
            targetDevice = targetDeviceIn;
            this.basicLogin();
        }

        //Basic Web Auth
        private void basicLogin()
        {
            String deviceInfo = targetDevice.deviceLocation + " " + targetDevice.deviceHostName + " " + targetDevice.deviceType;
            String url = String.Format("http://{0}", targetDevice.ipAddressString);
                
            //uri = string.Format("http://{0}:{1}@{2}", targetDevice.deviceLoginName, targetDevice.devicePassword, targetDevice.ipAddressString);
        
            Browser wb = new Browser(url, deviceInfo);
            wb.Show();

        }
}//END OF CLASS (NOT REALLY)




And the browser class, just in case my suppression function is hampering me somehow that I'm unaware of.

  public partial class Browser : Window
    {
        public Browser(string URL, string device)
        {
            InitializeComponent();
            lblDevice.Content  = "Viewing " + device;
            this.wb.Navigate(URL);
        }

        //SUPRESS JS ERRORS FROM POORLY WRITTEN WEBSITES
        private void HideScriptErrors(WebBrowser wb, bool Hide)
        {

            FieldInfo fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);

            if (fiComWebBrowser == null) return;

            object objComWebBrowser = fiComWebBrowser.GetValue(wb);

            if (objComWebBrowser == null) return;

            objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { Hide });

        }

          //CALL ERROR SUPRESSION ON NAVIGATE
        private void wb_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
        {
            WebBrowser wb = sender as WebBrowser;
            HideScriptErrors(wb, true);
        }
       

        //return to dashboard
        private void btnDashboard_Click(object sender, RoutedEventArgs e)
        {
            Dashboard dashboard = new Dashboard();
            this.Close();
            dashboard.Show();
        }

        //return to view devices window
        private void btnViewDevices_Click(object sender, RoutedEventArgs e)
        {
            ViewDevice winView = new ViewDevice();
            this.Close();
            winView.Show();
        }    
    }//END CLASS 



Edit: I have been looking for a noob friendly tool that shows me the HTTP requests made when I login to the interface manually. What would you guys recommend?

This post has been edited by synlight: 26 September 2013 - 10:59 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Automatic Web Interface Login

#2 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4577
  • View blog
  • Posts: 8,019
  • Joined: 08-June 10

Re: Automatic Web Interface Login

Posted 26 September 2013 - 11:30 AM

Not sure on the rest, but for your final question, I suggest Fiddler. Very, very useful. Anyone doing any kind of HTTP request work should look into fiddler.
Was This Post Helpful? 0
  • +
  • -

#3 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 26 September 2013 - 11:32 AM

More reply to myself, sorry.. I found Fiddler and figured it out. So here are 2 requests, a GET to go to the login page, and a POST that logged in (do I understand that correctly?)...

So, I need to figure out how to write that in C#..using the HTTPRequest class. If I were able to do that, would I just pass it to the browser like a URL?


Main Interface:
GET http://192.168.1.139/ HTTP/1.1
Host: 192.168.1.139
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.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
Connection: keep-alive




And login..



POST http://192.168.1.139/login.cgi HTTP/1.1
Host: 192.168.1.139
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.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
Referer: http://192.168.1.139/
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 25

name=admin&password=admin



LOL@Curtis we were posting at the same time!

PS Curtis ZOMG Gimme TEH CODEZ!!

This post has been edited by synlight: 26 September 2013 - 11:36 AM

Was This Post Helpful? 0
  • +
  • -

#4 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4577
  • View blog
  • Posts: 8,019
  • Joined: 08-June 10

Re: Automatic Web Interface Login

Posted 26 September 2013 - 11:58 AM

Ha. Well, I actually am this time. I've never used the WebBrowser to post data, but it looks like you can, from the quick test I set up:

void Form1_Load(object sender, EventArgs e)
{
    byte[] postdata = Encoding.UTF8.GetBytes("username=curtis&password=yeahRight");
    webBrowser1.Navigate("http://localhost:60201/Home/Login", null, postdata, "Content-Type: application/x-www-form-urlencoded\r\n");
}



Remember, this is just an example, so you'll have to build your own postdata string.

Notice how at the bottom of your post request, it shows name=admin&password=admin. That's the payload, the form data that it's POSTing. That's basically what you have to replicate.

What I've done is just convert the string into a bytewise representation of itself (in UTF8 encoding) and use it for the postData parameter. It's built just like a query string, so you separate each pair with the ampersand (&). You also have to pass the Content-Type header to let the server know how to read the request.

Hopefully that makes sense.
Was This Post Helpful? 1
  • +
  • -

#5 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 26 September 2013 - 12:09 PM

I was totally kidding with the gimme crap,,, I'm sure you know that or you would have told me to GTFO.

It made sense for the most part, although I'm going to look up bytewise now. I had gone in the direction of using a WebRequest(see code below), but was still scratching my head. Yours makes much more sense.

byte [] buffer;
WebRequest request = WebRequest.Create ("name=admin:password=admin http://192.168.1.139/login.cgi");
request.Method = "POST";
Stream os = request.GetRequestStream();
os.Write(buffer, 0, buffer.Length);
os.Close();  



I guess that would work (the code above), but then I would still have to figure out how to display it in my browser.
Was This Post Helpful? 0
  • +
  • -

#6 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 26 September 2013 - 12:26 PM

OMGOMG IT WORKS!

I'm so excited I just ran up and down the halls yelling "I DID IT"

Maybe I should have yelled "Curtis helped me and it worked!"

That's it!! My prototype works! Well.. it works on that family of devices.. but that's all the boss wanted. My first real non-school related software.

Now i have to test it to death, and fix it a bunch of times, and clean it up A LOT.
But for now... I'm savoring the victory.

...Did I mention I'm EXCITED>?!>! THANK YOU CURTIS!
Was This Post Helpful? 0
  • +
  • -

#7 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4577
  • View blog
  • Posts: 8,019
  • Joined: 08-June 10

Re: Automatic Web Interface Login

Posted 26 September 2013 - 12:27 PM

"bytewise" was probably the wrong wording. What it means is that all characters are actually stored as a byte or sequence of bytes, based on the rules of the particular encoding you use. What the code does is actually let you use that sequence of bytes instead of C#'s abstracted string. I'm not sure why they decided to require a byte array; my guess is that since different web servers support different encodings, they give you the option. For instance, if the web server you were communicating with didn't understand UTF-8, you could use the ASCII encoding.

Don't worry too much about it for now.

For the record, the WebRequest/Response classes are designed to let you do web stuff under the covers. For instance, if you needed to connect to a website, grab some data, and store it, you'd need to get the HTML returned in a string and handle it. That's where you really want to use the WebRequest/Response.

Here's the MSDN page on them:

http://msdn.microsof...webrequest.aspx

They use the Factory Pattern, so you need to cast them to use them as intended (Http/Ftp/File/etc...)

And yeah, I know you were kidding :)/> You're right, I would have closed the thread if I thought you were only interested in getting us to do your work. But I think that sometimes, you just need an example. Sometimes it makes more sense to show than tell.

Edit: It's a great feeling, right? Getting to that point in the project is always a big relief. Just wait until you work with some really big projects. I've been on one that lasted over a year from design to first release. I spent the next almost-year supporting and enhancing it, before getting a new job doing the same thing for someone else :P
Was This Post Helpful? 1
  • +
  • -

#8 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 30 September 2013 - 05:41 AM

Hmm. Last week when I was working on this, I hard coded the data needed to navigate to the URL.

So, now i am trying to clean the process up, and something is happening that I don't understand. Here is how I originally wrote/tested it:


public Browser(string deviceIn)
{
InitializeComponent();
lblDevice.Content  = "Viewing " + deviceIn;

byte[] postdata = Encoding.UTF8.GetBytes("name=admin&password=admin");
wb.Navigate("http://192.168.1.139/login.cgi", null, postdata, "Content-Type: application/x-www-form-urlencoded\r\n");

}



This opened the browser inside my window as desired.

So now I have it thusly:

Device Viewer passing to Browser window:

 class DeviceViewer
    {
        Device targetDevice = new Device();
        
        public DeviceViewer(Device targetDeviceIn)
        {
            targetDevice = targetDeviceIn;

            //string to display in viewing label
                        String deviceInfo = String.Format("{0} {1} {2}", targetDevice.deviceLocation, targetDevice.deviceHostName, targetDevice.deviceType);

    
            //variables needed to form HTTP request within browser           
            Uri url = new Uri ("http://"+targetDevice.ipAddressString);
            string targetFrame = "null";
            byte[] postdata = Encoding.UTF8.GetBytes("name=admin&password=admin");
            string headers = "Content-Type: application/x-www-form-urlencoded\r\n";

            //pass all to browser window for display
            
            Browser winViewer = new Browser(url, targetFrame , postdata , headers, deviceInfo);
            winViewer.Show();
            
        }



And inside the Browser class (the window code behind)

public partial class Browser : Window
    {

       
        Uri url;
        string targetFrame = "";
        byte[] postData;
        string headers = "";
        


        public Browser(Uri urlIn, string targetFrameIn, byte[] postDataIn, string headersIn, string deviceIn)
        {
            url = urlIn;
            targetFrame = targetFrameIn;
            postData = postDataIn;
            headers = headersIn;
            
            
            InitializeComponent();
            lblDevice.Content  = "Viewing " + deviceIn;

        //byte[] postdata = Encoding.UTF8.GetBytes("name=admin&password=admin");
        //wb.Navigate("http://192.168.1.139/login.cgi", null, postdata, "Content-Type: application/x-www-form-urlencoded\r\n");


            wb.Navigate(url,targetFrame ,postData,headers);
        }




The problem is that this is opening a NEW browser window with full IE capabilities. The functionality still works, but why won't it display inside my WPF window when I pass the parameters as variables? I know the WebBrowser control does use IE, but I want that to be invisible to the user.

Posted Image

This post has been edited by synlight: 30 September 2013 - 06:49 AM

Was This Post Helpful? 0
  • +
  • -

#9 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 30 September 2013 - 07:00 AM

Oookay I figured it out! Yay me!

So, the constructor I was using for WebBroswer.Navigate expects a target frame to be passed in as a string. I was passing in the string "null", which is NOT actually null, it is a STRING that contains the letters "null". I changed the call to contain the hardcoded keyword null, and it is now working. I'm going to tweak it a bit to try to pass the keyword null though, since that seems to me the proper way to do things.

Did I get that right? I mean, it works, but I want to make sure I understand it properly. Thank you!!!!
Was This Post Helpful? 0
  • +
  • -

#10 Michael26  Icon User is offline

  • DIC-head, major DIC-head
  • member icon

Reputation: 362
  • View blog
  • Posts: 1,539
  • Joined: 08-April 09

Re: Automatic Web Interface Login

Posted 30 September 2013 - 10:51 AM

If you are having doubts about methods or properties always check MSDN first, don't rely on intellisense to much, that was my beginner mistake.

WebBrowser.Navigate Method

This post has been edited by Michael26: 30 September 2013 - 10:54 AM

Was This Post Helpful? 0
  • +
  • -

#11 Curtis Rutland  Icon User is offline

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4577
  • View blog
  • Posts: 8,019
  • Joined: 08-June 10

Re: Automatic Web Interface Login

Posted 30 September 2013 - 11:10 AM

View Postsynlight, on 30 September 2013 - 09:00 AM, said:

I'm going to tweak it a bit to try to pass the keyword null though, since that seems to me the proper way to do things.

Did I get that right? I mean, it works, but I want to make sure I understand it properly. Thank you!!!!


null is a keyword that represents a literal value (that value being a reference to nothing). That literal is assignable to all reference types (anything defined as a class), so you can pass it just like you would a literal string or any other object.

If you're not sure what null is, exactly, read the following. If you already get it, disregard, and hopefully it'll help someone who hasn't seen it yet:

http://msdn.microsof...y/edakx9da.aspx

To understand null, you have to understand what reference types are and what is special about them. When the following line of code is executed:

string str = "hello world";


You might think that the variable str holds the string "hello world" in it. But that's not entirely accurate. That string value is stored somewhere in memory, and the address of that memory address is stored in the str variable. Most of that is abstracted away for you, so you don't have to think about it.

But since we have a way to represent something, we must also have a way to represent nothing as well. null is similar to the concept of 0 in mathematics. In C# (and many, many other languages), it's a way to say that a variable points to no memory location at all.

That makes it convenient for us to have a constant, common reference to nothing. Actually, in VB.NET, their keyword actually is Nothing (though the internal behavior is slightly different, the concept is identical).
Was This Post Helpful? 1
  • +
  • -

#12 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 02 October 2013 - 02:15 PM

So I'm still playing with this while I wait for new test devices to come in.

When my software navigates to the device IP address, it need to go to ipaddress/login to actually enter the form data. I have it hardcoded to do that, but I was wondering if there was a way for the software to determine what it needs to do from the raw IP address (without hardcoding the additional /login to the end of the IP string. I've been reading here and there, but I'm not seeing anything.

Here is the HTML from the main page:

<form action="login.cgi" method="post" name="loginForm">


So I was thinking I would need to navigate to the page, search through the HTML elements to find the form action tag, then use the data in the form action tag to request a new page? I'll have to figure out how to do the search for the tag and all, but I can do the legwork. I just wanted to see if my logic was sound:

1. Nav to IP Address
2. search for form action tag
3. append form action contents onto IP address
4. Re-navigate

Does that sound like it would work?
Was This Post Helpful? 0
  • +
  • -

#13 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3666
  • View blog
  • Posts: 11,497
  • Joined: 05-May 12

Re: Automatic Web Interface Login

Posted 02 October 2013 - 06:07 PM

Although, I applaud your attempt at making your code more data driven by doing the search for the form action attribute (good planning!), I think that it'll only be a half baked solution. You would also have to parse the contents of the form to know what to compose as the form data to be posted. Since it's very unlikely that you'll go to that extent, and you'll end up pre-formatting the post data with the name and password as variables, you might as well pre-format the URI as well and just have the IP address as the variable.
Was This Post Helpful? 1
  • +
  • -

#14 synlight  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 89
  • View blog
  • Posts: 582
  • Joined: 14-September 11

Re: Automatic Web Interface Login

Posted 03 October 2013 - 05:35 AM

Thanks skydiver! I actually did think about parsing the whole form. Eventually this software will be extended to other types of devices, and I will have to figure out how to determine the field names for username and password, as well as how to post the form data for other types of login. This is probably a year away. In the next couple of weeks the boss wants me to start writing mobile apps (of the current software) for both Android and iPhone.. so I'll spend the next few months learning Objective C and then brushing off my Java skills.

But, back to the original question. I was trying to wrap my mind around how to parse the form totally, since the name and password fields are not universal.. how would one go about accounting for all possibilities? I would have to search for:
"username", "user", "name", "UN", and I'm sure others just to make sure I get a hit to format my request properly.

So, if I am reading your response correctly, I CAN make this work with the logic I laid out? Now i just have to teach myself how to do it. And then, I need to progress to parsing the whole thing to get the username and password field names to completely have this running in a proper way? I can do that, I don't mind the work. I just didn't want to spend days and days trying if someone could tell me off the bat that "no, that won't work because _________"
Was This Post Helpful? 0
  • +
  • -

#15 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3666
  • View blog
  • Posts: 11,497
  • Joined: 05-May 12

Re: Automatic Web Interface Login

Posted 03 October 2013 - 05:50 AM

Ignoring the semantic issue of figuring out if a field named "pass" is actually a field asking for a password vs. asking if the user passed their exam, parsing the HTML has gotten easier if you use the HTML agility pack.

If you are guaranteed that you'll get XHTML, you may get by with treating the HTML as XML to find the fields.

As for the semantic meaning and figuring out which field is which, unless there is a standard that somebody can point to, I think you are left to writing heuristics that will have to guess.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1