Handling table acces per user with consistent Xf GUI

A place to discuss development of the Xataface core.

Handling table acces per user with consistent Xf GUI

Postby t.peichl » Sun Oct 21, 2012 2:40 am

Dear Steve,

first of all I want to thank you for your great work. I had tried to put up some MySQL gui before - but due to my limited time never came to the point where I trusted my code enough to use it for a live system ;-)


Dear Xataface community,

up till now a have read a lot in this forum but never been active myself. Since everyone using a system like Xataface has different needs I now want to share my experience on the topic stated above since that was one of my primary concerns.
After realizing the power of Xataface I was facing the problem that I had many related tables with some of them containing sensible data not to be exposed to the public. After reading about Xataface permissions I found that the mechanism provided by conf.ini with [_tables], [_disallowed_tables] and [_allowed_tables] would be the top level/most secure one. But this mechanism seemed to be static. Working with the Xataface 1.3.2 code I found the following solution to my needs especially providing a consistant Xataface gui by using conf/ApplicationDelegate.php class:
Code: Select all
class conf_ApplicationDelegate {
   function disable_table($table) {
      $app =& Dataface_Application::getInstance(); unset($app->_conf['_allowed_tables'][$table]); }
   function enable_table($table, $name) {
      $app =& Dataface_Application::getInstance(); $app->_conf['_allowed_tables'][$table] = $table; }
   function hide_table($table) {
      $app =& Dataface_Application::getInstance(); unset($app->_conf['_tables'][$table]); unset($app->_conf['_allowed_tables'][$table]); }
   function show_table($table, $name) {
      $app =& Dataface_Application::getInstance(); $app->_conf['_tables'][$table] = $name; $app->_conf['_allowed_tables'][$table] = $table; }

