aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs')
-rw-r--r--OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs566
1 files changed, 566 insertions, 0 deletions
diff --git a/OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs b/OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs
new file mode 100644
index 0000000..a312445
--- /dev/null
+++ b/OpenGridServices-Source/OpenGridServices.UserServer/UserManager.cs
@@ -0,0 +1,566 @@
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Text;
5using OpenGrid.Framework.Data;
6using libsecondlife;
7using System.Reflection;
8
9using System.Xml;
10using Nwc.XmlRpc;
11using OpenSim.Framework.Sims;
12using OpenSim.Framework.Inventory;
13using OpenSim.Framework.Utilities;
14
15using System.Security.Cryptography;
16
17namespace OpenGridServices.UserServer
18{
19 public class UserManager
20 {
21 public OpenSim.Framework.Interfaces.UserConfig _config;
22 Dictionary<string, IUserData> _plugins = new Dictionary<string, IUserData>();
23
24 /// <summary>
25 /// Adds a new user server plugin - user servers will be requested in the order they were loaded.
26 /// </summary>
27 /// <param name="FileName">The filename to the user server plugin DLL</param>
28 public void AddPlugin(string FileName)
29 {
30 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Userstorage: Attempting to load " + FileName);
31 Assembly pluginAssembly = Assembly.LoadFrom(FileName);
32
33 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Userstorage: Found " + pluginAssembly.GetTypes().Length + " interfaces.");
34 foreach (Type pluginType in pluginAssembly.GetTypes())
35 {
36 if (!pluginType.IsAbstract)
37 {
38 Type typeInterface = pluginType.GetInterface("IUserData", true);
39
40 if (typeInterface != null)
41 {
42 IUserData plug = (IUserData)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
43 plug.Initialise();
44 this._plugins.Add(plug.getName(), plug);
45 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Userstorage: Added IUserData Interface");
46 }
47
48 typeInterface = null;
49 }
50 }
51
52 pluginAssembly = null;
53 }
54
55 /// <summary>
56 /// Loads a user profile from a database by UUID
57 /// </summary>
58 /// <param name="uuid">The target UUID</param>
59 /// <returns>A user profile</returns>
60 public UserProfileData getUserProfile(LLUUID uuid)
61 {
62 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
63 {
64 try
65 {
66 UserProfileData profile = plugin.Value.getUserByUUID(uuid);
67 profile.currentAgent = getUserAgent(profile.UUID);
68 return profile;
69 }
70 catch (Exception e)
71 {
72 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
73 }
74 }
75
76 return null;
77 }
78
79
80 /// <summary>
81 /// Loads a user profile by name
82 /// </summary>
83 /// <param name="name">The target name</param>
84 /// <returns>A user profile</returns>
85 public UserProfileData getUserProfile(string name)
86 {
87 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
88 {
89 try
90 {
91 UserProfileData profile = plugin.Value.getUserByName(name);
92 profile.currentAgent = getUserAgent(profile.UUID);
93 return profile;
94 }
95 catch (Exception e)
96 {
97 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
98 }
99 }
100
101 return null;
102 }
103
104 /// <summary>
105 /// Loads a user profile by name
106 /// </summary>
107 /// <param name="fname">First name</param>
108 /// <param name="lname">Last name</param>
109 /// <returns>A user profile</returns>
110 public UserProfileData getUserProfile(string fname, string lname)
111 {
112 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
113 {
114 try
115 {
116 UserProfileData profile = plugin.Value.getUserByName(fname,lname);
117 try
118 {
119 profile.currentAgent = getUserAgent(profile.UUID);
120 }
121 catch (Exception e)
122 {
123 // Ignore
124 }
125 return profile;
126 }
127 catch (Exception e)
128 {
129 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
130 }
131 }
132
133 return null;
134 }
135
136 /// <summary>
137 /// Loads a user agent by uuid (not called directly)
138 /// </summary>
139 /// <param name="uuid">The agents UUID</param>
140 /// <returns>Agent profiles</returns>
141 public UserAgentData getUserAgent(LLUUID uuid)
142 {
143 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
144 {
145 try
146 {
147 return plugin.Value.getAgentByUUID(uuid);
148 }
149 catch (Exception e)
150 {
151 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
152 }
153 }
154
155 return null;
156 }
157
158 /// <summary>
159 /// Loads a user agent by name (not called directly)
160 /// </summary>
161 /// <param name="name">The agents name</param>
162 /// <returns>A user agent</returns>
163 public UserAgentData getUserAgent(string name)
164 {
165 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
166 {
167 try
168 {
169 return plugin.Value.getAgentByName(name);
170 }
171 catch (Exception e)
172 {
173 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
174 }
175 }
176
177 return null;
178 }
179
180 /// <summary>
181 /// Loads a user agent by name (not called directly)
182 /// </summary>
183 /// <param name="fname">The agents firstname</param>
184 /// <param name="lname">The agents lastname</param>
185 /// <returns>A user agent</returns>
186 public UserAgentData getUserAgent(string fname, string lname)
187 {
188 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
189 {
190 try
191 {
192 return plugin.Value.getAgentByName(fname,lname);
193 }
194 catch (Exception e)
195 {
196 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
197 }
198 }
199
200 return null;
201 }
202
203 /// <summary>
204 /// Creates a error response caused by invalid XML
205 /// </summary>
206 /// <returns>An XMLRPC response</returns>
207 private static XmlRpcResponse CreateErrorConnectingToGridResponse()
208 {
209 XmlRpcResponse response = new XmlRpcResponse();
210 Hashtable ErrorRespData = new Hashtable();
211 ErrorRespData["reason"] = "key";
212 ErrorRespData["message"] = "Error connecting to grid. Could not percieve credentials from login XML.";
213 ErrorRespData["login"] = "false";
214 response.Value = ErrorRespData;
215 return response;
216 }
217
218 /// <summary>
219 /// Creates an error response caused by bad login credentials
220 /// </summary>
221 /// <returns>An XMLRPC response</returns>
222 private static XmlRpcResponse CreateLoginErrorResponse()
223 {
224 XmlRpcResponse response = new XmlRpcResponse();
225 Hashtable ErrorRespData = new Hashtable();
226 ErrorRespData["reason"] = "key";
227 ErrorRespData["message"] = "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.";
228 ErrorRespData["login"] = "false";
229 response.Value = ErrorRespData;
230 return response;
231 }
232
233 /// <summary>
234 /// Creates an error response caused by being logged in already
235 /// </summary>
236 /// <returns>An XMLRPC Response</returns>
237 private static XmlRpcResponse CreateAlreadyLoggedInResponse()
238 {
239 XmlRpcResponse response = new XmlRpcResponse();
240 Hashtable PresenceErrorRespData = new Hashtable();
241 PresenceErrorRespData["reason"] = "presence";
242 PresenceErrorRespData["message"] = "You appear to be already logged in, if this is not the case please wait for your session to timeout, if this takes longer than a few minutes please contact the grid owner";
243 PresenceErrorRespData["login"] = "false";
244 response.Value = PresenceErrorRespData;
245 return response;
246 }
247
248 /// <summary>
249 /// Customises the login response and fills in missing values.
250 /// </summary>
251 /// <param name="response">The existing response</param>
252 /// <param name="theUser">The user profile</param>
253 public virtual void CustomiseResponse(ref Hashtable response, ref UserProfileData theUser)
254 {
255 // Load information from the gridserver
256 SimProfile SimInfo = new SimProfile();
257 SimInfo = SimInfo.LoadFromGrid(theUser.currentAgent.currentHandle, _config.GridServerURL, _config.GridSendKey, _config.GridRecvKey);
258
259 // Customise the response
260 // Home Location
261 response["home"] = "{'region_handle':[r" + (SimInfo.RegionLocX * 256).ToString() + ",r" + (SimInfo.RegionLocY * 256).ToString() + "], " +
262 "'position':[r" + theUser.homeLocation.X.ToString() + ",r" + theUser.homeLocation.Y.ToString() + ",r" + theUser.homeLocation.Z.ToString() + "], " +
263 "'look_at':[r" + theUser.homeLocation.X.ToString() + ",r" + theUser.homeLocation.Y.ToString() + ",r" + theUser.homeLocation.Z.ToString() + "]}";
264
265 // Destination
266 response["sim_ip"] = SimInfo.sim_ip;
267 response["sim_port"] = (Int32)SimInfo.sim_port;
268 response["region_y"] = (Int32)SimInfo.RegionLocY * 256;
269 response["region_x"] = (Int32)SimInfo.RegionLocX * 256;
270
271 // Notify the target of an incoming user
272 Console.WriteLine("Notifying " + SimInfo.regionname + " (" + SimInfo.caps_url + ")");
273
274 // Prepare notification
275 Hashtable SimParams = new Hashtable();
276 SimParams["session_id"] = theUser.currentAgent.sessionID.ToString();
277 SimParams["secure_session_id"] = theUser.currentAgent.secureSessionID.ToString();
278 SimParams["firstname"] = theUser.username;
279 SimParams["lastname"] = theUser.surname;
280 SimParams["agent_id"] = theUser.UUID.ToString();
281 SimParams["circuit_code"] = (Int32)Convert.ToUInt32(response["circuit_code"]);
282 SimParams["startpos_x"] = theUser.currentAgent.currentPos.X.ToString();
283 SimParams["startpos_y"] = theUser.currentAgent.currentPos.Y.ToString();
284 SimParams["startpos_z"] = theUser.currentAgent.currentPos.Z.ToString();
285 ArrayList SendParams = new ArrayList();
286 SendParams.Add(SimParams);
287
288 // Update agent with target sim
289 theUser.currentAgent.currentRegion = SimInfo.UUID;
290 theUser.currentAgent.currentHandle = SimInfo.regionhandle;
291
292 // Send
293 XmlRpcRequest GridReq = new XmlRpcRequest("expect_user", SendParams);
294 XmlRpcResponse GridResp = GridReq.Send(SimInfo.caps_url, 3000);
295 }
296
297 /// <summary>
298 /// Checks a user against it's password hash
299 /// </summary>
300 /// <param name="profile">The users profile</param>
301 /// <param name="password">The supplied password</param>
302 /// <returns>Authenticated?</returns>
303 public bool AuthenticateUser(ref UserProfileData profile, string password)
304 {
305 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(
306 OpenSim.Framework.Console.LogPriority.LOW,
307 "Authenticating " + profile.username + " " + profile.surname);
308
309 password = password.Remove(0, 3); //remove $1$
310
311 string s = Util.Md5Hash(password + ":" + profile.passwordSalt);
312
313 return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase);
314 }
315
316 /// <summary>
317 /// Creates and initialises a new user agent - make sure to use CommitAgent when done to submit to the DB
318 /// </summary>
319 /// <param name="profile">The users profile</param>
320 /// <param name="request">The users loginrequest</param>
321 public void CreateAgent(ref UserProfileData profile, XmlRpcRequest request)
322 {
323 Hashtable requestData = (Hashtable)request.Params[0];
324
325 UserAgentData agent = new UserAgentData();
326
327 // User connection
328 agent.agentIP = "";
329 agent.agentOnline = true;
330 agent.agentPort = 0;
331
332 // Generate sessions
333 RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
334 byte[] randDataS = new byte[16];
335 byte[] randDataSS = new byte[16];
336 rand.GetBytes(randDataS);
337 rand.GetBytes(randDataSS);
338
339 agent.secureSessionID = new LLUUID(randDataSS, 0);
340 agent.sessionID = new LLUUID(randDataS, 0);
341
342 // Profile UUID
343 agent.UUID = profile.UUID;
344
345 // Current position (from Home)
346 agent.currentHandle = profile.homeRegion;
347 agent.currentPos = profile.homeLocation;
348
349 // If user specified additional start, use that
350 if (requestData.ContainsKey("start"))
351 {
352 string startLoc = (string)requestData["start"];
353 if (!(startLoc == "last" || startLoc == "home"))
354 {
355 // Ignore it! Heh.
356 }
357 }
358
359 // What time did the user login?
360 agent.loginTime = Util.UnixTimeSinceEpoch();
361 agent.logoutTime = 0;
362
363 // Current location
364 agent.regionID = new LLUUID(); // Fill in later
365 agent.currentRegion = new LLUUID(); // Fill in later
366
367 profile.currentAgent = agent;
368 }
369
370 /// <summary>
371 /// Saves a target agent to the database
372 /// </summary>
373 /// <param name="profile">The users profile</param>
374 /// <returns>Successful?</returns>
375 public bool CommitAgent(ref UserProfileData profile)
376 {
377 // Saves the agent to database
378 return true;
379 }
380
381 /// <summary>
382 /// Main user login function
383 /// </summary>
384 /// <param name="request">The XMLRPC request</param>
385 /// <returns>The response to send</returns>
386 public XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request)
387 {
388 XmlRpcResponse response = new XmlRpcResponse();
389 Hashtable requestData = (Hashtable)request.Params[0];
390
391 bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && requestData.Contains("passwd"));
392 bool GoodLogin = false;
393 string firstname = "";
394 string lastname = "";
395 string passwd = "";
396
397 UserProfileData TheUser;
398
399 if (GoodXML)
400 {
401 firstname = (string)requestData["first"];
402 lastname = (string)requestData["last"];
403 passwd = (string)requestData["passwd"];
404
405 TheUser = getUserProfile(firstname, lastname);
406 if (TheUser == null)
407 return CreateLoginErrorResponse();
408
409 GoodLogin = AuthenticateUser(ref TheUser, passwd);
410 }
411 else
412 {
413 return CreateErrorConnectingToGridResponse();
414 }
415
416 if (!GoodLogin)
417 {
418 return CreateLoginErrorResponse();
419 }
420 else
421 {
422 // If we already have a session...
423 if (TheUser.currentAgent != null && TheUser.currentAgent.agentOnline)
424 {
425 // Reject the login
426 return CreateAlreadyLoggedInResponse();
427 }
428 // Otherwise...
429 // Create a new agent session
430 CreateAgent(ref TheUser, request);
431
432 try
433 {
434 Hashtable responseData = new Hashtable();
435
436 LLUUID AgentID = TheUser.UUID;
437
438 // Global Texture Section
439 Hashtable GlobalT = new Hashtable();
440 GlobalT["sun_texture_id"] = "cce0f112-878f-4586-a2e2-a8f104bba271";
441 GlobalT["cloud_texture_id"] = "fc4b9f0b-d008-45c6-96a4-01dd947ac621";
442 GlobalT["moon_texture_id"] = "fc4b9f0b-d008-45c6-96a4-01dd947ac621";
443 ArrayList GlobalTextures = new ArrayList();
444 GlobalTextures.Add(GlobalT);
445
446 // Login Flags Section
447 Hashtable LoginFlagsHash = new Hashtable();
448 LoginFlagsHash["daylight_savings"] = "N";
449 LoginFlagsHash["stipend_since_login"] = "N";
450 LoginFlagsHash["gendered"] = "Y";
451 LoginFlagsHash["ever_logged_in"] = "N"; // Should allow male/female av selection
452 ArrayList LoginFlags = new ArrayList();
453 LoginFlags.Add(LoginFlagsHash);
454
455 // UI Customisation Section
456 Hashtable uiconfig = new Hashtable();
457 uiconfig["allow_first_life"] = "Y";
458 ArrayList ui_config = new ArrayList();
459 ui_config.Add(uiconfig);
460
461 // Classified Categories Section
462 Hashtable ClassifiedCategoriesHash = new Hashtable();
463 ClassifiedCategoriesHash["category_name"] = "Generic";
464 ClassifiedCategoriesHash["category_id"] = (Int32)1;
465 ArrayList ClassifiedCategories = new ArrayList();
466 ClassifiedCategories.Add(ClassifiedCategoriesHash);
467
468 // Inventory Library Section
469 ArrayList AgentInventoryArray = new ArrayList();
470 Hashtable TempHash;
471
472 AgentInventory Library = new AgentInventory();
473 Library.CreateRootFolder(AgentID, true);
474
475 foreach (InventoryFolder InvFolder in Library.InventoryFolders.Values)
476 {
477 TempHash = new Hashtable();
478 TempHash["name"] = InvFolder.FolderName;
479 TempHash["parent_id"] = InvFolder.ParentID.ToStringHyphenated();
480 TempHash["version"] = (Int32)InvFolder.Version;
481 TempHash["type_default"] = (Int32)InvFolder.DefaultType;
482 TempHash["folder_id"] = InvFolder.FolderID.ToStringHyphenated();
483 AgentInventoryArray.Add(TempHash);
484 }
485
486 Hashtable InventoryRootHash = new Hashtable();
487 InventoryRootHash["folder_id"] = Library.InventoryRoot.FolderID.ToStringHyphenated();
488 ArrayList InventoryRoot = new ArrayList();
489 InventoryRoot.Add(InventoryRootHash);
490
491 Hashtable InitialOutfitHash = new Hashtable();
492 InitialOutfitHash["folder_name"] = "Nightclub Female";
493 InitialOutfitHash["gender"] = "female";
494 ArrayList InitialOutfit = new ArrayList();
495 InitialOutfit.Add(InitialOutfitHash);
496
497 // Circuit Code
498 uint circode = (uint)(Util.RandomClass.Next());
499
500 // Generics
501 responseData["last_name"] = TheUser.surname;
502 responseData["ui-config"] = ui_config;
503 responseData["sim_ip"] = "127.0.0.1"; //SimInfo.sim_ip.ToString();
504 responseData["login-flags"] = LoginFlags;
505 responseData["global-textures"] = GlobalTextures;
506 responseData["classified_categories"] = ClassifiedCategories;
507 responseData["event_categories"] = new ArrayList();
508 responseData["inventory-skeleton"] = AgentInventoryArray;
509 responseData["inventory-skel-lib"] = new ArrayList();
510 responseData["inventory-root"] = InventoryRoot;
511 responseData["event_notifications"] = new ArrayList();
512 responseData["gestures"] = new ArrayList();
513 responseData["inventory-lib-owner"] = new ArrayList();
514 responseData["initial-outfit"] = InitialOutfit;
515 responseData["seconds_since_epoch"] = (Int32)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
516 responseData["start_location"] = "last";
517 responseData["home"] = "!!null temporary value {home}!!"; // Overwritten
518 responseData["message"] = _config.DefaultStartupMsg;
519 responseData["first_name"] = TheUser.username;
520 responseData["circuit_code"] = (Int32)circode;
521 responseData["sim_port"] = 0; //(Int32)SimInfo.sim_port;
522 responseData["secure_session_id"] = TheUser.currentAgent.secureSessionID.ToStringHyphenated();
523 responseData["look_at"] = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n";
524 responseData["agent_id"] = AgentID.ToStringHyphenated();
525 responseData["region_y"] = (Int32)0; // Overwritten
526 responseData["region_x"] = (Int32)0; // Overwritten
527 responseData["seed_capability"] = "";
528 responseData["agent_access"] = "M";
529 responseData["session_id"] = TheUser.currentAgent.sessionID.ToStringHyphenated();
530 responseData["login"] = "true";
531
532 this.CustomiseResponse(ref responseData, ref TheUser);
533
534 CommitAgent(ref TheUser);
535
536 response.Value = responseData;
537 // TheUser.SendDataToSim(SimInfo);
538 return response;
539
540 }
541 catch (Exception E)
542 {
543 Console.WriteLine(E.ToString());
544 }
545 //}
546 }
547 return response;
548
549 }
550
551 /// <summary>
552 /// Deletes an active agent session
553 /// </summary>
554 /// <param name="request">The request</param>
555 /// <param name="path">The path (eg /bork/narf/test)</param>
556 /// <param name="param">Parameters sent</param>
557 /// <returns>Success "OK" else error</returns>
558 public string RestDeleteUserSessionMethod(string request, string path, string param)
559 {
560 // TODO! Important!
561
562 return "OK";
563 }
564
565 }
566}