changeset 410:b2c6cc90288c

reintegration from lua-scripting
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 03 May 2013 12:23:32 +0200
parents 2d269089078f (current diff) 63f707278fc8 (diff)
children 5f6d75cd4b46
files
diffstat 5 files changed, 144 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpServer/MongooseServer.cpp	Thu May 02 16:49:28 2013 +0200
+++ b/Core/HttpServer/MongooseServer.cpp	Fri May 03 12:23:32 2013 +0200
@@ -454,6 +454,37 @@
   }
 
 
+  static std::string GetAuthenticatedUsername(const HttpHandler::Arguments& headers)
+  {
+    HttpHandler::Arguments::const_iterator auth = headers.find("authorization");
+
+    if (auth == headers.end())
+    {
+      return "";
+    }
+
+    std::string s = auth->second;
+    if (s.substr(0, 6) != "Basic ")
+    {
+      return "";
+    }
+
+    std::string b64 = s.substr(6);
+    std::string decoded = Toolbox::DecodeBase64(b64);
+    size_t semicolons = decoded.find(':');
+
+    if (semicolons == std::string::npos)
+    {
+      // Bad-formatted request
+      return "";
+    }
+    else
+    {
+      return decoded.substr(0, semicolons);
+    }
+  }
+
+
 
   static void* Callback(enum mg_event event,
                         struct mg_connection *connection,
@@ -511,6 +542,28 @@
         return (void*) "";
       }
 
+
+      // Apply the filter, if it is installed
+      const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter();
+      if (filter != NULL)
+      {
+        std::string username = GetAuthenticatedUsername(headers);
+
+        char remoteIp[24];
+        sprintf(remoteIp, "%d.%d.%d.%d", 
+                reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], 
+                reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], 
+                reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], 
+                reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]);
+
+        if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str()))
+        {
+          SendUnauthorized(output);
+          return (void*) "";
+        }
+      }
+
+
       std::string postData;
 
       if (method == Orthanc_HttpMethod_Get)
@@ -737,6 +790,11 @@
     remoteAllowed_ = allowed;
   }
 
+  void MongooseServer::SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter)
+  {
+    Stop();
+    filter_ = &filter;
+  }
 
   bool MongooseServer::IsValidBasicHttpAuthentication(const std::string& basic) const
   {
--- a/Core/HttpServer/MongooseServer.h	Thu May 02 16:49:28 2013 +0200
+++ b/Core/HttpServer/MongooseServer.h	Fri May 03 12:23:32 2013 +0200
@@ -44,6 +44,19 @@
 {
   class ChunkStore;
 
+  class IIncomingHttpRequestFilter
+  {
+  public:
+    virtual ~IIncomingHttpRequestFilter()
+    {
+    }
+
+    virtual bool IsAllowed(Orthanc_HttpMethod method,
+                           const char* uri,
+                           const char* ip,
+                           const char* username) const = 0;
+  };
+
   class MongooseServer
   {
   private:
@@ -62,6 +75,7 @@
     bool ssl_;
     std::string certificate_;
     uint16_t port_;
+    IIncomingHttpRequestFilter* filter_;
   
     bool IsRunning() const;
 
@@ -116,6 +130,13 @@
 
     void SetRemoteAccessAllowed(bool allowed);
 
+    const IIncomingHttpRequestFilter* GetIncomingHttpRequestFilter() const
+    {
+      return filter_;
+    }
+
+    void SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter);
+
     void ClearHandlers();
 
     // Can return NULL if no handler is associated to this URI
--- a/NEWS	Thu May 02 16:49:28 2013 +0200
+++ b/NEWS	Fri May 03 12:23:32 2013 +0200
@@ -5,6 +5,8 @@
 * Store-SCU for patients and studies in Orthanc Explorer.
 * "Bulk" Store-SCU (send several DICOM instances with the same
   DICOM connexion).
+* Filtering of incoming DICOM instances (through Lua scripting).
+* Filtering of incoming HTTP requests (through Lua scripting).
 
 
 Version 0.5.1 (2013/04/17)
--- a/OrthancServer/ServerContext.cpp	Thu May 02 16:49:28 2013 +0200
+++ b/OrthancServer/ServerContext.cpp	Fri May 03 12:23:32 2013 +0200
@@ -100,7 +100,7 @@
 
       if (!call.ExecutePredicate())
       {
-        LOG(INFO) << "An incoming instance has been discarded by a filter";
+        LOG(INFO) << "An incoming instance has been discarded by the filter";
         return StoreStatus_FilteredOut;
       }
     }
--- a/OrthancServer/main.cpp	Thu May 02 16:49:28 2013 +0200
+++ b/OrthancServer/main.cpp	Fri May 03 12:23:32 2013 +0200
@@ -148,6 +148,66 @@
 };
 
 
+class MyIncomingHttpRequestFilter : public IIncomingHttpRequestFilter
+{
+private:
+  ServerContext& context_;
+
+public:
+  MyIncomingHttpRequestFilter(ServerContext& context) : context_(context)
+  {
+  }
+
+  virtual bool IsAllowed(Orthanc_HttpMethod method,
+                         const char* uri,
+                         const char* ip,
+                         const char* username) const
+  {
+    static const char* HTTP_FILTER = "IncomingHttpRequestFilter";
+
+    // Test if the instance must be filtered out
+    if (context_.GetLuaContext().IsExistingFunction(HTTP_FILTER))
+    {
+      LuaFunctionCall call(context_.GetLuaContext(), HTTP_FILTER);
+
+      switch (method)
+      {
+        case Orthanc_HttpMethod_Get:
+          call.PushString("GET");
+          break;
+
+        case Orthanc_HttpMethod_Put:
+          call.PushString("PUT");
+          break;
+
+        case Orthanc_HttpMethod_Post:
+          call.PushString("POST");
+          break;
+
+        case Orthanc_HttpMethod_Delete:
+          call.PushString("DELETE");
+          break;
+
+        default:
+          return true;
+      }
+
+      call.PushString(uri);
+      call.PushString(ip);
+      call.PushString(username);
+
+      if (!call.ExecutePredicate())
+      {
+        LOG(INFO) << "An incoming HTTP request has been discarded by the filter";
+        return false;
+      }
+    }
+
+    return true;
+  }
+};
+
+
 void PrintHelp(char* path)
 {
   std::cout 
@@ -321,9 +381,11 @@
       dicomServer.SetApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC"));
 
       // HTTP server
+      MyIncomingHttpRequestFilter httpFilter(context);
       MongooseServer httpServer;
       httpServer.SetPortNumber(GetGlobalIntegerParameter("HttpPort", 8042));
       httpServer.SetRemoteAccessAllowed(GetGlobalBoolParameter("RemoteAccessAllowed", false));
+      httpServer.SetIncomingHttpRequestFilter(httpFilter);
 
       httpServer.SetAuthenticationEnabled(GetGlobalBoolParameter("AuthenticationEnabled", false));
       SetupRegisteredUsers(httpServer);