aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/UserManager/UserManagerBase.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/UserManager/UserManagerBase.cs')
-rw-r--r--OpenSim/Framework/UserManager/UserManagerBase.cs641
1 files changed, 641 insertions, 0 deletions
diff --git a/OpenSim/Framework/UserManager/UserManagerBase.cs b/OpenSim/Framework/UserManager/UserManagerBase.cs
new file mode 100644
index 0000000..eb46c14
--- /dev/null
+++ b/OpenSim/Framework/UserManager/UserManagerBase.cs
@@ -0,0 +1,641 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Text;
32using OpenSim.Framework.Data;
33using libsecondlife;
34using System.Reflection;
35
36using System.Xml;
37using Nwc.XmlRpc;
38using OpenSim.Framework.Sims;
39using OpenSim.Framework.Inventory;
40using OpenSim.Framework.Utilities;
41
42using System.Security.Cryptography;
43
44namespace OpenSim.Framework.UserManagement
45{
46 public class UserManagerBase
47 {
48 public OpenSim.Framework.Interfaces.UserConfig _config;
49 Dictionary<string, IUserData> _plugins = new Dictionary<string, IUserData>();
50
51 /// <summary>
52 /// Adds a new user server plugin - user servers will be requested in the order they were loaded.
53 /// </summary>
54 /// <param name="FileName">The filename to the user server plugin DLL</param>
55 public void AddPlugin(string FileName)
56 {
57 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Attempting to load " + FileName);
58 Assembly pluginAssembly = Assembly.LoadFrom(FileName);
59
60 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Found " + pluginAssembly.GetTypes().Length + " interfaces.");
61 foreach (Type pluginType in pluginAssembly.GetTypes())
62 {
63 if (!pluginType.IsAbstract)
64 {
65 Type typeInterface = pluginType.GetInterface("IUserData", true);
66
67 if (typeInterface != null)
68 {
69 IUserData plug = (IUserData)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
70 plug.Initialise();
71 this._plugins.Add(plug.getName(), plug);
72 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Userstorage: Added IUserData Interface");
73 }
74
75 typeInterface = null;
76 }
77 }
78
79 pluginAssembly = null;
80 }
81
82 #region Get UserProfile
83 /// <summary>
84 /// Loads a user profile from a database by UUID
85 /// </summary>
86 /// <param name="uuid">The target UUID</param>
87 /// <returns>A user profile</returns>
88 public UserProfileData getUserProfile(LLUUID uuid)
89 {
90 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
91 {
92 try
93 {
94 UserProfileData profile = plugin.Value.getUserByUUID(uuid);
95 profile.currentAgent = getUserAgent(profile.UUID);
96 return profile;
97 }
98 catch (Exception e)
99 {
100 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
101 }
102 }
103
104 return null;
105 }
106
107
108 /// <summary>
109 /// Loads a user profile by name
110 /// </summary>
111 /// <param name="name">The target name</param>
112 /// <returns>A user profile</returns>
113 public UserProfileData getUserProfile(string name)
114 {
115 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
116 {
117 try
118 {
119 UserProfileData profile = plugin.Value.getUserByName(name);
120 profile.currentAgent = getUserAgent(profile.UUID);
121 return profile;
122 }
123 catch (Exception e)
124 {
125 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
126 }
127 }
128
129 return null;
130 }
131
132 /// <summary>
133 /// Loads a user profile by name
134 /// </summary>
135 /// <param name="fname">First name</param>
136 /// <param name="lname">Last name</param>
137 /// <returns>A user profile</returns>
138 public UserProfileData getUserProfile(string fname, string lname)
139 {
140 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
141 {
142 try
143 {
144 UserProfileData profile = plugin.Value.getUserByName(fname,lname);
145 try
146 {
147 profile.currentAgent = getUserAgent(profile.UUID);
148 }
149 catch (Exception e)
150 {
151 // Ignore
152 }
153 return profile;
154 }
155 catch (Exception e)
156 {
157 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
158 }
159 }
160
161 return null;
162 }
163 #endregion
164
165 #region Get UserAgent
166 /// <summary>
167 /// Loads a user agent by uuid (not called directly)
168 /// </summary>
169 /// <param name="uuid">The agents UUID</param>
170 /// <returns>Agent profiles</returns>
171 public UserAgentData getUserAgent(LLUUID uuid)
172 {
173 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
174 {
175 try
176 {
177 return plugin.Value.getAgentByUUID(uuid);
178 }
179 catch (Exception e)
180 {
181 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
182 }
183 }
184
185 return null;
186 }
187
188 /// <summary>
189 /// Loads a user agent by name (not called directly)
190 /// </summary>
191 /// <param name="name">The agents name</param>
192 /// <returns>A user agent</returns>
193 public UserAgentData getUserAgent(string name)
194 {
195 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
196 {
197 try
198 {
199 return plugin.Value.getAgentByName(name);
200 }
201 catch (Exception e)
202 {
203 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
204 }
205 }
206
207 return null;
208 }
209
210 /// <summary>
211 /// Loads a user agent by name (not called directly)
212 /// </summary>
213 /// <param name="fname">The agents firstname</param>
214 /// <param name="lname">The agents lastname</param>
215 /// <returns>A user agent</returns>
216 public UserAgentData getUserAgent(string fname, string lname)
217 {
218 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
219 {
220 try
221 {
222 return plugin.Value.getAgentByName(fname,lname);
223 }
224 catch (Exception e)
225 {
226 OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")");
227 }
228 }
229
230 return null;
231 }
232
233 #endregion
234
235 #region CreateAgent
236 /// <summary>
237 /// Creates and initialises a new user agent - make sure to use CommitAgent when done to submit to the DB
238 /// </summary>
239 /// <param name="profile">The users profile</param>
240 /// <param name="request">The users loginrequest</param>
241 public void CreateAgent(ref UserProfileData profile, XmlRpcRequest request)
242 {
243 Hashtable requestData = (Hashtable)request.Params[0];
244
245 UserAgentData agent = new UserAgentData();
246
247 // User connection
248 agent.agentIP = "";
249 agent.agentOnline = true;
250 agent.agentPort = 0;
251
252 // Generate sessions
253 RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
254 byte[] randDataS = new byte[16];
255 byte[] randDataSS = new byte[16];
256 rand.GetBytes(randDataS);
257 rand.GetBytes(randDataSS);
258
259 agent.secureSessionID = new LLUUID(randDataSS, 0);
260 agent.sessionID = new LLUUID(randDataS, 0);
261
262 // Profile UUID
263 agent.UUID = profile.UUID;
264
265 // Current position (from Home)
266 agent.currentHandle = profile.homeRegion;
267 agent.currentPos = profile.homeLocation;
268
269 // If user specified additional start, use that
270 if (requestData.ContainsKey("start"))
271 {
272 string startLoc = ((string)requestData["start"]).Trim();
273 if (!(startLoc == "last" || startLoc == "home"))
274 {
275 // Format: uri:Ahern&162&213&34
276 try
277 {
278 string[] parts = startLoc.Remove(0, 4).Split('&');
279 string region = parts[0];
280
281 ////////////////////////////////////////////////////
282 //SimProfile SimInfo = new SimProfile();
283 //SimInfo = SimInfo.LoadFromGrid(theUser.currentAgent.currentHandle, _config.GridServerURL, _config.GridSendKey, _config.GridRecvKey);
284 }
285 catch (Exception e)
286 {
287
288 }
289 }
290 }
291
292 // What time did the user login?
293 agent.loginTime = Util.UnixTimeSinceEpoch();
294 agent.logoutTime = 0;
295
296 // Current location
297 agent.regionID = new LLUUID(); // Fill in later
298 agent.currentRegion = new LLUUID(); // Fill in later
299
300 profile.currentAgent = agent;
301 }
302
303 /// <summary>
304 /// Saves a target agent to the database
305 /// </summary>
306 /// <param name="profile">The users profile</param>
307 /// <returns>Successful?</returns>
308 public bool CommitAgent(ref UserProfileData profile)
309 {
310 // Saves the agent to database
311 return true;
312 }
313
314 #endregion
315
316 /// <summary>
317 /// Checks a user against it's password hash
318 /// </summary>
319 /// <param name="profile">The users profile</param>
320 /// <param name="password">The supplied password</param>
321 /// <returns>Authenticated?</returns>
322 public virtual bool AuthenticateUser(ref UserProfileData profile, string password)
323 {
324 OpenSim.Framework.Console.MainLog.Instance.Verbose(
325 "Authenticating " + profile.username + " " + profile.surname);
326
327 password = password.Remove(0, 3); //remove $1$
328
329 string s = Util.Md5Hash(password + ":" + profile.passwordSalt);
330
331 return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase);
332 }
333
334 #region Xml Response
335
336 /// <summary>
337 ///
338 /// </summary>
339 /// <param name="firstname"></param>
340 /// <param name="lastname"></param>
341 /// <returns></returns>
342 public virtual UserProfileData GetTheUser(string firstname, string lastname)
343 {
344 return getUserProfile(firstname, lastname);
345 }
346
347 /// <summary>
348 ///
349 /// </summary>
350 /// <returns></returns>
351 public virtual string GetMessage()
352 {
353 return _config.DefaultStartupMsg;
354 }
355
356 /// <summary>
357 /// Customises the login response and fills in missing values.
358 /// </summary>
359 /// <param name="response">The existing response</param>
360 /// <param name="theUser">The user profile</param>
361 public virtual void CustomiseResponse(ref LoginResponse response, ref UserProfileData theUser)
362 {
363
364 }
365
366 /// <summary>
367 /// Main user login function
368 /// </summary>
369 /// <param name="request">The XMLRPC request</param>
370 /// <returns>The response to send</returns>
371 public XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request)
372 {
373 XmlRpcResponse response = new XmlRpcResponse();
374 Hashtable requestData = (Hashtable)request.Params[0];
375
376 bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && requestData.Contains("passwd"));
377 bool GoodLogin = false;
378 string firstname = "";
379 string lastname = "";
380 string passwd = "";
381
382 UserProfileData TheUser;
383 LoginResponse logResponse = new LoginResponse();
384
385 if (GoodXML)
386 {
387 firstname = (string)requestData["first"];
388 lastname = (string)requestData["last"];
389 passwd = (string)requestData["passwd"];
390
391 TheUser = GetTheUser(firstname, lastname);
392 if (TheUser == null)
393 return logResponse.CreateLoginFailedResponse();
394
395 GoodLogin = AuthenticateUser(ref TheUser, passwd);
396 }
397 else
398 {
399 return logResponse.CreateGridErrorResponse();
400 }
401
402 if (!GoodLogin)
403 {
404 return logResponse.CreateLoginFailedResponse();
405 }
406 else
407 {
408 // If we already have a session...
409 if (TheUser.currentAgent != null && TheUser.currentAgent.agentOnline)
410 {
411 // Reject the login
412 return logResponse.CreateAlreadyLoggedInResponse();
413 }
414 // Otherwise...
415 // Create a new agent session
416 CreateAgent(ref TheUser, request);
417
418 try
419 {
420
421 LLUUID AgentID = TheUser.UUID;
422
423 // Inventory Library Section
424 ArrayList AgentInventoryArray = new ArrayList();
425 Hashtable TempHash;
426
427 AgentInventory Library = new AgentInventory();
428 Library.CreateRootFolder(AgentID, true);
429
430 foreach (InventoryFolder InvFolder in Library.InventoryFolders.Values)
431 {
432 TempHash = new Hashtable();
433 TempHash["name"] = InvFolder.FolderName;
434 TempHash["parent_id"] = InvFolder.ParentID.ToStringHyphenated();
435 TempHash["version"] = (Int32)InvFolder.Version;
436 TempHash["type_default"] = (Int32)InvFolder.DefaultType;
437 TempHash["folder_id"] = InvFolder.FolderID.ToStringHyphenated();
438 AgentInventoryArray.Add(TempHash);
439 }
440
441 Hashtable InventoryRootHash = new Hashtable();
442 InventoryRootHash["folder_id"] = Library.InventoryRoot.FolderID.ToStringHyphenated();
443 ArrayList InventoryRoot = new ArrayList();
444 InventoryRoot.Add(InventoryRootHash);
445
446 // Circuit Code
447 uint circode = (uint)(Util.RandomClass.Next());
448
449 logResponse.Lastname = TheUser.surname;
450 logResponse.Firstname = TheUser.username;
451 logResponse.AgentID = AgentID.ToStringHyphenated();
452 logResponse.SessionID = TheUser.currentAgent.sessionID.ToStringHyphenated();
453 logResponse.SecureSessionID = TheUser.currentAgent.secureSessionID.ToStringHyphenated();
454 logResponse.InventoryRoot = InventoryRoot;
455 logResponse.InventorySkeleton = AgentInventoryArray;
456 logResponse.CircuitCode = (Int32)circode;
457 logResponse.RegionX = 0; //overwritten
458 logResponse.RegionY = 0; //overwritten
459 logResponse.Home = "!!null temporary value {home}!!"; // Overwritten
460 //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n";
461 logResponse.SimAddress = "127.0.0.1"; //overwritten
462 logResponse.SimPort = 0; //overwritten
463 logResponse.Message = this.GetMessage();
464
465 try
466 {
467 this.CustomiseResponse(ref logResponse, ref TheUser);
468 }
469 catch (Exception e)
470 {
471 System.Console.WriteLine(e.ToString());
472 return logResponse.CreateDeadRegionResponse();
473 }
474 CommitAgent(ref TheUser);
475
476 return logResponse.ToXmlRpcResponse();
477
478 }
479 catch (Exception E)
480 {
481 System.Console.WriteLine(E.ToString());
482 }
483 //}
484 }
485 return response;
486
487 }
488
489 #endregion
490
491 /// <summary>
492 /// Deletes an active agent session
493 /// </summary>
494 /// <param name="request">The request</param>
495 /// <param name="path">The path (eg /bork/narf/test)</param>
496 /// <param name="param">Parameters sent</param>
497 /// <returns>Success "OK" else error</returns>
498 public string RestDeleteUserSessionMethod(string request, string path, string param)
499 {
500 // TODO! Important!
501
502 return "OK";
503 }
504
505 /// <summary>
506 ///
507 /// </summary>
508 /// <param name="user"></param>
509 public void AddUserProfile(string firstName, string lastName, string pass, uint regX, uint regY)
510 {
511 UserProfileData user = new UserProfileData();
512 user.homeLocation = new LLVector3(128, 128, 100);
513 user.UUID = LLUUID.Random();
514 user.username = firstName;
515 user.surname = lastName;
516 user.passwordHash = pass;
517 user.passwordSalt = "";
518 user.created = Util.UnixTimeSinceEpoch();
519 user.homeLookAt = new LLVector3(100, 100, 100);
520 user.homeRegion = Util.UIntsToLong((regX * 256), (regY * 256));
521
522 foreach (KeyValuePair<string, IUserData> plugin in _plugins)
523 {
524 try
525 {
526 plugin.Value.addNewUserProfile(user);
527
528 }
529 catch (Exception e)
530 {
531 OpenSim.Framework.Console.MainLog.Instance.Verbose("Unable to add user via " + plugin.Key + "(" + e.ToString() + ")");
532 }
533 }
534 }
535
536 /// <summary>
537 /// Returns an error message that the user could not be found in the database
538 /// </summary>
539 /// <returns>XML string consisting of a error element containing individual error(s)</returns>
540 public string CreateUnknownUserErrorResponse()
541 {
542 System.IO.StringWriter sw = new System.IO.StringWriter();
543 XmlTextWriter xw = new XmlTextWriter(sw);
544
545 // Header
546 xw.Formatting = Formatting.Indented;
547 xw.WriteStartDocument();
548 xw.WriteDocType("error", null, null, null);
549 xw.WriteComment("An error occured");
550 xw.WriteStartElement("error");
551
552 // User
553 xw.WriteElementString("unknownuser", "Unable to find a user with that name");
554
555 // Footer
556 xw.WriteEndElement();
557 xw.Flush();
558 xw.Close();
559
560 return sw.ToString();
561 }
562
563 /// <summary>
564 /// Converts a user profile to an XML element which can be returned
565 /// </summary>
566 /// <param name="profile">The user profile</param>
567 /// <returns>A string containing an XML Document of the user profile</returns>
568 public string ProfileToXml(UserProfileData profile)
569 {
570 System.IO.StringWriter sw = new System.IO.StringWriter();
571 XmlTextWriter xw = new XmlTextWriter(sw);
572
573 // Header
574 xw.Formatting = Formatting.Indented;
575 xw.WriteStartDocument();
576 xw.WriteDocType("userprofile", null, null, null);
577 xw.WriteComment("Found user profiles matching the request");
578 xw.WriteStartElement("users");
579
580 // User
581 xw.WriteStartElement("user");
582 // Account information
583 xw.WriteAttributeString("firstname", profile.username);
584 xw.WriteAttributeString("lastname", profile.surname);
585 xw.WriteAttributeString("uuid", profile.UUID.ToStringHyphenated());
586 // Server Information
587 xw.WriteAttributeString("server_inventory", profile.userInventoryURI);
588 xw.WriteAttributeString("server_asset", profile.userAssetURI);
589 // Profile Information
590 xw.WriteAttributeString("profile_about", profile.profileAboutText);
591 xw.WriteAttributeString("profile_firstlife_about", profile.profileFirstText);
592 xw.WriteAttributeString("profile_firstlife_image", profile.profileFirstImage.ToStringHyphenated());
593 xw.WriteAttributeString("profile_can_do", profile.profileCanDoMask.ToString());
594 xw.WriteAttributeString("profile_want_do", profile.profileWantDoMask.ToString());
595 xw.WriteAttributeString("profile_image", profile.profileImage.ToStringHyphenated());
596 xw.WriteAttributeString("profile_created",profile.created.ToString());
597 xw.WriteAttributeString("profile_lastlogin",profile.lastLogin.ToString());
598 // Home region information
599 xw.WriteAttributeString("home_coordinates", profile.homeLocation.ToString());
600 xw.WriteAttributeString("home_region", profile.homeRegion.ToString());
601 xw.WriteAttributeString("home_look", profile.homeLookAt.ToString());
602
603 xw.WriteEndElement();
604
605 // Footer
606 xw.WriteEndElement();
607 xw.Flush();
608 xw.Close();
609
610 return sw.ToString();
611 }
612
613 #region REST Methods
614 //should most likely move out of here and into the grid's userserver sub class
615 public string RestGetUserMethodName(string request, string path, string param)
616 {
617 UserProfileData userProfile = getUserProfile(param.Trim());
618
619 if (userProfile == null)
620 {
621 return CreateUnknownUserErrorResponse();
622 }
623
624 return ProfileToXml(userProfile);
625 }
626
627 public string RestGetUserMethodUUID(string request, string path, string param)
628 {
629 UserProfileData userProfile = getUserProfile(new LLUUID(param));
630
631 if (userProfile == null)
632 {
633 return CreateUnknownUserErrorResponse();
634 }
635
636 return ProfileToXml(userProfile);
637 }
638 #endregion
639
640 }
641}