This patch adds the admin_authenticate_user
command to OpenSim and allows authenticating to OpenSim via PHP
it will also show up on the release version of OpenSim from 0.8
and onward.
--- OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs.orig 2014-05-28 17:47:10.254150459 +0100 +++ OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs 2014-05-28 17:47:13.926150343 +0100 @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Xml; using System.Net; @@ -51,6 +52,7 @@ using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using PermissionMask = OpenSim.Framework.PermissionMask; +using RegionInfo = OpenSim.Framework.RegionInfo; namespace OpenSim.ApplicationPlugins.RemoteController { @@ -145,6 +147,7 @@ availableMethods["admin_create_user_email"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcCreateUserMethod); availableMethods["admin_exists_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcUserExistsMethod); availableMethods["admin_update_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcUpdateUserAccountMethod); + availableMethods["admin_authenticate_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAuthenticateUserMethod); // Region state management availableMethods["admin_load_xml"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcLoadXMLMethod); @@ -1280,6 +1283,139 @@ } } + /// <summary> + /// Authenticate an user. + /// <summary> + /// <param name="request">incoming XML RPC request</param> + /// <remarks> + /// XmlRpcAuthenticateUserMethod takes the following XMLRPC + /// parameters + /// <list type="table"> + /// <listheader><term>parameter name</term><description>description</description></listheader> + /// <item><term>password</term> + /// <description>admin password as set in OpenSim.ini</description></item> + /// <item><term>user_firstname</term> + /// <description>avatar's first name</description></item> + /// <item><term>user_lastname</term> + /// <description>avatar's last name</description></item> + /// <item><term>user_password</term> + /// <description>MD5 hash of avatar's password</description></item> + /// <item><term>token_lifetime</term> + /// <description>the lifetime of the returned token (upper bounded to 30s)</description></item> + /// </list> + /// + /// XmlRpcAuthenticateUserMethod returns + /// <list type="table"> + /// <listheader><term>name</term><description>description</description></listheader> + /// <item><term>success</term> + /// <description>true or false</description></item> + /// <item><term>token</term> + /// <description>the authentication token sent by OpenSim</description></item> + /// <item><term>error</term> + /// <description>error message if success is false</description></item> + /// </list> + /// </remarks> + private void XmlRpcAuthenticateUserMethod(XmlRpcRequest request, XmlRpcResponse response, + IPEndPoint remoteClient) + { + m_log.Info("[RADMIN]: AuthenticateUser: new request"); + + var responseData = (Hashtable)response.Value; + var requestData = (Hashtable)request.Params[0]; + + lock (m_requestLock) + { + try + { + CheckStringParameters(requestData, responseData, new[] + { + "user_firstname", + "user_lastname", + "user_password", + "token_lifetime" + }); + + var firstName = (string)requestData["user_firstname"]; + var lastName = (string)requestData["user_lastname"]; + var password = (string)requestData["user_password"]; + + var scene = m_application.SceneManager.CurrentOrFirstScene; + + if (scene.Equals(null)) + { + m_log.Debug("scene does not exist"); + throw new Exception("Scene does not exist."); + } + + var scopeID = scene.RegionInfo.ScopeID; + var account = scene.UserAccountService.GetUserAccount(scopeID, firstName, lastName); + + if (account.Equals(null) || account.PrincipalID.Equals(UUID.Zero)) + { + m_log.DebugFormat("avatar {0} {1} does not exist", firstName, lastName); + throw new Exception(String.Format("avatar {0} {1} does not exist", firstName, lastName)); + } + + if (String.IsNullOrEmpty(password)) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: no password provided for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("no password provided for {0} {1}", firstName, + lastName)); + } + + int lifetime; + if (int.TryParse((string)requestData["token_lifetime"], NumberStyles.Integer, CultureInfo.InvariantCulture, out lifetime) == false) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: no token lifetime provided for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("no token lifetime provided for {0} {1}", firstName, + lastName)); + } + + // Upper bound on lifetime set to 30s. + if (lifetime > 30) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: token lifetime longer than 30s for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("token lifetime longer than 30s for {0} {1}", firstName, + lastName)); + } + + var authModule = scene.RequestModuleInterface<IAuthenticationService>(); + if (authModule == null) + { + m_log.Debug("[RADMIN]: AuthenticateUser: no authentication module loded"); + throw new Exception("no authentication module loaded"); + } + + var token = authModule.Authenticate(account.PrincipalID, password, lifetime); + if (String.IsNullOrEmpty(token)) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: authentication failed for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("authentication failed for {0} {1}", firstName, + lastName)); + } + + m_log.DebugFormat("[RADMIN]: AuthenticateUser: account for user {0} {1} identified with token {2}", + firstName, lastName, token); + + responseData["token"] = token; + responseData["success"] = true; + + } + catch (Exception e) + { + responseData["success"] = false; + responseData["error"] = e.Message; + throw e; + } + + m_log.Info("[RADMIN]: AuthenticateUser: request complete"); + } + } + /// <summary> /// Load an OAR file into a region.. /// <summary>