   function beforeHandleRequest() {
      $app =& Dataface_Application::getInstance();
      $query =& $app->getQuery();
      if($query['-table'] == 'Dashboard' and $query['-action'] == 'list') $query['-action'] = 'dashboard';

      $auth =& Dataface_AuthenticationTool::getInstance();
      $user =& $auth->getLoggedInUser();
      if(isset($user)) {
         switch($user->val('user')) {
         case 'userX':
            $this->show_table('tbl_everyone', 'Table seen by everyone';
            $this->show_table('tbl_userx', 'Table seen/accessable only by userX');
            break;
         default:
            $this->show_table('tbl_everyone', 'Table seen by everyone';
         }
      }
   }
}

together with listing all my tables under [_disallowed_tables] in the conf.ini and only my Dashboard under [_tables]. The fine grained access control on the exposed tables is done by Xatafaces permission system using table delegate classes.

=> This solution works really flawless with Xataface 1.3.2.

After my system grew in the past months I noticed an annoying problem. Using MySQL views to filter data - meaning the views are not complex representing one single table and for this reason are still writeable - creating new records behaves bad. After entering the record data a click to the save button leeds to an empty result set with the message: record created/saved successfully. no record matching criteria found. If I click on the find action I notice that the auto_increment value of the primary key is in this case not handled correctly. The find form indicates for the ID field just = meaning the new ID is not passed to xataface at all. This happens in all combinations fields.ini key=PRI together with widget:type=static/hidden/... . The same setup working on the original table not the view works flawlessly. Since I was not finding any information about this issue I wanted to try Xataface SVN since I thouhgt, maybe this problem is already solved there. So I setup xataface_svn together with the svn g2 module.

=> Surprise! This solution is not working with the new Xataface SVN!!!
=> Further reading and trying to unserstand the code even more brouhgt me to this other solution which seems to be the more intended way.
=> But this new solution needs a minor patch of the XatafaceSVN code.

Looking at Dataface/Application.php shows that there ist another delegate function called conf(). Seems to be the right place for the things I did in first place. So I changed my conf/ApplicationDelegate.php:
Code: Select all
class conf_ApplicationDelegate {
   var $_conf;

   function disable_table($table) {
      unset($this->_conf['_allowed_tables'][$table]); }
   function enable_table($table, $name) {
      $this->_conf['_allowed_tables'][$table] = $table; }
   function hide_table($table) {
      unset($this->_conf['_tables'][$table]); unset($this->_conf['_allowed_tables'][$table]); }
   function show_table($table, $name) {
      $this->_conf['_tables'][$table] = $name; $this->_conf['_allowed_tables'][$table] = $table; }

   function conf() {
      $this->_conf = array();
      $auth =& Dataface_AuthenticationTool::getInstance();
      $user =& $auth->getLoggedInUser();
      if(isset($user)) {
         switch($user->val('user')) {
         case 'userX':
            $this->show_table('tbl_everyone', 'Table seen by everyone';
            $this->show_table('tbl_userx', 'Table seen/accessable only by userX');
            break;
         default:
            $this->show_table('tbl_everyone', 'Table seen by everyone';
         }
      }
      return $this->_conf;
   }

   function beforeHandleRequest() {
      $app =& Dataface_Application::getInstance();
      $query =& $app->getQuery();
      if($query['-table'] == 'Dashboard' and $query['-action'] == 'list') $query['-action'] = 'dashboard';
   }
}

This worked in conjunction with the g2 module but at all places except the upper navigation menu instead of the table names the table ids like tbl_... got used. Disabling the g2 module made the menu disappear in the old layout. A little debugging showed me that Xataface ist using _table, _conf['_table'] and con() a little bit unconsistantly. (at least to my pure understanding of Xataface code) The desired result ist finally consisntantly achieved by patching the original Dataface/Application.php: function display() in the following way:

!PATCH!
Code: Select all
   function display($main_content_only=false, $disableCache=false){
      // ---------------- Set the Default Character set for output -----------
      //!PATCH! comment out the following three lines and copy them to the new location
      //foreach ($this->_tables as $key=>$value){
      //   $this->_tables[$key] = $this->_conf['_tables'][$key] = df_translate('tables.'.$key.'.label', $value);
      //}
      
      $this->main_content_only = $main_content_only;
      if ( $this->autoSession or $this->sessionEnabled() ){
         $this->startSession();
      }

      //... (other code cut out)

      // handle authentication
      if ( !(defined('XATAFACE_DISABLE_AUTH') and XATAFACE_DISABLE_AUTH) and isset($this->_conf['_auth']) ){
         //...         
         if ( PEAR::isError($auth_result) and $auth_result->getCode() == DATAFACE_E_LOGIN_FAILURE ){
            // There was a login failure, show the login prompt
            $loginPrompt = true;
            $loginError = $auth_result->getMessage();
         } else if ( $authTool->isLoggedIn() ){
            // The user is logged in ok
            // Handle the request

      //!PATCH! insert the three lines here with modified first row!
      foreach ($this->conf()['_tables'] as $key=>$value){
         $this->_tables[$key] = $this->_conf['_tables'][$key] = df_translate('tables.'.$key.'.label', $value);
      }
            $result = $this->handleRequest();
            if ( Dataface_Error::isPermissionDenied($result) ){
               // Permission was denied on the request.  Since the user is already
               // logged in, there is no use giving him the login prompt.  Just give
               // him the permission denied screen.
               $permissionDenied = true;
               $permissionError = $result->getMessage();
            }

//...


Note: The same minor patch is possible with Xataface 1.3.2 making the same conf/ApplicationDelegate.php work with both versions in a consistent/expected way.

During my investigations I found another small problem introduced by the priority of the overwriting of smarty template code in conjunction with the new g2 module theme.

=> Solution: minor patch to Dataface/SkinTool.php
Code: Select all
        function register_skin( $name, $template_dir){
                if ( !is_array($this->template_dir) ){
                        if ( strlen($this->template_dir) > 0 ){
                                $this->template_dir = array($this->template_dir);
                        } else {
                                $this->template_dir = array();
                        }
                }
                //!PATCH! added next line
                if(count($this->template_dir) >= 3) $slt = array_shift($this->template_dir);
                array_unshift($this->template_dir, $template_dir);
                //!PATCH! added next line
                if(isset($slt)) array_unshift($this->template_dir, $slt);
                $this->skins[$template_dir] = $name;

        }

preserving the SITE/templates having highest priority at all time.

I hope that this might be useful to someone. :-)


Sincerely yours
Torben

P.S.: Finally I'd like to ask one question by myself:
I noticed that the new g2 look&feel seems to be missing some features. E.g. in the result list I find no pages links and cannot adapt the number of elements per page. Is this functionality in the g2 still missing or do I have to update some settings (permissions.ini, conf.ini / [_prefs]) ?

P.P.S: If someone has an idea how to make inserting records into views work I would be really interested since this was my original intention playing with the xataface code;-)
Last edited by t.peichl on Sun Jan 06, 2013 1:27 pm, edited 1 time in total.
t.peichl
 
Posts: 2
Joined: Sun Oct 21, 2012 1:30 am

Re: Handling table acces per user with consistant Xf GUI

Postby shannah » Fri Oct 26, 2012 9:42 am

I noticed that the new g2 look&feel seems to be missing some features. E.g. in the result list I find no pages links and cannot adapt the number of elements per page. Is this functionality in the g2 still missing or do I have to update some settings (permissions.ini, conf.ini / [_prefs]) ?


Are you looking for the options to change the number of records per page? These are still there but hidden. You need to click on the text that says "0 to 30" (i.e. where it says which records are showing now. This will pop up a little dialog to change the number of records shown per page or skip to another start position.

If someone has an idea how to make inserting records into views work I would be really interested since this was my original intention playing with the xataface code;-)


Getting views to work depends on the view. Auto-increment fields is an easy fix. You need to tell Xataface which fields are autoincrement in the fields.ini file (it doesn't know this by default for views). Just add the following to the fields.ini file:
Code: Select all
[myfield]
    Extra="auto_increment"


Note that this is case sensitive.
--
Steve Hannah
@shannah78 (on twitter)
sjhannah.com blog
shannah
 
Posts: 4457
Joined: Wed Dec 31, 1969 5:00 pm

Re: Handling table acces per user with consistant Xf GUI

Postby t.peichl » Sat Oct 27, 2012 2:44 am

Are you looking for the options to change the number of records per page? These are still there but hidden. You need to click on the text that says "0 to 30" (i.e. where it says which records are showing now. This will pop up a little dialog to change the number of records shown per page or skip to another start position.

Exactly, that was what I'm looking for and it's even more convenient this way. :)
Just add the following to the fields.ini file:
Code: Select all
[myfield]
    Extra="auto_increment"


Works like a charm. Thank you very much for your quick reply.
t.peichl
 
Posts: 2
Joined: Sun Oct 21, 2012 1:30 am

Re: Handling table acces per user with consistant Xf GUI

Postby jvinolas » Fri Dec 14, 2012 1:14 pm

Hi,

I have the same problem as t.peich: After upgrading to 2.0alpha1+g2 module I can't hide (unset) tables through ApplicationDelegate.php. I've reduced the code because it disables or enables tables depending on user:

Code: Select all
class conf_ApplicationDelegate {
     function getPermissions(&$record){
        $auth =& Dataface_AuthenticationTool::getInstance();
        $user =& $auth->getLoggedInUser();
        if ( !isset($user) ) return Dataface_PermissionsTool::NO_ACCESS();
        if ($user->val('ACTIU')=='NO') return Dataface_PermissionsTool::NO_ACCESS();
        $app =& Dataface_Application::getInstance();
        unset($app->_conf['_tables']['contractes']);
        $app->_conf['_disallowed_tables']['hide_admin2'] = 'contractes';
    }
}


I've seen that t.peich explains a patch to the xataface core. Is that the only way to accomplish this?
jvinolas
 
Posts: 51
Joined: Thu Apr 15, 2010 12:31 am

Re: Handling table acces per user with consistant Xf GUI

Postby shannah » Fri Dec 14, 2012 2:12 pm

Code: Select all
$app =& Dataface_Application::getInstance();
        unset($app->_conf['_tables']['contractes']);
        $app->_conf['_disallowed_tables']['hide_admin2'] = 'contractes';


This section of code shouldn't be in the getPermissions() method. It should be in the beforeHandleRequest() method of the application delegate class. This will guarantee that it is only run once per request.

-Steve
--
Steve Hannah
@shannah78 (on twitter)
sjhannah.com blog
shannah
 
Posts: 4457
Joined: Wed Dec 31, 1969 5:00 pm

Re: Handling table acces per user with consistant Xf GUI

Postby jvinolas » Sat Dec 15, 2012 12:20 pm

No success hidding nor disabling table 'contractes'.

Code: Select all
   function beforeHandleRequest(){
      if (!isset($_SESSION['loggedInAlready']) and isLoggedIn() ){
         $_SESSION['loggedInAlready'] = true;
         $app =& Dataface_Application::getInstance();
         unset($app->_conf['_tables']['contractes']);
         $app->_conf['_disallowed_tables']['hide_admin2'] = 'contractes';
         //setNavMenu();
      }
   }


2.0alpha1+g2 module
jvinolas
 
Posts: 51
Joined: Thu Apr 15, 2010 12:31 am

Re: Handling table acces per user with consistent Xf GUI

Postby shannah » Mon Jan 21, 2013 12:24 pm

The G2 module works a little differently. Your disallowed tables call should be working correctly though. E.g. if you actually try to click on the table in question, it should give you an error of some kind.

As for removing the menu item, G2 converts the table menu items into actions and this has already occurred by the time this code runs (it happens as soon as the module loads). This makes it significatly easier to add menu items to the top left (The category is "top_left_menu_bar"). However, removing the items needs to be done, now via the getNavItem() delegate class method.
http://xataface.com/wiki/getNavItem

-Steve
--
Steve Hannah
@shannah78 (on twitter)
sjhannah.com blog
shannah
 
Posts: 4457
Joined: Wed Dec 31, 1969 5:00 pm


Return to Xataface Developers

Who is online

Users browsing this forum: No registered users and 15 guests

cron
Powered by Dataface
© 2005-2007 Steve Hannah All rights reserved