OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
GatekeeperService.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Collections.Generic;
30 using System.Net;
31 using System.Reflection;
32 using System.Text.RegularExpressions;
33 
34 using OpenSim.Framework;
35 using OpenSim.Services.Interfaces;
37 using OpenSim.Server.Base;
38 using OpenSim.Services.Connectors.Hypergrid;
39 
40 using OpenMetaverse;
41 
42 using Nini.Config;
43 using log4net;
44 
45 namespace OpenSim.Services.HypergridService
46 {
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  string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "GatekeeperService" };
135  m_AllowedClients = Util.GetConfigVarFromSections<string>(
136  config, "AllowedClients", possibleAccessControlConfigSections, string.Empty);
137  m_DeniedClients = Util.GetConfigVarFromSections<string>(
138  config, "DeniedClients", possibleAccessControlConfigSections, string.Empty);
139  m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
140 
141  LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
142  LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
143 
144  if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
145  throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
146 
147  m_log.Debug("[GATEKEEPER SERVICE]: Starting...");
148  }
149  }
150 
151  public GatekeeperService(IConfigSource config)
152  : this(config, null)
153  {
154  }
155 
156  protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
157  {
158  string value = config.GetString(variable, string.Empty);
159  string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
160 
161  foreach (string s in parts)
162  exceptions.Add(s.Trim());
163  }
164 
165  public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
166  {
167  regionID = UUID.Zero;
168  regionHandle = 0;
169  externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : "");
170  imageURL = string.Empty;
171  reason = string.Empty;
172  GridRegion region = null;
173 
174  m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
175  if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
176  {
177  List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
178  if (defs != null && defs.Count > 0)
179  {
180  region = defs[0];
181  m_DefaultGatewayRegion = region;
182  }
183  else
184  {
185  reason = "Grid setup problem. Try specifying a particular region here.";
186  m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!");
187  return false;
188  }
189  }
190  else
191  {
192  region = m_GridService.GetRegionByName(m_ScopeID, regionName);
193  if (region == null)
194  {
195  reason = "Region not found";
196  return false;
197  }
198  }
199 
200  regionID = region.RegionID;
201  regionHandle = region.RegionHandle;
202 
203  string regionimage = "regionImage" + regionID.ToString();
204  regionimage = regionimage.Replace("-", "");
205  imageURL = region.ServerURI + "index.php?method=" + regionimage;
206 
207  return true;
208  }
209 
210  public GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message)
211  {
212  message = null;
213 
214  if (!m_AllowTeleportsToAnyRegion)
215  {
216  // Don't even check the given regionID
217  m_log.DebugFormat(
218  "[GATEKEEPER SERVICE]: Returning gateway region {0} {1} @ {2} to user {3}{4} as teleporting to arbitrary regions is not allowed.",
219  m_DefaultGatewayRegion.RegionName,
220  m_DefaultGatewayRegion.RegionID,
221  m_DefaultGatewayRegion.ServerURI,
222  agentID,
223  agentHomeURI == null ? "" : " @ " + agentHomeURI);
224 
225  message = "Teleporting to the default region.";
226  return m_DefaultGatewayRegion;
227  }
228 
229  GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
230 
231  if (region == null)
232  {
233  m_log.DebugFormat(
234  "[GATEKEEPER SERVICE]: Could not find region with ID {0} as requested by user {1}{2}. Returning null.",
235  regionID, agentID, (agentHomeURI == null) ? "" : " @ " + agentHomeURI);
236 
237  message = "The teleport destination could not be found.";
238  return null;
239  }
240 
241  m_log.DebugFormat(
242  "[GATEKEEPER SERVICE]: Returning region {0} {1} @ {2} to user {3}{4}.",
243  region.RegionName,
244  region.RegionID,
245  region.ServerURI,
246  agentID,
247  agentHomeURI == null ? "" : " @ " + agentHomeURI);
248 
249  return region;
250  }
251 
252  #region Login Agent
253  public bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason)
254  {
255  reason = string.Empty;
256 
257  string authURL = string.Empty;
258  if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
259  authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
260 
261  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}",
262  aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionID,
263  aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, (TeleportFlags)aCircuit.teleportFlags,
264  (source == null) ? "Unknown" : string.Format("{0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI));
265 
266  string curViewer = Util.GetViewerName(aCircuit);
267 
268  //
269  // Check client
270  //
271  if (m_AllowedClients != string.Empty)
272  {
273  Regex arx = new Regex(m_AllowedClients);
274  Match am = arx.Match(curViewer);
275 
276  if (!am.Success)
277  {
278  m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer);
279  return false;
280  }
281  }
282 
283  if (m_DeniedClients != string.Empty)
284  {
285  Regex drx = new Regex(m_DeniedClients);
286  Match dm = drx.Match(curViewer);
287 
288  if (dm.Success)
289  {
290  m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer);
291  return false;
292  }
293  }
294 
295  //
296  // Authenticate the user
297  //
298  if (!Authenticate(aCircuit))
299  {
300  reason = "Unable to verify identity";
301  m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
302  return false;
303  }
304  m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
305 
306  //
307  // Check for impersonations
308  //
309  UserAccount account = null;
310  if (m_UserAccountService != null)
311  {
312  // Check to see if we have a local user with that UUID
313  account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
314  if (account != null)
315  {
316  // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
317  if (m_UserAgentService != null)
318  {
319  if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
320  {
321  // Can't do, sorry
322  reason = "Unauthorized";
323  m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
324  aCircuit.firstname, aCircuit.lastname);
325  return false;
326 
327  }
328  }
329  }
330  }
331 
332  //
333  // Foreign agents allowed? Exceptions?
334  //
335  if (account == null)
336  {
337  bool allowed = m_ForeignAgentsAllowed;
338 
339  if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
340  allowed = false;
341 
342  if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
343  allowed = true;
344 
345  if (!allowed)
346  {
347  reason = "Destination does not allow visitors from your world";
348  m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
349  aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
350  return false;
351  }
352  }
353 
354  //
355  // Is the user banned?
356  // This uses a Ban service that's more powerful than the configs
357  //
358  string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
359  if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
360  {
361  reason = "You are banned from this world";
362  m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
363  return false;
364  }
365 
366  m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name);
367 
368  bool isFirstLogin = false;
369  //
370  // Login the presence, if it's not there yet (by the login service)
371  //
372  PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
373  if (presence != null) // it has been placed there by the login service
374  isFirstLogin = true;
375 
376  else
377  {
378  if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
379  {
380  reason = "Unable to login presence";
381  m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
382  aCircuit.firstname, aCircuit.lastname);
383  return false;
384  }
385 
386  m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name);
387 
388  // Also login foreigners with GridUser service
389  if (m_GridUserService != null && account == null)
390  {
391  string userId = aCircuit.AgentID.ToString();
392  string first = aCircuit.firstname, last = aCircuit.lastname;
393  if (last.StartsWith("@"))
394  {
395  string[] parts = aCircuit.firstname.Split('.');
396  if (parts.Length >= 2)
397  {
398  first = parts[0];
399  last = parts[1];
400  }
401  }
402 
403  userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
404  m_GridUserService.LoggedIn(userId);
405  }
406  }
407 
408  //
409  // Get the region
410  //
411  destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
412  if (destination == null)
413  {
414  reason = "Destination region not found";
415  return false;
416  }
417 
418  m_log.DebugFormat(
419  "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name);
420 
421  //
422  // Adjust the visible name
423  //
424  if (account != null)
425  {
426  aCircuit.firstname = account.FirstName;
427  aCircuit.lastname = account.LastName;
428  }
429  if (account == null)
430  {
431  if (!aCircuit.lastname.StartsWith("@"))
432  aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
433  try
434  {
435  Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
436  aCircuit.lastname = "@" + uri.Authority;
437  }
438  catch
439  {
440  m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
441  aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
442  }
443  }
444 
445  //
446  // Finally launch the agent at the destination
447  //
448  Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
449 
450  // Preserve our TeleportFlags we have gathered so-far
451  loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags;
452 
453  m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0}, Teleport Flags: {1}", aCircuit.Name, loginFlag);
454 
456 
457  if (!m_SimulationService.QueryAccess(
458  destination, aCircuit.AgentID, aCircuit.ServiceURLs["HomeURI"].ToString(),
459  true, aCircuit.startpos, new List<UUID>(), ctx, out reason))
460  return false;
461 
462  return m_SimulationService.CreateAgent(source, destination, aCircuit, (uint)loginFlag, ctx, out reason);
463  }
464 
465  protected bool Authenticate(AgentCircuitData aCircuit)
466  {
467  if (!CheckAddress(aCircuit.ServiceSessionID))
468  return false;
469 
470  if (string.IsNullOrEmpty(aCircuit.IPAddress))
471  {
472  m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address.");
473  return false;
474  }
475 
476  string userURL = string.Empty;
477  if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
478  userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
479 
480  if (userURL == string.Empty)
481  {
482  m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
483  return false;
484  }
485 
486  if (userURL == m_ExternalName)
487  {
488  return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
489  }
490  else
491  {
492  IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
493 
494  try
495  {
496  return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
497  }
498  catch
499  {
500  m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
501  return false;
502  }
503  }
504  }
505 
506  // Check that the service token was generated for *this* grid.
507  // If it wasn't then that's a fake agent.
508  protected bool CheckAddress(string serviceToken)
509  {
510  string[] parts = serviceToken.Split(new char[] { ';' });
511  if (parts.Length < 2)
512  return false;
513 
514  char[] trailing_slash = new char[] { '/' };
515  string addressee = parts[0].TrimEnd(trailing_slash);
516  string externalname = m_ExternalName.TrimEnd(trailing_slash);
517  m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
518 
519  Uri uri;
520  try
521  {
522  uri = new Uri(addressee);
523  }
524  catch
525  {
526  m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
527  return false;
528  }
529 
530  return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
531  }
532 
533  #endregion
534 
535 
536  #region Misc
537 
538  private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
539  {
540  bool exception = false;
541  if (exceptions.Count > 0) // we have exceptions
542  {
543  // Retrieve the visitor's origin
544  string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
545  if (!userURL.EndsWith("/"))
546  userURL += "/";
547 
548  if (exceptions.Find(delegate(string s)
549  {
550  if (!s.EndsWith("/"))
551  s += "/";
552  return s == userURL;
553  }) != null)
554  exception = true;
555  }
556 
557  return exception;
558  }
559 
560  #endregion
561  }
562 }
string ServiceSessionID
Hypergrid service token; generated by the user domain, consumed by the receiving grid. There is one such unique token for each grid visited.
string lastname
Agent's account last name
OpenSim.Framework.Constants.TeleportFlags TeleportFlags
string Id0
The id0 as reported by the viewer at login
bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason)
Dictionary< string, object > ServiceURLs
GatekeeperService(IConfigSource config, ISimulationService simService)
string IPAddress
The client's IP address, as captured by the login service
UUID SessionID
Non secure Session ID
string firstname
Agent's account first name
void LoadDomainExceptionsFromConfig(IConfig config, string variable, List< string > exceptions)
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
string ServerURI
A well-formed URI for the host region server (namely "http://" + ExternalHostName) ...
Interactive OpenSim region server
Definition: OpenSim.cs:55
GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message)
Returns the region a Hypergrid visitor should enter.
UUID AgentID
Avatar Unique Agent Identifier
OpenSim.Services.Interfaces.GridRegion GridRegion
uint teleportFlags
How this agent got here