OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SimianAuthenticationServiceConnector.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.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 {
46  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAuthenticationServiceConnector")]
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 
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, out UUID realID)
106  {
107  realID = UUID.Zero;
108  return Authenticate(principalID, password, lifetime);
109  }
110 
111  public string Authenticate(UUID principalID, string password, int lifetime)
112  {
113  NameValueCollection requestArgs = new NameValueCollection
114  {
115  { "RequestMethod", "GetIdentities" },
116  { "UserID", principalID.ToString() }
117  };
118 
119  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
120  if (response["Success"].AsBoolean() && response["Identities"] is OSDArray)
121  {
122  bool md5hashFound = false;
123 
124  OSDArray identities = (OSDArray)response["Identities"];
125  for (int i = 0; i < identities.Count; i++)
126  {
127  OSDMap identity = identities[i] as OSDMap;
128  if (identity != null)
129  {
130  if (identity["Type"].AsString() == "md5hash")
131  {
132  string authorizeResult;
133  if (CheckPassword(principalID, password, identity["Credential"].AsString(), out authorizeResult))
134  return authorizeResult;
135 
136  md5hashFound = true;
137  break;
138  }
139  }
140  }
141 
142  if (!md5hashFound)
143  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + principalID + ", no md5hash identity found");
144  }
145  else
146  {
147  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
148  response["Message"].AsString());
149  }
150 
151  return String.Empty;
152  }
153 
154  public bool Verify(UUID principalID, string token, int lifetime)
155  {
156  NameValueCollection requestArgs = new NameValueCollection
157  {
158  { "RequestMethod", "GetSession" },
159  { "SessionID", token }
160  };
161 
162  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
163  if (response["Success"].AsBoolean())
164  {
165  return true;
166  }
167  else
168  {
169  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Could not verify session for " + principalID + ": " +
170  response["Message"].AsString());
171  }
172 
173  return false;
174  }
175 
176  public bool Release(UUID principalID, string token)
177  {
178  NameValueCollection requestArgs = new NameValueCollection
179  {
180  { "RequestMethod", "RemoveSession" },
181  { "UserID", principalID.ToString() }
182  };
183 
184  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
185  if (response["Success"].AsBoolean())
186  {
187  return true;
188  }
189  else
190  {
191  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " +
192  response["Message"].AsString());
193  }
194 
195  return false;
196  }
197 
198  public bool SetPassword(UUID principalID, string passwd)
199  {
200  // Fetch the user name first
201  NameValueCollection requestArgs = new NameValueCollection
202  {
203  { "RequestMethod", "GetUser" },
204  { "UserID", principalID.ToString() }
205  };
206 
207  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
208  if (response["Success"].AsBoolean() && response["User"] is OSDMap)
209  {
210  OSDMap userMap = (OSDMap)response["User"];
211  string identifier = userMap["Name"].AsString();
212 
213  if (!String.IsNullOrEmpty(identifier))
214  {
215  // Add/update the md5hash identity
216  // TODO: Support salts when AddIdentity does
217  // TODO: Create an a1hash too for WebDAV logins
218  requestArgs = new NameValueCollection
219  {
220  { "RequestMethod", "AddIdentity" },
221  { "Identifier", identifier },
222  { "Credential", "$1$" + Utils.MD5String(passwd) },
223  { "Type", "md5hash" },
224  { "UserID", principalID.ToString() }
225  };
226 
227  response = SimianGrid.PostToService(m_serverUrl, requestArgs);
228  bool success = response["Success"].AsBoolean();
229 
230  if (!success)
231  m_log.WarnFormat("[SIMIAN AUTH CONNECTOR]: Failed to set password for {0} ({1})", identifier, principalID);
232 
233  return success;
234  }
235  }
236  else
237  {
238  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
239  response["Message"].AsString());
240  }
241 
242  return false;
243  }
244 
245  public AuthInfo GetAuthInfo(UUID principalID)
246  {
247  throw new NotImplementedException();
248  }
249 
250  public bool SetAuthInfo(AuthInfo info)
251  {
252  throw new NotImplementedException();
253  }
254 
255  private bool CheckPassword(UUID userID, string password, string simianGridCredential, out string authorizeResult)
256  {
257  if (simianGridCredential.Contains(":"))
258  {
259  // Salted version
260  int idx = simianGridCredential.IndexOf(':');
261  string finalhash = simianGridCredential.Substring(0, idx);
262  string salt = simianGridCredential.Substring(idx + 1);
263 
264  if (finalhash == Utils.MD5String(password + ":" + salt))
265  {
266  authorizeResult = Authorize(userID);
267  return true;
268  }
269  else
270  {
271  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
272  " using md5hash " + Utils.MD5String(password) + ":" + salt);
273  }
274  }
275  else
276  {
277  // Unsalted version
278  if (password == simianGridCredential ||
279  "$1$" + password == simianGridCredential ||
280  "$1$" + Utils.MD5String(password) == simianGridCredential ||
281  Utils.MD5String(password) == simianGridCredential ||
282  "$1$" + Utils.MD5String(password + ":") == simianGridCredential)
283  {
284  authorizeResult = Authorize(userID);
285  return true;
286  }
287  else
288  {
289  m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
290  " using md5hash $1$" + Utils.MD5String(password));
291  }
292  }
293 
294  authorizeResult = null;
295  return false;
296  }
297 
298  private string Authorize(UUID userID)
299  {
300  NameValueCollection requestArgs = new NameValueCollection
301  {
302  { "RequestMethod", "AddSession" },
303  { "UserID", userID.ToString() }
304  };
305 
306  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
307  if (response["Success"].AsBoolean())
308  return response["SessionID"].AsUUID().ToString();
309  else
310  return String.Empty;
311  }
312  }
313 }
OpenMetaverse.StructuredData.OSDArray OSDArray
OpenSim.Server.Handlers.Simulation.Utils Utils
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
OpenMetaverse.StructuredData.OSDMap OSDMap
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
string Authenticate(UUID principalID, string password, int lifetime, out UUID realID)
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...