r20559: Web Application Framework
authorDerrell Lipman <derrell@samba.org>
Fri, 5 Jan 2007 19:29:45 +0000 (19:29 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:36:56 +0000 (14:36 -0500)
- Disallow, for now, any ScriptTransport access.  A serious security issue has
  been described, and since we don't currently need it for anything, disable
  it completely.

- Continued clean-up towards implementing the common authentication code

services/json_auth.esp
services/request.esp
webapps/swat/source/class/swat/module/AbstractModuleFsm.js
webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
webapps/swat/source/class/swat/module/ldbbrowse/Gui.js
webapps/swat/source/class/swat/module/statistics/Fsm.js

index 2d58b6e2af05aeaf349af1d2bb48498234082f6d..0fdd98037d6ab46d9ddf6c3b2d508c12bb0bb9c5 100644 (file)
@@ -1,7 +1,13 @@
 <%
 /* Return true to allow access; false otherwise */
-function json_authenticate(serviceComponents, method)
+function json_authenticate(serviceComponents, method, scriptTransportId)
 {
+    // Don't allow any access via ScriptTransport, for now.
+    if (scriptTransportId != jsonrpc.Constant.ScriptTransport.NotInUse)
+    {
+        return false;
+    }
+
     return true;
 }
 
index 1b33b6196475b6a953abb4cfb271a5d1aaf4108f..6f7e61e6e4e1b14908f84cb43756cee91d9ebb47 100644 (file)
@@ -292,6 +292,8 @@ if (request["REQUEST_METHOD"] == "POST" &&
 }
 else if (request["REQUEST_METHOD"] == "GET" &&
          form["_ScriptTransport_id"] != undefined &&
+         form["_ScriptTransport_id"] !=
+           jsonrpc.Constant.ScriptTransport.NotInUse &&
          form["_ScriptTransport_data"] != undefined)
 {
     /* We have what looks like a valid ScriptTransport request */
@@ -455,8 +457,17 @@ if (! valid)
     return;
 }
 
-/* Ensure the logged-in user is allowed to issue the requested method */
-if (! json_authenticate(serviceComponents, jsonInput.method))
+/*
+ * Ensure the logged-in user is allowed to issue the requested method.  We
+ * provide the scriptTransportId as one of the determining factors because
+ * accepting requests via ScriptTransport is dangerous.  Only methods which
+ * one might allow when unauthenticated should be allowed via ScriptTransport
+ * as it is easy for a rogue site to trick a user into bypassing
+ * authentication.
+ */
+if (! json_authenticate(serviceComponents,
+                        jsonInput.method,
+                        scriptTransportId))
 {
     error.setError(jsonrpc.Constant.ErrorCode.PermissionDenied,
                    "Permission denied");
index cffeb8b00ad137aaf0d76e5d5719c8c7d4534752..a2564e708a9a901ede1d7879d66694e5e6cd09a9 100644 (file)
@@ -151,10 +151,10 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = _this.getCurrentRpcRequest();
+          var rpcRequest = _this.getCurrentRpcRequest();
 
           // Issue an abort for the pending request
-          request.abort();
+          rpcRequest.request.abort();
         }
     });
   state.addTransition(trans);
@@ -174,14 +174,14 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = _this.getCurrentRpcRequest();
+          var rpcRequest = _this.getCurrentRpcRequest();
           
           // Generate the result for a completed request
-          request.setUserData("result",
-                              {
-                                  type : "complete",
-                                  data : event.getData()
-                              });
+          rpcRequest.setUserData("result",
+                                  {
+                                      type : "complete",
+                                      data : event.getData()
+                                  });
         }
     });
   state.addTransition(trans);
@@ -201,14 +201,14 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = _this.getCurrentRpcRequest();
+          var rpcRequest = _this.getCurrentRpcRequest();
           
           // Generate the result for a completed request
-          request.setUserData("result",
-                              {
-                                  type : "failed",
-                                  data : event.getData()
-                              });
+          rpcRequest.setUserData("result",
+                                  {
+                                      type : "failed",
+                                      data : event.getData()
+                                  });
         }
     });
   state.addTransition(trans);
@@ -221,68 +221,64 @@ qx.Proto.addAwaitRpcResultState = function(module)
  * @param fsm {qx.util.fsm.FiniteStateMachine}
  *   The finite state machine issuing this remote procedure call.
  *
- * @param service {String}
+ * @param service {string}
  *   The name of the remote service which provides the specified method.
  *
