clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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.Specialized;
30 using System.Reflection;
31 using log4net;
32 using Mono.Addins;
33 using Nini.Config;
34 using OpenMetaverse;
35 using OpenMetaverse.StructuredData;
36 using OpenSim.Framework;
37 using OpenSim.Region.Framework.Interfaces;
38 using OpenSim.Region.Framework.Scenes;
39 using OpenSim.Services.Interfaces;
40  
41 namespace OpenSim.Services.Connectors.SimianGrid
42 {
43 /// <summary>
44 /// Connects authentication/authorization to the SimianGrid backend
45 /// </summary>
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAuthenticationServiceConnector")]
47 public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52  
53 private string m_serverUrl = String.Empty;
54 private bool m_Enabled = false;
55  
56 #region ISharedRegionModule
57  
58 public Type ReplaceableInterface { get { return null; } }
59 public void RegionLoaded(Scene scene) { }
60 public void PostInitialise() { }
61 public void Close() { }
62  
63 public SimianAuthenticationServiceConnector() { }
64 public string Name { get { return "SimianAuthenticationServiceConnector"; } }
65 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAuthenticationService>(this); } }
66 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAuthenticationService>(this); } }
67  
68 #endregion ISharedRegionModule
69  
70 public SimianAuthenticationServiceConnector(IConfigSource source)
71 {
72 CommonInit(source);
73 }
74  
75 public void Initialise(IConfigSource source)
76 {
77 IConfig moduleConfig = source.Configs["Modules"];
78 if (moduleConfig != null)
79 {
80 string name = moduleConfig.GetString("AuthenticationServices", "");
81 if (name == Name)
82 CommonInit(source);
83 }
84 }
85  
86 private void CommonInit(IConfigSource source)
87 {
88 IConfig gridConfig = source.Configs["AuthenticationService"];
89 if (gridConfig != null)
90 {
91 string serviceUrl = gridConfig.GetString("AuthenticationServerURI");
92 if (!String.IsNullOrEmpty(serviceUrl))
93 {
94 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
95 serviceUrl = serviceUrl + '/';
96 m_serverUrl = serviceUrl;
97 m_Enabled = true;
98 }
99 }
100  
101 if (String.IsNullOrEmpty(m_serverUrl))
102 m_log.Info("[SIMIAN AUTH CONNECTOR]: No AuthenticationServerURI specified, disabling connector");
103 }
104  
105 public string Authenticate(UUID principalID, string password, int lifetime)
106 {
107 NameValueCollection requestArgs = new NameValueCollection
108 {
109 { "RequestMethod", "GetIdentities" },
110 { "UserID", principalID.ToString() }
111 };
112  
113 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
114 if (response["Success"].AsBoolean() && response["Identities"] is OSDArray)
115 {
116 bool md5hashFound = false;
117  
118 OSDArray identities = (OSDArray)response["Identities"];
119 for (int i = 0; i < identities.Count; i++)
120 {
121 OSDMap identity = identities[i] as OSDMap;
122 if (identity != null)
123 {
124 if (identity["Type"].AsString() == "md5hash")
125 {
126 string authorizeResult;
127 if (CheckPassword(principalID, password, identity["Credential"].AsString(), out authorizeResult))
128 return authorizeResult;
129  
130 md5hashFound = true;
131 break;
132 }
133 }
134 }
135  
136 if (!md5hashFound)
137 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + principalID + ", no md5hash identity found");
138 }
139 else
140 {
141 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
142 response["Message"].AsString());
143 }
144  
145 return String.Empty;
146 }
147  
148 public bool Verify(UUID principalID, string token, int lifetime)
149 {
150 NameValueCollection requestArgs = new NameValueCollection
151 {
152 { "RequestMethod", "GetSession" },
153 { "SessionID", token }
154 };
155  
156 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
157 if (response["Success"].AsBoolean())
158 {
159 return true;
160 }
161 else
162 {
163 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Could not verify session for " + principalID + ": " +
164 response["Message"].AsString());
165 }
166  
167 return false;
168 }
169  
170 public bool Release(UUID principalID, string token)
171 {
172 NameValueCollection requestArgs = new NameValueCollection
173 {
174 { "RequestMethod", "RemoveSession" },
175 { "UserID", principalID.ToString() }
176 };
177  
178 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
179 if (response["Success"].AsBoolean())
180 {
181 return true;
182 }
183 else
184 {
185 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " +
186 response["Message"].AsString());
187 }
188  
189 return false;
190 }
191  
192 public bool SetPassword(UUID principalID, string passwd)
193 {
194 // Fetch the user name first
195 NameValueCollection requestArgs = new NameValueCollection
196 {
197 { "RequestMethod", "GetUser" },
198 { "UserID", principalID.ToString() }
199 };
200  
201 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
202 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
203 {
204 OSDMap userMap = (OSDMap)response["User"];
205 string identifier = userMap["Name"].AsString();
206  
207 if (!String.IsNullOrEmpty(identifier))
208 {
209 // Add/update the md5hash identity
210 // TODO: Support salts when AddIdentity does
211 // TODO: Create an a1hash too for WebDAV logins
212 requestArgs = new NameValueCollection
213 {
214 { "RequestMethod", "AddIdentity" },
215 { "Identifier", identifier },
216 { "Credential", "$1$" + Utils.MD5String(passwd) },
217 { "Type", "md5hash" },
218 { "UserID", principalID.ToString() }
219 };
220  
221 response = SimianGrid.PostToService(m_serverUrl, requestArgs);
222 bool success = response["Success"].AsBoolean();
223  
224 if (!success)
225 m_log.WarnFormat("[SIMIAN AUTH CONNECTOR]: Failed to set password for {0} ({1})", identifier, principalID);
226  
227 return success;
228 }
229 }
230 else
231 {
232 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
233 response["Message"].AsString());
234 }
235  
236 return false;
237 }
238  
239 public AuthInfo GetAuthInfo(UUID principalID)
240 {
241 throw new NotImplementedException();
242 }
243  
244 public bool SetAuthInfo(AuthInfo info)
245 {
246 throw new NotImplementedException();
247 }
248  
249 private bool CheckPassword(UUID userID, string password, string simianGridCredential, out string authorizeResult)
250 {
251 if (simianGridCredential.Contains(":"))
252 {
253 // Salted version
254 int idx = simianGridCredential.IndexOf(':');
255 string finalhash = simianGridCredential.Substring(0, idx);
256 string salt = simianGridCredential.Substring(idx + 1);
257  
258 if (finalhash == Utils.MD5String(password + ":" + salt))
259 {
260 authorizeResult = Authorize(userID);
261 return true;
262 }
263 else
264 {
265 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
266 " using md5hash " + Utils.MD5String(password) + ":" + salt);
267 }
268 }
269 else
270 {
271 // Unsalted version
272 if (password == simianGridCredential ||
273 "$1$" + password == simianGridCredential ||
274 "$1$" + Utils.MD5String(password) == simianGridCredential ||
275 Utils.MD5String(password) == simianGridCredential ||
276 "$1$" + Utils.MD5String(password + ":") == simianGridCredential)
277 {
278 authorizeResult = Authorize(userID);
279 return true;
280 }
281 else
282 {
283 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
284 " using md5hash $1$" + Utils.MD5String(password));
285 }
286 }
287  
288 authorizeResult = null;
289 return false;
290 }
291  
292 private string Authorize(UUID userID)
293 {
294 NameValueCollection requestArgs = new NameValueCollection
295 {
296 { "RequestMethod", "AddSession" },
297 { "UserID", userID.ToString() }
298 };
299  
300 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
301 if (response["Success"].AsBoolean())
302 return response["SessionID"].AsUUID().ToString();
303 else
304 return String.Empty;
305 }
306 }
307 }