UserManagementModule.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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.IO;
  30. using System.Reflection;
  31. using OpenSim.Framework;
  32. using OpenSim.Framework.Console;
  33. using OpenSim.Region.ClientStack.LindenUDP;
  34. using OpenSim.Region.Framework;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Services.Interfaces;
  38. using OpenSim.Services.Connectors.Hypergrid;
  39. using OpenMetaverse;
  40. using OpenMetaverse.Packets;
  41. using log4net;
  42. using Nini.Config;
  43. using Mono.Addins;
  44. namespace OpenSim.Region.CoreModules.Framework.UserManagement
  45. {
  46. public class UserData
  47. {
  48. public UUID Id { get; set; }
  49. public string FirstName { get; set; }
  50. public string LastName { get; set; }
  51. public string HomeURL { get; set; }
  52. public Dictionary<string, object> ServerURLs { get; set; }
  53. }
  54. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")]
  55. public class UserManagementModule : ISharedRegionModule, IUserManagement
  56. {
  57. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  58. protected bool m_Enabled;
  59. protected List<Scene> m_Scenes = new List<Scene>();
  60. // The cache
  61. protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>();
  62. #region ISharedRegionModule
  63. public void Initialise(IConfigSource config)
  64. {
  65. string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name);
  66. if (umanmod == Name)
  67. {
  68. m_Enabled = true;
  69. RegisterConsoleCmds();
  70. m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
  71. }
  72. }
  73. public bool IsSharedModule
  74. {
  75. get { return true; }
  76. }
  77. public virtual string Name
  78. {
  79. get { return "BasicUserManagementModule"; }
  80. }
  81. public Type ReplaceableInterface
  82. {
  83. get { return null; }
  84. }
  85. public void AddRegion(Scene scene)
  86. {
  87. if (m_Enabled)
  88. {
  89. m_Scenes.Add(scene);
  90. scene.RegisterModuleInterface<IUserManagement>(this);
  91. scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
  92. scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
  93. }
  94. }
  95. public void RemoveRegion(Scene scene)
  96. {
  97. if (m_Enabled)
  98. {
  99. scene.UnregisterModuleInterface<IUserManagement>(this);
  100. m_Scenes.Remove(scene);
  101. }
  102. }
  103. public void RegionLoaded(Scene s)
  104. {
  105. }
  106. public void PostInitialise()
  107. {
  108. }
  109. public void Close()
  110. {
  111. m_Scenes.Clear();
  112. lock (m_UserCache)
  113. m_UserCache.Clear();
  114. }
  115. #endregion ISharedRegionModule
  116. #region Event Handlers
  117. void EventManager_OnPrimsLoaded(Scene s)
  118. {
  119. // let's sniff all the user names referenced by objects in the scene
  120. m_log.DebugFormat("[USER MANAGEMENT MODULE]: Caching creators' data from {0} ({1} objects)...", s.RegionInfo.RegionName, s.GetEntities().Length);
  121. s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); });
  122. }
  123. void EventManager_OnNewClient(IClientAPI client)
  124. {
  125. client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed);
  126. client.OnNameFromUUIDRequest += new UUIDNameRequest(HandleUUIDNameRequest);
  127. client.OnAvatarPickerRequest += new AvatarPickerRequest(HandleAvatarPickerRequest);
  128. }
  129. void HandleConnectionClosed(IClientAPI client)
  130. {
  131. client.OnNameFromUUIDRequest -= new UUIDNameRequest(HandleUUIDNameRequest);
  132. client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest);
  133. }
  134. void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client)
  135. {
  136. if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
  137. {
  138. remote_client.SendNameReply(uuid, "Mr", "OpenSim");
  139. }
  140. else
  141. {
  142. string[] names = GetUserNames(uuid);
  143. if (names.Length == 2)
  144. {
  145. //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]);
  146. remote_client.SendNameReply(uuid, names[0], names[1]);
  147. }
  148. }
  149. }
  150. public void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query)
  151. {
  152. //EventManager.TriggerAvatarPickerRequest();
  153. m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
  154. // searhc the user accounts service
  155. List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
  156. List<UserData> users = new List<UserData>();
  157. if (accs != null)
  158. {
  159. foreach (UserAccount acc in accs)
  160. {
  161. UserData ud = new UserData();
  162. ud.FirstName = acc.FirstName;
  163. ud.LastName = acc.LastName;
  164. ud.Id = acc.PrincipalID;
  165. users.Add(ud);
  166. }
  167. }
  168. // search the local cache
  169. foreach (UserData data in m_UserCache.Values)
  170. if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
  171. (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
  172. users.Add(data);
  173. AddAdditionalUsers(avatarID, query, users);
  174. AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
  175. // TODO: don't create new blocks if recycling an old packet
  176. AvatarPickerReplyPacket.DataBlock[] searchData =
  177. new AvatarPickerReplyPacket.DataBlock[users.Count];
  178. AvatarPickerReplyPacket.AgentDataBlock agentData = new AvatarPickerReplyPacket.AgentDataBlock();
  179. agentData.AgentID = avatarID;
  180. agentData.QueryID = RequestID;
  181. replyPacket.AgentData = agentData;
  182. //byte[] bytes = new byte[AvatarResponses.Count*32];
  183. int i = 0;
  184. foreach (UserData item in users)
  185. {
  186. UUID translatedIDtem = item.Id;
  187. searchData[i] = new AvatarPickerReplyPacket.DataBlock();
  188. searchData[i].AvatarID = translatedIDtem;
  189. searchData[i].FirstName = Utils.StringToBytes((string)item.FirstName);
  190. searchData[i].LastName = Utils.StringToBytes((string)item.LastName);
  191. i++;
  192. }
  193. if (users.Count == 0)
  194. {
  195. searchData = new AvatarPickerReplyPacket.DataBlock[0];
  196. }
  197. replyPacket.Data = searchData;
  198. AvatarPickerReplyAgentDataArgs agent_data = new AvatarPickerReplyAgentDataArgs();
  199. agent_data.AgentID = replyPacket.AgentData.AgentID;
  200. agent_data.QueryID = replyPacket.AgentData.QueryID;
  201. List<AvatarPickerReplyDataArgs> data_args = new List<AvatarPickerReplyDataArgs>();
  202. for (i = 0; i < replyPacket.Data.Length; i++)
  203. {
  204. AvatarPickerReplyDataArgs data_arg = new AvatarPickerReplyDataArgs();
  205. data_arg.AvatarID = replyPacket.Data[i].AvatarID;
  206. data_arg.FirstName = replyPacket.Data[i].FirstName;
  207. data_arg.LastName = replyPacket.Data[i].LastName;
  208. data_args.Add(data_arg);
  209. }
  210. client.SendAvatarPickerReply(agent_data, data_args);
  211. }
  212. protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users)
  213. {
  214. }
  215. #endregion Event Handlers
  216. private void CacheCreators(SceneObjectGroup sog)
  217. {
  218. //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
  219. AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
  220. foreach (SceneObjectPart sop in sog.Parts)
  221. {
  222. AddUser(sop.CreatorID, sop.CreatorData);
  223. foreach (TaskInventoryItem item in sop.TaskInventory.Values)
  224. AddUser(item.CreatorID, item.CreatorData);
  225. }
  226. }
  227. private string[] GetUserNames(UUID uuid)
  228. {
  229. string[] returnstring = new string[2];
  230. lock (m_UserCache)
  231. {
  232. if (m_UserCache.ContainsKey(uuid))
  233. {
  234. returnstring[0] = m_UserCache[uuid].FirstName;
  235. returnstring[1] = m_UserCache[uuid].LastName;
  236. return returnstring;
  237. }
  238. }
  239. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid);
  240. if (account != null)
  241. {
  242. returnstring[0] = account.FirstName;
  243. returnstring[1] = account.LastName;
  244. UserData user = new UserData();
  245. user.FirstName = account.FirstName;
  246. user.LastName = account.LastName;
  247. lock (m_UserCache)
  248. m_UserCache[uuid] = user;
  249. }
  250. else
  251. {
  252. returnstring[0] = "Unknown";
  253. returnstring[1] = "User";
  254. }
  255. return returnstring;
  256. }
  257. #region IUserManagement
  258. public UUID GetUserIdByName(string name)
  259. {
  260. string[] parts = name.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
  261. if (parts.Length < 2)
  262. throw new Exception("Name must have 2 components");
  263. return GetUserIdByName(parts[0], parts[1]);
  264. }
  265. public UUID GetUserIdByName(string firstName, string lastName)
  266. {
  267. // TODO: Optimize for reverse lookup if this gets used by non-console commands.
  268. lock (m_UserCache)
  269. {
  270. foreach (UserData user in m_UserCache.Values)
  271. {
  272. if (user.FirstName == firstName && user.LastName == lastName)
  273. return user.Id;
  274. }
  275. }
  276. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName);
  277. if (account != null)
  278. return account.PrincipalID;
  279. return UUID.Zero;
  280. }
  281. public string GetUserName(UUID uuid)
  282. {
  283. string[] names = GetUserNames(uuid);
  284. if (names.Length == 2)
  285. {
  286. string firstname = names[0];
  287. string lastname = names[1];
  288. return firstname + " " + lastname;
  289. }
  290. return "(hippos)";
  291. }
  292. public string GetUserHomeURL(UUID userID)
  293. {
  294. lock (m_UserCache)
  295. {
  296. if (m_UserCache.ContainsKey(userID))
  297. return m_UserCache[userID].HomeURL;
  298. }
  299. return string.Empty;
  300. }
  301. public string GetUserServerURL(UUID userID, string serverType)
  302. {
  303. UserData userdata;
  304. lock (m_UserCache)
  305. m_UserCache.TryGetValue(userID, out userdata);
  306. if (userdata != null)
  307. {
  308. // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID);
  309. if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
  310. {
  311. return userdata.ServerURLs[serverType].ToString();
  312. }
  313. if (userdata.HomeURL != null && userdata.HomeURL != string.Empty)
  314. {
  315. //m_log.DebugFormat(
  316. // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}",
  317. // serverType, userdata.HomeURL, userID);
  318. UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
  319. userdata.ServerURLs = uConn.GetServerURLs(userID);
  320. if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
  321. return userdata.ServerURLs[serverType].ToString();
  322. }
  323. }
  324. return string.Empty;
  325. }
  326. public string GetUserUUI(UUID userID)
  327. {
  328. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID);
  329. if (account != null)
  330. return userID.ToString();
  331. UserData ud;
  332. lock (m_UserCache)
  333. m_UserCache.TryGetValue(userID, out ud);
  334. if (ud != null)
  335. {
  336. string homeURL = ud.HomeURL;
  337. string first = ud.FirstName, last = ud.LastName;
  338. if (ud.LastName.StartsWith("@"))
  339. {
  340. string[] parts = ud.FirstName.Split('.');
  341. if (parts.Length >= 2)
  342. {
  343. first = parts[0];
  344. last = parts[1];
  345. }
  346. return userID + ";" + homeURL + ";" + first + " " + last;
  347. }
  348. }
  349. return userID.ToString();
  350. }
  351. public void AddUser(UUID uuid, string first, string last)
  352. {
  353. lock (m_UserCache)
  354. {
  355. if (m_UserCache.ContainsKey(uuid))
  356. return;
  357. }
  358. UserData user = new UserData();
  359. user.Id = uuid;
  360. user.FirstName = first;
  361. user.LastName = last;
  362. AddUserInternal(user);
  363. }
  364. public void AddUser(UUID uuid, string first, string last, string homeURL)
  365. {
  366. //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
  367. if (homeURL == string.Empty)
  368. return;
  369. AddUser(uuid, homeURL + ";" + first + " " + last);
  370. }
  371. public void AddUser (UUID id, string creatorData)
  372. {
  373. //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
  374. UserData oldUser;
  375. //lock the whole block - prevent concurrent update
  376. lock (m_UserCache)
  377. {
  378. m_UserCache.TryGetValue (id, out oldUser);
  379. if (oldUser != null)
  380. {
  381. if (creatorData == null || creatorData == String.Empty)
  382. {
  383. //ignore updates without creator data
  384. return;
  385. }
  386. //try update unknown users
  387. //and creator's home URL's
  388. if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL)))
  389. {
  390. m_UserCache.Remove (id);
  391. // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL);
  392. }
  393. else
  394. {
  395. //we have already a valid user within the cache
  396. return;
  397. }
  398. }
  399. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id);
  400. if (account != null)
  401. {
  402. AddUser (id, account.FirstName, account.LastName);
  403. }
  404. else
  405. {
  406. UserData user = new UserData ();
  407. user.Id = id;
  408. if (creatorData != null && creatorData != string.Empty)
  409. {
  410. //creatorData = <endpoint>;<name>
  411. string[] parts = creatorData.Split (';');
  412. if (parts.Length >= 1)
  413. {
  414. user.HomeURL = parts [0];
  415. try
  416. {
  417. Uri uri = new Uri (parts [0]);
  418. user.LastName = "@" + uri.Authority;
  419. }
  420. catch (UriFormatException)
  421. {
  422. m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]);
  423. user.LastName = "@unknown";
  424. }
  425. }
  426. if (parts.Length >= 2)
  427. user.FirstName = parts [1].Replace (' ', '.');
  428. }
  429. else
  430. {
  431. user.FirstName = "Unknown";
  432. user.LastName = "User";
  433. }
  434. AddUserInternal (user);
  435. }
  436. }
  437. }
  438. void AddUserInternal(UserData user)
  439. {
  440. lock (m_UserCache)
  441. m_UserCache[user.Id] = user;
  442. //m_log.DebugFormat(
  443. // "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}",
  444. // user.Id, user.FirstName, user.LastName, user.HomeURL);
  445. }
  446. public bool IsLocalGridUser(UUID uuid)
  447. {
  448. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid);
  449. if (account == null || (account != null && !account.LocalToGrid))
  450. return false;
  451. return true;
  452. }
  453. #endregion IUserManagement
  454. protected void RegisterConsoleCmds()
  455. {
  456. MainConsole.Instance.Commands.AddCommand("Users", true,
  457. "show names",
  458. "show names",
  459. "Show the bindings between user UUIDs and user names",
  460. String.Empty,
  461. HandleShowUsers);
  462. }
  463. private void HandleShowUsers(string module, string[] cmd)
  464. {
  465. lock (m_UserCache)
  466. {
  467. if (m_UserCache.Count == 0)
  468. {
  469. MainConsole.Instance.Output("No users found");
  470. return;
  471. }
  472. MainConsole.Instance.Output("UUID User Name");
  473. MainConsole.Instance.Output("-----------------------------------------------------------------------------");
  474. foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
  475. {
  476. MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
  477. kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
  478. }
  479. return;
  480. }
  481. }
  482. }
  483. }