aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authordiva2009-03-21 20:16:35 +0000
committerdiva2009-03-21 20:16:35 +0000
commit09732b4d5dfdb3a9e326e99c2e86d7492bc06e55 (patch)
tree2fcb55c9e341c7abf7225c5880a6984ab8544ff2
parentMinor changes in names inside. (diff)
downloadopensim-SC_OLD-09732b4d5dfdb3a9e326e99c2e86d7492bc06e55.zip
opensim-SC_OLD-09732b4d5dfdb3a9e326e99c2e86d7492bc06e55.tar.gz
opensim-SC_OLD-09732b4d5dfdb3a9e326e99c2e86d7492bc06e55.tar.bz2
opensim-SC_OLD-09732b4d5dfdb3a9e326e99c2e86d7492bc06e55.tar.xz
Initial support for authentication/authorization keys in UserManagerBase, and use of it in HGStandaloneLoginService (producer of initial key for user, and of subsequent keys) and HGStandaloneInventoryService (consumer of a key).
Keys are of the form http://<authority>/<random uuid> and they are sent over http header "authorization".
-rw-r--r--OpenSim/Framework/Communications/IAuthentication.cs13
-rw-r--r--OpenSim/Framework/Communications/UserManagerBase.cs83
-rw-r--r--OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs272
-rw-r--r--OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginModule.cs252
-rw-r--r--OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginService.cs349
5 files changed, 962 insertions, 7 deletions
diff --git a/OpenSim/Framework/Communications/IAuthentication.cs b/OpenSim/Framework/Communications/IAuthentication.cs
new file mode 100644
index 0000000..5d6d5f2
--- /dev/null
+++ b/OpenSim/Framework/Communications/IAuthentication.cs
@@ -0,0 +1,13 @@
1using System;
2
3using OpenMetaverse;
4
5
6namespace OpenSim.Framework.Communications
7{
8 public interface IAuthentication
9 {
10 string GetNewKey(string url, UUID userID, UUID authToken);
11 bool VerifyKey(UUID userID, string key);
12 }
13}
diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs
index 62c3f89..c177d4f 100644
--- a/OpenSim/Framework/Communications/UserManagerBase.cs
+++ b/OpenSim/Framework/Communications/UserManagerBase.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Framework.Communications
42 /// <summary> 42 /// <summary>
43 /// Base class for user management (create, read, etc) 43 /// Base class for user management (create, read, etc)
44 /// </summary> 44 /// </summary>
45 public abstract class UserManagerBase : IUserService, IUserAdminService, IAvatarService, IMessagingService 45 public abstract class UserManagerBase : IUserService, IUserAdminService, IAvatarService, IMessagingService, IAuthentication
46 { 46 {
47 private static readonly ILog m_log 47 private static readonly ILog m_log
48 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -750,5 +750,86 @@ namespace OpenSim.Framework.Communications
750 } 750 }
751 } 751 }
752 } 752 }
753
754 #region IAuthentication
755
756 protected Dictionary<UUID, List<string>> m_userKeys = new Dictionary<UUID, List<string>>();
757
758 /// <summary>
759 /// This generates authorization keys in the form
760 /// http://userserver/uuid
761 /// after verifying that the caller is, indeed, authorized to request a key
762 /// </summary>
763 /// <param name="url">URL of the user server</param>
764 /// <param name="userID">The user ID requesting the new key</param>
765 /// <param name="authToken">The original authorization token for that user, obtained during login</param>
766 /// <returns></returns>
767 public string GetNewKey(string url, UUID userID, UUID authToken)
768 {
769 UserProfileData profile = GetUserProfile(userID);
770 string newKey = string.Empty;
771 if (!url.EndsWith("/"))
772 url = url + "/";
773
774 if (profile != null)
775 {
776 // I'm overloading webloginkey for this, so that no changes are needed in the DB
777 // The uses of webloginkey are fairly mutually exclusive
778 if (profile.WebLoginKey.Equals(authToken))
779 {
780 newKey = UUID.Random().ToString();
781 List<string> keys;
782 lock (m_userKeys)
783 {
784 if (m_userKeys.ContainsKey(userID))
785 {
786 keys = m_userKeys[userID];
787 }
788 else
789 {
790 keys = new List<string>();
791 m_userKeys.Add(userID, keys);
792 }
793 keys.Add(newKey);
794 }
795 m_log.InfoFormat("[USERAUTH]: Successfully generated new auth key for user {0}", userID);
796 }
797 else
798 m_log.Info("[USERAUTH]: Unauthorized key generation request. Denying new key.");
799 }
800 else
801 m_log.Info("[USERAUTH]: User not found.");
802
803 return url + newKey;
804 }
805
806 /// <summary>
807 /// This verifies the uuid portion of the key given out by GenerateKey
808 /// </summary>
809 /// <param name="userID"></param>
810 /// <param name="key"></param>
811 /// <returns></returns>
812 public bool VerifyKey(UUID userID, string key)
813 {
814 lock (m_userKeys)
815 {
816 if (m_userKeys.ContainsKey(userID))
817 {
818 List<string> keys = m_userKeys[userID];
819 if (keys.Contains(key))
820 {
821 // Keys are one-time only, so remove it
822 keys.Remove(key);
823 return true;
824 }
825 return false;
826 }
827 else
828 return false;
829 }
830 }
831
832 #endregion
833
753 } 834 }
754} 835}
diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs b/OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs
index cff3611..35db298 100644
--- a/OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs
+++ b/OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs
@@ -27,6 +27,7 @@
27 */ 27 */
28 28
29using System; 29using System;
30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.Reflection; 32using System.Reflection;
32using log4net; 33using log4net;
@@ -38,6 +39,9 @@ using OpenSim.Framework.Servers;
38using OpenSim.Framework.Servers.Interfaces; 39using OpenSim.Framework.Servers.Interfaces;
39using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.CoreModules.Communications.REST;
43
44using OpenMetaverse.StructuredData;
41 45
42namespace OpenSim.Region.CoreModules.Hypergrid 46namespace OpenSim.Region.CoreModules.Hypergrid
43{ 47{
@@ -97,8 +101,10 @@ namespace OpenSim.Region.CoreModules.Hypergrid
97 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 101 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98 102
99 private InventoryServiceBase m_inventoryService; 103 private InventoryServiceBase m_inventoryService;
100 private IUserService m_userService; 104 private UserManagerBase m_userService;
105 private Scene m_scene;
101 private bool m_doLookup = false; 106 private bool m_doLookup = false;
107 private string m_thisInventoryUrl = "http://localhost:9000";
102 108
103 public bool DoLookup 109 public bool DoLookup
104 { 110 {
@@ -106,17 +112,24 @@ namespace OpenSim.Region.CoreModules.Hypergrid
106 set { m_doLookup = value; } 112 set { m_doLookup = value; }
107 } 113 }
108 114
109 public InventoryService(Scene m_scene) 115 public InventoryService(Scene _m_scene)
110 { 116 {
117 m_scene = _m_scene;
111 m_inventoryService = (InventoryServiceBase)m_scene.CommsManager.SecureInventoryService; 118 m_inventoryService = (InventoryServiceBase)m_scene.CommsManager.SecureInventoryService;
112 m_userService = m_scene.CommsManager.UserService; 119 m_userService = (UserManagerBase)m_scene.CommsManager.UserService;
113 AddHttpHandlers(m_scene); 120 m_thisInventoryUrl = m_scene.CommsManager.NetworkServersInfo.InventoryURL;
121 if (!m_thisInventoryUrl.EndsWith("/"))
122 m_thisInventoryUrl += "/";
123
124 AddHttpHandlers();
114 } 125 }
115 126
116 protected void AddHttpHandlers(Scene m_scene) 127 protected void AddHttpHandlers()
117 { 128 {
118 IHttpServer httpServer = m_scene.CommsManager.HttpServer; 129 IHttpServer httpServer = m_scene.CommsManager.HttpServer;
119 130
131 httpServer.AddHTTPHandler("/InvCap/", CapHandler);
132
120 httpServer.AddStreamHandler( 133 httpServer.AddStreamHandler(
121 new RestDeserialiseSecureHandler<Guid, InventoryCollection>( 134 new RestDeserialiseSecureHandler<Guid, InventoryCollection>(
122 "POST", "/GetInventory/", GetUserInventory, CheckAuthSession)); 135 "POST", "/GetInventory/", GetUserInventory, CheckAuthSession));
@@ -231,6 +244,17 @@ namespace OpenSim.Region.CoreModules.Hypergrid
231 } 244 }
232 } 245 }
233 246
247 // In truth, this is not called from the outside, for standalones. I'm just making it
248 // a handler already so that this can be reused for the InventoryServer.
249 public string CreateCapUrl(Guid _userid)
250 {
251 UUID userID = new UUID(_userid);
252 UUID random = UUID.Random();
253 string url = m_thisInventoryUrl + random.ToString() + "/";
254 m_log.InfoFormat("[HGStandaloneInvService] Creating Cap URL {0} for user {1}", url, userID.ToString());
255 return url;
256 }
257
234 258
235 /// <summary> 259 /// <summary>
236 /// Return a user's entire inventory 260 /// Return a user's entire inventory
@@ -290,6 +314,37 @@ namespace OpenSim.Region.CoreModules.Hypergrid
290 return invCollection; 314 return invCollection;
291 } 315 }
292 316
317 public InventoryCollection FetchDescendants(InventoryFolderBase fb)
318 {
319 m_log.Info("[HGStandaloneInvService]: Processing request for folder " + fb.ID);
320
321 // Uncomment me to simulate a slow responding inventory server
322 //Thread.Sleep(16000);
323
324 InventoryCollection invCollection = new InventoryCollection();
325
326 List<InventoryItemBase> items = ((InventoryServiceBase)m_inventoryService).RequestFolderItems(fb.ID);
327 List<InventoryFolderBase> folders = ((InventoryServiceBase)m_inventoryService).RequestSubFolders(fb.ID);
328
329 invCollection.UserID = fb.Owner;
330 invCollection.Folders = folders;
331 invCollection.Items = items;
332
333 m_log.DebugFormat("[HGStandaloneInvService]: Found {0} items and {1} folders", items.Count, folders.Count);
334
335 return invCollection;
336 }
337
338 public InventoryItemBase GetInventoryItem(InventoryItemBase item)
339 {
340 m_log.Info("[HGStandaloneInvService]: Processing request for item " + item.ID);
341
342 item = ((InventoryServiceBase)m_inventoryService).GetInventoryItem(item.ID);
343 if (item == null)
344 m_log.Debug("[HGStandaloneInvService]: null item");
345 return item;
346 }
347
293 /// <summary> 348 /// <summary>
294 /// Guid to UUID wrapper for same name IInventoryServices method 349 /// Guid to UUID wrapper for same name IInventoryServices method
295 /// </summary> 350 /// </summary>
@@ -309,5 +364,210 @@ namespace OpenSim.Region.CoreModules.Hypergrid
309 364
310 return ((InventoryServiceBase)m_inventoryService).GetActiveGestures(userID); 365 return ((InventoryServiceBase)m_inventoryService).GetActiveGestures(userID);
311 } 366 }
367
368
369 #region Caps
370
371 Dictionary<UUID, List<string>> invCaps = new Dictionary<UUID, List<string>>();
372
373 public Hashtable CapHandler(Hashtable request)
374 {
375 m_log.Debug("[CONNECTION DEBUGGING]: InvCapHandler Called");
376
377 m_log.Debug("---------------------------");
378 m_log.Debug(" >> uri=" + request["uri"]);
379 m_log.Debug(" >> content-type=" + request["content-type"]);
380 m_log.Debug(" >> http-method=" + request["http-method"]);
381 m_log.Debug("---------------------------\n");
382
383 // these are requests if the type
384 // http://inventoryserver/InvCap/uuuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu/kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk/
385
386 Hashtable responsedata = new Hashtable();
387 responsedata["content_type"] = "text/plain";
388
389 UUID userID;
390 string authToken = string.Empty;
391 string authority = string.Empty;
392 if (!GetParams(request, out userID, out authority, out authToken))
393 {
394 m_log.InfoFormat("[HGStandaloneInvService]: Invalid parameters for InvCap message {0}", request["uri"]);
395 responsedata["int_response_code"] = 404;
396 responsedata["str_response_string"] = "Not found";
397
398 return responsedata;
399 }
400
401 // Next, let's parse the verb
402 string method = (string)request["http-method"];
403 if (method.Equals("GET"))
404 {
405 DoInvCapPost(request, responsedata, userID, authToken);
406 return responsedata;
407 }
408 //else if (method.Equals("DELETE"))
409 //{
410 // DoAgentDelete(request, responsedata, agentID, action, regionHandle);
411
412 // return responsedata;
413 //}
414 else
415 {
416 m_log.InfoFormat("[HGStandaloneInvService]: method {0} not supported in agent message", method);
417 responsedata["int_response_code"] = 405;
418 responsedata["str_response_string"] = "Method not allowed";
419
420 return responsedata;
421 }
422
423 }
424
425 public virtual void DoInvCapPost(Hashtable request, Hashtable responsedata, UUID userID, string authToken)
426 {
427
428 // This is the meaning of POST agent
429
430 // Check Auth Token
431 if (!(m_userService is IAuthentication))
432 {
433 m_log.Debug("[HGStandaloneInvService]: UserService is not IAuthentication. Denying access to inventory.");
434 responsedata["int_response_code"] = 501;
435 responsedata["str_response_string"] = "Not implemented";
436 return;
437 }
438
439 bool success = ((IAuthentication)m_userService).VerifyKey(userID, authToken);
440
441 if (success)
442 {
443
444 m_log.DebugFormat("[HGStandaloneInvService]: User has been authorized. Creating service handlers.");
445
446 // Then establish secret service handlers
447
448 RegisterCaps(userID, authToken);
449
450 responsedata["int_response_code"] = 200;
451 responsedata["str_response_string"] = "OK";
452 }
453 else
454 {
455 m_log.DebugFormat("[HGStandaloneInvService]: User has is unauthorized. Denying service handlers.");
456 responsedata["int_response_code"] = 403;
457 responsedata["str_response_string"] = "Forbidden";
458 }
459 }
460
461
462 /// <summary>
463 /// Extract the params from a request.
464 /// </summary>
465 public static bool GetParams(Hashtable request, out UUID uuid, out string authority, out string authKey)
466 {
467 uuid = UUID.Zero;
468 authority = string.Empty;
469 authKey = string.Empty;
470
471 string uri = (string)request["uri"];
472 uri = uri.Trim(new char[] { '/' });
473 string[] parts = uri.Split('/');
474 if (parts.Length <= 1)
475 {
476 return false;
477 }
478 else
479 {
480 if (!UUID.TryParse(parts[1], out uuid))
481 return false;
482
483 if (parts.Length >= 3)
484 {
485 authKey = parts[2];
486 return true;
487 }
488 }
489
490 Uri authUri;
491 Hashtable headers = (Hashtable)request["headers"];
492
493 // Authorization keys look like this:
494 // http://orgrid.org:8002/<uuid>
495 if (headers.ContainsKey("authorization"))
496 {
497 if (Uri.TryCreate((string)headers["authorization"], UriKind.Absolute, out authUri))
498 {
499 authority = authUri.Authority;
500 authKey = authUri.PathAndQuery.Trim('/');
501 m_log.DebugFormat("[HGStandaloneInvService]: Got authority {0} and key {1}", authority, authKey);
502 return true;
503 }
504 else
505 m_log.Debug("[HGStandaloneInvService]: Wrong format for Authorization header: " + (string)headers["authorization"]);
506 }
507 else
508 m_log.Debug("[HGStandaloneInvService]: Authorization header not found");
509
510 return false;
511 }
512
513 void RegisterCaps(UUID userID, string authToken)
514 {
515 IHttpServer httpServer = m_scene.CommsManager.HttpServer;
516
517 lock (invCaps)
518 {
519 if (invCaps.ContainsKey(userID))
520 {
521 // Remove the old ones
522 DeregisterCaps(httpServer, invCaps[userID]);
523 invCaps.Remove(userID);
524 }
525 }
526
527 List<string> caps = new List<string>();
528
529 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<Guid, InventoryCollection>(
530 "POST", AddAndGetCapUrl(authToken, "/GetInventory/", caps), GetUserInventory, CheckAuthSession));
531
532 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, InventoryCollection>(
533 "POST", AddAndGetCapUrl(authToken, "/FetchDescendants/", caps), FetchDescendants, CheckAuthSession));
534 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>(
535 "POST", AddAndGetCapUrl(authToken, "/GetItem/", caps), GetInventoryItem, CheckAuthSession));
536 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>(
537 "POST", AddAndGetCapUrl(authToken, "/NewFolder/", caps), m_inventoryService.AddFolder, CheckAuthSession));
538 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>(
539 "POST", AddAndGetCapUrl(authToken, "/UpdateFolder/", caps), m_inventoryService.UpdateFolder, CheckAuthSession));
540 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>(
541 "POST", AddAndGetCapUrl(authToken, "/MoveFolder/", caps), m_inventoryService.MoveFolder, CheckAuthSession));
542 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>(
543 "POST", AddAndGetCapUrl(authToken, "/PurgeFolder/", caps), m_inventoryService.PurgeFolder, CheckAuthSession));
544 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, bool>(
545 "POST", AddAndGetCapUrl(authToken, "/NewItem/", caps), m_inventoryService.AddItem, CheckAuthSession));
546 httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, bool>(
547 "POST", AddAndGetCapUrl(authToken, "/DeleteItem/", caps), m_inventoryService.DeleteItem, CheckAuthSession));
548
549 lock (invCaps)
550 invCaps.Add(userID, caps);
551 }
552
553 string AddAndGetCapUrl(string authToken, string capType, List<string> caps)
554 {
555 string capUrl = "/" + authToken + capType;
556
557 m_log.Debug("[HGStandaloneInvService] Adding inventory cap " + capUrl);
558 caps.Add(capUrl);
559 return capUrl;
560 }
561
562 void DeregisterCaps(IHttpServer httpServer, List<string> caps)
563 {
564 foreach (string capUrl in caps)
565 {
566 m_log.Debug("[HGStandaloneInvService] Removing inventory cap " + capUrl);
567 httpServer.RemoveStreamHandler("POST", capUrl);
568 }
569 }
570
571 #endregion Caps
312 } 572 }
313} 573}
diff --git a/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginModule.cs b/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginModule.cs
new file mode 100644
index 0000000..4b74ed5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginModule.cs
@@ -0,0 +1,252 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using log4net;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Cache;
40using OpenSim.Framework.Communications.Capabilities;
41using OpenSim.Framework.Servers.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Interfaces;
44
45namespace OpenSim.Region.CoreModules.Hypergrid
46{
47 public class HGStandaloneLoginModule : IRegionModule, ILoginServiceToRegionsConnector
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 protected List<Scene> m_scenes = new List<Scene>();
52 protected Scene m_firstScene;
53
54 protected bool m_enabled = false; // Module is only enabled if running in standalone mode
55
56
57 public bool RegionLoginsEnabled
58 {
59 get
60 {
61 if (m_firstScene != null)
62 {
63 return m_firstScene.CommsManager.GridService.RegionLoginsEnabled;
64 }
65 else
66 {
67 return false;
68 }
69 }
70 }
71
72 protected HGStandaloneLoginService m_loginService;
73
74 #region IRegionModule Members
75
76 public void Initialise(Scene scene, IConfigSource source)
77 {
78 if (m_firstScene == null)
79 {
80 m_firstScene = scene;
81
82 IConfig startupConfig = source.Configs["Startup"];
83 if (startupConfig != null)
84 {
85 m_enabled = !startupConfig.GetBoolean("gridmode", false);
86 }
87
88 if (m_enabled)
89 {
90 m_log.Debug("[HGLogin] HGlogin module enabled");
91 bool authenticate = true;
92 string welcomeMessage = "Welcome to OpenSim";
93 IConfig standaloneConfig = source.Configs["StandAlone"];
94 if (standaloneConfig != null)
95 {
96 authenticate = standaloneConfig.GetBoolean("accounts_authenticate", true);
97 welcomeMessage = standaloneConfig.GetString("welcome_message");
98 }
99
100 //TODO: fix casting.
101 LibraryRootFolder rootFolder = m_firstScene.CommsManager.UserProfileCacheService.LibraryRoot as LibraryRootFolder;
102
103 IHttpServer httpServer = m_firstScene.CommsManager.HttpServer;
104
105 //TODO: fix the casting of the user service, maybe by registering the userManagerBase with scenes, or refactoring so we just need a IUserService reference
106 m_loginService = new HGStandaloneLoginService((UserManagerBase)m_firstScene.CommsManager.UserService, welcomeMessage, m_firstScene.CommsManager.InterServiceInventoryService, m_firstScene.CommsManager.NetworkServersInfo, authenticate, rootFolder, this);
107
108 httpServer.AddXmlRPCHandler("hg_login", m_loginService.XmlRpcLoginMethod);
109 httpServer.AddXmlRPCHandler("hg_new_auth_key", m_loginService.XmlRpcGenerateKeyMethod);
110 httpServer.AddXmlRPCHandler("hg_verify_auth_key", m_loginService.XmlRpcVerifyKeyMethod);
111
112 }
113 }
114
115 if (m_enabled)
116 {
117 AddScene(scene);
118 }
119 }
120
121 public void PostInitialise()
122 {
123
124 }
125
126 public void Close()
127 {
128
129 }
130
131 public string Name
132 {
133 get { return "HGStandaloneLoginModule"; }
134 }
135
136 public bool IsSharedModule
137 {
138 get { return true; }
139 }
140
141 #endregion
142
143 protected void AddScene(Scene scene)
144 {
145 lock (m_scenes)
146 {
147 if (!m_scenes.Contains(scene))
148 {
149 m_scenes.Add(scene);
150 }
151 }
152 }
153
154 public bool NewUserConnection(ulong regionHandle, AgentCircuitData agent)
155 {
156 return true;
157 }
158
159 public void LogOffUserFromGrid(ulong regionHandle, UUID AvatarID, UUID RegionSecret, string message)
160 {
161 Scene scene;
162 if (TryGetRegion(regionHandle, out scene))
163 {
164 scene.HandleLogOffUserFromGrid(AvatarID, RegionSecret, message);
165 }
166 }
167
168 public RegionInfo RequestNeighbourInfo(ulong regionhandle)
169 {
170 Scene scene;
171 if (TryGetRegion(regionhandle, out scene))
172 {
173 return scene.RegionInfo;
174 }
175 return null;
176 }
177
178 public RegionInfo RequestClosestRegion(string region)
179 {
180 Scene scene;
181 if (TryGetRegion(region, out scene))
182 {
183 return scene.RegionInfo;
184 }
185 return null;
186 }
187
188 public RegionInfo RequestNeighbourInfo(UUID regionID)
189 {
190 Scene scene;
191 if (TryGetRegion(regionID, out scene))
192 {
193 return scene.RegionInfo;
194 }
195 return null;
196 }
197
198 protected bool TryGetRegion(ulong regionHandle, out Scene scene)
199 {
200 lock (m_scenes)
201 {
202 foreach (Scene nextScene in m_scenes)
203 {
204 if (nextScene.RegionInfo.RegionHandle == regionHandle)
205 {
206 scene = nextScene;
207 return true;
208 }
209 }
210 }
211
212 scene = null;
213 return false;
214 }
215
216 protected bool TryGetRegion(UUID regionID, out Scene scene)
217 {
218 lock (m_scenes)
219 {
220 foreach (Scene nextScene in m_scenes)
221 {
222 if (nextScene.RegionInfo.RegionID == regionID)
223 {
224 scene = nextScene;
225 return true;
226 }
227 }
228 }
229
230 scene = null;
231 return false;
232 }
233
234 protected bool TryGetRegion(string regionName, out Scene scene)
235 {
236 lock (m_scenes)
237 {
238 foreach (Scene nextScene in m_scenes)
239 {
240 if (nextScene.RegionInfo.RegionName == regionName)
241 {
242 scene = nextScene;
243 return true;
244 }
245 }
246 }
247
248 scene = null;
249 return false;
250 }
251 }
252}
diff --git a/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginService.cs b/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginService.cs
new file mode 100644
index 0000000..5ac50f1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Hypergrid/Login/HGStandaloneLoginService.cs
@@ -0,0 +1,349 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Framework.Communications.Capabilities;
38using OpenSim.Framework.Servers;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Interfaces;
41
42using OpenMetaverse;
43
44using log4net;
45using Nini.Config;
46using Nwc.XmlRpc;
47
48namespace OpenSim.Region.CoreModules.Hypergrid
49{
50 public class HGStandaloneLoginService : LoginService
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 protected NetworkServersInfo m_serversInfo;
55 protected bool m_authUsers = false;
56
57 /// <summary>
58 /// Used by the login service to make requests to the inventory service.
59 /// </summary>
60 protected IInterServiceInventoryServices m_interServiceInventoryService;
61
62 /// <summary>
63 /// Used to make requests to the local regions.
64 /// </summary>
65 protected ILoginServiceToRegionsConnector m_regionsConnector;
66
67
68 public HGStandaloneLoginService(
69 UserManagerBase userManager, string welcomeMess,
70 IInterServiceInventoryServices interServiceInventoryService,
71 NetworkServersInfo serversInfo,
72 bool authenticate, LibraryRootFolder libraryRootFolder, ILoginServiceToRegionsConnector regionsConnector)
73 : base(userManager, libraryRootFolder, welcomeMess)
74 {
75 this.m_serversInfo = serversInfo;
76 m_defaultHomeX = this.m_serversInfo.DefaultHomeLocX;
77 m_defaultHomeY = this.m_serversInfo.DefaultHomeLocY;
78 m_authUsers = authenticate;
79
80 m_interServiceInventoryService = interServiceInventoryService;
81 m_regionsConnector = regionsConnector;
82 m_inventoryService = interServiceInventoryService;
83 }
84
85 public override XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request)
86 {
87 m_log.Info("[HGLOGIN] HGLogin called " + request.MethodName);
88 XmlRpcResponse response = base.XmlRpcLoginMethod(request);
89 Hashtable responseData = (Hashtable)response.Value;
90
91 responseData["grid_service"] = m_serversInfo.GridURL;
92 responseData["grid_service_send_key"] = m_serversInfo.GridSendKey;
93 responseData["inventory_service"] = m_serversInfo.InventoryURL;
94 responseData["asset_service"] = m_serversInfo.AssetURL;
95 responseData["asset_service_send_key"] = m_serversInfo.AssetSendKey;
96 int x = (Int32)responseData["region_x"];
97 int y = (Int32)responseData["region_y"];
98 uint ux = (uint)(x / Constants.RegionSize);
99 uint uy = (uint)(y / Constants.RegionSize);
100 ulong regionHandle = Util.UIntsToLong(ux, uy);
101 responseData["region_handle"] = regionHandle.ToString();
102 responseData["http_port"] = (UInt32)m_serversInfo.HttpListenerPort;
103
104 // Let's remove the seed cap from the login
105 //responseData.Remove("seed_capability");
106
107 // Let's add the appearance
108 UUID userID = UUID.Zero;
109 UUID.TryParse((string)responseData["agent_id"], out userID);
110 AvatarAppearance appearance = m_userManager.GetUserAppearance(userID);
111 if (appearance == null)
112 {
113 m_log.WarnFormat("[INTER]: Appearance not found for {0}. Creating default.", userID);
114 appearance = new AvatarAppearance();
115 }
116
117 responseData["appearance"] = appearance.ToHashTable();
118
119 // Let's also send the auth token
120 UUID token = UUID.Random();
121 responseData["auth_token"] = token.ToString();
122 UserProfileData userProfile = m_userManager.GetUserProfile(userID);
123 if (userProfile != null)
124 {
125 userProfile.WebLoginKey = token;
126 m_userManager.CommitAgent(ref userProfile);
127 }
128
129 return response;
130 }
131
132 public XmlRpcResponse XmlRpcGenerateKeyMethod(XmlRpcRequest request)
133 {
134
135 // Verify the key of who's calling
136 UUID userID = UUID.Zero;
137 UUID authKey = UUID.Zero;
138 UUID.TryParse((string)request.Params[0], out userID);
139 UUID.TryParse((string)request.Params[1], out authKey);
140
141 m_log.InfoFormat("[HGLOGIN] HGGenerateKey called with authToken ", authKey);
142 string newKey = string.Empty;
143
144 if (!(m_userManager is IAuthentication))
145 {
146 m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Returning empty key.");
147 }
148 else
149 {
150 newKey = ((IAuthentication)m_userManager).GetNewKey(m_serversInfo.UserURL, userID, authKey);
151 }
152
153 XmlRpcResponse response = new XmlRpcResponse();
154 response.Value = (string) newKey;
155 return response;
156 }
157
158 public XmlRpcResponse XmlRpcVerifyKeyMethod(XmlRpcRequest request)
159 {
160 foreach (object o in request.Params)
161 {
162 if (o != null)
163 m_log.Debug(" >> Param " + o.ToString());
164 else
165 m_log.Debug(" >> Null");
166 }
167
168 // Verify the key of who's calling
169 UUID userID = UUID.Zero;
170 string authKey = string.Empty;
171 UUID.TryParse((string)request.Params[0], out userID);
172 authKey = (string)request.Params[1];
173
174 m_log.InfoFormat("[HGLOGIN] HGVerifyKey called with key ", authKey);
175 bool success = false;
176
177 if (!(m_userManager is IAuthentication))
178 {
179 m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Denying.");
180 }
181 else
182 {
183 success = ((IAuthentication)m_userManager).VerifyKey(userID, authKey);
184 }
185
186 XmlRpcResponse response = new XmlRpcResponse();
187 response.Value = (string)success.ToString();
188 return response;
189 }
190
191 public override UserProfileData GetTheUser(string firstname, string lastname)
192 {
193 UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname);
194 if (profile != null)
195 {
196 return profile;
197 }
198
199 if (!m_authUsers)
200 {
201 //no current user account so make one
202 m_log.Info("[LOGIN]: No user account found so creating a new one.");
203
204 m_userManager.AddUser(firstname, lastname, "test", "", m_defaultHomeX, m_defaultHomeY);
205
206 return m_userManager.GetUserProfile(firstname, lastname);
207 }
208
209 return null;
210 }
211
212 public override bool AuthenticateUser(UserProfileData profile, string password)
213 {
214 if (!m_authUsers)
215 {
216 //for now we will accept any password in sandbox mode
217 m_log.Info("[LOGIN]: Authorising user (no actual password check)");
218
219 return true;
220 }
221 else
222 {
223 m_log.Info(
224 "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName);
225
226 if (!password.StartsWith("$1$"))
227 password = "$1$" + Util.Md5Hash(password);
228
229 password = password.Remove(0, 3); //remove $1$
230
231 string s = Util.Md5Hash(password + ":" + profile.PasswordSalt);
232
233 bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
234 || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase));
235 return loginresult;
236 }
237 }
238
239 protected override RegionInfo RequestClosestRegion(string region)
240 {
241 return m_regionsConnector.RequestClosestRegion(region);
242 }
243
244 protected override RegionInfo GetRegionInfo(ulong homeRegionHandle)
245 {
246 return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle);
247 }
248
249 protected override RegionInfo GetRegionInfo(UUID homeRegionId)
250 {
251 return m_regionsConnector.RequestNeighbourInfo(homeRegionId);
252 }
253
254
255 /// <summary>
256 /// Prepare a login to the given region. This involves both telling the region to expect a connection
257 /// and appropriately customising the response to the user.
258 /// </summary>
259 /// <param name="sim"></param>
260 /// <param name="user"></param>
261 /// <param name="response"></param>
262 /// <returns>true if the region was successfully contacted, false otherwise</returns>
263 protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response)
264 {
265 IPEndPoint endPoint = regionInfo.ExternalEndPoint;
266 response.SimAddress = endPoint.Address.ToString();
267 response.SimPort = (uint)endPoint.Port;
268 response.RegionX = regionInfo.RegionLocX;
269 response.RegionY = regionInfo.RegionLocY;
270
271 string capsPath = CapsUtil.GetRandomCapsObjectPath();
272 string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath);
273
274 // Don't use the following! It Fails for logging into any region not on the same port as the http server!
275 // Kept here so it doesn't happen again!
276 // response.SeedCapability = regionInfo.ServerURI + capsSeedPath;
277
278 string seedcap = "http://";
279
280 if (m_serversInfo.HttpUsesSSL)
281 {
282 seedcap = "https://" + m_serversInfo.HttpSSLCN + ":" + m_serversInfo.httpSSLPort + capsSeedPath;
283 }
284 else
285 {
286 seedcap = "http://" + regionInfo.ExternalHostName + ":" + m_serversInfo.HttpListenerPort + capsSeedPath;
287 }
288
289 response.SeedCapability = seedcap;
290
291 // Notify the target of an incoming user
292 m_log.InfoFormat(
293 "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection",
294 regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI);
295
296 // Update agent with target sim
297 user.CurrentAgent.Region = regionInfo.RegionID;
298 user.CurrentAgent.Handle = regionInfo.RegionHandle;
299
300 AgentCircuitData agent = new AgentCircuitData();
301 agent.AgentID = user.ID;
302 agent.firstname = user.FirstName;
303 agent.lastname = user.SurName;
304 agent.SessionID = user.CurrentAgent.SessionID;
305 agent.SecureSessionID = user.CurrentAgent.SecureSessionID;
306 agent.circuitcode = Convert.ToUInt32(response.CircuitCode);
307 agent.BaseFolder = UUID.Zero;
308 agent.InventoryFolder = UUID.Zero;
309 agent.startpos = user.CurrentAgent.Position;
310 agent.CapsPath = capsPath;
311 agent.Appearance = m_userManager.GetUserAppearance(user.ID);
312 if (agent.Appearance == null)
313 {
314 m_log.WarnFormat("[INTER]: Appearance not found for {0} {1}. Creating default.", agent.firstname, agent.lastname);
315 agent.Appearance = new AvatarAppearance();
316 }
317
318 if (m_regionsConnector.RegionLoginsEnabled)
319 {
320 // m_log.Info("[LLStandaloneLoginModule] Informing region about user");
321 return m_regionsConnector.NewUserConnection(regionInfo.RegionHandle, agent);
322 }
323
324 return false;
325 }
326
327 public override void LogOffUser(UserProfileData theUser, string message)
328 {
329 RegionInfo SimInfo;
330 try
331 {
332 SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle);
333
334 if (SimInfo == null)
335 {
336 m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in");
337 return;
338 }
339 }
340 catch (Exception)
341 {
342 m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off");
343 return;
344 }
345
346 m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off");
347 }
348 }
349}