PDA

View Full Version : Help with socket.http when authentication is required



Invent
January 10th, 2012, 10:22 PM
OK, rare that I have to actually report surfing the internet, manual, and forum did not solve this one for me, so here goes.

I've got one of these little critters from digital loggers (web/ethernet based power control strip):
http://www.digital-loggers.com/lpc.html

Seems to be a very nice unit. Basically, it uses HTTP commands such as;

http://admin:1234@10.1.1.16/outlet1?=ON

to turn an outlet on, off, get status, etc.

This works perfectly fine from a perl script,



#!/usr/bin/perl -w
use LWP::UserAgent;
use HTTP::Status;
push @{ $ua->requests_redirectable }, 'POST';
push @{ $ua->requests_redirectable }, 'GET';
$ua->get("http://admin:1234@10.1.1.16/outlet1?=ON");


Now, that is obviously simple code using perl and LWP. Additionally, I can log into the web interface, and issue these commands via the browser bar, and they work.

Now, doing things from the command line is lame, obviously, for getting status back and spawning a zillion shell processes, etc.

One would WAY rather use Lua, Girder and the socket.http functions to pull this off, as it would simply be a http GET from within Girder, simplifying many many things.

Except I can't get it to work!

I'm confident it is the authentication. Here is what I've tried;

based on the lua examples pointed to by the Girder manual (points you to here (http://w3.impa.br/~diego/software/luasocket/reference.html) )

I've tried;



local http = require("socket.http")

b, c, h = http.request("http://admin:1234@10.1.1.16/outlet?1=OFF")


which does not error out; and in the variable inspector you can see c get set to "200" (this is good), but you see b set to

"<HTML><HEAD><META HTTP-EQUIV="refresh" content="0; URL=/"></HEAD><BODY></BODY></HTML>"

I think this is BAD, because it is redirection to the root page (where you're greeted, in a browser, with the login prompt if you have not already logged in)

So, I tried things like this;



local http = require ("socket.http")

response = http.request{
url = "http://10.1.1.16/outlet1?=OFF",
user = "admin",
password = "1234"
}


and this




http = require("socket.http")
mime = require("mime")

r, c = http.request {
url = "http://10.1.1.16/outlet1?=OFF",
headers = { authentication = "Basic " .. (mime.b64("admin:1234")) }
}


getting fancier and fancier, eh? Well, they all greet me with "Lua Success (nothing triggered)" in the log, and happily do nothing to the device.

Now, from a browser, I get the following behavior.

1) navigate to 10.1.1.16, get greeted by a login page, login, then enter things like "http://admin:1234@10.1.1.16/outlet?1=OFF" in the browser bar, and things work.
2) logout of the web page at 10.1.1.16, and try those same "http://admin:1234@10.1.1.16/outlet?1=OFF" commands - get redirected to the root page and asked to login; even though I sent the authentication in the browser bar.

SO, here is where my brain is at.

I know this can work, because the uber simple perl script works.
The behavior (from inspecting the lua variables, above) seems identical to the browser behavior if I'm logged out - it is trying to redirect the girder GET to a login page, just like the browser does.

So, Girder/Lua socket.http seems to 'work', but for authentication, it clearly behaves differently than the perl equivalents.

I therefore MUST be doing authentication wrong??

Does anyone have experience doing something like this? Thanks!

Paul

Invent
January 11th, 2012, 11:00 AM
OK, the plot thickens.

I suspect, but can't prove, that this devices is using Digest authentication instead of Basic. I.e., instead of passwords in the clear, it is using MD5 authentication.

This is the source code for the main login page (which is a very simple page);



<html>
<head>
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">

<title>Power Controller </title>

<script language="javascript" src="/md5.js"></script>
<script language="javascript">
<!--
function calcResponse(){
var str;
str=document.login.Challenge.value+document.login. Username.value+document.login.Password.value+docum ent.login.Challenge.value;
document.secin.Password.value = hex_md5(str);
document.secin.Username.value = document.login.Username.value;
document.secin.submit();
}//-->
</script>
</head>
<body>
<noscript>
<table width="100%" border=0>
<tr><td bgcolor=red>&nbsp;</td></tr>
<tr><td align=center><h1>Warning: Insecure Authentication</h1></td></tr>
<tr><td bgcolor=red>&nbsp;</td></tr></table>
</noscript>
<FORM NAME="login" ID="login" ACTION="/login.tgi" METHOD=post>
<TABLE BORDER="0">
<TR>
<TD>User Name</TD>
<TD><INPUT TYPE="text" NAME="Username" VALUE="" SIZE=16 MAXLENGTH=32></TD>
</TR>
<TR>
<TD>Password</TD>
<TD><INPUT TYPE="password" NAME="Password" SIZE=16 MAXLENGTH=32></TD>
</TR>
<TR ALIGN=RIGHT>
<TD></TD>
<TD><INPUT onClick="calcResponse(); return false;" TYPE="Submit" NAME="Submitbtn" VALUE="OK">

<input type="hidden" name="Challenge" value="Nk8LRgk/hTiE+C2">

</TD></TR>
</TABLE>
</FORM>
<script language="javascript">
<!--
document.login.Username.focus();
//-->
</script>
<FORM NAME="secin" ID="secin" ACTION="/login.tgi" METHOD=post>
<INPUT TYPE="hidden" NAME="Username">
<INPUT TYPE="hidden" NAME="Password">
</FORM>
</body>
</html>



Again, it is a blindingly simple web page:

6359

Now, I'm not a whiz at web-magic so I don't know if they're just making an MD5 hash out of the password, and using that, or using full MD5 based Digest authentication.

Anyhow, this is *probably* why the perl and browser approaches work, but the Lua does not (As the socket lua does not appear to support digest authentication)

I will contact the manufacturer, but I think the question now becomes,

Anyone know how to do Digest authentication with Lua??

Thanks,
Paul