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.cs383
1 files changed, 383 insertions, 0 deletions
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
new file mode 100644
index 0000000..5d99c79
--- /dev/null
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -0,0 +1,383 @@
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
61 protected string m_AllowedClients = string.Empty;
62 protected string m_DeniedClients = string.Empty;
63
64 private static UUID m_ScopeID;
65 private static bool m_AllowTeleportsToAnyRegion;
66 private static string m_ExternalName;
67 private static GridRegion m_DefaultGatewayRegion;
68
69 public GatekeeperService(IConfigSource config, ISimulationService simService)
70 {
71 if (!m_Initialized)
72 {
73 m_Initialized = true;
74
75 IConfig serverConfig = config.Configs["GatekeeperService"];
76 if (serverConfig == null)
77 throw new Exception(String.Format("No section GatekeeperService in config file"));
78
79 string accountService = serverConfig.GetString("UserAccountService", String.Empty);
80 string homeUsersService = serverConfig.GetString("UserAgentService", string.Empty);
81 string gridService = serverConfig.GetString("GridService", String.Empty);
82 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
83 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
84
85 // These 3 are mandatory, the others aren't
86 if (gridService == string.Empty || presenceService == string.Empty)
87 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
88
89 string scope = serverConfig.GetString("ScopeID", UUID.Zero.ToString());
90 UUID.TryParse(scope, out m_ScopeID);
91 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
92 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true);
93 m_ExternalName = serverConfig.GetString("ExternalName", string.Empty);
94 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
95 m_ExternalName = m_ExternalName + "/";
96
97 Object[] args = new Object[] { config };
98 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
99 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
100
101 if (accountService != string.Empty)
102 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
103 if (homeUsersService != string.Empty)
104 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
105
106 if (simService != null)
107 m_SimulationService = simService;
108 else if (simulationService != string.Empty)
109 m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
110
111 m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty);
112 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
113
114 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
115 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
116
117 m_log.Debug("[GATEKEEPER SERVICE]: Starting...");
118 }
119 }
120
121 public GatekeeperService(IConfigSource config)
122 : this(config, null)
123 {
124 }
125
126 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
127 {
128 regionID = UUID.Zero;
129 regionHandle = 0;
130 externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : "");
131 imageURL = string.Empty;
132 reason = string.Empty;
133 GridRegion region = null;
134
135 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
136 if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
137 {
138 List<GridRegion> defs = m_GridService.GetDefaultRegions(m_ScopeID);
139 if (defs != null && defs.Count > 0)
140 {
141 region = defs[0];
142 m_DefaultGatewayRegion = region;
143 }
144 else
145 {
146 reason = "Grid setup problem. Try specifying a particular region here.";
147 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!");
148 return false;
149 }
150 }
151 else
152 {
153 region = m_GridService.GetRegionByName(m_ScopeID, regionName);
154 if (region == null)
155 {
156 reason = "Region not found";
157 return false;
158 }
159 }
160
161 regionID = region.RegionID;
162 regionHandle = region.RegionHandle;
163
164 string regionimage = "regionImage" + regionID.ToString();
165 regionimage = regionimage.Replace("-", "");
166 imageURL = region.ServerURI + "index.php?method=" + regionimage;
167
168 return true;
169 }
170
171 public GridRegion GetHyperlinkRegion(UUID regionID)
172 {
173 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to get hyperlink region {0}", regionID);
174
175 if (!m_AllowTeleportsToAnyRegion)
176 // Don't even check the given regionID
177 return m_DefaultGatewayRegion;
178
179 GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
180 return region;
181 }
182
183 #region Login Agent
184 public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason)
185 {
186 reason = string.Empty;
187
188 string authURL = string.Empty;
189 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
190 authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
191 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}",
192 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName,
193 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0);
194
195 //
196 // Check client
197 //
198 if (m_AllowedClients != string.Empty)
199 {
200 Regex arx = new Regex(m_AllowedClients);
201 Match am = arx.Match(aCircuit.Viewer);
202
203 if (!am.Success)
204 {
205 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", aCircuit.Viewer);
206 return false;
207 }
208 }
209
210 if (m_DeniedClients != string.Empty)
211 {
212 Regex drx = new Regex(m_DeniedClients);
213 Match dm = drx.Match(aCircuit.Viewer);
214
215 if (dm.Success)
216 {
217 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", aCircuit.Viewer);
218 return false;
219 }
220 }
221
222 //
223 // Authenticate the user
224 //
225 if (!Authenticate(aCircuit))
226 {
227 reason = "Unable to verify identity";
228 m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
229 return false;
230 }
231 m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
232
233 //
234 // Check for impersonations
235 //
236 UserAccount account = null;
237 if (m_UserAccountService != null)
238 {
239 // Check to see if we have a local user with that UUID
240 account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
241 if (account != null)
242 {
243 // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
244 if (m_UserAgentService != null)
245 {
246 if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
247 {
248 // Can't do, sorry
249 reason = "Unauthorized";
250 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
251 aCircuit.firstname, aCircuit.lastname);
252 return false;
253
254 }
255 }
256 }
257 }
258 m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok");
259
260 // May want to authorize
261
262 bool isFirstLogin = false;
263 //
264 // Login the presence, if it's not there yet (by the login service)
265 //
266 PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
267 if (presence != null) // it has been placed there by the login service
268 isFirstLogin = true;
269
270 else
271 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
272 {
273 reason = "Unable to login presence";
274 m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
275 aCircuit.firstname, aCircuit.lastname);
276 return false;
277 }
278 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok");
279
280 //
281 // Get the region
282 //
283 destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
284 if (destination == null)
285 {
286 reason = "Destination region not found";
287 return false;
288 }
289 m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName);
290
291 //
292 // Adjust the visible name
293 //
294 if (account != null)
295 {
296 aCircuit.firstname = account.FirstName;
297 aCircuit.lastname = account.LastName;
298 }
299 if (account == null && !aCircuit.lastname.StartsWith("@"))
300 {
301 aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
302 try
303 {
304 Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
305 aCircuit.lastname = "@" + uri.Host; // + ":" + uri.Port;
306 }
307 catch
308 {
309 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
310 aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
311 }
312 }
313
314 //
315 // Finally launch the agent at the destination
316 //
317 Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
318 m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag);
319 return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason);
320 }
321
322 protected bool Authenticate(AgentCircuitData aCircuit)
323 {
324 if (!CheckAddress(aCircuit.ServiceSessionID))
325 return false;
326
327 string userURL = string.Empty;
328 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
329 userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
330
331 if (userURL == string.Empty)
332 {
333 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
334 return false;
335 }
336
337 if (userURL == m_ExternalName)
338 {
339 return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
340 }
341 else
342 {
343 IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
344
345 try
346 {
347 return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
348 }
349 catch
350 {
351 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
352 return false;
353 }
354 }
355
356 return false;
357 }
358
359 // Check that the service token was generated for *this* grid.
360 // If it wasn't then that's a fake agent.
361 protected bool CheckAddress(string serviceToken)
362 {
363 string[] parts = serviceToken.Split(new char[] { ';' });
364 if (parts.Length < 2)
365 return false;
366
367 char[] trailing_slash = new char[] { '/' };
368 string addressee = parts[0].TrimEnd(trailing_slash);
369 string externalname = m_ExternalName.TrimEnd(trailing_slash);
370 m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
371
372 return string.Equals(addressee, externalname, StringComparison.OrdinalIgnoreCase);
373 }
374
375 #endregion
376
377
378 #region Misc
379
380
381 #endregion
382 }
383}