We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 20546
    • 74 Posts
    Hi there,

    I want to create a Component with one mysql-table to store users data and I need to apply different group privileges to each database entry.
    Is there an easy way to use the built-in Access Control System of modx (Revolution) to check Access Rights?
    Is there anything like e.g. $modx->hasAccess()?
    Or is there an article or a tutorial about how to use the Access Control System?

    Many thanks
      • 28215
      • 4,149 Posts
      Quote from: mt85 at May 22, 2010, 08:54 PM

      I want to create a Component with one mysql-table to store users data and I need to apply different group privileges to each database entry.
      Is there an easy way to use the built-in Access Control System of modx (Revolution) to check Access Rights?
      Is there anything like e.g. $modx->hasAccess()?
      Or is there an article or a tutorial about how to use the Access Control System?

      You can use $modx->hasPermission().

      Create a custom Access Policy with the Permissions you want, assign it to a User Group of your choice and the ’mgr’ Context, and then "flush permissions" and re-login. And viola, you should be able to use $modx->hasPermission to restrict access.
        shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
        • 20546
        • 74 Posts
        Maybe I wasn’t precise enough. It shouldn’t be a component with backend user interface. I wanted to create a web application with just frontend interaction. An admin should be able to create a new database entry and assign group permissions to it. i.e. When a user logs into the application he should just see database entries that are assigned to his user group.

        For this purpose I need to know if there are functions to easily add permissions to a 3rd party mysql-table (admin) and to check the privileges of the database entries for a logged in user.

        Can I use $modx->hasPermission() for this purpose? I think if I use $modx->hasPermission(’delete_entry’) it doesn’t check whether the database entry is assigned to his account, instead It just checks if he’s allowed to delete entries in general. Is this assumption correct?

        Please let me know if the description is still vague.

        Thanks
        • One approach would be to create an xPDO model for your table, and have your table class extend modAccessibleObject/modAccessibleSimpleObject; you can actually do this quite easily. You will create one additional table and model class that extends modAccess. With this table you can insert ACL entries that relate a Principal (modUser or modUserGroup) with a specific Authority, an Access Policy, and any target (aka primary key) from your table. You’ll implement one method on your main table class, findPolicy(), and you are in business. Then you can create a UI to manage the ACL table entries and/or add/remove ACL entries programatically (as you would any object in xPDO). Your policies will define who can "load", "remove", and/or "save" specific rows of your table. By default all rows are anonymously accessible, but as soon as one policy is tied to a row, it is then additive security and only those with the "load" permission will know the row exists (as long as xPDO methods are used to access the data; you can bypass by avoiding loading results sets from any xPDOCriteria/xPDOQuery as an object).

          One caveat atm: you may need to extend modUser to have it load the policies you define for your modAccess derivative in the loadAttributes() method, but I am going to alter this today to automate loading of custom "target" classes by default. This will be available in an SVN update or the soon-to-be-released RC2, or I can provide a patched file for the version you are using if you need it.
            • 20546
            • 74 Posts
            Many, many thanks for your detailed reply. That’s what I was looking for. But I didn’t understand the thing with extending modUser...

            I made the two tables modAccessTest > extends modAccess and modTest > extends modAccessibleSimpleObject. I can add the ACL’s to modAccessTest and the content to modTest and it works fine. Then I implemented findPolicy() to modtest.class.php. But when I load the table content with following code I get all the data without restriction:
            $tests = $modx->getCollection('modTest');
            foreach ($tests as $test) {
            echo $test->get('name')."<br />";
            }
            

            Is it because I didn’t extend modUser? Or maybe because I used the wrong xPDO method?
            If it’s just the modUser thing it would be great to get this patched file.

            If this would work that would be really great. smiley
            • Quote from: mt85 at May 23, 2010, 07:23 AM

              Many, many thanks for your detailed reply. That’s what I was looking for. But I didn’t understand the thing with extending modUser...
              The issue with modUser is in loadAttributes(). The first parameter is target, which identifies the modAccess derivatives to load user policies for. Unless you add code in the case statements to handle modAccessTest, atm the users will never get the policies they need to get permission to this ACL target. I will work on adding a generic handler for this today, so custom targets like modAccessTest can be automatically loaded.

              Also, you have to login/logout, or flush user permissions in the manager after making any changes to ACLs before the user session gets the updated policy permissions.

              Quote from: mt85 at May 23, 2010, 07:23 AM

              Then I implemented findPolicy() to modtest.class.php.
              Is it because I didn’t extend modUser? Or maybe because I used the wrong xPDO method?
              If it’s just the modUser thing it would be great to get this patched file.
              Can you share your findPolicy() implementation?

              Also, FWIW, you can use $modx->setDebug(true) in your code before checking the permissions to get some information in the log that can help identify what is going on, including the policies being compared between target and principal.
                • 20546
                • 74 Posts
                Unless you add code in the case statements to handle modAccessTest, atm the users will never get the policies they need to get permission to this ACL target.
                I already tried to copy both modAccessContext-case statements in moduser.class.php and changed them to modAccessTest, but it won’t work. I think I’ll wait for your updated modUser file to not have to hack the core file. Do you already know when the new file is ready to use?

                I’ll try to use $modx->setDebug(true) tomorrow since I don’t have any time today.

                My modtest.class.php
                class modTest extends modAccessibleSimpleObject {
                public function __construct(& $xpdo) {
                parent :: __construct($xpdo);
                }

                public function findPolicy($context = ’’) {
                $policy = array();
                $context = !empty($context) ? $context : $this->xpdo->context->get(’key’);
                if (empty($this->_policies) || !isset($this->_policies[$context])) {
                $accessTable = $this->xpdo->getTableName(’modAccessTest’);
                $policyTable = $this->xpdo->getTableName(’modAccessPolicy’);
                $sql = "SELECT acl.target, acl.principal, acl.authority, acl.policy, p.data FROM {$accessTable} acl " .
                "LEFT JOIN {$policyTable} p ON p.id = acl.policy " .
                "WHERE acl.principal_class = ’modUserGroup’ " .
                "AND acl.target = :context " .
                "GROUP BY acl.target, acl.principal, acl.authority, acl.policy";
                $bindings = array(
                ’:context’ => $this->get(’key’)
                );
                $query = new xPDOCriteria($this->xpdo, $sql, $bindings);
                if ($query->stmt && $query->stmt->execute()) {
                while ($row = $query->stmt->fetch(PDO::FETCH_ASSOC)) {
                $policy[’modAccessTest’][$row[’target’]][] = array(
                ’principal’ => $row[’principal’],
                ’authority’ => $row[’authority’],
                ’policy’ => $row[’data’] ? xPDO :: fromJSON($row[’data’], true) : array(),
                );
                }
                }
                $this->_policies[$context] = $policy;
                } else {
                $policy = $this->_policies[$context];
                }
                return $policy;
                }


                }

                I really hope that I’ll get it running with your help, that would be marvelous.

                Thanks again
                  • 20546
                  • 74 Posts
                  I added the modAccessTest-case statements in moduser.class.php again and executed my code like this:
                  $modx->setDebug(true);
                  
                  $tests = $modx->getCollection('modTest');
                  foreach ($tests as $test) {
                  echo $test->get('name')."<br />";
                  }
                  


                  I attached the edited moduser.class.php, the main class modtest.class.php (with findpolicy()) and the log files.
                  Can you find anything userful in it?
                  • Actually, look at line 42 in core/model/modx/modprincipal.class.php; it should look similar to this (in the latest from branches/2.0):
                                $targets = array('modAccessContext', 'modAccessResourceGroup', 'modAccessCategory');

                    Just add your "target" into this array and it should work, e.g.
                                $targets = array('modAccessContext', 'modAccessResourceGroup', 'modAccessCategory', 'modAccessTest');

                    Make sure you flush permissions or flush all sessions after making the change.

                    Looking for a good way to do this more generically and will hopefully have a solution very soon.
                      • 20546
                      • 74 Posts
                      I just made this change, but it won’t work. It outputs all the database entries, even when I’m not logged in.
                      Do I have to use the new modprincipal.class.php file from svn or does it also work with the rc1 installation?
                      Also, do I have to download the new moduser.class.php from svn and add the case-statements?

                      Is my implementation of findpolicy() correct or is there something wrong?

                      That’s what I get when I output the SESSION Variable:
                       Array
                      (
                          [modx.user.contextTokens] => Array
                              (
                                  [web] => 2
                              )
                      
                          [modx.user..attributes] => Array
                              (
                                  [web] => Array
                                      (
                                          [modAccessContext] => Array()
                                          [modAccessResourceGroup] => Array()
                                          [modAccessCategory] => Array()
                                          [modAccessTest] => Array()
                                      )
                              )
                      
                          [webDocgroups] => Array
                              (
                                  [0] => 1
                              )
                      
                          [webShortname] => testuser
                          [webFullname] => testuser
                          [webEmail] => [email protected]
                          [webValidated] => 1
                          [webInternalKey] => 2
                          [webValid] => OWJhNmYyZFc5MjkwZGJiODIwYuAtNDVjOGZhujVmOWQ=
                          [webUser] => bxlrQXRydWEtZXI=
                          [webFailedlogins] => 0
                          [webLastlogin] => 1254823266
                          [webnrlogins] => 15
                          [webUserGroupNames] => 
                          [modx.web.session.cookie.lifetime] => 0
                          [modx.request.referrer.redirected] => Array
                              (
                                  [id] => 8
                                  [rememberme] => 
                                  [returnUrl] => /modx/index.php?id=8
                                  [service] => login
                                  [username] => testuser
                                  [password] => testuser
                                  [Login] => Login
                              )
                      
                          [modx.user.2.attributes] => Array
                              (
                                  [web] => Array
                                      (
                                          [modAccessContext] => Array
                                              (
                                                  [web] => Array
                                                      (
                                                          [0] => Array
                                                              (
                                                                  [principal] => 2
                                                                  [authority] => 9999
                                                                  [policy] => Array
                                                                      (
                                                                          [create] => 1
                                                                          [delete] => 1
                                                                          [load] => 1
                                                                          [list] => 1
                                                                          [remove] => 1
                                                                          [save] => 1
                                                                          [view] => 1
                                                                      )
                                                              )
                                                      )
                                              )
                      
                                          [modAccessResourceGroup] => Array
                                              (
                                                  [1] => Array
                                                      (
                                                          [0] => Array
                                                              (
                                                                  [principal] => 2
                                                                  [authority] => 9999
                                                                  [policy] => Array
                                                                      (
                                                                          [create] => 1
                                                                          [delete] => 1
                                                                          [load] => 1
                                                                          [list] => 1
                                                                          [remove] => 1
                                                                          [save] => 1
                                                                          [view] => 1
                                                                      )
                                                              )
                                                      )
                                              )
                                          [modAccessCategory] => Array()
                                          [modAccessTest] => Array()
                                      )
                              )
                      )