Taking external action

Previous: Sending notifications ] [ Top:  ] [ Next: Making decisions: wftk_decide ]

Actions encapsulate both scripts and anything which requires permissions to be done. Logically I'll want some way of suppressing permissions calculations on scripts, but I'm not sure how best to do that. It could be that the adaptor itself would say, "I'm a scripting adaptor, don't check permissions." All in all, this is a sticky wicket given the availability of ad-hoc workflow; you don't want just any schmuck running ad-hoc workflow with malicious scripts embedded, which are then run just because they're embedded scripts. So I really don't know how to approach security yet. If you're reading this, and you have a good idea, please feel free to tell me.

August 18, 2003: Well, with ACTION_http, I guess it's time for actions to hit the big time. Lots of stuff I don't like here. Like the fact that the datasheet to be used as context for the action isn't part of the API. Oy.
WFTK_EXPORT int wftk_action (XML * session, XML * action, XML * datasheet) {
   XML * permission;
   XML * approval;
   XML * start;
   XML * user;

   if (!action) return 0;

   /* TODO: determine the permissions regimen.  I.e. how dangerous does the action adaptor consider itself? */

   /* First, we check permissions. */
   ad = wftk_get_adaptor (session, PERMS, NULL);  /* The specific permission adaptor is ignored anyway. */
   user = wftk_session_getuser (session);
   permission = wftk_call_adaptor (ad, "perm", action, user);
   wftk_free_adaptor (session, ad);
   if (!permission) {
      xml_set (action, "status", "error");
      return 0;

   /* If perms=ok, we execute the action.  TODO: setting up action queues to specify actions on alternate machines. */
   if (!strcmp (xml_attrval (permission, "value"), "yes")) {
      ad = wftk_get_adaptor (session, ACTION, xml_attrval (action, "handler"));
      if (ad) {
         wftk_call_adaptor (ad, "do", action, datasheet);
         wftk_free_adaptor (session, ad);
         xml_set (action, "status", "ok");
         xml_set (action, "status.reason", xml_attrval (permission, "reason"));
         /* TODO: execute any data actions to set datasheet values, using specs as yet undefined. */
      } else {
         xml_set (action, "status", "fail");
         xml_set (action, "status.reason", "Action handler does not exist.");
         /* TODO: log this sorry situation. */

      xml_free (permission);
      return 1;

   if (!strcmp (xml_attrval (permission, "value"), "no")) {
      xml_set (action, "status", "no");
      xml_set (action, "status.reason", xml_attrval (permission, "reason"));
      xml_free (permission);
      return 1;

   /* Start up approval process. */
   /* TODO: if no default process list under repmgr, do something sensible.  (And test this situation, because something's broken here anyway.) */
   approval = wftk_process_new (session, NULL, NULL);
   xml_append_pretty (approval, xml_copy (action));
   wftk_process_define (session, approval, NULL, xml_attrval (permission, "value"));
   wftk_process_save (session, approval);
   if (user) {
      wftk_user_add (session, approval, user);
      wftk_role_assign (session, approval, "Requester", xml_attrval (user, "id"));
   start = wftk_task_retrieve (session, approval);
   wftk_task_complete (session, start);
   xml_free (approval); /* TODO: remove this if/when we restore the cache. */
   xml_free (start);

   /* Tell the user what happened. */
   xml_set (action, "status", "deferred");
   xml_set (action, "status.reason", xml_attrval (permission, "reason"));
   xml_set (action, "dsrep", xml_attrval (approval, "repository"));
   xml_set (action, "process", xml_attrval (approval, "id"));

   xml_free (permission);
   return 1;
Previous: Sending notifications ] [ Top:  ] [ Next: Making decisions: wftk_decide ]

This code and documentation are released under the terms of the GNU license. They are copyright (c) 2000-2004, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.