- * @param method {String}
+ * @param method {string}
  *   The name of the method within the specified service.
  *
  * @param params {Array}
  *   The parameters to be passed to the specified method.
  *
- * @return {qx.io.remote.Request}
+ * @return {Object}
  *   The request object for the just-issued RPC request.
  */
 qx.Proto.callRpc = function(fsm, service, method, params)
 {
   // Create an object to hold a copy of the parameters.  (We need a
   // qx.core.Object() to be able to store this in the finite state machine.)
-  var o = new qx.core.Object();
+  var rpcRequest = new qx.core.Object();
 
-  // copy the parameters; we'll prefix our copy with additional params
-  o.allParams = params.slice(0);
+  // Save the service name
+  rpcRequest.service = service;
 
-  // prepend the method
-  o.allParams.unshift(method);
+  // Copy the parameters; we'll prefix our copy with additional params
+  rpcRequest.params = params.slice(0);
 
-  // prepend the flag indicating to coalesce failure events
-  o.allParams.unshift(true);
+  // Prepend the method
+  rpcRequest.params.unshift(method);
 
-  // prepend the service name
-  o.allParams.unshift(service);
+  // Prepend the flag indicating to coalesce failure events
+  rpcRequest.params.unshift(true);
 
-  // Save the complete parameter list in case authentication fails and we need
-  // to reissue the request.
-  fsm.addObject("swat.module.rpc_params", o);
-  
   // Retrieve the RPC object */
   var rpc = fsm.getObject("swat.module.rpc");
 
   // Set the service name
-  rpc.setServiceName(o.allParams[0]);
+  rpc.setServiceName(rpcRequest.service);
 
   // Issue the request, skipping the already-specified service name
-  var request =
+  rpcRequest.request =
     qx.io.remote.Rpc.prototype.callAsyncListeners.apply(rpc,
-                                                        o.allParams.slice(1));
+                                                        rpcRequest.params);
 
-  // Make the request object available to the AwaitRpcResult state
-  this.pushRpcRequest(request);
+  // Make the rpc request object available to the AwaitRpcResult state
+  this.pushRpcRequest(rpcRequest);
 
   // Give 'em what they came for
-  return request;
+  return rpcRequest;
 };
 
 
 /**
  * Push an RPC request onto the request stack.
  *
- * @param request {qx.io.remote.Request}
- *   The just-issued request
+ * @param request {Object}
+ *   The just-issued rpc request object
  */
-qx.Proto.pushRpcRequest = function(request)
+qx.Proto.pushRpcRequest = function(rpcRequest)
 {
-  this._requests.push(request);
+  this._requests.push(rpcRequest);
 };
 
 
@@ -290,8 +286,8 @@ qx.Proto.pushRpcRequest = function(request)
  * Retrieve the most recent RPC request from the request stack and pop the
  * stack.
  *
- * @return {qx.io.remote.Request}
- *   The request from the top of the request stack
+ * @return {Object}
+ *   The rpc request object from the top of the request stack
  */
 qx.Proto.popRpcRequest = function()
 {
@@ -300,16 +296,16 @@ qx.Proto.popRpcRequest = function()
     throw new Error("Attempt to pop an RPC request when list is empty.");
   }
 
-  var request = this._requests.pop();
-  return request;
+  var rpcRequest = this._requests.pop();
+  return rpcRequest;
 };
 
 
 /**
  * Retrieve the most recent RPC request.
  *
- * @return {qx.io.remote.Request}
- *   The request at the top of the request stack
+ * @return {Object}
+ *   The rpc request object at the top of the request stack
  */
 qx.Proto.getCurrentRpcRequest = function()
 {
index 8052d9a57964721b4a81e07b992617f3fdd59de0..6b5ae695bf771ee456a95949678b5bb31355f92b 100644 (file)
@@ -43,15 +43,15 @@ qx.Proto.buildFsm = function(module)
           if (fsm.getPreviousState() == "State_AwaitRpcResult")
           {
             // Yup.  Display the result.  We need to get the request object
-            var request = _this.popRpcRequest();
+            var rpcRequest = _this.popRpcRequest();
 
             // Display the result
             var gui = swat.module.ldbbrowse.Gui.getInstance();
-            gui.displayData(module, request);
+            gui.displayData(module, rpcRequest);
 
             // Dispose of the request
-            request.dispose();
-            request = null;
+            rpcRequest.request.dispose();
+            rpcRequest.request = null;
           }
         },
 
index 9e86be25e9569d5e2fc1eaa1a653240c115a5470..52db8fdd887ccb5721541e792f727180eb3d248c 100644 (file)
@@ -114,12 +114,12 @@ qx.Proto.buildGui = function(module)
  *   The result returned by SAMBA to our request.  We display the data
  *   provided by this result.
  */
