From b0bbe861cd0f3eb06de73a371ab961428c549c69 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 10 Jan 2010 17:15:02 -0800 Subject: Moved OpenId authentication from user server to Server.Handlers.Authentication. --- OpenSim/Grid/UserServer.Modules/OpenIdService.cs | 338 -------------------- .../Authentication/OpenIdServerConnector.cs | 77 +++++ .../Handlers/Authentication/OpenIdServerHandler.cs | 345 +++++++++++++++++++++ bin/OpenSim.Server.ini.example | 12 +- prebuild.xml | 1 + 5 files changed, 433 insertions(+), 340 deletions(-) delete mode 100644 OpenSim/Grid/UserServer.Modules/OpenIdService.cs create mode 100644 OpenSim/Server/Handlers/Authentication/OpenIdServerConnector.cs create mode 100644 OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs diff --git a/OpenSim/Grid/UserServer.Modules/OpenIdService.cs b/OpenSim/Grid/UserServer.Modules/OpenIdService.cs deleted file mode 100644 index 49dfd86..0000000 --- a/OpenSim/Grid/UserServer.Modules/OpenIdService.cs +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Net; -using System.Web; -using DotNetOpenId; -using DotNetOpenId.Provider; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.Grid.UserServer.Modules -{ - /// - /// Temporary, in-memory store for OpenID associations - /// - public class ProviderMemoryStore : IAssociationStore - { - private class AssociationItem - { - public AssociationRelyingPartyType DistinguishingFactor; - public string Handle; - public DateTime Expires; - public byte[] PrivateData; - } - - Dictionary m_store = new Dictionary(); - SortedList m_sortedStore = new SortedList(); - object m_syncRoot = new object(); - - #region IAssociationStore Members - - public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association assoc) - { - AssociationItem item = new AssociationItem(); - item.DistinguishingFactor = distinguishingFactor; - item.Handle = assoc.Handle; - item.Expires = assoc.Expires.ToLocalTime(); - item.PrivateData = assoc.SerializePrivateData(); - - lock (m_syncRoot) - { - m_store[item.Handle] = item; - m_sortedStore[item.Expires] = item; - } - } - - public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor) - { - lock (m_syncRoot) - { - if (m_sortedStore.Count > 0) - { - AssociationItem item = m_sortedStore.Values[m_sortedStore.Count - 1]; - return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); - } - else - { - return null; - } - } - } - - public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) - { - AssociationItem item; - bool success = false; - lock (m_syncRoot) - success = m_store.TryGetValue(handle, out item); - - if (success) - return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); - else - return null; - } - - public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) - { - lock (m_syncRoot) - { - for (int i = 0; i < m_sortedStore.Values.Count; i++) - { - AssociationItem item = m_sortedStore.Values[i]; - if (item.Handle == handle) - { - m_sortedStore.RemoveAt(i); - break; - } - } - - return m_store.Remove(handle); - } - } - - public void ClearExpiredAssociations() - { - lock (m_syncRoot) - { - List itemsCopy = new List(m_sortedStore.Values); - DateTime now = DateTime.Now; - - for (int i = 0; i < itemsCopy.Count; i++) - { - AssociationItem item = itemsCopy[i]; - - if (item.Expires <= now) - { - m_sortedStore.RemoveAt(i); - m_store.Remove(item.Handle); - } - } - } - } - - #endregion - } - - public class OpenIdStreamHandler : IStreamHandler - { - #region HTML - - /// Login form used to authenticate OpenID requests - const string LOGIN_PAGE = -@" -OpenSim OpenID Login - -

OpenSim Login

-
- - - - -
- -"; - - /// Page shown for a valid OpenID identity - const string OPENID_PAGE = -@" - -{2} {3} - - -OpenID identifier for {2} {3} - -"; - - /// Page shown for an invalid OpenID identity - const string INVALID_OPENID_PAGE = -@"Identity not found -Invalid OpenID identity"; - - /// Page shown if the OpenID endpoint is requested directly - const string ENDPOINT_PAGE = -@"OpenID Endpoint -This is an OpenID server endpoint, not a human-readable resource. -For more information, see http://openid.net/. -"; - - #endregion HTML - - public string ContentType { get { return m_contentType; } } - public string HttpMethod { get { return m_httpMethod; } } - public string Path { get { return m_path; } } - - string m_contentType; - string m_httpMethod; - string m_path; - UserLoginService m_loginService; - ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); - - /// - /// Constructor - /// - public OpenIdStreamHandler(string httpMethod, string path, UserLoginService loginService) - { - m_loginService = loginService; - m_httpMethod = httpMethod; - m_path = path; - - m_contentType = "text/html"; - } - - /// - /// Handles all GET and POST requests for OpenID identifier pages and endpoint - /// server communication - /// - public void Handle(string path, Stream request, Stream response, OSHttpRequest httpRequest, OSHttpResponse httpResponse) - { - Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); - - // Defult to returning HTML content - m_contentType = "text/html"; - - try - { - NameValueCollection postQuery = HttpUtility.ParseQueryString(new StreamReader(httpRequest.InputStream).ReadToEnd()); - NameValueCollection getQuery = HttpUtility.ParseQueryString(httpRequest.Url.Query); - NameValueCollection openIdQuery = (postQuery.GetValues("openid.mode") != null ? postQuery : getQuery); - - OpenIdProvider provider = new OpenIdProvider(m_openidStore, providerEndpoint, httpRequest.Url, openIdQuery); - - if (provider.Request != null) - { - if (!provider.Request.IsResponseReady && provider.Request is IAuthenticationRequest) - { - IAuthenticationRequest authRequest = (IAuthenticationRequest)provider.Request; - string[] passwordValues = postQuery.GetValues("pass"); - - UserProfileData profile; - if (TryGetProfile(new Uri(authRequest.ClaimedIdentifier.ToString()), out profile)) - { - // Check for form POST data - if (passwordValues != null && passwordValues.Length == 1) - { - if (profile != null && m_loginService.AuthenticateUser(profile, passwordValues[0])) - authRequest.IsAuthenticated = true; - else - authRequest.IsAuthenticated = false; - } - else - { - // Authentication was requested, send the client a login form - using (StreamWriter writer = new StreamWriter(response)) - writer.Write(String.Format(LOGIN_PAGE, profile.FirstName, profile.SurName)); - return; - } - } - else - { - // Cannot find an avatar matching the claimed identifier - authRequest.IsAuthenticated = false; - } - } - - // Add OpenID headers to the response - foreach (string key in provider.Request.Response.Headers.Keys) - httpResponse.AddHeader(key, provider.Request.Response.Headers[key]); - - string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); - if (contentTypeValues != null && contentTypeValues.Length == 1) - m_contentType = contentTypeValues[0]; - - // Set the response code and document body based on the OpenID result - httpResponse.StatusCode = (int)provider.Request.Response.Code; - response.Write(provider.Request.Response.Body, 0, provider.Request.Response.Body.Length); - response.Close(); - } - else if (httpRequest.Url.AbsolutePath.Contains("/openid/server")) - { - // Standard HTTP GET was made on the OpenID endpoint, send the client the default error page - using (StreamWriter writer = new StreamWriter(response)) - writer.Write(ENDPOINT_PAGE); - } - else - { - // Try and lookup this avatar - UserProfileData profile; - if (TryGetProfile(httpRequest.Url, out profile)) - { - using (StreamWriter writer = new StreamWriter(response)) - { - // TODO: Print out a full profile page for this avatar - writer.Write(String.Format(OPENID_PAGE, httpRequest.Url.Scheme, - httpRequest.Url.Authority, profile.FirstName, profile.SurName)); - } - } - else - { - // Couldn't parse an avatar name, or couldn't find the avatar in the user server - using (StreamWriter writer = new StreamWriter(response)) - writer.Write(INVALID_OPENID_PAGE); - } - } - } - catch (Exception ex) - { - httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError; - using (StreamWriter writer = new StreamWriter(response)) - writer.Write(ex.Message); - } - } - - /// - /// Parse a URL with a relative path of the form /users/First_Last and try to - /// retrieve the profile matching that avatar name - /// - /// URL to parse for an avatar name - /// Profile data for the avatar - /// True if the parse and lookup were successful, otherwise false - bool TryGetProfile(Uri requestUrl, out UserProfileData profile) - { - if (requestUrl.Segments.Length == 3 && requestUrl.Segments[1] == "users/") - { - // Parse the avatar name from the path - string username = requestUrl.Segments[requestUrl.Segments.Length - 1]; - string[] name = username.Split('_'); - - if (name.Length == 2) - { - profile = m_loginService.GetTheUser(name[0], name[1]); - return (profile != null); - } - } - - profile = null; - return false; - } - } -} diff --git a/OpenSim/Server/Handlers/Authentication/OpenIdServerConnector.cs b/OpenSim/Server/Handlers/Authentication/OpenIdServerConnector.cs new file mode 100644 index 0000000..a0a92ed --- /dev/null +++ b/OpenSim/Server/Handlers/Authentication/OpenIdServerConnector.cs @@ -0,0 +1,77 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using log4net; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; + +namespace OpenSim.Server.Handlers.Authentication +{ + public class OpenIdServerConnector : ServiceConnector + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private IAuthenticationService m_AuthenticationService; + private IUserAccountService m_UserAccountService; + private string m_ConfigName = "OpenIdService"; + + public OpenIdServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); + + string authService = serverConfig.GetString("AuthenticationServiceModule", + String.Empty); + string userService = serverConfig.GetString("UserAccountServiceModule", + String.Empty); + + if (authService == String.Empty || userService == String.Empty) + throw new Exception("No AuthenticationServiceModule or no UserAccountServiceModule in config file for OpenId authentication"); + + Object[] args = new Object[] { config }; + m_AuthenticationService = ServerUtils.LoadPlugin(authService, args); + m_UserAccountService = ServerUtils.LoadPlugin(authService, args); + + // Handler for OpenID user identity pages + server.AddStreamHandler(new OpenIdStreamHandler("GET", "/users/", m_UserAccountService, m_AuthenticationService)); + // Handlers for the OpenID endpoint server + server.AddStreamHandler(new OpenIdStreamHandler("POST", "/openid/server/", m_UserAccountService, m_AuthenticationService)); + server.AddStreamHandler(new OpenIdStreamHandler("GET", "/openid/server/", m_UserAccountService, m_AuthenticationService)); + + m_log.Info("[OPENID]: OpenId service enabled"); + } + } +} diff --git a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs new file mode 100644 index 0000000..e73961b --- /dev/null +++ b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs @@ -0,0 +1,345 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Web; +using DotNetOpenId; +using DotNetOpenId.Provider; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenSim.Services.Interfaces; +using Nini.Config; +using OpenMetaverse; + +namespace OpenSim.Server.Handlers.Authentication +{ + /// + /// Temporary, in-memory store for OpenID associations + /// + public class ProviderMemoryStore : IAssociationStore + { + private class AssociationItem + { + public AssociationRelyingPartyType DistinguishingFactor; + public string Handle; + public DateTime Expires; + public byte[] PrivateData; + } + + Dictionary m_store = new Dictionary(); + SortedList m_sortedStore = new SortedList(); + object m_syncRoot = new object(); + + #region IAssociationStore Members + + public void StoreAssociation(AssociationRelyingPartyType distinguishingFactor, Association assoc) + { + AssociationItem item = new AssociationItem(); + item.DistinguishingFactor = distinguishingFactor; + item.Handle = assoc.Handle; + item.Expires = assoc.Expires.ToLocalTime(); + item.PrivateData = assoc.SerializePrivateData(); + + lock (m_syncRoot) + { + m_store[item.Handle] = item; + m_sortedStore[item.Expires] = item; + } + } + + public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor) + { + lock (m_syncRoot) + { + if (m_sortedStore.Count > 0) + { + AssociationItem item = m_sortedStore.Values[m_sortedStore.Count - 1]; + return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); + } + else + { + return null; + } + } + } + + public Association GetAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) + { + AssociationItem item; + bool success = false; + lock (m_syncRoot) + success = m_store.TryGetValue(handle, out item); + + if (success) + return Association.Deserialize(item.Handle, item.Expires.ToUniversalTime(), item.PrivateData); + else + return null; + } + + public bool RemoveAssociation(AssociationRelyingPartyType distinguishingFactor, string handle) + { + lock (m_syncRoot) + { + for (int i = 0; i < m_sortedStore.Values.Count; i++) + { + AssociationItem item = m_sortedStore.Values[i]; + if (item.Handle == handle) + { + m_sortedStore.RemoveAt(i); + break; + } + } + + return m_store.Remove(handle); + } + } + + public void ClearExpiredAssociations() + { + lock (m_syncRoot) + { + List itemsCopy = new List(m_sortedStore.Values); + DateTime now = DateTime.Now; + + for (int i = 0; i < itemsCopy.Count; i++) + { + AssociationItem item = itemsCopy[i]; + + if (item.Expires <= now) + { + m_sortedStore.RemoveAt(i); + m_store.Remove(item.Handle); + } + } + } + } + + #endregion + } + + public class OpenIdStreamHandler : IStreamHandler + { + #region HTML + + /// Login form used to authenticate OpenID requests + const string LOGIN_PAGE = +@" +OpenSim OpenID Login + +

OpenSim Login

+
+ + + + +
+ +"; + + /// Page shown for a valid OpenID identity + const string OPENID_PAGE = +@" + +{2} {3} + + +OpenID identifier for {2} {3} + +"; + + /// Page shown for an invalid OpenID identity + const string INVALID_OPENID_PAGE = +@"Identity not found +Invalid OpenID identity"; + + /// Page shown if the OpenID endpoint is requested directly + const string ENDPOINT_PAGE = +@"OpenID Endpoint +This is an OpenID server endpoint, not a human-readable resource. +For more information, see http://openid.net/. +"; + + #endregion HTML + + public string ContentType { get { return m_contentType; } } + public string HttpMethod { get { return m_httpMethod; } } + public string Path { get { return m_path; } } + + string m_contentType; + string m_httpMethod; + string m_path; + IAuthenticationService m_authenticationService; + IUserAccountService m_userAccountService; + ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); + + /// + /// Constructor + /// + public OpenIdStreamHandler(string httpMethod, string path, IUserAccountService userService, IAuthenticationService authService) + { + m_authenticationService = authService; + m_userAccountService = userService; + m_httpMethod = httpMethod; + m_path = path; + + m_contentType = "text/html"; + } + + /// + /// Handles all GET and POST requests for OpenID identifier pages and endpoint + /// server communication + /// + public void Handle(string path, Stream request, Stream response, OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); + + // Defult to returning HTML content + m_contentType = "text/html"; + + try + { + NameValueCollection postQuery = HttpUtility.ParseQueryString(new StreamReader(httpRequest.InputStream).ReadToEnd()); + NameValueCollection getQuery = HttpUtility.ParseQueryString(httpRequest.Url.Query); + NameValueCollection openIdQuery = (postQuery.GetValues("openid.mode") != null ? postQuery : getQuery); + + OpenIdProvider provider = new OpenIdProvider(m_openidStore, providerEndpoint, httpRequest.Url, openIdQuery); + + if (provider.Request != null) + { + if (!provider.Request.IsResponseReady && provider.Request is IAuthenticationRequest) + { + IAuthenticationRequest authRequest = (IAuthenticationRequest)provider.Request; + string[] passwordValues = postQuery.GetValues("pass"); + + UserAccount account; + if (TryGetAccount(new Uri(authRequest.ClaimedIdentifier.ToString()), out account)) + { + // Check for form POST data + if (passwordValues != null && passwordValues.Length == 1) + { + if (account != null && + (m_authenticationService.Authenticate(account.PrincipalID, passwordValues[0], 30) != string.Empty)) + authRequest.IsAuthenticated = true; + else + authRequest.IsAuthenticated = false; + } + else + { + // Authentication was requested, send the client a login form + using (StreamWriter writer = new StreamWriter(response)) + writer.Write(String.Format(LOGIN_PAGE, account.FirstName, account.LastName)); + return; + } + } + else + { + // Cannot find an avatar matching the claimed identifier + authRequest.IsAuthenticated = false; + } + } + + // Add OpenID headers to the response + foreach (string key in provider.Request.Response.Headers.Keys) + httpResponse.AddHeader(key, provider.Request.Response.Headers[key]); + + string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); + if (contentTypeValues != null && contentTypeValues.Length == 1) + m_contentType = contentTypeValues[0]; + + // Set the response code and document body based on the OpenID result + httpResponse.StatusCode = (int)provider.Request.Response.Code; + response.Write(provider.Request.Response.Body, 0, provider.Request.Response.Body.Length); + response.Close(); + } + else if (httpRequest.Url.AbsolutePath.Contains("/openid/server")) + { + // Standard HTTP GET was made on the OpenID endpoint, send the client the default error page + using (StreamWriter writer = new StreamWriter(response)) + writer.Write(ENDPOINT_PAGE); + } + else + { + // Try and lookup this avatar + UserAccount account; + if (TryGetAccount(httpRequest.Url, out account)) + { + using (StreamWriter writer = new StreamWriter(response)) + { + // TODO: Print out a full profile page for this avatar + writer.Write(String.Format(OPENID_PAGE, httpRequest.Url.Scheme, + httpRequest.Url.Authority, account.FirstName, account.LastName)); + } + } + else + { + // Couldn't parse an avatar name, or couldn't find the avatar in the user server + using (StreamWriter writer = new StreamWriter(response)) + writer.Write(INVALID_OPENID_PAGE); + } + } + } + catch (Exception ex) + { + httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError; + using (StreamWriter writer = new StreamWriter(response)) + writer.Write(ex.Message); + } + } + + /// + /// Parse a URL with a relative path of the form /users/First_Last and try to + /// retrieve the profile matching that avatar name + /// + /// URL to parse for an avatar name + /// Profile data for the avatar + /// True if the parse and lookup were successful, otherwise false + bool TryGetAccount(Uri requestUrl, out UserAccount account) + { + if (requestUrl.Segments.Length == 3 && requestUrl.Segments[1] == "users/") + { + // Parse the avatar name from the path + string username = requestUrl.Segments[requestUrl.Segments.Length - 1]; + string[] name = username.Split('_'); + + if (name.Length == 2) + { + account = m_userAccountService.GetUserAccount(UUID.Zero, name[0], name[1]); + return (account != null); + } + } + + account = null; + return false; + } + } +} diff --git a/bin/OpenSim.Server.ini.example b/bin/OpenSim.Server.ini.example index b93bbd6..c76ac4d 100644 --- a/bin/OpenSim.Server.ini.example +++ b/bin/OpenSim.Server.ini.example @@ -10,7 +10,7 @@ ; * ; * [Startup] -ServiceConnectors = "OpenSim.Server.Handlers.dll:AssetServiceConnector,OpenSim.Server.Handlers.dll:InventoryServiceInConnector,OpenSim.Server.Handlers.dll:FreeswitchServerConnector,OpenSim.Server.Handlers.dll:GridServiceConnector,OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,OpenSim.Server.Handlers.dll:AvatarServiceConnector,OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,OpenSim.Server.Handlers.dll:PresenceServiceConnector,,OpenSim.Server.Handlers.dll:UserAccountServiceConnector" +ServiceConnectors = "OpenSim.Server.Handlers.dll:AssetServiceConnector,OpenSim.Server.Handlers.dll:InventoryServiceInConnector,OpenSim.Server.Handlers.dll:FreeswitchServerConnector,OpenSim.Server.Handlers.dll:GridServiceConnector,OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,OpenSim.Server.Handlers.dll:OpenIdServerConnector,OpenSim.Server.Handlers.dll:AvatarServiceConnector,OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,OpenSim.Server.Handlers.dll:PresenceServiceConnector,,OpenSim.Server.Handlers.dll:UserAccountServiceConnector" ; * This is common for all services, it's the network setup for the entire ; * server instance @@ -66,17 +66,25 @@ ServiceConnectors = "OpenSim.Server.Handlers.dll:AssetServiceConnector,OpenSim.S ; * as an authentication source. ; * [AuthenticationService] + ; for the server connector AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" + ; for the service StorageProvider = "OpenSim.Data.MySQL.dll" ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=opensim123;" +[OpenIdService] + ; for the server connector + AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" + UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + ; * This is the new style user service. ; * "Realm" is the table that is used for user lookup. ; * It defaults to "users", which uses the legacy tables ; * [UserAccountService] - AuthenticationServiceModule = "OpenSim.Services.UserService.dll:UserAccountService" + ; for the server connector LocalServiceModule = "OpenSim.Services.UserAccountService.dll:UserAccountService" + ; for the service StorageProvider = "OpenSim.Data.MySQL.dll" ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=opensim123;" ; Realm = "useraccounts" diff --git a/prebuild.xml b/prebuild.xml index 6568bae..9c326ea 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1572,6 +1572,7 @@ + -- cgit v1.1