aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Client/Linden/LLStandaloneLoginService.cs
diff options
context:
space:
mode:
authorMW2009-03-03 15:41:21 +0000
committerMW2009-03-03 15:41:21 +0000
commit171015f65fc2226b92b0f881a49e0110445e5045 (patch)
treee4d1dcbb4739cc61057dd3d89dc278ed67e56c29 /OpenSim/Client/Linden/LLStandaloneLoginService.cs
parentRefactoring of CreateCommsManagerPlugin. (diff)
downloadopensim-SC_OLD-171015f65fc2226b92b0f881a49e0110445e5045.zip
opensim-SC_OLD-171015f65fc2226b92b0f881a49e0110445e5045.tar.gz
opensim-SC_OLD-171015f65fc2226b92b0f881a49e0110445e5045.tar.bz2
opensim-SC_OLD-171015f65fc2226b92b0f881a49e0110445e5045.tar.xz
Moved Linden protocol login handling to modules in OpenSim.Client.Linden. There are two region modules in there LLStandaloneLoginModule (for standalone mode) and LLProxyLoginModule (for grid mode which just handles incoming expect_user and logoff_user messages from the remote login server)
Changed OpenSim.Framework.Communications.Tests.LoginServiceTests to use the LLStandaloneLoginService (from the LLStandaloneLoginModule) rather than LocalLoginService. Really these login tests should most likely be somewhere else as they are testing specific implementations of login services. Commented out the old LocalLoginService as its no longer used, but want to check there are no problems before it gets deleted.
Diffstat (limited to 'OpenSim/Client/Linden/LLStandaloneLoginService.cs')
-rw-r--r--OpenSim/Client/Linden/LLStandaloneLoginService.cs433
1 files changed, 433 insertions, 0 deletions
diff --git a/OpenSim/Client/Linden/LLStandaloneLoginService.cs b/OpenSim/Client/Linden/LLStandaloneLoginService.cs
new file mode 100644
index 0000000..f772185
--- /dev/null
+++ b/OpenSim/Client/Linden/LLStandaloneLoginService.cs
@@ -0,0 +1,433 @@
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;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Interfaces;
44
45namespace OpenSim.Client.Linden
46{
47 public class LLStandaloneLoginService : LoginService
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 protected NetworkServersInfo serversInfo;
52 protected uint defaultHomeX;
53 protected uint defaultHomeY;
54 protected bool authUsers = false;
55
56 /// <summary>
57 /// Used by the login service to make requests to the inventory service.
58 /// </summary>
59 protected IInterServiceInventoryServices m_interServiceInventoryService;
60
61 /// <summary>
62 /// Used to make requests to the local regions.
63 /// </summary>
64 protected ILoginRegionsConnector m_regionsConnector;
65
66
67 public LLStandaloneLoginService(
68 UserManagerBase userManager, string welcomeMess,
69 IInterServiceInventoryServices interServiceInventoryService,
70 NetworkServersInfo serversInfo,
71 bool authenticate, LibraryRootFolder libraryRootFolder, ILoginRegionsConnector regionsConnector)
72 : base(userManager, libraryRootFolder, welcomeMess)
73 {
74 this.serversInfo = serversInfo;
75 defaultHomeX = this.serversInfo.DefaultHomeLocX;
76 defaultHomeY = this.serversInfo.DefaultHomeLocY;
77 authUsers = authenticate;
78
79 m_interServiceInventoryService = interServiceInventoryService;
80 m_regionsConnector = regionsConnector;
81 }
82
83 public override UserProfileData GetTheUser(string firstname, string lastname)
84 {
85 UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname);
86 if (profile != null)
87 {
88 return profile;
89 }
90
91 if (!authUsers)
92 {
93 //no current user account so make one
94 m_log.Info("[LOGIN]: No user account found so creating a new one.");
95
96 m_userManager.AddUser(firstname, lastname, "test", "", defaultHomeX, defaultHomeY);
97
98 return m_userManager.GetUserProfile(firstname, lastname);
99 }
100
101 return null;
102 }
103
104 public override bool AuthenticateUser(UserProfileData profile, string password)
105 {
106 if (!authUsers)
107 {
108 //for now we will accept any password in sandbox mode
109 m_log.Info("[LOGIN]: Authorising user (no actual password check)");
110
111 return true;
112 }
113 else
114 {
115 m_log.Info(
116 "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName);
117
118 if (!password.StartsWith("$1$"))
119 password = "$1$" + Util.Md5Hash(password);
120
121 password = password.Remove(0, 3); //remove $1$
122
123 string s = Util.Md5Hash(password + ":" + profile.PasswordSalt);
124
125 bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
126 || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase));
127 return loginresult;
128 }
129 }
130
131 /// <summary>
132 /// Customises the login response and fills in missing values.
133 /// </summary>
134 /// <param name="response">The existing response</param>
135 /// <param name="theUser">The user profile</param>
136 /// <param name="startLocationRequest">The requested start location</param>
137 public override bool CustomiseResponse(LoginResponse response, UserProfileData theUser, string startLocationRequest)
138 {
139 // add active gestures to login-response
140 AddActiveGestures(response, theUser);
141
142 // HomeLocation
143 RegionInfo homeInfo = null;
144
145 // use the homeRegionID if it is stored already. If not, use the regionHandle as before
146 UUID homeRegionId = theUser.HomeRegionID;
147 ulong homeRegionHandle = theUser.HomeRegion;
148 if (homeRegionId != UUID.Zero)
149 {
150 homeInfo = GetRegionInfo(homeRegionId);
151 }
152 else
153 {
154 homeInfo = GetRegionInfo(homeRegionHandle);
155 }
156
157 if (homeInfo != null)
158 {
159 response.Home =
160 string.Format(
161 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
162 (homeInfo.RegionLocX * Constants.RegionSize),
163 (homeInfo.RegionLocY * Constants.RegionSize),
164 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
165 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
166 }
167 else
168 {
169 m_log.InfoFormat("not found the region at {0} {1}", theUser.HomeRegionX, theUser.HomeRegionY);
170 // Emergency mode: Home-region isn't available, so we can't request the region info.
171 // Use the stored home regionHandle instead.
172 // NOTE: If the home-region moves, this will be wrong until the users update their user-profile again
173 ulong regionX = homeRegionHandle >> 32;
174 ulong regionY = homeRegionHandle & 0xffffffff;
175 response.Home =
176 string.Format(
177 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
178 regionX, regionY,
179 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
180 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
181
182 m_log.InfoFormat("[LOGIN] Home region of user {0} {1} is not available; using computed region position {2} {3}",
183 theUser.FirstName, theUser.SurName,
184 regionX, regionY);
185 }
186
187 // StartLocation
188 RegionInfo regionInfo = null;
189 if (startLocationRequest == "home")
190 {
191 regionInfo = homeInfo;
192 theUser.CurrentAgent.Position = theUser.HomeLocation;
193 response.LookAt = "[r" + theUser.HomeLookAt.X.ToString() + ",r" + theUser.HomeLookAt.Y.ToString() + ",r" + theUser.HomeLookAt.Z.ToString() + "]";
194 }
195 else if (startLocationRequest == "last")
196 {
197 UUID lastRegion = theUser.CurrentAgent.Region;
198 regionInfo = GetRegionInfo(lastRegion);
199 response.LookAt = "[r" + theUser.CurrentAgent.LookAt.X.ToString() + ",r" + theUser.CurrentAgent.LookAt.Y.ToString() + ",r" + theUser.CurrentAgent.LookAt.Z.ToString() + "]";
200 }
201 else
202 {
203 Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$");
204 Match uriMatch = reURI.Match(startLocationRequest);
205 if (uriMatch == null)
206 {
207 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, but can't process it", startLocationRequest);
208 }
209 else
210 {
211 string region = uriMatch.Groups["region"].ToString();
212 regionInfo = RequestClosestRegion(region);
213 if (regionInfo == null)
214 {
215 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, can't locate region {1}", startLocationRequest, region);
216 }
217 else
218 {
219 theUser.CurrentAgent.Position = new Vector3(float.Parse(uriMatch.Groups["x"].Value),
220 float.Parse(uriMatch.Groups["y"].Value), float.Parse(uriMatch.Groups["z"].Value));
221 }
222 }
223 response.LookAt = "[r0,r1,r0]";
224 // can be: last, home, safe, url
225 response.StartLocation = "url";
226 }
227
228 if ((regionInfo != null) && (PrepareLoginToRegion(regionInfo, theUser, response)))
229 {
230 return true;
231 }
232
233 // StartLocation not available, send him to a nearby region instead
234 // regionInfo = m_gridService.RequestClosestRegion("");
235 //m_log.InfoFormat("[LOGIN]: StartLocation not available sending to region {0}", regionInfo.regionName);
236
237 // Send him to default region instead
238 ulong defaultHandle = (((ulong)defaultHomeX * Constants.RegionSize) << 32) |
239 ((ulong)defaultHomeY * Constants.RegionSize);
240
241 if ((regionInfo != null) && (defaultHandle == regionInfo.RegionHandle))
242 {
243 m_log.ErrorFormat("[LOGIN]: Not trying the default region since this is the same as the selected region");
244 return false;
245 }
246
247 m_log.Error("[LOGIN]: Sending user to default region " + defaultHandle + " instead");
248 regionInfo = GetRegionInfo(defaultHandle);
249
250 // Customise the response
251 //response.Home =
252 // string.Format(
253 // "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
254 // (SimInfo.regionLocX * Constants.RegionSize),
255 // (SimInfo.regionLocY*Constants.RegionSize),
256 // theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
257 // theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
258 theUser.CurrentAgent.Position = new Vector3(128, 128, 0);
259 response.StartLocation = "safe";
260
261 return PrepareLoginToRegion(regionInfo, theUser, response);
262 }
263
264 protected RegionInfo RequestClosestRegion(string region)
265 {
266 return m_regionsConnector.RequestClosestRegion(region);
267 }
268
269 protected RegionInfo GetRegionInfo(ulong homeRegionHandle)
270 {
271 return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle);
272 }
273
274 protected RegionInfo GetRegionInfo(UUID homeRegionId)
275 {
276 return m_regionsConnector.RequestNeighbourInfo(homeRegionId);
277 }
278
279 /// <summary>
280 /// Add active gestures of the user to the login response.
281 /// </summary>
282 /// <param name="response">
283 /// A <see cref="LoginResponse"/>
284 /// </param>
285 /// <param name="theUser">
286 /// A <see cref="UserProfileData"/>
287 /// </param>
288 private void AddActiveGestures(LoginResponse response, UserProfileData theUser)
289 {
290 List<InventoryItemBase> gestures = m_interServiceInventoryService.GetActiveGestures(theUser.ID);
291 //m_log.DebugFormat("[LOGIN]: AddActiveGestures, found {0}", gestures == null ? 0 : gestures.Count);
292 ArrayList list = new ArrayList();
293 if (gestures != null)
294 {
295 foreach (InventoryItemBase gesture in gestures)
296 {
297 Hashtable item = new Hashtable();
298 item["item_id"] = gesture.ID.ToString();
299 item["asset_id"] = gesture.AssetID.ToString();
300 list.Add(item);
301 }
302 }
303 response.ActiveGestures = list;
304 }
305
306 /// <summary>
307 /// Prepare a login to the given region. This involves both telling the region to expect a connection
308 /// and appropriately customising the response to the user.
309 /// </summary>
310 /// <param name="sim"></param>
311 /// <param name="user"></param>
312 /// <param name="response"></param>
313 /// <returns>true if the region was successfully contacted, false otherwise</returns>
314 protected bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response)
315 {
316 IPEndPoint endPoint = regionInfo.ExternalEndPoint;
317 response.SimAddress = endPoint.Address.ToString();
318 response.SimPort = (uint)endPoint.Port;
319 response.RegionX = regionInfo.RegionLocX;
320 response.RegionY = regionInfo.RegionLocY;
321
322 string capsPath = CapsUtil.GetRandomCapsObjectPath();
323 string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath);
324
325 // Don't use the following! It Fails for logging into any region not on the same port as the http server!
326 // Kept here so it doesn't happen again!
327 // response.SeedCapability = regionInfo.ServerURI + capsSeedPath;
328
329 string seedcap = "http://";
330
331 if (serversInfo.HttpUsesSSL)
332 {
333 seedcap = "https://" + serversInfo.HttpSSLCN + ":" + serversInfo.httpSSLPort + capsSeedPath;
334 }
335 else
336 {
337 seedcap = "http://" + regionInfo.ExternalHostName + ":" + serversInfo.HttpListenerPort + capsSeedPath;
338 }
339
340 response.SeedCapability = seedcap;
341
342 // Notify the target of an incoming user
343 m_log.InfoFormat(
344 "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection",
345 regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI);
346
347 // Update agent with target sim
348 user.CurrentAgent.Region = regionInfo.RegionID;
349 user.CurrentAgent.Handle = regionInfo.RegionHandle;
350
351 AgentCircuitData agent = new AgentCircuitData();
352 agent.AgentID = user.ID;
353 agent.firstname = user.FirstName;
354 agent.lastname = user.SurName;
355 agent.SessionID = user.CurrentAgent.SessionID;
356 agent.SecureSessionID = user.CurrentAgent.SecureSessionID;
357 agent.circuitcode = Convert.ToUInt32(response.CircuitCode);
358 agent.BaseFolder = UUID.Zero;
359 agent.InventoryFolder = UUID.Zero;
360 agent.startpos = user.CurrentAgent.Position;
361 agent.CapsPath = capsPath;
362 agent.Appearance = m_userManager.GetUserAppearance(user.ID);
363 if (agent.Appearance == null)
364 {
365 m_log.WarnFormat("[INTER]: Appearance not found for {0} {1}. Creating default.", agent.firstname, agent.lastname);
366 agent.Appearance = new AvatarAppearance();
367 }
368
369 if (m_regionsConnector.RegionLoginsEnabled)
370 {
371 // m_log.Info("[LLStandaloneLoginModule] Informing region about user");
372 return m_regionsConnector.NewUserConnection(regionInfo.RegionHandle, agent);
373 }
374
375 return false;
376 }
377
378 // See LoginService
379 protected override InventoryData GetInventorySkeleton(UUID userID)
380 {
381 List<InventoryFolderBase> folders = m_interServiceInventoryService.GetInventorySkeleton(userID);
382
383 // If we have user auth but no inventory folders for some reason, create a new set of folders.
384 if (null == folders || 0 == folders.Count)
385 {
386 m_interServiceInventoryService.CreateNewUserInventory(userID);
387 folders = m_interServiceInventoryService.GetInventorySkeleton(userID);
388 }
389
390 UUID rootID = UUID.Zero;
391 ArrayList AgentInventoryArray = new ArrayList();
392 Hashtable TempHash;
393 foreach (InventoryFolderBase InvFolder in folders)
394 {
395 if (InvFolder.ParentID == UUID.Zero)
396 {
397 rootID = InvFolder.ID;
398 }
399 TempHash = new Hashtable();
400 TempHash["name"] = InvFolder.Name;
401 TempHash["parent_id"] = InvFolder.ParentID.ToString();
402 TempHash["version"] = (Int32)InvFolder.Version;
403 TempHash["type_default"] = (Int32)InvFolder.Type;
404 TempHash["folder_id"] = InvFolder.ID.ToString();
405 AgentInventoryArray.Add(TempHash);
406 }
407
408 return new InventoryData(AgentInventoryArray, rootID);
409 }
410
411 public override void LogOffUser(UserProfileData theUser, string message)
412 {
413 RegionInfo SimInfo;
414 try
415 {
416 SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle);
417
418 if (SimInfo == null)
419 {
420 m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in");
421 return;
422 }
423 }
424 catch (Exception)
425 {
426 m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off");
427 return;
428 }
429
430 m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off");
431 }
432 }
433}