-qx.Proto.displayData = function(module, request)
+qx.Proto.displayData = function(module, rpcRequest)
 {
   var gui = module.gui;
   var fsm = module.fsm;
-  var result = request.getUserData("result")
-  var requestType = request.getUserData("requestType");
+  var result = rpcRequest.getUserData("result")
+  var requestType = rpcRequest.getUserData("requestType");
 
   // Did the request fail?
   if (result.type == "failed")
@@ -133,19 +133,19 @@ qx.Proto.displayData = function(module, request)
   switch(requestType)
   {
   case "find":
-    this._displayFindResults(module, request);
+    this._displayFindResults(module, rpcRequest);
     break;
     
   case "tree_open":
-    this._displayTreeOpenResults(module, request);
+    this._displayTreeOpenResults(module, rpcRequest);
     break;
 
   case "tree_selection_changed":
-    this._displayTreeSelectionChangedResults(module, request);
+    this._displayTreeSelectionChangedResults(module, rpcRequest);
     break;
 
   case "database_name_changed":
-    this._clearAllFields(module, request);
+    this._clearAllFields(module, rpcRequest);
     break;
 
   default:
@@ -409,7 +409,7 @@ qx.Proto._buildPageBrowse = function(module, page)
 };
 
 
-qx.Proto._displayFindResults = function(module, request)
+qx.Proto._displayFindResults = function(module, rpcRequest)
 {
   var rowData = [];
   var fsm = module.fsm;
@@ -418,7 +418,7 @@ qx.Proto._displayFindResults = function(module, request)
   var maxLen = 0;
 
   // Obtain the result object
-  result = request.getUserData("result").data;
+  result = rpcRequest.getUserData("result").data;
 
   if (result && result["length"])
   {
@@ -497,18 +497,18 @@ qx.Proto._displayFindResults = function(module, request)
 };
 
 
-qx.Proto._displayTreeOpenResults = function(module, request)
+qx.Proto._displayTreeOpenResults = function(module, rpcRequest)
 {
   var t;
   var trs;
   var child;
 
   // Obtain the result object
-  var result = request.getUserData("result").data;
+  var result = rpcRequest.getUserData("result").data;
 
   // We also need some of the original parameters passed to the request
-  var parent = request.getUserData("parent");
-  var attributes = request.getUserData("attributes");
+  var parent = rpcRequest.getUserData("parent");
+  var attributes = rpcRequest.getUserData("attributes");
 
   // Any children?
   if (! result || result["length"] == 0)
@@ -548,12 +548,12 @@ qx.Proto._displayTreeOpenResults = function(module, request)
 };
 
 
-qx.Proto._displayTreeSelectionChangedResults = function(module, request)
+qx.Proto._displayTreeSelectionChangedResults = function(module, rpcRequest)
 {
   var fsm = module.fsm;
 
   // Obtain the result object
-  var result = request.getUserData("result").data;
+  var result = rpcRequest.getUserData("result").data;
 
   // If we received an empty list, ...
   if (result == null)
@@ -612,10 +612,10 @@ qx.Proto._displayTreeSelectionChangedResults = function(module, request)
 };
 
 
-qx.Proto._clearAllFields = function(module, request)
+qx.Proto._clearAllFields = function(module, rpcRequest)
 {
   // Obtain the result object
-  var result = request.getUserData("result").data;
+  var result = rpcRequest.getUserData("result").data;
 
   // Retrieve the database handle
   module.dbHandle = result;
index 1aeab8a4a335391eae1aadda6acf766ed828ffc2..5e4843691c1593ebd3e1bbeebcb5bd29530b29f5 100644 (file)
@@ -67,15 +67,15 @@ qx.Proto.buildFsm = function(module)
           if (fsm.getPreviousState() == "State_AwaitRpcResult")
           {
             // Yup.  Display the result.  We need to get the request object
-            var request = _this.popRpcRequest();
+            var rpcRequest = _this.popRpcRequest();
 
             // Display the result
             var gui = swat.module.statistics.Gui.getInstance();
-            gui.displayData(module, request.getUserData("result"));
+            gui.displayData(module, rpcRequest.getUserData("result"));
 
             // Dispose of the request
-            request.dispose();
-            request = null;
+            rpcRequest.request.dispose();
+            rpcRequest.request = null;
 
             // Restart the timer.
             swat.module.statistics.Fsm._startTimer(fsm);