aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/HypergridService/GatekeeperService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/HypergridService/GatekeeperService.cs')
-rw-r--r--OpenSim/Services/HypergridService/GatekeeperService.cs559
1 files changed, 559 insertions, 0 deletions
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
new file mode 100644
index 0000000..44b26d5
--- /dev/null
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -0,0 +1,559 @@
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.Generic;
30using System.Net;
31using System.Reflection;
32using System.Text.RegularExpressions;
33
34using OpenSim.Framework;
35using OpenSim.Services.Interfaces;
36using GridRegion = OpenSim.Services.Interfaces.GridRegion;
37using OpenSim.Server.Base;
38using OpenSim.Services.Connectors.Hypergrid;
39
40using OpenMetaverse;
41
42using Nini.Config;
43using log4net;
44
45namespace OpenSim.Services.HypergridService
46{
47 public class GatekeeperService : IGatekeeperService
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52
53 private static bool m_Initialized = false;
54
55 private static IGridService m_GridService;
56 private static IPresenceService m_PresenceService;
57 private static IUserAccountService m_UserAccountService;
58 private static IUserAgentService m_UserAgentService;
59 private static ISimulationService m_SimulationService;
60 private static IGridUserService m_GridUserService;
61 private static IBansService m_BansService;
62
63 private static string m_AllowedClients = string.Empty;
64 private static string m_DeniedClients = string.Empty;
65 private static bool m_ForeignAgentsAllowed = true;
66 private static List<string> m_ForeignsAllowedExceptions = new List<string>();
67 private static List<string> m_ForeignsDisallowedExceptions = new List<string>();
68
69 private static UUID m_ScopeID;
70 private static bool m_AllowTeleportsToAnyRegion;
71 private static string m_ExternalName;
72 private static Uri m_Uri;
73 private static GridRegion m_DefaultGatewayRegion;
74
75 public GatekeeperService(IConfigSource config, ISimulationService simService)
76 {
77 if (!m_Initialized)
78 {
79 m_Initialized = true;
80
81 IConfig serverConfig = config.Configs["GatekeeperService"];
82 if (serverConfig == null)
83 throw new Exception(String.Format("No section GatekeeperService in config file"));
84
85 string accountService = serverConfig.GetString("UserAccountService", String.Empty);
86 string homeUsersService = serverConfig.GetString("UserAgentService", string.Empty);
87 string gridService = serverConfig.GetString("GridService", String.Empty);
88 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
89 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
90 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
91 string bansService = serverConfig.GetString("BansService", String.Empty);
92
93 // These are mandatory, the others aren't
94 if (gridService == string.Empty || presenceService == string.Empty)
95 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
96
97 string scope = serverConfig.GetString("ScopeID", UUID.Zero.ToString());
98 UUID.TryParse(scope, out m_ScopeID);
99 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
100 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true);
101 m_ExternalName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
102 new string[] { "Startup", "Hypergrid", "GatekeeperService" }, String.Empty);
103 m_ExternalName = serverConfig.GetString("ExternalName", m_ExternalName);
104 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
105 m_ExternalName = m_ExternalName + "/";
106
107 try
108 {
109 m_Uri = new Uri(m_ExternalName);
110 }
111 catch
112 {
113 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed gatekeeper address {0}", m_ExternalName);
114 }
115
116 Object[] args = new Object[] { config };
117 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
118 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
119
120 if (accountService != string.Empty)
121 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
122 if (homeUsersService != string.Empty)
123 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
124 if (gridUserService != string.Empty)
125 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
126 if (bansService != string.Empty)
127 m_BansService = ServerUtils.LoadPlugin<IBansService>(bansService, args);
128
129 if (simService != null)
130 m_SimulationService = simService;
131 else if (simulationService != string.Empty)
132 m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
133
134 m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty);
135 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
136 m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
137
138 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
139 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
140
141 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
142 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
143
144 m_log.Debug("[GATEKEEPER SERVICE]: Starting...");
145 }
146 }
147
148 public GatekeeperService(IConfigSource config)
149 : this(config, null)
150 {
151 }
152
153 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
154 {
155 string value = config.GetString(variable, string.Empty);
156 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
157
158 foreach (string s in parts)
159 exceptions.Add(s.Trim());
160 }
161
162 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
163 {
164 regionID = UUID.Zero;
165 regionHandle = 0;
166 externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : "");
167 imageURL = string.Empty;
168 reason = string.Empty;
169 GridRegion region = null;
170
171 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
172 if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
173 {
174 List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
175 if (defs != null && defs.Count > 0)
176 {
177 region = defs[0];
178 m_DefaultGatewayRegion = region;
179 }
180 else
181 {
182 reason = "Grid setup problem. Try specifying a particular region here.";
183 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!");
184 return false;
185 }
186 }
187 else
188 {
189 region = m_GridService.GetRegionByName(m_ScopeID, regionName);
190 if (region == null)
191 {
192 reason = "Region not found";
193 return false;
194 }
195 }
196
197 regionID = region.RegionID;
198 regionHandle = region.RegionHandle;
199
200 string regionimage = "regionImage" + regionID.ToString();
201 regionimage = regionimage.Replace("-", "");
202 imageURL = region.ServerURI + "index.php?method=" + regionimage;
203
204 return true;
205 }
206
207 public GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message)
208 {
209 message = null;
210
211 if (!m_AllowTeleportsToAnyRegion)
212 {
213 // Don't even check the given regionID
214 m_log.DebugFormat(
215 "[GATEKEEPER SERVICE]: Returning gateway region {0} {1} @ {2} to user {3}{4} as teleporting to arbitrary regions is not allowed.",
216 m_DefaultGatewayRegion.RegionName,
217 m_DefaultGatewayRegion.RegionID,
218 m_DefaultGatewayRegion.ServerURI,
219 agentID,
220 agentHomeURI == null ? "" : " @ " + agentHomeURI);
221
222 message = "Teleporting to the default region.";
223 return m_DefaultGatewayRegion;
224 }
225
226 GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
227
228 if (region == null)
229 {
230 m_log.DebugFormat(
231 "[GATEKEEPER SERVICE]: Could not find region with ID {0} as requested by user {1}{2}. Returning null.",
232 regionID, agentID, (agentHomeURI == null) ? "" : " @ " + agentHomeURI);
233
234 message = "The teleport destination could not be found.";
235 return null;
236 }
237
238 m_log.DebugFormat(
239 "[GATEKEEPER SERVICE]: Returning region {0} {1} @ {2} to user {3}{4}.",
240 region.RegionName,
241 region.RegionID,
242 region.ServerURI,
243 agentID,
244 agentHomeURI == null ? "" : " @ " + agentHomeURI);
245
246 return region;
247 }
248
249 #region Login Agent
250 public bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason)
251 {
252 reason = string.Empty;
253
254 string authURL = string.Empty;
255 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
256 authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
257
258 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9}, Teleport Flags: {10}. From region {11}",
259 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionID,
260 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, (TeleportFlags)aCircuit.teleportFlags,
261 (source == null) ? "Unknown" : string.Format("{0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI));
262
263 string curViewer = Util.GetViewerName(aCircuit);
264
265 //
266 // Check client
267 //
268 if (m_AllowedClients != string.Empty)
269 {
270 Regex arx = new Regex(m_AllowedClients);
271 Match am = arx.Match(curViewer);
272
273 if (!am.Success)
274 {
275 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer);
276 return false;
277 }
278 }
279
280 if (m_DeniedClients != string.Empty)
281 {
282 Regex drx = new Regex(m_DeniedClients);
283 Match dm = drx.Match(curViewer);
284
285 if (dm.Success)
286 {
287 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer);
288 return false;
289 }
290 }
291
292 //
293 // Authenticate the user
294 //
295 if (!Authenticate(aCircuit))
296 {
297 reason = "Unable to verify identity";
298 m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
299 return false;
300 }
301 m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
302
303 //
304 // Check for impersonations
305 //
306 UserAccount account = null;
307 if (m_UserAccountService != null)
308 {
309 // Check to see if we have a local user with that UUID
310 account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
311 if (account != null)
312 {
313 // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
314 if (m_UserAgentService != null)
315 {
316 if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
317 {
318 // Can't do, sorry
319 reason = "Unauthorized";
320 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
321 aCircuit.firstname, aCircuit.lastname);
322 return false;
323
324 }
325 }
326 }
327 }
328
329 //
330 // Foreign agents allowed? Exceptions?
331 //
332 if (account == null)
333 {
334 bool allowed = m_ForeignAgentsAllowed;
335
336 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
337 allowed = false;
338
339 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
340 allowed = true;
341
342 if (!allowed)
343 {
344 reason = "Destination does not allow visitors from your world";
345 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
346 aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
347 return false;
348 }
349 }
350
351 //
352 // Is the user banned?
353 // This uses a Ban service that's more powerful than the configs
354 //
355 string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
356 if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
357 {
358 reason = "You are banned from this world";
359 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
360 return false;
361 }
362
363 m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name);
364
365 bool isFirstLogin = false;
366 //
367 // Login the presence, if it's not there yet (by the login service)
368 //
369 PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
370 if (presence != null) // it has been placed there by the login service
371 isFirstLogin = true;
372
373 else
374 {
375 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
376 {
377 reason = "Unable to login presence";
378 m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
379 aCircuit.firstname, aCircuit.lastname);
380 return false;
381 }
382
383 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name);
384
385 // Also login foreigners with GridUser service
386 if (m_GridUserService != null && account == null)
387 {
388 string userId = aCircuit.AgentID.ToString();
389 string first = aCircuit.firstname, last = aCircuit.lastname;
390 if (last.StartsWith("@"))
391 {
392 string[] parts = aCircuit.firstname.Split('.');
393 if (parts.Length >= 2)
394 {
395 first = parts[0];
396 last = parts[1];
397 }
398 }
399
400 userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
401 m_GridUserService.LoggedIn(userId);
402 }
403 }
404
405 //
406 // Get the region
407 //
408 destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
409 if (destination == null)
410 {
411 reason = "Destination region not found";
412 return false;
413 }
414
415 m_log.DebugFormat(
416 "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name);
417
418 //
419 // Adjust the visible name
420 //
421 if (account != null)
422 {
423 aCircuit.firstname = account.FirstName;
424 aCircuit.lastname = account.LastName;
425 }
426 if (account == null)
427 {
428 if (!aCircuit.lastname.StartsWith("@"))
429 aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
430 try
431 {
432 Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
433 aCircuit.lastname = "@" + uri.Authority;
434 }
435 catch
436 {
437 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
438 aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
439 }
440 }
441
442 //
443 // Finally launch the agent at the destination
444 //
445 Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
446
447 // Preserve our TeleportFlags we have gathered so-far
448 loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags;
449
450 m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0}, Teleport Flags: {1}", aCircuit.Name, loginFlag);
451
452 string version;
453
454 if (!m_SimulationService.QueryAccess(
455 destination, aCircuit.AgentID, aCircuit.ServiceURLs["HomeURI"].ToString(),
456 true, aCircuit.startpos, "SIMULATION/0.3", new List<UUID>(), out version, out reason))
457 return false;
458
459 return m_SimulationService.CreateAgent(source, destination, aCircuit, (uint)loginFlag, out reason);
460 }
461
462 protected bool Authenticate(AgentCircuitData aCircuit)
463 {
464 if (!CheckAddress(aCircuit.ServiceSessionID))
465 return false;
466
467 if (string.IsNullOrEmpty(aCircuit.IPAddress))
468 {
469 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address.");
470 return false;
471 }
472
473 string userURL = string.Empty;
474 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
475 userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
476
477 if (userURL == string.Empty)
478 {
479 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
480 return false;
481 }
482
483 if (userURL == m_ExternalName)
484 {
485 return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
486 }
487 else
488 {
489 IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
490
491 try
492 {
493 return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
494 }
495 catch
496 {
497 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
498 return false;
499 }
500 }
501 }
502
503 // Check that the service token was generated for *this* grid.
504 // If it wasn't then that's a fake agent.
505 protected bool CheckAddress(string serviceToken)
506 {
507 string[] parts = serviceToken.Split(new char[] { ';' });
508 if (parts.Length < 2)
509 return false;
510
511 char[] trailing_slash = new char[] { '/' };
512 string addressee = parts[0].TrimEnd(trailing_slash);
513 string externalname = m_ExternalName.TrimEnd(trailing_slash);
514 m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
515
516 Uri uri;
517 try
518 {
519 uri = new Uri(addressee);
520 }
521 catch
522 {
523 m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
524 return false;
525 }
526
527 return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
528 }
529
530 #endregion
531
532
533 #region Misc
534
535 private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
536 {
537 bool exception = false;
538 if (exceptions.Count > 0) // we have exceptions
539 {
540 // Retrieve the visitor's origin
541 string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
542 if (!userURL.EndsWith("/"))
543 userURL += "/";
544
545 if (exceptions.Find(delegate(string s)
546 {
547 if (!s.EndsWith("/"))
548 s += "/";
549 return s == userURL;
550 }) != null)
551 exception = true;
552 }
553
554 return exception;
555 }
556
557 #endregion
558 }
559}