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