* This update enables the web_login method.

* Remember, the client doesn't support web_login to other grids in the current RC, however the next RC will.
ThreadPoolClientBranch
Teravus Ovares 2008-01-09 22:05:28 +00:00
parent 49fe4eb3cd
commit 85fe8ed085
6 changed files with 210 additions and 20 deletions

View File

@ -30,6 +30,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using libsecondlife; using libsecondlife;
using libsecondlife.StructuredData; using libsecondlife.StructuredData;
@ -359,21 +360,103 @@ namespace OpenSim.Framework.UserManagement
public Hashtable ProcessHTMLLogin(Hashtable keysvals) public Hashtable ProcessHTMLLogin(Hashtable keysvals)
{ {
// Matches all unspecified characters
// Currently specified,; lowercase letters, upper case letters, numbers, underline
// period, space, parens, and dash.
Regex wfcut = new Regex("[^a-zA-Z0-9_\\.\\$ \\(\\)\\-]");
Hashtable returnactions = new Hashtable(); Hashtable returnactions = new Hashtable();
int statuscode = 200; int statuscode = 200;
returnactions["int_response_code"] = statuscode; string firstname = "";
returnactions["str_response_string"] = GetDefaultLoginForm(); string lastname = "";
string location = "";
string region ="";
string grid = "";
string channel = "";
string version = "";
string lang = "";
string password = "";
string errormessages = "";
// the client requires the HTML form field be named 'username'
// however, the data it sends when it loads the first time is 'firstname'
// another one of those little nuances.
if (keysvals.Contains("firstname"))
firstname = wfcut.Replace((string)keysvals["firstname"],"",99999);
if (keysvals.Contains("username"))
firstname = wfcut.Replace((string)keysvals["username"],"",99999);
if (keysvals.Contains("lastname"))
lastname = wfcut.Replace((string)keysvals["lastname"],"",99999);
if (keysvals.Contains("location"))
location = wfcut.Replace((string)keysvals["location"],"",99999);
if (keysvals.Contains("region"))
region = wfcut.Replace((string)keysvals["region"],"",99999);
if (keysvals.Contains("grid"))
grid = wfcut.Replace((string)keysvals["grid"],"",99999);
if (keysvals.Contains("channel"))
channel = wfcut.Replace((string)keysvals["channel"],"",99999);
if (keysvals.Contains("version"))
version = wfcut.Replace((string)keysvals["version"],"",99999);
if (keysvals.Contains("lang"))
lang = wfcut.Replace((string)keysvals["lang"],"",99999);
if (keysvals.Contains("password"))
password = wfcut.Replace((string)keysvals["password"], "", 99999);
// load our login form.
string loginform = GetLoginForm(firstname,lastname,location,region,grid,channel,version,lang,password,errormessages);
if (keysvals.ContainsKey("show_login_form")) if (keysvals.ContainsKey("show_login_form"))
{ {
if ((string)keysvals["show_login_form"] == "TRUE") if ((string)keysvals["show_login_form"] == "TRUE")
{ {
returnactions["int_response_code"] = statuscode;
returnactions["str_response_string"] = loginform;
} }
else else
{ {
UserProfileData user = GetTheUser(firstname, lastname);
bool goodweblogin = false;
if (user != null)
goodweblogin = AuthenticateUser(user, password);
if (goodweblogin)
{
LLUUID webloginkey = LLUUID.Random();
m_userManager.StoreWebLoginKey(user.UUID, webloginkey);
statuscode = 301;
string redirectURL = "secondlife:///app/login?first_name=" + firstname + "&last_name=" +
lastname +
"&location=" + location + "&grid=Other&web_login_key=" + webloginkey.ToString();
returnactions["int_response_code"] = statuscode;
returnactions["str_redirect_location"] = redirectURL;
returnactions["str_response_string"] = "<HTML><BODY>GoodLogin</BODY></HTML>";
}
else
{
errormessages = "The Username and password supplied did not match our records. Check your caps lock and try again";
loginform = GetLoginForm(firstname, lastname, location, region, grid, channel, version, lang, password, errormessages);
returnactions["int_response_code"] = statuscode;
returnactions["str_response_string"] = loginform;
}
} }
@ -382,16 +465,36 @@ namespace OpenSim.Framework.UserManagement
} }
public string GetLoginForm() public string GetLoginForm(string firstname, string lastname, string location, string region,
string grid, string channel, string version, string lang,
string password, string errormessages)
{ {
// inject our values in the form at the markers
string loginform="";
string file = Path.Combine(Util.configDir(), "http_loginform.html"); string file = Path.Combine(Util.configDir(), "http_loginform.html");
if (!File.Exists(file)) if (!File.Exists(file))
return GetDefaultLoginForm(); {
loginform = GetDefaultLoginForm();
StreamReader sr = File.OpenText(file); }
string result = sr.ReadToEnd(); else
sr.Close(); {
return result; StreamReader sr = File.OpenText(file);
loginform = sr.ReadToEnd();
sr.Close();
}
loginform = loginform.Replace("[$firstname]", firstname);
loginform = loginform.Replace("[$lastname]", lastname);
loginform = loginform.Replace("[$location]", location);
loginform = loginform.Replace("[$region]", region);
loginform = loginform.Replace("[$grid]", grid);
loginform = loginform.Replace("[$channel]", channel);
loginform = loginform.Replace("[$version]", version);
loginform = loginform.Replace("[$lang]", lang);
loginform = loginform.Replace("[$password]", password);
loginform = loginform.Replace("[$errors]", errormessages);
return loginform;
} }
public string GetDefaultLoginForm() public string GetDefaultLoginForm()
@ -405,7 +508,7 @@ namespace OpenSim.Framework.UserManagement
responseString = responseString + "<meta http-equiv=\"cache-control\" content=\"no-cache\">"; responseString = responseString + "<meta http-equiv=\"cache-control\" content=\"no-cache\">";
responseString = responseString + "<meta http-equiv=\"Pragma\" content=\"no-cache\">"; responseString = responseString + "<meta http-equiv=\"Pragma\" content=\"no-cache\">";
responseString = responseString + "<title>Second Life Login</title>"; responseString = responseString + "<title>Second Life Login</title>";
responseString = responseString + "<body>"; responseString = responseString + "<body><br />";
responseString = responseString + "<div id=\"login_box\">"; responseString = responseString + "<div id=\"login_box\">";
responseString = responseString + "<form action=\"/\" method=\"GET\" id=\"login-form\">"; responseString = responseString + "<form action=\"/\" method=\"GET\" id=\"login-form\">";
@ -434,6 +537,11 @@ namespace OpenSim.Framework.UserManagement
responseString = responseString + "<input type=\"hidden\" name=\"show_login_form\" value=\"FALSE\" />"; responseString = responseString + "<input type=\"hidden\" name=\"show_login_form\" value=\"FALSE\" />";
responseString = responseString + "<input type=\"hidden\" name=\"method\" value=\"login\" />"; responseString = responseString + "<input type=\"hidden\" name=\"method\" value=\"login\" />";
responseString = responseString + "<input type=\"hidden\" id=\"grid\" name=\"grid\" value=\"[$grid]\" />"; responseString = responseString + "<input type=\"hidden\" id=\"grid\" name=\"grid\" value=\"[$grid]\" />";
responseString = responseString + "<input type=\"hidden\" id=\"region\" name=\"region\" value=\"[$region]\" />";
responseString = responseString + "<input type=\"hidden\" id=\"location\" name=\"location\" value=\"[$location]\" />";
responseString = responseString + "<input type=\"hidden\" id=\"channel\" name=\"channel\" value=\"[$channel]\" />";
responseString = responseString + "<input type=\"hidden\" id=\"version\" name=\"version\" value=\"[$version]\" />";
responseString = responseString + "<input type=\"hidden\" id=\"lang\" name=\"lang\" value=\"[$lang]\" />";
responseString = responseString + "<div id=\"submitbtn\">"; responseString = responseString + "<div id=\"submitbtn\">";
responseString = responseString + "<input class=\"input_over\" type=\"submit\" value=\"Connect\" />"; responseString = responseString + "<input class=\"input_over\" type=\"submit\" value=\"Connect\" />";
responseString = responseString + "</div>"; responseString = responseString + "</div>";
@ -444,7 +552,7 @@ namespace OpenSim.Framework.UserManagement
responseString = responseString + "<a href=\"http://www.secondlife.com/account/request.php\" target=\"_blank\">Forgot password?</a>"; responseString = responseString + "<a href=\"http://www.secondlife.com/account/request.php\" target=\"_blank\">Forgot password?</a>";
responseString = responseString + "</div>"; responseString = responseString + "</div>";
responseString = responseString + "<div id=\"channelinfo\"> [$clientchannelinfo] | [$clientversion]=[$clientlanguage]</div>"; responseString = responseString + "<div id=\"channelinfo\"> [$channel] | [$version]=[$lang]</div>";
responseString = responseString + "</form>"; responseString = responseString + "</form>";
responseString = responseString + "<script language=\"JavaScript\">"; responseString = responseString + "<script language=\"JavaScript\">";
responseString = responseString + "document.getElementById('firstname_input').focus();"; responseString = responseString + "document.getElementById('firstname_input').focus();";
@ -480,14 +588,26 @@ namespace OpenSim.Framework.UserManagement
"LOGIN", "Authenticating {0} {1} ({2})", profile.username, profile.surname, profile.UUID); "LOGIN", "Authenticating {0} {1} ({2})", profile.username, profile.surname, profile.UUID);
// Web Login method seems to also occasionally send the hashed password itself // Web Login method seems to also occasionally send the hashed password itself
// we do this to get our hash in a form that the server password code can consume
// when the web-login-form submits the password in the clear (supposed to be over SSL!)
if (!password.StartsWith("$1$"))
password = "$1$" + Util.Md5Hash(password);
password = password.Remove(0, 3); //remove $1$ password = password.Remove(0, 3); //remove $1$
string s = Util.Md5Hash(password + ":" + profile.passwordSalt); string s = Util.Md5Hash(password + ":" + profile.passwordSalt);
// Testing...
//MainLog.Instance.Verbose("LOGIN", "SubHash:" + s + " userprofile:" + profile.passwordHash);
//MainLog.Instance.Verbose("LOGIN", "userprofile:" + profile.passwordHash + " SubCT:" + password);
passwordSuccess = (profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) passwordSuccess = (profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
|| profile.passwordHash.Equals(password.ToString(),StringComparison.InvariantCultureIgnoreCase)); || profile.passwordHash.Equals(password,StringComparison.InvariantCultureIgnoreCase));
return passwordSuccess; return passwordSuccess;
} }

