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