UserManagementModule.cs 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.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 OpenSimulator 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. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Concurrent;
  30. using System.IO;
  31. using System.Reflection;
  32. using System.Threading;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Console;
  35. using OpenSim.Framework.Monitoring;
  36. using OpenSim.Region.ClientStack.LindenUDP;
  37. using OpenSim.Region.Framework;
  38. using OpenSim.Region.Framework.Interfaces;
  39. using OpenSim.Region.Framework.Scenes;
  40. using OpenSim.Services.Interfaces;
  41. using OpenSim.Services.Connectors.Hypergrid;
  42. using OpenMetaverse;
  43. using OpenMetaverse.Packets;
  44. using log4net;
  45. using Nini.Config;
  46. using Mono.Addins;
  47. using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
  48. namespace OpenSim.Region.CoreModules.Framework.UserManagement
  49. {
  50. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")]
  51. public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople
  52. {
  53. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  54. protected bool m_Enabled;
  55. protected List<Scene> m_Scenes = new List<Scene>();
  56. protected IServiceThrottleModule m_ServiceThrottle;
  57. // The cache
  58. protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>();
  59. protected bool m_DisplayChangingHomeURI = false;
  60. #region ISharedRegionModule
  61. public virtual void Initialise(IConfigSource config)
  62. {
  63. string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name);
  64. if (umanmod == Name)
  65. {
  66. m_Enabled = true;
  67. Init();
  68. m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
  69. }
  70. if(!m_Enabled)
  71. {
  72. return;
  73. }
  74. IConfig userManagementConfig = config.Configs["UserManagement"];
  75. if (userManagementConfig == null)
  76. return;
  77. m_DisplayChangingHomeURI = userManagementConfig.GetBoolean("DisplayChangingHomeURI", false);
  78. }
  79. public virtual bool IsSharedModule
  80. {
  81. get { return true; }
  82. }
  83. public virtual string Name
  84. {
  85. get { return "BasicUserManagementModule"; }
  86. }
  87. public virtual Type ReplaceableInterface
  88. {
  89. get { return null; }
  90. }
  91. public virtual void AddRegion(Scene scene)
  92. {
  93. if (m_Enabled)
  94. {
  95. lock (m_Scenes)
  96. {
  97. m_Scenes.Add(scene);
  98. }
  99. scene.RegisterModuleInterface<IUserManagement>(this);
  100. scene.RegisterModuleInterface<IPeople>(this);
  101. scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
  102. scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
  103. }
  104. }
  105. public virtual void RemoveRegion(Scene scene)
  106. {
  107. if (m_Enabled)
  108. {
  109. scene.UnregisterModuleInterface<IUserManagement>(this);
  110. lock (m_Scenes)
  111. {
  112. m_Scenes.Remove(scene);
  113. }
  114. }
  115. }
  116. public virtual void RegionLoaded(Scene s)
  117. {
  118. if (m_Enabled && m_ServiceThrottle == null)
  119. m_ServiceThrottle = s.RequestModuleInterface<IServiceThrottleModule>();
  120. }
  121. public virtual void PostInitialise()
  122. {
  123. }
  124. public virtual void Close()
  125. {
  126. lock (m_Scenes)
  127. {
  128. m_Scenes.Clear();
  129. }
  130. lock (m_UserCache)
  131. m_UserCache.Clear();
  132. }
  133. #endregion ISharedRegionModule
  134. #region Event Handlers
  135. protected virtual void EventManager_OnPrimsLoaded(Scene s)
  136. {
  137. // let's sniff all the user names referenced by objects in the scene
  138. m_log.DebugFormat("[USER MANAGEMENT MODULE]: Caching creators' data from {0} ({1} objects)...", s.RegionInfo.RegionName, s.GetEntities().Length);
  139. s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); });
  140. }
  141. protected virtual void EventManager_OnNewClient(IClientAPI client)
  142. {
  143. client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed);
  144. client.OnNameFromUUIDRequest += new UUIDNameRequest(HandleUUIDNameRequest);
  145. client.OnAvatarPickerRequest += new AvatarPickerRequest(HandleAvatarPickerRequest);
  146. }
  147. protected virtual void HandleConnectionClosed(IClientAPI client)
  148. {
  149. client.OnNameFromUUIDRequest -= new UUIDNameRequest(HandleUUIDNameRequest);
  150. client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest);
  151. client.OnConnectionClosed -= new Action<IClientAPI>(HandleConnectionClosed);
  152. }
  153. protected virtual void HandleUUIDNameRequest(UUID uuid, IClientAPI client)
  154. {
  155. // m_log.DebugFormat(
  156. // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}",
  157. // uuid, remote_client.Name);
  158. if(m_Scenes.Count <= 0)
  159. return;
  160. if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
  161. {
  162. client.SendNameReply(uuid, "Mr", "OpenSim");
  163. }
  164. else
  165. {
  166. UserData user;
  167. /* bypass that continuation here when entry is already available */
  168. lock (m_UserCache)
  169. {
  170. if (m_UserCache.TryGetValue(uuid, out user))
  171. {
  172. if (!user.IsUnknownUser && user.HasGridUserTried)
  173. {
  174. client.SendNameReply(uuid, user.FirstName, user.LastName);
  175. return;
  176. }
  177. }
  178. }
  179. // Not found in cache, queue continuation
  180. m_ServiceThrottle.Enqueue("uuidname", uuid.ToString(), delegate
  181. {
  182. //m_log.DebugFormat("[YYY]: Name request {0}", uuid);
  183. // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients
  184. // appear to clear this when the user asks it to clear the cache, but others may not.
  185. //
  186. // So to avoid clients
  187. // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
  188. // instead drop the request entirely.
  189. if(!client.IsActive)
  190. return;
  191. if (GetUser(uuid, client.ScopeId, out user))
  192. {
  193. if(client.IsActive)
  194. client.SendNameReply(uuid, user.FirstName, user.LastName);
  195. }
  196. // else
  197. // m_log.DebugFormat(
  198. // "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
  199. // uuid, client.Name);
  200. });
  201. }
  202. }
  203. public virtual void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query)
  204. {
  205. //EventManager.TriggerAvatarPickerRequest();
  206. m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
  207. List<UserData> users = GetUserData(query, 500, 1);
  208. client.SendAvatarPickerReply(RequestID, users);
  209. }
  210. protected virtual void AddAdditionalUsers(string query, List<UserData> users)
  211. {
  212. }
  213. #endregion Event Handlers
  214. #region IPeople
  215. public virtual List<UserData> GetUserData(string query, int page_size, int page_number)
  216. {
  217. if(m_Scenes.Count <= 0)
  218. return new List<UserData>();;
  219. // search the user accounts service
  220. List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
  221. List<UserData> users = new List<UserData>();
  222. if (accs != null)
  223. {
  224. foreach (UserAccount acc in accs)
  225. {
  226. UserData ud = new UserData();
  227. ud.FirstName = acc.FirstName;
  228. ud.LastName = acc.LastName;
  229. ud.Id = acc.PrincipalID;
  230. ud.HasGridUserTried = true;
  231. ud.IsUnknownUser = false;
  232. users.Add(ud);
  233. }
  234. }
  235. // search the local cache
  236. foreach (UserData data in m_UserCache.Values)
  237. {
  238. if (data.Id != UUID.Zero && !data.IsUnknownUser &&
  239. users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
  240. (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower())))
  241. users.Add(data);
  242. }
  243. AddAdditionalUsers(query, users);
  244. return users;
  245. }
  246. #endregion IPeople
  247. protected virtual void CacheCreators(SceneObjectGroup sog)
  248. {
  249. //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
  250. AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
  251. foreach (SceneObjectPart sop in sog.Parts)
  252. {
  253. AddUser(sop.CreatorID, sop.CreatorData);
  254. foreach (TaskInventoryItem item in sop.TaskInventory.Values)
  255. AddUser(item.CreatorID, item.CreatorData);
  256. }
  257. }
  258. /// <summary>
  259. ///
  260. /// </summary>
  261. /// <param name="uuid"></param>
  262. /// <param name="names">Caller please provide a properly instantiated array for names, string[2]</param>
  263. /// <returns></returns>
  264. protected virtual bool TryGetUserNames(UUID uuid, string[] names)
  265. {
  266. if (names == null)
  267. names = new string[2];
  268. if (TryGetUserNamesFromCache(uuid, names))
  269. return true;
  270. if (TryGetUserNamesFromServices(uuid, names))
  271. return true;
  272. return false;
  273. }
  274. protected virtual bool TryGetUserNamesFromCache(UUID uuid, string[] names)
  275. {
  276. lock (m_UserCache)
  277. {
  278. if (m_UserCache.ContainsKey(uuid))
  279. {
  280. names[0] = m_UserCache[uuid].FirstName;
  281. names[1] = m_UserCache[uuid].LastName;
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287. /// <summary>
  288. /// Try to get the names bound to the given uuid, from the services.
  289. /// </summary>
  290. /// <returns>True if the name was found, false if not.</returns>
  291. /// <param name='uuid'></param>
  292. /// <param name='names'>The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User"</param>
  293. protected virtual bool TryGetUserNamesFromServices(UUID uuid, string[] names)
  294. {
  295. if(m_Scenes.Count <= 0)
  296. return false;
  297. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid);
  298. if (account != null)
  299. {
  300. names[0] = account.FirstName;
  301. names[1] = account.LastName;
  302. UserData user = new UserData();
  303. user.FirstName = account.FirstName;
  304. user.LastName = account.LastName;
  305. lock (m_UserCache)
  306. m_UserCache[uuid] = user;
  307. return true;
  308. }
  309. else
  310. {
  311. // Let's try the GridUser service
  312. GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString());
  313. if (uInfo != null)
  314. {
  315. string url, first, last, tmp;
  316. UUID u;
  317. if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp))
  318. {
  319. AddUser(uuid, first, last, url);
  320. if (m_UserCache.ContainsKey(uuid))
  321. {
  322. names[0] = m_UserCache[uuid].FirstName;
  323. names[1] = m_UserCache[uuid].LastName;
  324. return true;
  325. }
  326. }
  327. else
  328. m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID);
  329. }
  330. // else
  331. // {
  332. // m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid);
  333. // }
  334. names[0] = "Unknown";
  335. names[1] = "UserUMMTGUN9";
  336. return false;
  337. }
  338. }
  339. #region IUserManagement
  340. public virtual UUID GetUserIdByName(string name)
  341. {
  342. string[] parts = name.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
  343. if (parts.Length < 2)
  344. throw new Exception("Name must have 2 components");
  345. return GetUserIdByName(parts[0], parts[1]);
  346. }
  347. public virtual UUID GetUserIdByName(string firstName, string lastName)
  348. {
  349. if(m_Scenes.Count <= 0)
  350. return UUID.Zero;
  351. // TODO: Optimize for reverse lookup if this gets used by non-console commands.
  352. lock (m_UserCache)
  353. {
  354. foreach (UserData user in m_UserCache.Values)
  355. {
  356. if (user.FirstName == firstName && user.LastName == lastName)
  357. return user.Id;
  358. }
  359. }
  360. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName);
  361. if (account != null)
  362. return account.PrincipalID;
  363. return UUID.Zero;
  364. }
  365. public virtual string GetUserName(UUID uuid)
  366. {
  367. UserData user;
  368. GetUser(uuid, out user);
  369. return user.FirstName + " " + user.LastName;
  370. }
  371. public virtual Dictionary<UUID,string> GetUsersNames(string[] ids, UUID scopeID)
  372. {
  373. Dictionary<UUID,string> ret = new Dictionary<UUID,string>();
  374. if(m_Scenes.Count <= 0)
  375. return ret;
  376. List<string> missing = new List<string>();
  377. Dictionary<UUID,string> untried = new Dictionary<UUID, string>();
  378. // look in cache
  379. UserData userdata = new UserData();
  380. UUID uuid = UUID.Zero;
  381. foreach(string id in ids)
  382. {
  383. if(UUID.TryParse(id, out uuid))
  384. {
  385. lock (m_UserCache)
  386. {
  387. if (m_UserCache.TryGetValue(uuid, out userdata) &&
  388. userdata.FirstName != "Unknown" && userdata.FirstName != string.Empty)
  389. {
  390. string name = userdata.FirstName + " " + userdata.LastName;
  391. if(userdata.HasGridUserTried)
  392. ret[uuid] = name;
  393. else
  394. {
  395. untried[uuid] = name;
  396. missing.Add(id);
  397. }
  398. }
  399. else
  400. missing.Add(id);
  401. }
  402. }
  403. }
  404. if(missing.Count == 0)
  405. return ret;
  406. // try user account service
  407. List<UserAccount> accounts = m_Scenes[0].UserAccountService.GetUserAccounts(
  408. scopeID, missing);
  409. if(accounts.Count != 0)
  410. {
  411. foreach(UserAccount uac in accounts)
  412. {
  413. if(uac != null)
  414. {
  415. string name = uac.FirstName + " " + uac.LastName;
  416. ret[uac.PrincipalID] = name;
  417. missing.Remove(uac.PrincipalID.ToString()); // slowww
  418. untried.Remove(uac.PrincipalID);
  419. userdata = new UserData();
  420. userdata.Id = uac.PrincipalID;
  421. userdata.FirstName = uac.FirstName;
  422. userdata.LastName = uac.LastName;
  423. userdata.HomeURL = string.Empty;
  424. userdata.IsUnknownUser = false;
  425. userdata.HasGridUserTried = true;
  426. lock (m_UserCache)
  427. m_UserCache[uac.PrincipalID] = userdata;
  428. }
  429. }
  430. }
  431. if (missing.Count == 0 || m_Scenes[0].GridUserService == null)
  432. return ret;
  433. // try grid user service
  434. GridUserInfo[] pinfos = m_Scenes[0].GridUserService.GetGridUserInfo(missing.ToArray());
  435. if(pinfos.Length > 0)
  436. {
  437. foreach(GridUserInfo uInfo in pinfos)
  438. {
  439. if (uInfo != null)
  440. {
  441. string url, first, last, tmp;
  442. if(uInfo.UserID.Length <= 36)
  443. continue;
  444. if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out uuid, out url, out first, out last, out tmp))
  445. {
  446. if (url != string.Empty)
  447. {
  448. try
  449. {
  450. userdata = new UserData();
  451. userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
  452. userdata.LastName = "@" + new Uri(url).Authority;
  453. userdata.Id = uuid;
  454. userdata.HomeURL = url;
  455. userdata.IsUnknownUser = false;
  456. userdata.HasGridUserTried = true;
  457. lock (m_UserCache)
  458. m_UserCache[uuid] = userdata;
  459. string name = userdata.FirstName + " " + userdata.LastName;
  460. ret[uuid] = name;
  461. missing.Remove(uuid.ToString());
  462. untried.Remove(uuid);
  463. }
  464. catch
  465. {
  466. }
  467. }
  468. }
  469. }
  470. }
  471. }
  472. // add the untried in cache that still failed
  473. if(untried.Count > 0)
  474. {
  475. foreach(KeyValuePair<UUID, string> kvp in untried)
  476. {
  477. ret[kvp.Key] = kvp.Value;
  478. missing.Remove((kvp.Key).ToString());
  479. }
  480. }
  481. // add the UMMthings ( not sure we should)
  482. if(missing.Count > 0)
  483. {
  484. foreach(string id in missing)
  485. {
  486. if(UUID.TryParse(id, out uuid) && uuid != UUID.Zero)
  487. {
  488. if (m_Scenes[0].LibraryService != null &&
  489. (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
  490. ret[uuid] = "Mr OpenSim";
  491. else
  492. ret[uuid] = "Unknown UserUMMAU43";
  493. }
  494. }
  495. }
  496. return ret;
  497. }
  498. public virtual string GetUserHomeURL(UUID userID)
  499. {
  500. UserData user;
  501. if(GetUser(userID, out user))
  502. {
  503. return user.HomeURL;
  504. }
  505. return string.Empty;
  506. }
  507. public virtual string GetUserServerURL(UUID userID, string serverType)
  508. {
  509. UserData userdata;
  510. if(!GetUser(userID, out userdata))
  511. {
  512. return string.Empty;
  513. }
  514. if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
  515. {
  516. return userdata.ServerURLs[serverType].ToString();
  517. }
  518. if (!string.IsNullOrEmpty(userdata.HomeURL))
  519. {
  520. // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID);
  521. UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
  522. try
  523. {
  524. userdata.ServerURLs = uConn.GetServerURLs(userID);
  525. }
  526. catch(System.Net.WebException e)
  527. {
  528. m_log.DebugFormat("[USER MANAGEMENT MODULE]: GetServerURLs call failed {0}", e.Message);
  529. userdata.ServerURLs = new Dictionary<string, object>();
  530. }
  531. catch (Exception e)
  532. {
  533. m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
  534. userdata.ServerURLs = new Dictionary<string, object>();
  535. }
  536. if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
  537. return userdata.ServerURLs[serverType].ToString();
  538. }
  539. return string.Empty;
  540. }
  541. public virtual string GetUserUUI(UUID userID)
  542. {
  543. string uui;
  544. GetUserUUI(userID, out uui);
  545. return uui;
  546. }
  547. public virtual bool GetUserUUI(UUID userID, out string uui)
  548. {
  549. UserData ud;
  550. bool result = GetUser(userID, out ud);
  551. if (ud != null)
  552. {
  553. string homeURL = ud.HomeURL;
  554. string first = ud.FirstName, last = ud.LastName;
  555. if (ud.LastName.StartsWith("@"))
  556. {
  557. string[] parts = ud.FirstName.Split('.');
  558. if (parts.Length >= 2)
  559. {
  560. first = parts[0];
  561. last = parts[1];
  562. }
  563. uui = userID + ";" + homeURL + ";" + first + " " + last;
  564. return result;
  565. }
  566. }
  567. uui = userID.ToString();
  568. return result;
  569. }
  570. #region Cache Management
  571. public virtual bool GetUser(UUID uuid, out UserData userdata)
  572. {
  573. if (m_Scenes.Count <= 0)
  574. {
  575. userdata = new UserData();
  576. return false;
  577. }
  578. return GetUser(uuid, m_Scenes[0].RegionInfo.ScopeID, out userdata);
  579. }
  580. public virtual bool GetUser(UUID uuid, UUID scopeID, out UserData userdata)
  581. {
  582. if (m_Scenes.Count <= 0)
  583. {
  584. userdata = new UserData();
  585. return false;
  586. }
  587. lock (m_UserCache)
  588. {
  589. if (m_UserCache.TryGetValue(uuid, out userdata))
  590. {
  591. if (userdata.HasGridUserTried)
  592. {
  593. return true;
  594. }
  595. }
  596. else
  597. {
  598. userdata = new UserData();
  599. userdata.Id = uuid;
  600. userdata.FirstName = "Unknown";
  601. userdata.LastName = "UserUMMAU42";
  602. userdata.HomeURL = string.Empty;
  603. userdata.IsUnknownUser = true;
  604. userdata.HasGridUserTried = false;
  605. }
  606. }
  607. /* BEGIN: do not wrap this code in any lock here
  608. * There are HTTP calls in here.
  609. */
  610. if (!userdata.HasGridUserTried)
  611. {
  612. /* rewrite here */
  613. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(scopeID, uuid);
  614. if (account != null)
  615. {
  616. userdata.FirstName = account.FirstName;
  617. userdata.LastName = account.LastName;
  618. userdata.HomeURL = string.Empty;
  619. userdata.IsUnknownUser = false;
  620. userdata.HasGridUserTried = true;
  621. }
  622. }
  623. if (!userdata.HasGridUserTried)
  624. {
  625. GridUserInfo uInfo = null;
  626. if (null != m_Scenes[0].GridUserService)
  627. {
  628. uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString());
  629. }
  630. if (uInfo != null)
  631. {
  632. string url, first, last, tmp;
  633. UUID u;
  634. if(uInfo.UserID.Length <= 36)
  635. {
  636. /* not a UUI */
  637. }
  638. else if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp))
  639. {
  640. if (url != string.Empty)
  641. {
  642. userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
  643. userdata.HomeURL = url;
  644. try
  645. {
  646. userdata.LastName = "@" + new Uri(url).Authority;
  647. userdata.IsUnknownUser = false;
  648. }
  649. catch
  650. {
  651. userdata.LastName = "@unknown";
  652. }
  653. userdata.HasGridUserTried = true;
  654. }
  655. }
  656. else
  657. m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID);
  658. }
  659. }
  660. /* END: do not wrap this code in any lock here */
  661. lock (m_UserCache)
  662. {
  663. m_UserCache[uuid] = userdata;
  664. }
  665. return !userdata.IsUnknownUser;
  666. }
  667. public virtual void AddUser(UUID uuid, string first, string last, bool isNPC = false)
  668. {
  669. lock (m_UserCache)
  670. {
  671. if (!m_UserCache.ContainsKey(uuid))
  672. {
  673. UserData user = new UserData();
  674. user.Id = uuid;
  675. user.FirstName = first;
  676. user.LastName = last;
  677. user.IsUnknownUser = false;
  678. user.HasGridUserTried = isNPC;
  679. m_UserCache.Add(uuid, user);
  680. }
  681. }
  682. }
  683. public virtual void AddUser(UUID uuid, string first, string last, string homeURL)
  684. {
  685. //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
  686. UserData oldUser;
  687. lock (m_UserCache)
  688. {
  689. if (m_UserCache.TryGetValue(uuid, out oldUser))
  690. {
  691. if (!oldUser.IsUnknownUser)
  692. {
  693. if (homeURL != oldUser.HomeURL && m_DisplayChangingHomeURI)
  694. {
  695. m_log.DebugFormat("[USER MANAGEMENT MODULE]: Different HomeURI for {0} {1} ({2}): {3} and {4}",
  696. first, last, uuid.ToString(), homeURL, oldUser.HomeURL);
  697. }
  698. /* no update needed */
  699. return;
  700. }
  701. }
  702. else if(!m_UserCache.ContainsKey(uuid))
  703. {
  704. oldUser = new UserData();
  705. oldUser.HasGridUserTried = false;
  706. oldUser.IsUnknownUser = false;
  707. if (homeURL != string.Empty)
  708. {
  709. oldUser.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
  710. try
  711. {
  712. oldUser.LastName = "@" + new Uri(homeURL).Authority;
  713. oldUser.IsUnknownUser = false;
  714. }
  715. catch
  716. {
  717. oldUser.LastName = "@unknown";
  718. }
  719. }
  720. else
  721. {
  722. oldUser.FirstName = first;
  723. oldUser.LastName = last;
  724. }
  725. oldUser.HomeURL = homeURL;
  726. oldUser.Id = uuid;
  727. m_UserCache.Add(uuid, oldUser);
  728. }
  729. }
  730. }
  731. public virtual void AddUser(UUID id, string creatorData)
  732. {
  733. // m_log.InfoFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
  734. if(string.IsNullOrEmpty(creatorData))
  735. {
  736. AddUser(id, string.Empty, string.Empty, string.Empty);
  737. }
  738. else
  739. {
  740. string homeURL;
  741. string firstname = string.Empty;
  742. string lastname = string.Empty;
  743. //creatorData = <endpoint>;<name>
  744. string[] parts = creatorData.Split(';');
  745. if(parts.Length > 1)
  746. {
  747. string[] nameparts = parts[1].Split(' ');
  748. firstname = nameparts[0];
  749. for(int xi = 1; xi < nameparts.Length; ++xi)
  750. {
  751. if(xi != 1)
  752. {
  753. lastname += " ";
  754. }
  755. lastname += nameparts[xi];
  756. }
  757. }
  758. else
  759. {
  760. firstname = "Unknown";
  761. lastname = "UserUMMAU5";
  762. }
  763. if (parts.Length >= 1)
  764. {
  765. homeURL = parts[0];
  766. if(Uri.IsWellFormedUriString(homeURL, UriKind.Absolute))
  767. {
  768. AddUser(id, firstname, lastname, homeURL);
  769. }
  770. else
  771. {
  772. m_log.DebugFormat("[SCENE]: Unable to parse Uri {0} for CreatorID {1}", parts[0], creatorData);
  773. lock (m_UserCache)
  774. {
  775. if(!m_UserCache.ContainsKey(id))
  776. {
  777. UserData newUser = new UserData();
  778. newUser.Id = id;
  779. newUser.FirstName = firstname + "." + lastname.Replace(' ', '.');
  780. newUser.LastName = "@unknown";
  781. newUser.HomeURL = string.Empty;
  782. newUser.HasGridUserTried = false;
  783. newUser.IsUnknownUser = true; /* we mark those users as Unknown user so a re-retrieve may be activated */
  784. m_UserCache.Add(id, newUser);
  785. }
  786. }
  787. }
  788. }
  789. else
  790. {
  791. lock(m_UserCache)
  792. {
  793. if(!m_UserCache.ContainsKey(id))
  794. {
  795. UserData newUser = new UserData();
  796. newUser.Id = id;
  797. newUser.FirstName = "Unknown";
  798. newUser.LastName = "UserUMMAU4";
  799. newUser.HomeURL = string.Empty;
  800. newUser.IsUnknownUser = true;
  801. newUser.HasGridUserTried = false;
  802. m_UserCache.Add(id, newUser);
  803. }
  804. }
  805. }
  806. }
  807. }
  808. public bool RemoveUser(UUID uuid)
  809. {
  810. lock (m_UserCache)
  811. {
  812. return m_UserCache.Remove(uuid);
  813. }
  814. }
  815. #endregion
  816. public virtual bool IsLocalGridUser(UUID uuid)
  817. {
  818. lock (m_Scenes)
  819. {
  820. if (m_Scenes.Count == 0)
  821. return true;
  822. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid);
  823. if (account == null || (account != null && !account.LocalToGrid))
  824. return false;
  825. }
  826. return true;
  827. }
  828. #endregion IUserManagement
  829. protected virtual void Init()
  830. {
  831. AddUser(UUID.Zero, "Unknown", "User");
  832. RegisterConsoleCmds();
  833. }
  834. protected virtual void RegisterConsoleCmds()
  835. {
  836. MainConsole.Instance.Commands.AddCommand("Users", true,
  837. "show name",
  838. "show name <uuid>",
  839. "Show the bindings between a single user UUID and a user name",
  840. String.Empty,
  841. HandleShowUser);
  842. MainConsole.Instance.Commands.AddCommand("Users", true,
  843. "show names",
  844. "show names",
  845. "Show the bindings between user UUIDs and user names",
  846. String.Empty,
  847. HandleShowUsers);
  848. MainConsole.Instance.Commands.AddCommand("Users", true,
  849. "reset user cache",
  850. "reset user cache",
  851. "reset user cache to allow changed settings to be applied",
  852. String.Empty,
  853. HandleResetUserCache);
  854. }
  855. protected virtual void HandleResetUserCache(string module, string[] cmd)
  856. {
  857. lock(m_UserCache)
  858. {
  859. m_UserCache.Clear();
  860. }
  861. }
  862. protected virtual void HandleShowUser(string module, string[] cmd)
  863. {
  864. if (cmd.Length < 3)
  865. {
  866. MainConsole.Instance.Output("Usage: show name <uuid>");
  867. return;
  868. }
  869. UUID userId;
  870. if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId))
  871. return;
  872. UserData ud;
  873. if(!GetUser(userId, out ud))
  874. {
  875. MainConsole.Instance.Output("No name known for user with id {0}", userId);
  876. return;
  877. }
  878. ConsoleDisplayTable cdt = new ConsoleDisplayTable();
  879. cdt.AddColumn("UUID", 36);
  880. cdt.AddColumn("Name", 30);
  881. cdt.AddColumn("HomeURL", 40);
  882. cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL);
  883. MainConsole.Instance.Output(cdt.ToString());
  884. }
  885. protected virtual void HandleShowUsers(string module, string[] cmd)
  886. {
  887. ConsoleDisplayTable cdt = new ConsoleDisplayTable();
  888. cdt.AddColumn("UUID", 36);
  889. cdt.AddColumn("Name", 30);
  890. cdt.AddColumn("HomeURL", 40);
  891. cdt.AddColumn("Checked", 10);
  892. Dictionary<UUID, UserData> copyDict;
  893. lock(m_UserCache)
  894. {
  895. copyDict = new Dictionary<UUID, UserData>(m_UserCache);
  896. }
  897. foreach(KeyValuePair<UUID, UserData> kvp in copyDict)
  898. {
  899. cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL, kvp.Value.HasGridUserTried ? "yes" : "no");
  900. }
  901. MainConsole.Instance.Output(cdt.ToString());
  902. }
  903. }
  904. }