View File

@ -389,12 +389,9 @@ namespace OpenSim.Framework.Servers
foreach (string queryname in querystringkeys) foreach (string queryname in querystringkeys)
{ {
keysvals.Add(queryname, request.QueryString[queryname]); keysvals.Add(queryname, request.QueryString[queryname]);
MainLog.Instance.Warn("HTTP", queryname + "=" + request.QueryString[queryname]);
} }
//foreach (string headername in rHeaders)
//{
//MainLog.Instance.Warn("HEADER", headername + "=" + request.Headers[headername]);
//}
if (keysvals.Contains("method")) if (keysvals.Contains("method"))
{ {
MainLog.Instance.Warn("HTTP", "Contains Method"); MainLog.Instance.Warn("HTTP", "Contains Method");

View File

@ -103,6 +103,8 @@ namespace OpenSim.Grid.UserServer
BaseHttpServer httpServer = new BaseHttpServer(Cfg.HttpPort); BaseHttpServer httpServer = new BaseHttpServer(Cfg.HttpPort);
httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod); httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod);
httpServer.AddHTTPHandler("login", m_loginService.ProcessHTMLLogin);
httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod);

View File

@ -323,7 +323,13 @@ namespace OpenSim
m_standaloneAuthenticate); m_standaloneAuthenticate);
m_loginService.OnLoginToRegion += backendService.AddNewSession; m_loginService.OnLoginToRegion += backendService.AddNewSession;
// XMLRPC action
m_httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod); m_httpServer.AddXmlRPCHandler("login_to_simulator", m_loginService.XmlRpcLoginMethod);
// provides the web form login
m_httpServer.AddHTTPHandler("login", m_loginService.ProcessHTMLLogin);
// Provides the LLSD login
m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod);
if (m_standaloneAuthenticate) if (m_standaloneAuthenticate)

