From 3255335c42ff348465d235a3ccf9558d0d6d414b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 4 Mar 2015 17:51:11 +0000 Subject: [PATCH] Make private services forbid llHTTPRequest() calls by rejecting those that have the X-SecondLife-Shard header. If you need to enable this, set AllowHttpRequestIn = true in [Network] for all private services or individual [*Service] sections. --- .../Servers/HttpServer/BaseStreamHandler.cs | 15 ++-- .../ServiceAuth/BasicHttpAuthentication.cs | 25 ++++--- .../ServiceAuth/CompoundAuthentication.cs | 71 +++++++++++++++++++ .../ServiceAuth/DisallowLlHttpRequest.cs | 57 +++++++++++++++ OpenSim/Framework/ServiceAuth/IServiceAuth.cs | 3 +- OpenSim/Framework/ServiceAuth/ServiceAuth.cs | 18 ++++- bin/Robust.HG.ini.example | 7 ++ bin/Robust.ini.example | 7 ++ 8 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs create mode 100644 OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index f1607342d4..41aa19b67c 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -56,12 +56,17 @@ namespace OpenSim.Framework.Servers.HttpServer string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { RequestsReceived++; - if (m_Auth != null && !m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader)) + + if (m_Auth != null) { - - httpResponse.StatusCode = (int)HttpStatusCode.Unauthorized; - httpResponse.ContentType = "text/plain"; - return new byte[0]; + HttpStatusCode statusCode; + + if (!m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader, out statusCode)) + { + httpResponse.StatusCode = (int)statusCode; + httpResponse.ContentType = "text/plain"; + return new byte[0]; + } } byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); diff --git a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs index b3d64e1e64..3c13bbf82f 100644 --- a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs +++ b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Net; using System.Reflection; using Nini.Config; @@ -82,24 +83,28 @@ namespace OpenSim.Framework.ServiceAuth return false; } - public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d) + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) { - //m_log.DebugFormat("[HTTP BASIC AUTH]: Authenticate in {0}", remove_me); - if (requestHeaders != null) +// m_log.DebugFormat("[HTTP BASIC AUTH]: Authenticate in {0}", "BasicHttpAuthentication"); + + string value = requestHeaders.Get("Authorization"); + if (value != null) { - string value = requestHeaders.Get("Authorization"); - if (value != null) + value = value.Trim(); + if (value.StartsWith("Basic ")) { - value = value.Trim(); - if (value.StartsWith("Basic ")) + value = value.Replace("Basic ", string.Empty); + if (Authenticate(value)) { - value = value.Replace("Basic ", string.Empty); - if (Authenticate(value)) - return true; + statusCode = HttpStatusCode.OK; + return true; } } } + d("WWW-Authenticate", "Basic realm = \"Asset Server\""); + + statusCode = HttpStatusCode.Unauthorized; return false; } } diff --git a/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs new file mode 100644 index 0000000000..8c88d1c50f --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs @@ -0,0 +1,71 @@ +/* + * 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.Linq; +using System.Net; + +namespace OpenSim.Framework.ServiceAuth +{ + public class CompoundAuthentication : IServiceAuth + { + private List m_authentications = new List(); + + public int Count { get { return m_authentications.Count; } } + + public void AddAuthenticator(IServiceAuth auth) + { + m_authentications.Add(auth); + } + + public void RemoveAuthenticator(IServiceAuth auth) + { + m_authentications.Remove(auth); + } + + public void AddAuthorization(NameValueCollection headers) {} + + public bool Authenticate(string data) + { + return m_authentications.TrueForAll(a => a.Authenticate(data)); + } + + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) + { + foreach (IServiceAuth auth in m_authentications) + { + if (!auth.Authenticate(requestHeaders, d, out statusCode)) + return false; + } + + statusCode = HttpStatusCode.OK; + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs new file mode 100644 index 0000000000..1e1ee562e9 --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs @@ -0,0 +1,57 @@ +/* + * 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.Specialized; +using System.Net; + +namespace OpenSim.Framework.ServiceAuth +{ + public class DisallowLlHttpRequest : IServiceAuth + { + public void AddAuthorization(NameValueCollection headers) {} + + public bool Authenticate(string data) + { + return false; + } + + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) + { +// Console.WriteLine("DisallowLlHttpRequest"); + + if (requestHeaders["X-SecondLife-Shard"] != null) + { + statusCode = HttpStatusCode.Forbidden; + return false; + } + + statusCode = HttpStatusCode.OK; + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServiceAuth/IServiceAuth.cs b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs index fdd97b21c3..adde62f8c1 100644 --- a/OpenSim/Framework/ServiceAuth/IServiceAuth.cs +++ b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs @@ -26,6 +26,7 @@ */ using System; +using System.Net; using System.Collections.Generic; using System.Collections.Specialized; @@ -36,7 +37,7 @@ namespace OpenSim.Framework.ServiceAuth public interface IServiceAuth { bool Authenticate(string data); - bool Authenticate(NameValueCollection headers, AddHeaderDelegate d); + bool Authenticate(NameValueCollection headers, AddHeaderDelegate d, out HttpStatusCode statusCode); void AddAuthorization(NameValueCollection headers); } } diff --git a/OpenSim/Framework/ServiceAuth/ServiceAuth.cs b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs index 5ab613b377..30f5bd61f0 100644 --- a/OpenSim/Framework/ServiceAuth/ServiceAuth.cs +++ b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs @@ -36,15 +36,27 @@ namespace OpenSim.Framework.ServiceAuth { public static IServiceAuth Create(IConfigSource config, string section) { + CompoundAuthentication compoundAuth = new CompoundAuthentication(); + + bool allowLlHttpRequestIn + = Util.GetConfigVarFromSections(config, "AllowllHTTPRequestIn", new string[] { "Network", section }, false); + + if (!allowLlHttpRequestIn) + compoundAuth.AddAuthenticator(new DisallowLlHttpRequest()); + string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", section }, "None"); switch (authType) { case "BasicHttpAuthentication": - return new BasicHttpAuthentication(config, section); + compoundAuth.AddAuthenticator(new BasicHttpAuthentication(config, section)); + break; } - return null; + if (compoundAuth.Count > 0) + return compoundAuth; + else + return null; } } -} +} \ No newline at end of file diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 5fa4026463..872a7f8e64 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -153,6 +153,13 @@ ;; Hypergrid services are not affected by this; they are publicly available ;; by design. + ;; By default, scripts are not allowed to call private services via llHttpRequest() + ;; Such calls are detected by the X-SecondLife-Shared HTTP header + ;; If you allow such calls you must be sure that they are restricted to very trusted scripters + ;; (remember scripts can also be in visiting avatar attachments). + ;; This can be overriden in individual private service sections if necessary + AllowllHTTPRequestIn = false + ; * The following are for the remote console ; * They have no effect for the local or basic console types ; * Leave commented to diable logins to the console diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index a0b8f50177..48deeaeba5 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -129,6 +129,13 @@ ;; This is useful in cases where you want to protect most of the services, ;; but unprotect individual services. Username and Password can also be ;; overriden if you want to use different credentials for the different services. + + ;; By default, scripts are not allowed to call private services via llHttpRequest() + ;; Such calls are detected by the X-SecondLife-Shared HTTP header + ;; If you allow such calls you must be sure that they are restricted to very trusted scripters + ;; (remember scripts can also be in visiting avatar attachments). + ;; This can be overriden in individual private service sections if necessary + AllowllHTTPRequestIn = false ; * The following are for the remote console ; * They have no effect for the local or basic console types