diff options
author | diva | 2009-03-21 20:16:35 +0000 |
---|---|---|
committer | diva | 2009-03-21 20:16:35 +0000 |
commit | 09732b4d5dfdb3a9e326e99c2e86d7492bc06e55 (patch) | |
tree | 2fcb55c9e341c7abf7225c5880a6984ab8544ff2 /OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs | |
parent | Minor changes in names inside. (diff) | |
download | opensim-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".
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/CoreModules/Hypergrid/HGStandaloneInventoryService.cs | 272 |
1 files changed, 266 insertions, 6 deletions
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 | ||
29 | using System; | 29 | using System; |
30 | using System.Collections; | ||
30 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using log4net; | 33 | using log4net; |
@@ -38,6 +39,9 @@ using OpenSim.Framework.Servers; | |||
38 | using OpenSim.Framework.Servers.Interfaces; | 39 | using OpenSim.Framework.Servers.Interfaces; |
39 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
40 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.CoreModules.Communications.REST; | ||
43 | |||
44 | using OpenMetaverse.StructuredData; | ||
41 | 45 | ||
42 | namespace OpenSim.Region.CoreModules.Hypergrid | 46 | namespace 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 | } |