View File

@ -103,12 +103,17 @@ namespace OpenSim.Region.Communications.Local
{ {
MainLog.Instance.Notice( MainLog.Instance.Notice(
"LOGIN", "Authenticating " + profile.username + " " + profile.surname); "LOGIN", "Authenticating " + profile.username + " " + profile.surname);
if (!password.StartsWith("$1$"))
password = "$1$" + Util.Md5Hash(password);
password = password.Remove(0, 3); //remove $1$ password = password.Remove(0, 3); //remove $1$
string s = Util.Md5Hash(password + ":" + profile.passwordSalt); string s = Util.Md5Hash(password + ":" + profile.passwordSalt);
return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase); bool loginresult = (profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
|| profile.passwordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase));
return loginresult;
} }
} }

View File

@ -0,0 +1,60 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<title>Second Life Login</title>
<body><br />
<div id="login_box">
<form action="/" method="GET" id="login-form">
<div id="message">[$errors]</div>
<fieldset id="firstname">
<legend>First Name:</legend>
<input type="text" id="firstname_input" size="15" maxlength="100" name="username" value="[$firstname]" />
</fieldset>
<fieldset id="lastname">
<legend>Last Name:</legend>
<input type="text" size="15" maxlength="100" name="lastname" value="[$lastname]" />
</fieldset>
<fieldset id="password">
<legend>Password:</legend>
<table cellspacing="0" cellpadding="0" border="0">
<tr>
<td colspan="2"><input type="password" size="15" maxlength="100" name="password" value="[$password]" /></td>
</tr>
<tr>
<td valign="middle"><input type="checkbox" name="remember_password" id="remember_password" [$remember_password] style="margin-left:0px;"/></td>
<td><label for="remember_password">Remember password</label></td>";
</tr>
</table>
</fieldset>
<input type="hidden" name="show_login_form" value="FALSE" />
<input type="hidden" name="method" value="login" />
<input type="hidden" id="grid" name="grid" value="[$grid]" />
<input type="hidden" id="region" name="region" value="[$region]" />
<input type="hidden" id="location" name="location" value="[$location]" />
<input type="hidden" id="channel" name="channel" value="[$channel]" />
<input type="hidden" id="version" name="version" value="[$version]" />
<input type="hidden" id="lang" name="lang" value="[$lang]" />
<div id="submitbtn">
<input class="input_over" type="submit" value="Connect" />
</div>
<div id="connecting" style="visibility:hidden"> Connecting...</div>
<div id="helplinks">
<a href="http://www.secondlife.com/join/index.php" target="_blank">Create new account</a> |
<a href="http://www.secondlife.com/account/request.php" target="_blank">Forgot password?</a>
</div>
<div id="channelinfo"> [$channel] | [$version]=[$lang]</div>
</form>
<script language="JavaScript">
document.getElementById('firstname_input').focus();
</script>
</div>
</div>
</body>
</html>