diff --git a/OpenSim/Framework/Communications/Clients/AuthClient.cs b/OpenSim/Framework/Communications/Clients/AuthClient.cs index ba5cf6668f..39a886c688 100644 --- a/OpenSim/Framework/Communications/Clients/AuthClient.cs +++ b/OpenSim/Framework/Communications/Clients/AuthClient.cs @@ -1,116 +1,118 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nwc.XmlRpc; -using OpenMetaverse; - -namespace OpenSim.Framework.Communications.Clients -{ - public class AuthClient - { - public static string GetNewKey(string authurl, UUID userID, UUID authToken) - { - //Hashtable keyParams = new Hashtable(); - //keyParams["user_id"] = userID; - //keyParams["auth_token"] = authKey; - - List SendParams = new List(); - SendParams.Add(userID.ToString()); - SendParams.Add(authToken.ToString()); - - XmlRpcRequest request = new XmlRpcRequest("hg_new_auth_key", SendParams); - XmlRpcResponse reply; - try - { - reply = request.Send(authurl, 6000); - } - catch (Exception e) - { - System.Console.WriteLine("[HGrid]: Failed to get new key. Reason: " + e.Message); - return string.Empty; - } - - if (!reply.IsFault) - { - string newKey = string.Empty; - if (reply.Value != null) - newKey = (string)reply.Value; - - return newKey; - } - else - { - System.Console.WriteLine("[HGrid]: XmlRpc request to get auth key failed with message {0}" + reply.FaultString + ", code " + reply.FaultCode); - return string.Empty; - } - - } - - public static bool VerifyKey(string authurl, UUID userID, string authKey) - { - List SendParams = new List(); - SendParams.Add(userID.ToString()); - SendParams.Add(authKey); - - XmlRpcRequest request = new XmlRpcRequest("hg_verify_auth_key", SendParams); - XmlRpcResponse reply; - try - { - reply = request.Send(authurl, 10000); - } - catch (Exception e) - { - System.Console.WriteLine("[HGrid]: Failed to verify key. Reason: " + e.Message); - return false; - } - - if (reply != null) - { - if (!reply.IsFault) - { - bool success = false; - if (reply.Value != null) - success = (bool)reply.Value; - - return success; - } - else - { - System.Console.WriteLine("[HGrid]: XmlRpc request to verify key failed with message {0}" + reply.FaultString + ", code " + reply.FaultCode); - return false; - } - } - else - { - System.Console.WriteLine("[HGrid]: XmlRpc request to verify key returned null reply"); - return false; - } - } - } -} +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nwc.XmlRpc; +using OpenMetaverse; + +namespace OpenSim.Framework.Communications.Clients +{ + public class AuthClient + { + public static string GetNewKey(string authurl, UUID userID, UUID authToken) + { + //Hashtable keyParams = new Hashtable(); + //keyParams["user_id"] = userID; + //keyParams["auth_token"] = authKey; + + List SendParams = new List(); + SendParams.Add(userID.ToString()); + SendParams.Add(authToken.ToString()); + + XmlRpcRequest request = new XmlRpcRequest("hg_new_auth_key", SendParams); + XmlRpcResponse reply; + try + { + reply = request.Send(authurl, 6000); + } + catch (Exception e) + { + System.Console.WriteLine("[HGrid]: Failed to get new key. Reason: " + e.Message); + return string.Empty; + } + + if (!reply.IsFault) + { + string newKey = string.Empty; + if (reply.Value != null) + newKey = (string)reply.Value; + + return newKey; + } + else + { + System.Console.WriteLine("[HGrid]: XmlRpc request to get auth key failed with message {0}" + reply.FaultString + ", code " + reply.FaultCode); + return string.Empty; + } + + } + + public static bool VerifyKey(string authurl, UUID userID, string authKey) + { + List SendParams = new List(); + SendParams.Add(userID.ToString()); + SendParams.Add(authKey); + + System.Console.WriteLine("[HGrid]: Verifying user key with authority " + authurl); + + XmlRpcRequest request = new XmlRpcRequest("hg_verify_auth_key", SendParams); + XmlRpcResponse reply; + try + { + reply = request.Send(authurl, 10000); + } + catch (Exception e) + { + System.Console.WriteLine("[HGrid]: Failed to verify key. Reason: " + e.Message); + return false; + } + + if (reply != null) + { + if (!reply.IsFault) + { + bool success = false; + if (reply.Value != null) + success = (bool)reply.Value; + + return success; + } + else + { + System.Console.WriteLine("[HGrid]: XmlRpc request to verify key failed with message {0}" + reply.FaultString + ", code " + reply.FaultCode); + return false; + } + } + else + { + System.Console.WriteLine("[HGrid]: XmlRpc request to verify key returned null reply"); + return false; + } + } + } +} diff --git a/OpenSim/Framework/Communications/Services/HGInventoryService.cs b/OpenSim/Framework/Communications/Services/HGInventoryService.cs index b01c30e8a1..7eaed89320 100644 --- a/OpenSim/Framework/Communications/Services/HGInventoryService.cs +++ b/OpenSim/Framework/Communications/Services/HGInventoryService.cs @@ -1,715 +1,714 @@ -/** - * Copyright (c) 2008, Contributors. All rights reserved. - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the Organizations nor the names of Individual - * Contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Data; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Clients; -using OpenSim.Framework.Communications.Cache; -using Caps = OpenSim.Framework.Communications.Capabilities.Caps; -using LLSDHelpers = OpenSim.Framework.Communications.Capabilities.LLSDHelpers; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.Interfaces; - -using OpenMetaverse.StructuredData; - -namespace OpenSim.Framework.Communications.Services -{ - public class HGInventoryService - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private InventoryServiceBase m_inventoryService; - IHttpServer httpServer; - private string m_thisInventoryUrl = "http://localhost:9000"; - private string m_thisHostname = "127.0.0.1"; - private uint m_thisPort = 9000; - - // These two used for local access, standalone mode - private UserManagerBase m_userService = null; - IAssetDataPlugin m_assetProvider = null; - - // These two used for remote access - string m_UserServerURL = string.Empty; - string m_AssetServerURL = string.Empty; - SynchronousGridAssetClient m_AssetClient = null; - - // Constructor for grid inventory server - public HGInventoryService(InventoryServiceBase invService, string assetServiceURL, string userServiceURL, IHttpServer httpserver, string thisurl) - { - m_UserServerURL = userServiceURL; - m_AssetServerURL = assetServiceURL; - - m_AssetClient = new SynchronousGridAssetClient(m_AssetServerURL); - - Init(invService, thisurl, httpserver); - } - - // Constructor for standalone mode - public HGInventoryService(InventoryServiceBase invService, IAssetDataPlugin assetService, UserManagerBase userService, IHttpServer httpserver, string thisurl) - { - m_userService = userService; - m_assetProvider = assetService; - - Init(invService, thisurl, httpserver); - } - - private void Init(InventoryServiceBase invService, string thisurl, IHttpServer httpserver) - { - m_inventoryService = invService; - m_thisInventoryUrl = thisurl; - if (!m_thisInventoryUrl.EndsWith("/")) - m_thisInventoryUrl += "/"; - - Uri uri = new Uri(m_thisInventoryUrl); - if (uri != null) - { - m_thisHostname = uri.Host; - m_thisPort = (uint)uri.Port; - } - - httpServer = httpserver; - - AddHttpHandlers(); - } - - public virtual void AddHttpHandlers() - { - httpServer.AddHTTPHandler("/InvCap/", CapHandler); - } - - public bool CheckAuthSession(string session_id, string avatar_id) - { - return true; - } - - - // In truth, this is not called from the outside, for standalones. I'm just making it - // a handler already so that this can be reused for the InventoryServer. - public string CreateCapUrl(Guid _userid) - { - UUID userID = new UUID(_userid); - UUID random = UUID.Random(); - string url = m_thisInventoryUrl + random.ToString() + "/"; - m_log.InfoFormat("[HGStandaloneInvService] Creating Cap URL {0} for user {1}", url, userID.ToString()); - return url; - } - - /// - /// Return a user's entire inventory - /// - /// - /// The user's inventory. If an inventory cannot be found then an empty collection is returned. - public InventoryCollection GetUserInventory(Guid rawUserID) - { - UUID userID = new UUID(rawUserID); - - m_log.Info("[HGStandaloneInvModule]: Processing request for inventory of " + userID); - - // Uncomment me to simulate a slow responding inventory server - //Thread.Sleep(16000); - - InventoryCollection invCollection = new InventoryCollection(); - - List allFolders = m_inventoryService.GetInventorySkeleton(userID); - - if (null == allFolders) - { - m_log.WarnFormat("[HGStandaloneInvModule]: No inventory found for user {0}", rawUserID); - - return invCollection; - } - - List allItems = new List(); - - foreach (InventoryFolderBase folder in allFolders) - { - List items = m_inventoryService.RequestFolderItems(folder.ID); - - if (items != null) - { - allItems.InsertRange(0, items); - } - } - - invCollection.UserID = userID; - invCollection.Folders = allFolders; - invCollection.Items = allItems; - - // foreach (InventoryFolderBase folder in invCollection.Folders) - // { - // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back folder {0} {1}", folder.Name, folder.ID); - // } - // - // foreach (InventoryItemBase item in invCollection.Items) - // { - // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back item {0} {1}, folder {2}", item.Name, item.ID, item.Folder); - // } - - m_log.InfoFormat( - "[HGStandaloneInvModule]: Sending back inventory response to user {0} containing {1} folders and {2} items", - invCollection.UserID, invCollection.Folders.Count, invCollection.Items.Count); - - return invCollection; - } - - public InventoryCollection FetchDescendants(InventoryFolderBase fb) - { - m_log.Info("[HGStandaloneInvService]: Processing request for folder " + fb.ID); - - // Uncomment me to simulate a slow responding inventory server - //Thread.Sleep(16000); - - InventoryCollection invCollection = new InventoryCollection(); - - List items = m_inventoryService.RequestFolderItems(fb.ID); - List folders = m_inventoryService.RequestSubFolders(fb.ID); - - invCollection.UserID = fb.Owner; - invCollection.Folders = folders; - invCollection.Items = items; - - m_log.DebugFormat("[HGStandaloneInvService]: Found {0} items and {1} folders", items.Count, folders.Count); - - return invCollection; - } - - public bool RemoveFolder(InventoryFolderBase folder) - { - m_log.Debug("[HGStandaloneInvService]: Removefolder: Operation not implemented yet."); - return false; - } - - public InventoryItemBase GetInventoryItem(InventoryItemBase item) - { - m_log.Info("[HGStandaloneInvService]: Get item " + item.ID); - - item = m_inventoryService.GetInventoryItem(item.ID); - if (item == null) - m_log.Debug("[HGStandaloneInvService]: null item"); - return item; - } - - public InventoryItemBase AddItem(InventoryItemBase item) - { - m_log.DebugFormat("[HGStandaloneInvService]: Add item {0} from {1}", item.ID, item.Owner); - if (m_inventoryService.AddItem(item)) - return item; - else - { - item.ID = UUID.Zero; - return item; - } - } - - public InventoryItemBase UpdateItem(InventoryItemBase item) - { - m_log.DebugFormat("[HGStandaloneInvService]: Update item {0} from {1}", item.ID, item.Owner); - InventoryItemBase it = m_inventoryService.GetInventoryItem(item.ID); - item.CurrentPermissions = it.CurrentPermissions; - item.AssetID = it.AssetID; - if (m_inventoryService.UpdateItem(item)) - return item; - else - { - item.ID = UUID.Zero; - return item; - } - } - - public InventoryItemBase MoveItem(InventoryItemBase newitem) - { - m_log.DebugFormat("[HGStandaloneInvService]: Move item {0} from {1}", newitem.ID, newitem.Owner); - InventoryItemBase Item = m_inventoryService.GetInventoryItem(newitem.ID); - if (Item != null) - { - if (newitem.Name != String.Empty) - { - Item.Name = newitem.Name; - } - Item.Folder = newitem.Folder; - m_inventoryService.UpdateItem(Item); - return Item; - } - else - { - m_log.Debug("[HGStandaloneInvService]: Failed to find item " + newitem.ID); - newitem.ID = UUID.Zero; - return newitem; - } - - } - - public InventoryItemBase DeleteItem(InventoryItemBase item) - { - item = m_inventoryService.GetInventoryItem(item.ID); - if (m_inventoryService.DeleteItem(item)) - return item; - else - { - item.ID = UUID.Zero; - return item; - } - } - - public InventoryItemBase CopyItem(InventoryItemBase olditem) - { - m_log.DebugFormat("[HGStandaloneInvService]: Copy item {0} from {1}", olditem.ID, olditem.Owner); - InventoryItemBase Item = m_inventoryService.GetInventoryItem(olditem.ID); // this is the old item id - // BIG HACK here - UUID newID = olditem.AssetID; - if (Item != null) - { - if (olditem.Name != String.Empty) - { - Item.Name = olditem.Name; - } - Item.ID = newID; - Item.Folder = olditem.Folder; - Item.Owner = olditem.Owner; - // There should be some tests here about the owner, etc but I'm going to ignore that - // because I'm not sure it makes any sense - // Also I should probably clone the asset... - m_inventoryService.AddItem(Item); - return Item; - } - else - { - m_log.Debug("[HGStandaloneInvService]: Failed to find item " + olditem.ID); - olditem.ID = UUID.Zero; - return olditem; - } - - } - - /// - /// Guid to UUID wrapper for same name IInventoryServices method - /// - /// - /// - public List GetInventorySkeleton(Guid rawUserID) - { - UUID userID = new UUID(rawUserID); - return m_inventoryService.GetInventorySkeleton(userID); - } - - public List GetActiveGestures(Guid rawUserID) - { - UUID userID = new UUID(rawUserID); - - m_log.InfoFormat("[HGStandaloneInvService]: fetching active gestures for user {0}", userID); - - return m_inventoryService.GetActiveGestures(userID); - } - - public AssetBase GetAsset(InventoryItemBase item) - { - m_log.Info("[HGStandaloneInvService]: Get asset " + item.AssetID + " for item " + item.ID); - AssetBase asset = new AssetBase(item.AssetID, "NULL"); // send an asset with no data - InventoryItemBase item2 = m_inventoryService.GetInventoryItem(item.ID); - if (item2 == null) - { - m_log.Debug("[HGStandaloneInvService]: null item"); - return asset; - } - if (item2.Owner != item.Owner) - { - m_log.DebugFormat("[HGStandaloneInvService]: client with uuid {0} is trying to get an item of owner {1}", item.Owner, item2.Owner); - return asset; - } - - // All good, get the asset - //AssetBase theasset = m_assetProvider.FetchAsset(item.AssetID); - AssetBase theasset = FetchAsset(item.AssetID, (item.InvType == (int)InventoryType.Texture)); - - m_log.Debug("[HGStandaloneInvService] Found asset " + ((theasset == null) ? "NULL" : "Not Null")); - if (theasset != null) - { - asset = theasset; - //m_log.Debug(" >> Sending assetID " + item.AssetID); - } - return asset; - } - - public bool PostAsset(AssetBase asset) - { - m_log.Info("[HGStandaloneInvService]: Post asset " + asset.FullID); - //m_assetProvider.CreateAsset(asset); - StoreAsset(asset); - - return true; - } - - /// - /// CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[]) - /// - public UUID UpdateInventoryItemAsset(UUID userID, UUID itemID, byte[] data) - { - m_log.Debug("[HGStandaloneInvService]: UpdateInventoryitemAsset for user " + userID + " item " + itemID); - InventoryItemBase item = m_inventoryService.GetInventoryItem(itemID); - - if (item != null) - { - // We're still not dealing with permissions - //if ((InventoryType)item.InvType == InventoryType.Notecard) - //{ - // if (!Permissions.CanEditNotecard(itemID, UUID.Zero, userID)) - // { - // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); - // return UUID.Zero; - // } - - // //remoteClient.SendAgentAlertMessage("Notecard saved", false); - //} - //else if ((InventoryType)item.InvType == InventoryType.LSL) - //{ - // if (!Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) - // { - // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); - // return UUID.Zero; - // } - - // //remoteClient.SendAgentAlertMessage("Script saved", false); - //} - - AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data); - PostAsset(asset); - - item.AssetID = asset.FullID; - item.Owner = userID; - m_inventoryService.UpdateItem(item); - - return (asset.FullID); - } - return UUID.Zero; - } - - private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data) - { - AssetBase asset = new AssetBase(); - asset.Name = name; - asset.Description = description; - asset.Type = assetType; - asset.FullID = UUID.Random(); - asset.Data = (data == null) ? new byte[1] : data; - - return asset; - } - - #region Caps - - Dictionary invCaps = new Dictionary(); - - public Hashtable CapHandler(Hashtable request) - { - m_log.Debug("[CONNECTION DEBUGGING]: InvCapHandler Called"); - - m_log.Debug("---------------------------"); - m_log.Debug(" >> uri=" + request["uri"]); - m_log.Debug(" >> content-type=" + request["content-type"]); - m_log.Debug(" >> http-method=" + request["http-method"]); - m_log.Debug("---------------------------\n"); - - // these are requests if the type - // http://inventoryserver/InvCap/uuuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu/kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk/ - - Hashtable responsedata = new Hashtable(); - responsedata["content_type"] = "text/plain"; - - UUID userID; - string authToken = string.Empty; - string authority = string.Empty; - if (!GetParams(request, out userID, out authority, out authToken)) - { - m_log.InfoFormat("[HGStandaloneInvService]: Invalid parameters for InvCap message {0}", request["uri"]); - responsedata["int_response_code"] = 404; - responsedata["str_response_string"] = "Not found"; - - return responsedata; - } - - // Next, let's parse the verb - string method = (string)request["http-method"]; - if (method.Equals("GET")) - { - DoInvCapPost(request, responsedata, userID, authToken); - return responsedata; - } - //else if (method.Equals("DELETE")) - //{ - // DoAgentDelete(request, responsedata, agentID, action, regionHandle); - - // return responsedata; - //} - else - { - m_log.InfoFormat("[HGStandaloneInvService]: method {0} not supported in agent message", method); - responsedata["int_response_code"] = 405; - responsedata["str_response_string"] = "Method not allowed"; - - return responsedata; - } - - } - - public virtual void DoInvCapPost(Hashtable request, Hashtable responsedata, UUID userID, string authToken) - { - - // This is the meaning of POST agent - - // Check Auth Token - if ((m_userService != null) && !(m_userService is IAuthentication)) - { - m_log.Debug("[HGStandaloneInvService]: UserService is not IAuthentication. Denying access to inventory."); - responsedata["int_response_code"] = 501; - responsedata["str_response_string"] = "Not implemented"; - return; - } - - bool success = VerifyKey(userID, authToken); - m_log.Debug("[HGStandaloneInvService]: Key verification returned " + success); - - if (success) - { - - m_log.DebugFormat("[HGStandaloneInvService]: User has been authorized. Creating service handlers."); - - // Then establish secret service handlers - - Hashtable usercaps = RegisterCaps(userID, authToken); - - responsedata["int_response_code"] = 200; - //responsedata["str_response_string"] = "OK"; - responsedata["str_response_string"] = SerializeHashtable(usercaps); - } - else - { - m_log.DebugFormat("[HGStandaloneInvService]: User has is unauthorized. Denying service handlers."); - responsedata["int_response_code"] = 403; - responsedata["str_response_string"] = "Forbidden"; - } - } - - - /// - /// Extract the params from a request. - /// - public static bool GetParams(Hashtable request, out UUID uuid, out string authority, out string authKey) - { - uuid = UUID.Zero; - authority = string.Empty; - authKey = string.Empty; - - string uri = (string)request["uri"]; - uri = uri.Trim(new char[] { '/' }); - string[] parts = uri.Split('/'); - if (parts.Length <= 1) - { - return false; - } - else - { - if (!UUID.TryParse(parts[1], out uuid)) - return false; - - if (parts.Length >= 3) - { - authKey = parts[2]; - return true; - } - } - - Uri authUri; - Hashtable headers = (Hashtable)request["headers"]; - - // Authorization keys look like this: - // http://orgrid.org:8002/ - if (headers.ContainsKey("authorization")) - { - if (Uri.TryCreate((string)headers["authorization"], UriKind.Absolute, out authUri)) - { - authority = authUri.Authority; - authKey = authUri.PathAndQuery.Trim('/'); - m_log.DebugFormat("[HGStandaloneInvService]: Got authority {0} and key {1}", authority, authKey); - return true; - } - else - m_log.Debug("[HGStandaloneInvService]: Wrong format for Authorization header: " + (string)headers["authorization"]); - } - else - m_log.Debug("[HGStandaloneInvService]: Authorization header not found"); - - return false; - } - - string SerializeHashtable(Hashtable hash) - { - string result = string.Empty; - foreach (object key in hash.Keys) - { - result += key.ToString() + "," + hash[key].ToString() + ";"; - } - return result; - } - - Hashtable RegisterCaps(UUID userID, string authToken) - { - lock (invCaps) - { - if (invCaps.ContainsKey(userID)) - { - // Remove the old ones - DeregisterCaps(httpServer, invCaps[userID]); - invCaps.Remove(userID); - } - } - - Caps caps = new Caps(null, httpServer, m_thisHostname, m_thisPort, authToken, userID, false, "Inventory"); - caps.RegisterInventoryServiceHandlers("/" + authToken + "/InventoryCap/"); - caps.ItemUpdatedCall = UpdateInventoryItemAsset; - Hashtable capsHandlers = caps.CapsHandlers.CapsDetails; - - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "GetInventory", capsHandlers), GetUserInventory, CheckAuthSession)); - - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "FetchDescendants", capsHandlers), FetchDescendants, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "NewFolder", capsHandlers), m_inventoryService.AddFolder, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "UpdateFolder", capsHandlers), m_inventoryService.UpdateFolder, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "MoveFolder", capsHandlers), m_inventoryService.MoveFolder, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "PurgeFolder", capsHandlers), m_inventoryService.PurgeFolder, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "RemoveFolder", capsHandlers), RemoveFolder, CheckAuthSession)); - - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "GetItem", capsHandlers), GetInventoryItem, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "NewItem", capsHandlers), AddItem, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "UpdateItem", capsHandlers), UpdateItem, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "MoveItem", capsHandlers), MoveItem, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "DeleteItem", capsHandlers), DeleteItem, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "CopyItem", capsHandlers), CopyItem, CheckAuthSession)); - - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "GetAsset", capsHandlers), GetAsset, CheckAuthSession)); - httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( - "POST", AddAndGetCapUrl(authToken, "PostAsset", capsHandlers), PostAsset, CheckAuthSession)); - - lock (invCaps) - invCaps.Add(userID, capsHandlers); - - return capsHandlers; - } - - string AddAndGetCapUrl(string authToken, string capType, Hashtable caps) - { - string capUrl = "/" + authToken + "/" + capType + "/"; - - m_log.Debug("[HGStandaloneInvService] Adding inventory cap " + capUrl); - caps.Add(capType, capUrl); - return capUrl; - } - - void DeregisterCaps(IHttpServer httpServer, Hashtable caps) - { - foreach (string capUrl in caps.Values) - { - m_log.Debug("[HGStandaloneInvService] Removing inventory cap " + capUrl); - httpServer.RemoveStreamHandler("POST", capUrl); - } - } - - #endregion Caps - - #region Local vs Remote - - bool VerifyKey(UUID userID, string key) - { - // Remote call to the Authorization server - if (m_userService == null) - return AuthClient.VerifyKey(m_UserServerURL, userID, key); - // local call - else - return ((IAuthentication)m_userService).VerifyKey(userID, key); - } - - AssetBase FetchAsset(UUID assetID, bool isTexture) - { - // Remote call to the Asset server - if (m_assetProvider == null) - return m_AssetClient.SyncGetAsset(assetID, isTexture); - // local call - else - return m_assetProvider.FetchAsset(assetID); - } - - void StoreAsset(AssetBase asset) - { - // Remote call to the Asset server - if (m_assetProvider == null) - m_AssetClient.StoreAsset(asset); - // local call - else - m_assetProvider.CreateAsset(asset); - } - - #endregion Local vs Remote - } - - class SynchronousGridAssetClient : GridAssetClient - { - public SynchronousGridAssetClient(string url) - : base(url) - { - } - - public AssetBase SyncGetAsset(UUID assetID, bool isTexture) - { - AssetRequest assReq = new AssetRequest(); - assReq.AssetID = assetID; - assReq.IsTexture = isTexture; - return base.GetAsset(assReq); - } - - } -} +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Clients; +using OpenSim.Framework.Communications.Cache; +using Caps = OpenSim.Framework.Communications.Capabilities.Caps; +using LLSDHelpers = OpenSim.Framework.Communications.Capabilities.LLSDHelpers; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.Interfaces; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Communications.Services +{ + public class HGInventoryService + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private InventoryServiceBase m_inventoryService; + IHttpServer httpServer; + private string m_thisInventoryUrl = "http://localhost:9000"; + private string m_thisHostname = "127.0.0.1"; + private uint m_thisPort = 9000; + + // These two used for local access, standalone mode + private UserManagerBase m_userService = null; + IAssetDataPlugin m_assetProvider = null; + + // These two used for remote access + string m_UserServerURL = string.Empty; + string m_AssetServerURL = string.Empty; + SynchronousGridAssetClient m_AssetClient = null; + + // Constructor for grid inventory server + public HGInventoryService(InventoryServiceBase invService, string assetServiceURL, string userServiceURL, IHttpServer httpserver, string thisurl) + { + m_UserServerURL = userServiceURL; + m_AssetServerURL = assetServiceURL; + + m_AssetClient = new SynchronousGridAssetClient(m_AssetServerURL); + + Init(invService, thisurl, httpserver); + } + + // Constructor for standalone mode + public HGInventoryService(InventoryServiceBase invService, IAssetDataPlugin assetService, UserManagerBase userService, IHttpServer httpserver, string thisurl) + { + m_userService = userService; + m_assetProvider = assetService; + + Init(invService, thisurl, httpserver); + } + + private void Init(InventoryServiceBase invService, string thisurl, IHttpServer httpserver) + { + m_inventoryService = invService; + m_thisInventoryUrl = thisurl; + if (!m_thisInventoryUrl.EndsWith("/")) + m_thisInventoryUrl += "/"; + + Uri uri = new Uri(m_thisInventoryUrl); + if (uri != null) + { + m_thisHostname = uri.Host; + m_thisPort = (uint)uri.Port; + } + + httpServer = httpserver; + + AddHttpHandlers(); + } + + public virtual void AddHttpHandlers() + { + httpServer.AddHTTPHandler("/InvCap/", CapHandler); + } + + public bool CheckAuthSession(string session_id, string avatar_id) + { + return true; + } + + + // In truth, this is not called from the outside, for standalones. I'm just making it + // a handler already so that this can be reused for the InventoryServer. + public string CreateCapUrl(Guid _userid) + { + UUID userID = new UUID(_userid); + UUID random = UUID.Random(); + string url = m_thisInventoryUrl + random.ToString() + "/"; + m_log.InfoFormat("[HGStandaloneInvService] Creating Cap URL {0} for user {1}", url, userID.ToString()); + return url; + } + + /// + /// Return a user's entire inventory + /// + /// + /// The user's inventory. If an inventory cannot be found then an empty collection is returned. + public InventoryCollection GetUserInventory(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + + m_log.Info("[HGStandaloneInvModule]: Processing request for inventory of " + userID); + + // Uncomment me to simulate a slow responding inventory server + //Thread.Sleep(16000); + + InventoryCollection invCollection = new InventoryCollection(); + + List allFolders = m_inventoryService.GetInventorySkeleton(userID); + + if (null == allFolders) + { + m_log.WarnFormat("[HGStandaloneInvModule]: No inventory found for user {0}", rawUserID); + + return invCollection; + } + + List allItems = new List(); + + foreach (InventoryFolderBase folder in allFolders) + { + List items = m_inventoryService.RequestFolderItems(folder.ID); + + if (items != null) + { + allItems.InsertRange(0, items); + } + } + + invCollection.UserID = userID; + invCollection.Folders = allFolders; + invCollection.Items = allItems; + + // foreach (InventoryFolderBase folder in invCollection.Folders) + // { + // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back folder {0} {1}", folder.Name, folder.ID); + // } + // + // foreach (InventoryItemBase item in invCollection.Items) + // { + // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back item {0} {1}, folder {2}", item.Name, item.ID, item.Folder); + // } + + m_log.InfoFormat( + "[HGStandaloneInvModule]: Sending back inventory response to user {0} containing {1} folders and {2} items", + invCollection.UserID, invCollection.Folders.Count, invCollection.Items.Count); + + return invCollection; + } + + public InventoryCollection FetchDescendants(InventoryFolderBase fb) + { + m_log.Info("[HGStandaloneInvService]: Processing request for folder " + fb.ID); + + // Uncomment me to simulate a slow responding inventory server + //Thread.Sleep(16000); + + InventoryCollection invCollection = new InventoryCollection(); + + List items = m_inventoryService.RequestFolderItems(fb.ID); + List folders = m_inventoryService.RequestSubFolders(fb.ID); + + invCollection.UserID = fb.Owner; + invCollection.Folders = folders; + invCollection.Items = items; + + m_log.DebugFormat("[HGStandaloneInvService]: Found {0} items and {1} folders", items.Count, folders.Count); + + return invCollection; + } + + public bool RemoveFolder(InventoryFolderBase folder) + { + m_log.Debug("[HGStandaloneInvService]: Removefolder: Operation not implemented yet."); + return false; + } + + public InventoryItemBase GetInventoryItem(InventoryItemBase item) + { + m_log.Info("[HGStandaloneInvService]: Get item " + item.ID); + + item = m_inventoryService.GetInventoryItem(item.ID); + if (item == null) + m_log.Debug("[HGStandaloneInvService]: null item"); + return item; + } + + public InventoryItemBase AddItem(InventoryItemBase item) + { + m_log.DebugFormat("[HGStandaloneInvService]: Add item {0} from {1}", item.ID, item.Owner); + if (m_inventoryService.AddItem(item)) + return item; + else + { + item.ID = UUID.Zero; + return item; + } + } + + public InventoryItemBase UpdateItem(InventoryItemBase item) + { + m_log.DebugFormat("[HGStandaloneInvService]: Update item {0} from {1}", item.ID, item.Owner); + InventoryItemBase it = m_inventoryService.GetInventoryItem(item.ID); + item.CurrentPermissions = it.CurrentPermissions; + item.AssetID = it.AssetID; + if (m_inventoryService.UpdateItem(item)) + return item; + else + { + item.ID = UUID.Zero; + return item; + } + } + + public InventoryItemBase MoveItem(InventoryItemBase newitem) + { + m_log.DebugFormat("[HGStandaloneInvService]: Move item {0} from {1}", newitem.ID, newitem.Owner); + InventoryItemBase Item = m_inventoryService.GetInventoryItem(newitem.ID); + if (Item != null) + { + if (newitem.Name != String.Empty) + { + Item.Name = newitem.Name; + } + Item.Folder = newitem.Folder; + m_inventoryService.UpdateItem(Item); + return Item; + } + else + { + m_log.Debug("[HGStandaloneInvService]: Failed to find item " + newitem.ID); + newitem.ID = UUID.Zero; + return newitem; + } + + } + + public InventoryItemBase DeleteItem(InventoryItemBase item) + { + item = m_inventoryService.GetInventoryItem(item.ID); + if (m_inventoryService.DeleteItem(item)) + return item; + else + { + item.ID = UUID.Zero; + return item; + } + } + + public InventoryItemBase CopyItem(InventoryItemBase olditem) + { + m_log.DebugFormat("[HGStandaloneInvService]: Copy item {0} from {1}", olditem.ID, olditem.Owner); + InventoryItemBase Item = m_inventoryService.GetInventoryItem(olditem.ID); // this is the old item id + // BIG HACK here + UUID newID = olditem.AssetID; + if (Item != null) + { + if (olditem.Name != String.Empty) + { + Item.Name = olditem.Name; + } + Item.ID = newID; + Item.Folder = olditem.Folder; + Item.Owner = olditem.Owner; + // There should be some tests here about the owner, etc but I'm going to ignore that + // because I'm not sure it makes any sense + // Also I should probably clone the asset... + m_inventoryService.AddItem(Item); + return Item; + } + else + { + m_log.Debug("[HGStandaloneInvService]: Failed to find item " + olditem.ID); + olditem.ID = UUID.Zero; + return olditem; + } + + } + + /// + /// Guid to UUID wrapper for same name IInventoryServices method + /// + /// + /// + public List GetInventorySkeleton(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + return m_inventoryService.GetInventorySkeleton(userID); + } + + public List GetActiveGestures(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + + m_log.InfoFormat("[HGStandaloneInvService]: fetching active gestures for user {0}", userID); + + return m_inventoryService.GetActiveGestures(userID); + } + + public AssetBase GetAsset(InventoryItemBase item) + { + m_log.Info("[HGStandaloneInvService]: Get asset " + item.AssetID + " for item " + item.ID); + AssetBase asset = new AssetBase(item.AssetID, "NULL"); // send an asset with no data + InventoryItemBase item2 = m_inventoryService.GetInventoryItem(item.ID); + if (item2 == null) + { + m_log.Debug("[HGStandaloneInvService]: null item"); + return asset; + } + if (item2.Owner != item.Owner) + { + m_log.DebugFormat("[HGStandaloneInvService]: client with uuid {0} is trying to get an item of owner {1}", item.Owner, item2.Owner); + return asset; + } + + // All good, get the asset + //AssetBase theasset = m_assetProvider.FetchAsset(item.AssetID); + AssetBase theasset = FetchAsset(item.AssetID, (item.InvType == (int)InventoryType.Texture)); + + m_log.Debug("[HGStandaloneInvService] Found asset " + ((theasset == null) ? "NULL" : "Not Null")); + if (theasset != null) + { + asset = theasset; + //m_log.Debug(" >> Sending assetID " + item.AssetID); + } + return asset; + } + + public bool PostAsset(AssetBase asset) + { + m_log.Info("[HGStandaloneInvService]: Post asset " + asset.FullID); + //m_assetProvider.CreateAsset(asset); + StoreAsset(asset); + + return true; + } + + /// + /// CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[]) + /// + public UUID UpdateInventoryItemAsset(UUID userID, UUID itemID, byte[] data) + { + m_log.Debug("[HGStandaloneInvService]: UpdateInventoryitemAsset for user " + userID + " item " + itemID); + InventoryItemBase item = m_inventoryService.GetInventoryItem(itemID); + + if (item != null) + { + // We're still not dealing with permissions + //if ((InventoryType)item.InvType == InventoryType.Notecard) + //{ + // if (!Permissions.CanEditNotecard(itemID, UUID.Zero, userID)) + // { + // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); + // return UUID.Zero; + // } + + // //remoteClient.SendAgentAlertMessage("Notecard saved", false); + //} + //else if ((InventoryType)item.InvType == InventoryType.LSL) + //{ + // if (!Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) + // { + // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); + // return UUID.Zero; + // } + + // //remoteClient.SendAgentAlertMessage("Script saved", false); + //} + + AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data); + PostAsset(asset); + + item.AssetID = asset.FullID; + item.Owner = userID; + m_inventoryService.UpdateItem(item); + + return (asset.FullID); + } + return UUID.Zero; + } + + private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data) + { + AssetBase asset = new AssetBase(); + asset.Name = name; + asset.Description = description; + asset.Type = assetType; + asset.FullID = UUID.Random(); + asset.Data = (data == null) ? new byte[1] : data; + + return asset; + } + + #region Caps + + Dictionary invCaps = new Dictionary(); + + public Hashtable CapHandler(Hashtable request) + { + m_log.Debug("[CONNECTION DEBUGGING]: InvCapHandler Called"); + + m_log.Debug("---------------------------"); + m_log.Debug(" >> uri=" + request["uri"]); + m_log.Debug(" >> content-type=" + request["content-type"]); + m_log.Debug(" >> http-method=" + request["http-method"]); + m_log.Debug("---------------------------\n"); + + // these are requests if the type + // http://inventoryserver/InvCap/uuuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu/kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk/ + + Hashtable responsedata = new Hashtable(); + responsedata["content_type"] = "text/plain"; + + UUID userID; + string authToken = string.Empty; + string authority = string.Empty; + if (!GetParams(request, out userID, out authority, out authToken)) + { + m_log.InfoFormat("[HGStandaloneInvService]: Invalid parameters for InvCap message {0}", request["uri"]); + responsedata["int_response_code"] = 404; + responsedata["str_response_string"] = "Not found"; + + return responsedata; + } + + // Next, let's parse the verb + string method = (string)request["http-method"]; + if (method.Equals("GET")) + { + DoInvCapPost(request, responsedata, userID, authority, authToken); + return responsedata; + } + //else if (method.Equals("DELETE")) + //{ + // DoAgentDelete(request, responsedata, agentID, action, regionHandle); + + // return responsedata; + //} + else + { + m_log.InfoFormat("[HGStandaloneInvService]: method {0} not supported in agent message", method); + responsedata["int_response_code"] = 405; + responsedata["str_response_string"] = "Method not allowed"; + + return responsedata; + } + + } + + public virtual void DoInvCapPost(Hashtable request, Hashtable responsedata, UUID userID, string authority, string authToken) + { + + // This is the meaning of POST agent + + // Check Auth Token + if ((m_userService != null) && !(m_userService is IAuthentication)) + { + m_log.Debug("[HGStandaloneInvService]: UserService is not IAuthentication. Denying access to inventory."); + responsedata["int_response_code"] = 501; + responsedata["str_response_string"] = "Not implemented"; + return; + } + + bool success = VerifyKey(userID, authority, authToken); + + if (success) + { + + m_log.DebugFormat("[HGStandaloneInvService]: User has been authorized. Creating service handlers."); + + // Then establish secret service handlers + + Hashtable usercaps = RegisterCaps(userID, authToken); + + responsedata["int_response_code"] = 200; + //responsedata["str_response_string"] = "OK"; + responsedata["str_response_string"] = SerializeHashtable(usercaps); + } + else + { + m_log.DebugFormat("[HGStandaloneInvService]: User has is unauthorized. Denying service handlers."); + responsedata["int_response_code"] = 403; + responsedata["str_response_string"] = "Forbidden"; + } + } + + + /// + /// Extract the params from a request. + /// + public static bool GetParams(Hashtable request, out UUID uuid, out string authority, out string authKey) + { + uuid = UUID.Zero; + authority = string.Empty; + authKey = string.Empty; + + string uri = (string)request["uri"]; + uri = uri.Trim(new char[] { '/' }); + string[] parts = uri.Split('/'); + if (parts.Length <= 1) + { + return false; + } + else + { + if (!UUID.TryParse(parts[1], out uuid)) + return false; + + if (parts.Length >= 3) + { + authKey = parts[2]; + return true; + } + } + + Uri authUri; + Hashtable headers = (Hashtable)request["headers"]; + + // Authorization keys look like this: + // http://orgrid.org:8002/ + if (headers.ContainsKey("authorization")) + { + if (Uri.TryCreate((string)headers["authorization"], UriKind.Absolute, out authUri)) + { + authority = authUri.Authority; + authKey = authUri.PathAndQuery.Trim('/'); + m_log.DebugFormat("[HGStandaloneInvService]: Got authority {0} and key {1}", authority, authKey); + return true; + } + else + m_log.Debug("[HGStandaloneInvService]: Wrong format for Authorization header: " + (string)headers["authorization"]); + } + else + m_log.Debug("[HGStandaloneInvService]: Authorization header not found"); + + return false; + } + + string SerializeHashtable(Hashtable hash) + { + string result = string.Empty; + foreach (object key in hash.Keys) + { + result += key.ToString() + "," + hash[key].ToString() + ";"; + } + return result; + } + + Hashtable RegisterCaps(UUID userID, string authToken) + { + lock (invCaps) + { + if (invCaps.ContainsKey(userID)) + { + // Remove the old ones + DeregisterCaps(httpServer, invCaps[userID]); + invCaps.Remove(userID); + } + } + + Caps caps = new Caps(null, httpServer, m_thisHostname, m_thisPort, authToken, userID, false, "Inventory"); + caps.RegisterInventoryServiceHandlers("/" + authToken + "/InventoryCap/"); + caps.ItemUpdatedCall = UpdateInventoryItemAsset; + Hashtable capsHandlers = caps.CapsHandlers.CapsDetails; + + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "GetInventory", capsHandlers), GetUserInventory, CheckAuthSession)); + + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "FetchDescendants", capsHandlers), FetchDescendants, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "NewFolder", capsHandlers), m_inventoryService.AddFolder, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "UpdateFolder", capsHandlers), m_inventoryService.UpdateFolder, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "MoveFolder", capsHandlers), m_inventoryService.MoveFolder, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "PurgeFolder", capsHandlers), m_inventoryService.PurgeFolder, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "RemoveFolder", capsHandlers), RemoveFolder, CheckAuthSession)); + + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "GetItem", capsHandlers), GetInventoryItem, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "NewItem", capsHandlers), AddItem, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "UpdateItem", capsHandlers), UpdateItem, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "MoveItem", capsHandlers), MoveItem, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "DeleteItem", capsHandlers), DeleteItem, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "CopyItem", capsHandlers), CopyItem, CheckAuthSession)); + + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "GetAsset", capsHandlers), GetAsset, CheckAuthSession)); + httpServer.AddStreamHandler(new RestDeserialiseSecureHandler( + "POST", AddAndGetCapUrl(authToken, "PostAsset", capsHandlers), PostAsset, CheckAuthSession)); + + lock (invCaps) + invCaps.Add(userID, capsHandlers); + + return capsHandlers; + } + + string AddAndGetCapUrl(string authToken, string capType, Hashtable caps) + { + string capUrl = "/" + authToken + "/" + capType + "/"; + + m_log.Debug("[HGStandaloneInvService] Adding inventory cap " + capUrl); + caps.Add(capType, capUrl); + return capUrl; + } + + void DeregisterCaps(IHttpServer httpServer, Hashtable caps) + { + foreach (string capUrl in caps.Values) + { + m_log.Debug("[HGStandaloneInvService] Removing inventory cap " + capUrl); + httpServer.RemoveStreamHandler("POST", capUrl); + } + } + + #endregion Caps + + #region Local vs Remote + + bool VerifyKey(UUID userID, string authority, string key) + { + // Remote call to the Authorization server + if (m_userService == null) + return AuthClient.VerifyKey("http://" + authority, userID, key); + // local call + else + return ((IAuthentication)m_userService).VerifyKey(userID, key); + } + + AssetBase FetchAsset(UUID assetID, bool isTexture) + { + // Remote call to the Asset server + if (m_assetProvider == null) + return m_AssetClient.SyncGetAsset(assetID, isTexture); + // local call + else + return m_assetProvider.FetchAsset(assetID); + } + + void StoreAsset(AssetBase asset) + { + // Remote call to the Asset server + if (m_assetProvider == null) + m_AssetClient.StoreAsset(asset); + // local call + else + m_assetProvider.CreateAsset(asset); + } + + #endregion Local vs Remote + } + + class SynchronousGridAssetClient : GridAssetClient + { + public SynchronousGridAssetClient(string url) + : base(url) + { + } + + public AssetBase SyncGetAsset(UUID assetID, bool isTexture) + { + AssetRequest assReq = new AssetRequest(); + assReq.AssetID = assetID; + assReq.IsTexture = isTexture; + return base.GetAsset(assReq); + } + + } +} diff --git a/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs b/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs index 72e2dfb507..99fbb2b431 100644 --- a/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs +++ b/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs @@ -1,328 +1,328 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Net; -using System.Reflection; -using System.Text.RegularExpressions; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Framework.Communications.Capabilities; -using OpenSim.Framework.Servers; - -using OpenMetaverse; - -using log4net; -using Nini.Config; -using Nwc.XmlRpc; - -namespace OpenSim.Framework.Communications.Services -{ - public class HGLoginAuthService : LoginService - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected NetworkServersInfo m_serversInfo; - protected bool m_authUsers = false; - - /// - /// Used by the login service to make requests to the inventory service. - /// - protected IInterServiceInventoryServices m_interServiceInventoryService; - - /// - /// Used to make requests to the local regions. - /// - protected ILoginServiceToRegionsConnector m_regionsConnector; - - - public HGLoginAuthService( - UserManagerBase userManager, string welcomeMess, - IInterServiceInventoryServices interServiceInventoryService, - NetworkServersInfo serversInfo, - bool authenticate, LibraryRootFolder libraryRootFolder, ILoginServiceToRegionsConnector regionsConnector) - : base(userManager, libraryRootFolder, welcomeMess) - { - this.m_serversInfo = serversInfo; - if (m_serversInfo != null) - { - m_defaultHomeX = this.m_serversInfo.DefaultHomeLocX; - m_defaultHomeY = this.m_serversInfo.DefaultHomeLocY; - } - m_authUsers = authenticate; - - m_interServiceInventoryService = interServiceInventoryService; - m_regionsConnector = regionsConnector; - m_inventoryService = interServiceInventoryService; - } - - public void SetServersInfo(NetworkServersInfo sinfo) - { - m_serversInfo = sinfo; - } - - public override XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) - { - m_log.Info("[HGLOGIN] HGLogin called " + request.MethodName); - XmlRpcResponse response = base.XmlRpcLoginMethod(request); - Hashtable responseData = (Hashtable)response.Value; - - responseData["grid_service"] = m_serversInfo.GridURL; - responseData["grid_service_send_key"] = m_serversInfo.GridSendKey; - responseData["inventory_service"] = m_serversInfo.InventoryURL; - responseData["asset_service"] = m_serversInfo.AssetURL; - responseData["asset_service_send_key"] = m_serversInfo.AssetSendKey; - int x = (Int32)responseData["region_x"]; - int y = (Int32)responseData["region_y"]; - uint ux = (uint)(x / Constants.RegionSize); - uint uy = (uint)(y / Constants.RegionSize); - ulong regionHandle = Util.UIntsToLong(ux, uy); - responseData["region_handle"] = regionHandle.ToString(); - - // Let's remove the seed cap from the login - //responseData.Remove("seed_capability"); - - // Let's add the appearance - UUID userID = UUID.Zero; - UUID.TryParse((string)responseData["agent_id"], out userID); - AvatarAppearance appearance = m_userManager.GetUserAppearance(userID); - if (appearance == null) - { - m_log.WarnFormat("[INTER]: Appearance not found for {0}. Creating default.", userID); - appearance = new AvatarAppearance(); - } - - responseData["appearance"] = appearance.ToHashTable(); - - // Let's also send the auth token - UUID token = UUID.Random(); - responseData["auth_token"] = token.ToString(); - UserProfileData userProfile = m_userManager.GetUserProfile(userID); - if (userProfile != null) - { - userProfile.WebLoginKey = token; - m_userManager.CommitAgent(ref userProfile); - } - - return response; - } - - public XmlRpcResponse XmlRpcGenerateKeyMethod(XmlRpcRequest request) - { - - // Verify the key of who's calling - UUID userID = UUID.Zero; - UUID authKey = UUID.Zero; - UUID.TryParse((string)request.Params[0], out userID); - UUID.TryParse((string)request.Params[1], out authKey); - - m_log.InfoFormat("[HGLOGIN] HGGenerateKey called with authToken ", authKey); - string newKey = string.Empty; - - if (!(m_userManager is IAuthentication)) - { - m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Returning empty key."); - } - else - { - newKey = ((IAuthentication)m_userManager).GetNewKey(m_serversInfo.UserURL, userID, authKey); - } - - XmlRpcResponse response = new XmlRpcResponse(); - response.Value = (string) newKey; - return response; - } - - public XmlRpcResponse XmlRpcVerifyKeyMethod(XmlRpcRequest request) - { - bool success = false; - - if (request.Params.Count >= 2) - { - // Verify the key of who's calling - UUID userID = UUID.Zero; - string authKey = string.Empty; - if (UUID.TryParse((string)request.Params[0], out userID)) - { - authKey = (string)request.Params[1]; - - m_log.InfoFormat("[HGLOGIN] HGVerifyKey called with key {0}", authKey); - - if (!(m_userManager is IAuthentication)) - { - m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Denying."); - } - else - { - success = ((IAuthentication)m_userManager).VerifyKey(userID, authKey); - } - } - } - - m_log.DebugFormat("[HGLOGIN]: Response to VerifyKey is {0}", success); - XmlRpcResponse response = new XmlRpcResponse(); - response.Value = success; - return response; - } - - public override UserProfileData GetTheUser(string firstname, string lastname) - { - UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname); - if (profile != null) - { - return profile; - } - - if (!m_authUsers) - { - //no current user account so make one - m_log.Info("[LOGIN]: No user account found so creating a new one."); - - m_userManager.AddUser(firstname, lastname, "test", "", m_defaultHomeX, m_defaultHomeY); - - return m_userManager.GetUserProfile(firstname, lastname); - } - - return null; - } - - public override bool AuthenticateUser(UserProfileData profile, string password) - { - if (!m_authUsers) - { - //for now we will accept any password in sandbox mode - m_log.Info("[LOGIN]: Authorising user (no actual password check)"); - - return true; - } - else - { - m_log.Info( - "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName); - - if (!password.StartsWith("$1$")) - password = "$1$" + Util.Md5Hash(password); - - password = password.Remove(0, 3); //remove $1$ - - string s = Util.Md5Hash(password + ":" + profile.PasswordSalt); - - bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) - || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase)); - return loginresult; - } - } - - protected override RegionInfo RequestClosestRegion(string region) - { - return m_regionsConnector.RequestClosestRegion(region); - } - - protected override RegionInfo GetRegionInfo(ulong homeRegionHandle) - { - return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle); - } - - protected override RegionInfo GetRegionInfo(UUID homeRegionId) - { - return m_regionsConnector.RequestNeighbourInfo(homeRegionId); - } - - - /// - /// Not really informing the region. Just filling out the response fields related to the region. - /// - /// - /// - /// - /// true if the region was successfully contacted, false otherwise - protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response) - { - IPEndPoint endPoint = regionInfo.ExternalEndPoint; - response.SimAddress = endPoint.Address.ToString(); - response.SimPort = (uint)endPoint.Port; - response.RegionX = regionInfo.RegionLocX; - response.RegionY = regionInfo.RegionLocY; - response.SimHttpPort = regionInfo.HttpPort; - - string capsPath = CapsUtil.GetRandomCapsObjectPath(); - string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath); - - // Don't use the following! It Fails for logging into any region not on the same port as the http server! - // Kept here so it doesn't happen again! - // response.SeedCapability = regionInfo.ServerURI + capsSeedPath; - - string seedcap = "http://"; - - if (m_serversInfo.HttpUsesSSL) - { - seedcap = "https://" + m_serversInfo.HttpSSLCN + ":" + regionInfo.HttpPort + capsSeedPath; - } - else - { - seedcap = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + capsSeedPath; - } - - response.SeedCapability = seedcap; - - // Notify the target of an incoming user - m_log.InfoFormat( - "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", - regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI); - - // Update agent with target sim - user.CurrentAgent.Region = regionInfo.RegionID; - user.CurrentAgent.Handle = regionInfo.RegionHandle; - - return true; - } - - public override void LogOffUser(UserProfileData theUser, string message) - { - RegionInfo SimInfo; - try - { - SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle); - - if (SimInfo == null) - { - m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in"); - return; - } - } - catch (Exception) - { - m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off"); - return; - } - - m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off"); - } - } -} +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Communications.Capabilities; +using OpenSim.Framework.Servers; + +using OpenMetaverse; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +namespace OpenSim.Framework.Communications.Services +{ + public class HGLoginAuthService : LoginService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected NetworkServersInfo m_serversInfo; + protected bool m_authUsers = false; + + /// + /// Used by the login service to make requests to the inventory service. + /// + protected IInterServiceInventoryServices m_interServiceInventoryService; + + /// + /// Used to make requests to the local regions. + /// + protected ILoginServiceToRegionsConnector m_regionsConnector; + + + public HGLoginAuthService( + UserManagerBase userManager, string welcomeMess, + IInterServiceInventoryServices interServiceInventoryService, + NetworkServersInfo serversInfo, + bool authenticate, LibraryRootFolder libraryRootFolder, ILoginServiceToRegionsConnector regionsConnector) + : base(userManager, libraryRootFolder, welcomeMess) + { + this.m_serversInfo = serversInfo; + if (m_serversInfo != null) + { + m_defaultHomeX = this.m_serversInfo.DefaultHomeLocX; + m_defaultHomeY = this.m_serversInfo.DefaultHomeLocY; + } + m_authUsers = authenticate; + + m_interServiceInventoryService = interServiceInventoryService; + m_regionsConnector = regionsConnector; + m_inventoryService = interServiceInventoryService; + } + + public void SetServersInfo(NetworkServersInfo sinfo) + { + m_serversInfo = sinfo; + } + + public override XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) + { + m_log.Info("[HGLOGIN] HGLogin called " + request.MethodName); + XmlRpcResponse response = base.XmlRpcLoginMethod(request); + Hashtable responseData = (Hashtable)response.Value; + + responseData["grid_service"] = m_serversInfo.GridURL; + responseData["grid_service_send_key"] = m_serversInfo.GridSendKey; + responseData["inventory_service"] = m_serversInfo.InventoryURL; + responseData["asset_service"] = m_serversInfo.AssetURL; + responseData["asset_service_send_key"] = m_serversInfo.AssetSendKey; + int x = (Int32)responseData["region_x"]; + int y = (Int32)responseData["region_y"]; + uint ux = (uint)(x / Constants.RegionSize); + uint uy = (uint)(y / Constants.RegionSize); + ulong regionHandle = Util.UIntsToLong(ux, uy); + responseData["region_handle"] = regionHandle.ToString(); + + // Let's remove the seed cap from the login + //responseData.Remove("seed_capability"); + + // Let's add the appearance + UUID userID = UUID.Zero; + UUID.TryParse((string)responseData["agent_id"], out userID); + AvatarAppearance appearance = m_userManager.GetUserAppearance(userID); + if (appearance == null) + { + m_log.WarnFormat("[INTER]: Appearance not found for {0}. Creating default.", userID); + appearance = new AvatarAppearance(); + } + + responseData["appearance"] = appearance.ToHashTable(); + + // Let's also send the auth token + UUID token = UUID.Random(); + responseData["auth_token"] = token.ToString(); + UserProfileData userProfile = m_userManager.GetUserProfile(userID); + if (userProfile != null) + { + userProfile.WebLoginKey = token; + m_userManager.CommitAgent(ref userProfile); + } + + return response; + } + + public XmlRpcResponse XmlRpcGenerateKeyMethod(XmlRpcRequest request) + { + + // Verify the key of who's calling + UUID userID = UUID.Zero; + UUID authKey = UUID.Zero; + UUID.TryParse((string)request.Params[0], out userID); + UUID.TryParse((string)request.Params[1], out authKey); + + m_log.InfoFormat("[HGLOGIN] HGGenerateKey called with authToken ", authKey); + string newKey = string.Empty; + + if (!(m_userManager is IAuthentication)) + { + m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Returning empty key."); + } + else + { + newKey = ((IAuthentication)m_userManager).GetNewKey(m_serversInfo.UserURL, userID, authKey); + } + + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = (string) newKey; + return response; + } + + public XmlRpcResponse XmlRpcVerifyKeyMethod(XmlRpcRequest request) + { + bool success = false; + + if (request.Params.Count >= 2) + { + // Verify the key of who's calling + UUID userID = UUID.Zero; + string authKey = string.Empty; + if (UUID.TryParse((string)request.Params[0], out userID)) + { + authKey = (string)request.Params[1]; + + m_log.InfoFormat("[HGLOGIN] HGVerifyKey called with key {0}", authKey); + + if (!(m_userManager is IAuthentication)) + { + m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Denying."); + } + else + { + success = ((IAuthentication)m_userManager).VerifyKey(userID, authKey); + } + } + } + + m_log.DebugFormat("[HGLOGIN]: Response to VerifyKey is {0}", success); + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = success; + return response; + } + + public override UserProfileData GetTheUser(string firstname, string lastname) + { + UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname); + if (profile != null) + { + return profile; + } + + if (!m_authUsers) + { + //no current user account so make one + m_log.Info("[LOGIN]: No user account found so creating a new one."); + + m_userManager.AddUser(firstname, lastname, "test", "", m_defaultHomeX, m_defaultHomeY); + + return m_userManager.GetUserProfile(firstname, lastname); + } + + return null; + } + + public override bool AuthenticateUser(UserProfileData profile, string password) + { + if (!m_authUsers) + { + //for now we will accept any password in sandbox mode + m_log.Info("[LOGIN]: Authorising user (no actual password check)"); + + return true; + } + else + { + m_log.Info( + "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName); + + if (!password.StartsWith("$1$")) + password = "$1$" + Util.Md5Hash(password); + + password = password.Remove(0, 3); //remove $1$ + + string s = Util.Md5Hash(password + ":" + profile.PasswordSalt); + + bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) + || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase)); + return loginresult; + } + } + + protected override RegionInfo RequestClosestRegion(string region) + { + return m_regionsConnector.RequestClosestRegion(region); + } + + protected override RegionInfo GetRegionInfo(ulong homeRegionHandle) + { + return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle); + } + + protected override RegionInfo GetRegionInfo(UUID homeRegionId) + { + return m_regionsConnector.RequestNeighbourInfo(homeRegionId); + } + + + /// + /// Not really informing the region. Just filling out the response fields related to the region. + /// + /// + /// + /// + /// true if the region was successfully contacted, false otherwise + protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response) + { + IPEndPoint endPoint = regionInfo.ExternalEndPoint; + response.SimAddress = endPoint.Address.ToString(); + response.SimPort = (uint)endPoint.Port; + response.RegionX = regionInfo.RegionLocX; + response.RegionY = regionInfo.RegionLocY; + response.SimHttpPort = regionInfo.HttpPort; + + string capsPath = CapsUtil.GetRandomCapsObjectPath(); + string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath); + + // Don't use the following! It Fails for logging into any region not on the same port as the http server! + // Kept here so it doesn't happen again! + // response.SeedCapability = regionInfo.ServerURI + capsSeedPath; + + string seedcap = "http://"; + + if (m_serversInfo.HttpUsesSSL) + { + seedcap = "https://" + m_serversInfo.HttpSSLCN + ":" + regionInfo.HttpPort + capsSeedPath; + } + else + { + seedcap = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + capsSeedPath; + } + + response.SeedCapability = seedcap; + + // Notify the target of an incoming user + m_log.InfoFormat( + "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", + regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI); + + // Update agent with target sim + user.CurrentAgent.Region = regionInfo.RegionID; + user.CurrentAgent.Handle = regionInfo.RegionHandle; + + return true; + } + + public override void LogOffUser(UserProfileData theUser, string message) + { + RegionInfo SimInfo; + try + { + SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle); + + if (SimInfo == null) + { + m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in"); + return; + } + } + catch (Exception) + { + m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off"); + return; + } + + m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off"); + } + } +}