| Joomla! http://forum.joomla.org/ |
|
| An Easy Way of Performing an Group Access Check ??? http://forum.joomla.org/viewtopic.php?f=304&t=117148 |
Page 1 of 1 |
| Author: | tcp [ Fri Nov 24, 2006 4:45 pm ] |
| Post subject: | An Easy Way of Performing an Group Access Check ??? |
Maybe it's been too long since I worked with Joomla groups but I'm trying to find the right API call to determine if a users is a public, registered, or special user. I need to know this so that I can make a check against a record's access permission, where 0 is public, 1 is registered, and 2 is special ( same as jos_content ). This is the code that I thought that I would use. Code: // Check for access $user = JFactory::getUser(); $gid = $user->get('gid'); echo "group id is $gid"; $sql .= " AND q.access <= $gid "; The admin's group is 25, however, so this doesn't work. com_content's frontend model uses this type of logic and it doesn't make sense to me. For example, in the method _buildWhereClause() around line 175 I have this code. Code: if ($noauth) { $where .= "\n AND a.access <= $gid"; echo "\n AND a.access <= $gid"; } On the frontpage $gid is show as '25'. The problem is that access will never be "25". It will be either 0, 1, or 2. A registered user's group is 25, so changing the article's access to special will not hide the article from a normal, registered user (screenshot attached). Here is the info in the db. Code: mysql> select title, access from jos_content where access != 0 -> ; +--------------------------------+--------+ | title | access | +--------------------------------+--------+ | What is uncategorised content? | 1 | | Welcome to Joomla! | 2 | +--------------------------------+--------+ 2 rows in set (0.00 sec) mysql> mysql> select id, gid from jos_users; +----+-----+ | id | gid | +----+-----+ | 62 | 25 | | 63 | 18 | +----+-----+ 2 rows in set (0.00 sec) mysql> So although there are numerous examples of using $user->gid to check table.access, it looks like this practice is faulty. So what exactly is the best way of checking table.access? I know that the ACL topic is hotly contested but there really does need to be a simple API that one can call to check if a user is a normal user or a special user. Even a JUser::isRegistered() or JUser::isSpecial() would be better than nothing. Please let me know if I'm doing something wrong. tcp |
|
| Author: | tcp [ Wed Dec 13, 2006 6:10 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Any suggestions about to check the group and access level of the current user? It seems like the best solution would be to add several methods to the JUser class so that a developer could do something like this. Code: $user = JFactory::getUser(); $access = $user->getHighestAccessLevel(); // returns 0 for public, 1 for registered, 2 for special $isAdmin = $user->isAdmin(); // return true if user is admin or admin related ( eg, manager ), otherwise, false I suppose that the table jos_core_acl_aro_groups is the ultimate authority on groups and group ids, and that this table needs to be checked. Perhaps the table could be read once, then the gid of the user could be compared to the a static result array. Code: mysql> select * from jos_core_acl_aro_groups; +----+-----------+---------------------+-----+-----+---------------------+ | id | parent_id | name | lft | rgt | value | +----+-----------+---------------------+-----+-----+---------------------+ | 17 | 0 | ROOT | 1 | 22 | ROOT | | 28 | 17 | USERS | 2 | 21 | USERS | | 29 | 28 | Public Frontend | 3 | 12 | Public Frontend | | 18 | 29 | Registered | 4 | 11 | Registered | | 19 | 18 | Author | 5 | 10 | Author | | 20 | 19 | Editor | 6 | 9 | Editor | | 21 | 20 | Publisher | 7 | 8 | Publisher | | 30 | 28 | Public Backend | 13 | 20 | Public Backend | | 23 | 30 | Manager | 14 | 19 | Manager | | 24 | 23 | Administrator | 15 | 18 | Administrator | | 25 | 24 | Super Administrator | 16 | 17 | Super Administrator | +----+-----------+---------------------+-----+-----+---------------------+ This may be a better approach over using the JAuthorization API because only a single query call is need to determine all group information. I would be willing to write some code but I'm still waiting for reviews of code that I wrote weeks ago, so perhaps this isn't an issue for most people. Certainly one reason for the relative silence around here is that Devs are busy with the 1.0.12 release. As far as I can tell, the current access checks in many of the core components are broken because they compare the access level in the table ( jos_content, for example ) with the gid of the user ( which will be 18 or 25 ). Please correct me if I'm wrong. I'd love to hear about alternative ways of approaching this problem. I don't have any problem pursuing my own implementation but I think this is a major issue for the framework. tcp |
|
| Author: | mjaz [ Wed Dec 13, 2006 8:44 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
If I remember correctly, in 1.0.x, the frontend has $my->gid = 0, 1 or 2, the backend has $my->gid = 17 - 25. I suppose it's the same with $user in 1.5 |
|
| Author: | tcp [ Wed Dec 13, 2006 11:06 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Try the following code on the frontend. Code: $user = JFactory::getUser(); $gid = $user->get('gid'); echo "gid is $gid<br/>"; When logged in as admin on the frontend, I get the following. Code: gid is 25 It's been a while since I worked with the 1.0 code so I can't say if this is a change or if it always was this way. tcp |
|
| Author: | tcp [ Wed Dec 13, 2006 1:34 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Attaching the code that I'm currently working with until something else better comes along. Basically, it demonstrates various is*() functions, such as userIsRegistered() and getHighestUserAccessLevel(). Ideally, these methods would be incorporated into the JUser class and could be called like $user->isRegistered() and $user->getHighestUserAccessLevel(). That would allow one to do something such as this. Code: if ( ! $user->isAdmin() ) { $access = (int) $user->getHighestUserAccessLevel(); $where[] = " jos_content.access <= $access "; } Although I simply coded the gids into the getGroupIDsForGroup() method, the final impelmentation would need to read the group acl table, parse the information, and store the results into a static lookup table. It could work like this ( steam-of-thought code ). Code: static $lookup; static $data; // Initalize if needed if ( is_null( $data ) { // DB code to fetch the table info $data = $results; $lookup = array(); } // Check if the ids for this group have been calculated already if ( ! array_key_exists($group, $lookup) ) $lookup[$group] = $this->_createGroupIDsForGroup($data, $group); // Return an array of group ids return $lookup[$group]; So, one DB call, build the lookup table incrementally, and all should be good. Well, that's the ideal anyways. Few quick notes. No, this doesn't addess the topic of ACLs. This simply provides an (proposed) API for JUser to help identify the user's group so that one can perform simple access checks based on the old Joomla notion of group id. Additionally, I work on PHP5 so this code doesn't return proper references under PHP4 and any implementation of the code should do so. Well, "you like" ? tcp |
|
| Author: | mjaz [ Thu Dec 28, 2006 11:10 am ] |
| Post subject: | bug in legacy $my |
There's definitely a bug: $my->gid using legacy mode is different from $my->gid in 1.0.x Code: <?php // J!1.0.12, site global $my; echo $my->gid; // '2' for super admin // J!1.5 nightly, site, legacy mode on global $my; echo $my->gid; // '25' for super admin, expected result: '2' // J!1.0.12, administrator global $my; echo $my->gid; // '25' for super admin // J!1.5 nightly, administrator, legacy mode on global $my; echo $my->gid; // '25' for super admin $user in 1.5 has the same behaviour, but perhaps this is intentional? Code: <?php // J!1.5 nightly, site, legacy mode on $user = & JFactory::getUser(); $gid = $user->get('gid'); echo $gid; // '25' for super admin // J!1.5 nightly, administrator, legacy mode on $user = & JFactory::getUser(); $gid = $user->get('gid'); echo $gid; // '25' for super admin Perhaps a dev can comment on this? |
|
| Author: | Jinx [ Sat Dec 30, 2006 2:19 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Just wanted to let you know that a solution for this one is in the works. You are right about the differences between 1.5 and 1.0, it slipped below radar. Using the oppurtunity todo a bit of refactoring in the way we handle users inside the system. |
|
| Author: | tcp [ Sat Dec 30, 2006 6:08 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
I don't think we need a complex solution at the moment ( ACLs will come in a later release according to the roadmap ). The current system supports three basic access groups ( Pub, Reg, and Special ) that are often used to check access and there needs to be a way to:
Finally, it needs to be easy. The authorize() method doesn't seem to help me understand what type of user I'm working with and looks overly complex for a simple task of "tell me if this user is an Author". Ideally, this API should work with other groups defined by the admin or by 3PD extensions. I'm thinking of the likes of AccessGranted. My suggestion was to add additional methods into JUser. Please feel free to look at my code, but I would be happy with any solution if it offered an API to help 3PDs work with groups. I'd also be available to help test any changes, so let me know what I can do to help. tcp |
|
| Author: | Jinx [ Sat Dec 30, 2006 11:42 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
I'll do
|
|
| Author: | Jinx [ Tue Jan 02, 2007 4:32 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
mjaz wrote: There's definitely a bug: $my->gid using legacy mode is different from $my->gid in 1.0.x I have fixed this issue in the SVN, an aid dynamic variable has been added to the user object. This 'aid' which stands for access identifier acts in the same way as the 'gid' in 1.0. When switching legacy on the $my variable now behaves in a consistent BC way. |
|
| Author: | tcp [ Tue Jan 02, 2007 5:43 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
I'll give a look as soon as the tree works - Rev 6150 is seriously broken. ![]() Quote: [02-Jan-2007 12:39:05] PHP Fatal error: Call to a member function getParam() on a non-object in /private/var/www/domains/joomla/html/libraries/joomla/application/application.php on line 439
[02-Jan-2007 12:39:51] PHP Fatal error: Call to a member function get() on a non-object in /private/var/www/domains/joomla/html/libraries/joomla/application/plugin/helper.php on line 208 |
|
| Author: | Chris Davenport [ Tue Jan 02, 2007 4:06 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Hi, I'd like to get this written up into a "How To" on the dev wiki. These are likely to be frequently asked questions so I think it's important that the info is readily available. Could someone (tcp?) spare a few minutes to gather the basic details together? Something along the lines of: 1. How to determine if a user is logged in. 2. How to determine group access. 3. How this differs from 1.0.x. If you'd like to write the whole thing that's okay , but I can flesh things out myself if I'm certain of the basic details.Thank you. Regards, Chris. |
|
| Author: | Jinx [ Tue Jan 02, 2007 5:07 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
@TCP : Try a reinstall, seems to work fine on my end and make sure you clean your sessions. This error is a typical session problem since the user isn't present in the session yet. @Chris : It works almost in the same way as in 1.5 with the expection that we now have two extra (dynamic) user paramaters. A quick overview : - aid : defines the user access identifier and acts in the same way as the gid in 1.0 (normally this is 0 for for public, 1 for registered and for for special). The aid is used against the systems access database fields to define if the user can access a certain database resource. - gid : defines the actual acl user group identifier (19, author, 20 editor, 22 publisher, 23 manager, 24 administrator, 25 super administrator). - guest : defines if a user is logged in or not (when logged in guest is 0) Note : aid en guest are dynamic parameters which are set at runtime by the application. They don't exist on the framework level and are additions to make things a bit easier until we have a full ACL implementation. Developers are encouraged to user the JUser::authorise setting when doing checks against the ACL instead of relying on directly on the gid. Is this enough to get you started ? Johan |
|
| Author: | Chris Davenport [ Tue Jan 02, 2007 10:34 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Thanks Johan, I'll take a stab at it and let you know if I hit any problems. Regards, Chris. |
|
| Author: | tcp [ Wed Jan 03, 2007 2:11 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Chris Davenport wrote: Could someone (tcp?) spare a few minutes to gather the basic details together? Sure. I'll follow-up using the Documentation forum. tcp |
|
| Author: | tcp [ Fri Jan 05, 2007 7:46 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Jinx, thanks for looking into this. I did some tests and $aid doesn't seem to be working so well. Am I doing this right? Code: Code: $user = JFactory::getUser(); $id = $user->get('id'); $name = $user->get('name'); $aid = $user->get('aid'); $group = $user->get('gid'); $guest = $user->get('guest'); echo "User $name ($id) is gid $group and access $aid as a ".($guest ? 'unregistered' : 'registered').' user<br/>'; $user2 = new JUser(); $user2->load(63); $id = $user2->get('id'); $name = $user2->get('name'); $aid = $user2->get('aid'); $group = $user2->get('gid'); $guest = $user2->get('guest'); echo "User2 $name ($id) is gid $group and access $aid as a ".($guest ? 'unregistered' : 'registered').' user<br/>'; Frontend, not logged in: Code: User (0) is gid 0 and access 0 as a unregistered user User2 tcp (63) is gid 19 and access as a registered user Current user is ok, but what about the access for $user2? Frontend, logged in as admin: Code: User Administrator (62) is gid 25 and access 2 as a registered user User2 tcp (63) is gid 19 and access as a registered user User is an author, but no access. Backend: Code: User Administrator (62) is gid 25 and access 2 as a registered user User2 tcp (63) is gid 19 and access as a registered user Same. Using JUser::authorize(), how can I check if the a user ( JUser->load(#) ) belongs to one of the admin groups ( Manager, Admin, Supa ) ? Overall, I really think any solution needs to be implemented in JUser, not JApplication and JFactory. This may be the reason why my results are inconsistent. Personally I think my solution is a bit more graceful because it doesn't rely on JUser::get(), so the internal implementation can be changed when ACLs are implemented. Yeah, it's a short-term solution but it's a solution to a real problem and the encapulation works to the framework's advantage in the long-term. Once you start offering JUser->get('aid'), it's there. Please give a look at my code which kinda shows the concepts that I'm suggesting. tcp |
|
| Author: | Jinx [ Fri Jan 05, 2007 8:10 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Quick reply : The second test your are doing will not work since the 'guest' and 'aid' parameters are dynamic and created at runtime by the application. If you load a user he won't know about 'guest' and 'aid'. The reason 'aid' is created at runtime is to mimic the behavior of 1.0 and to make it easy to remove it again in future version. The 'guest' parameter is also dynamic because we don't have a field to store it in the database and we also don't have a relation between the sessions and the user table. If you want to know if a user is logged in, we could consider allowing a relation between the session and user table based on user id. Quote: Using JUser::authorize(), how can I check if the a user ( JUser->load(#) ) belongs to one of the admin groups ( Manager, Admin, Supa ) ? The ACL we are moving towards isn't a role based system. It doesn't matter what group your users belongs too, all that matters is if your user is authorised to preform a certain action against a certain object. While your solution does indeed provide further possibilities it also uses a role based concept, implementing it would only makes things more difficult in the future. |
|
| Author: | tcp [ Fri Jan 05, 2007 8:43 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Jinx wrote: The ACL we are moving towards isn't a role based system. It doesn't matter what group your users belongs too, all that matters is if your user is authorised to preform a certain action against a certain object. While your solution does indeed provide further possibilities it also uses a role based concept, implementing it would only makes things more difficult in the future. Got it, at least conceptually. Practically, people will need to perform access checks in J 1.5+ until ACLs are fully implemented. Would it be better to move the dynamic generation of aid, access, and guest to JUser so that all JUser objects work consistently? |
|
| Author: | Jinx [ Fri Jan 05, 2007 8:44 pm ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
tcp wrote: Got it, at least conceptually. Practically, people will need to perform access checks in J 1.5+ until ACLs are fully implemented. Would it be better to move the dynamic generation of aid, access, and guest to JUser so that all JUser objects work consistently? That makes sense, you wanna have a look at that ? My list is already quite full at the moment. Need to implement your JToolTip work first
|
|
| Author: | tcp [ Sat Jan 06, 2007 6:16 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Where is the code that sets 'aid'? I grep'ed for 'aid' and only found the $user->set() call. tcp |
|
| Author: | Jinx [ Sat Jan 06, 2007 7:13 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
It's in the user plugin. |
|
| Author: | tcp [ Tue Jan 09, 2007 9:05 am ] |
| Post subject: | Re: An Easy Way of Performing an Group Access Check ??? |
Attaching the diff from my first attempt. Basically, I added a number of tests to the JUser::get() method to detect for the special attributes such as 'aid', 'admin', etc.... I think this provides some useful functionality in the J 1.0 sense of things. The diff is based on revision 6221. I tested using PHP 5.1.something. ??? To test the code, I used the following code. Code: $user1 = JFactory::getUser(); $id = $user1->get('id'); $name = $user1->get('name'); $aid = $user1->get('aid'); $group = $user1->get('gid'); $guest = $user1->get('guest'); $admin = $user1->get('admin'); $type = $user1->get('usertype'); $message= $guest ? 'Visitor' : ( $admin ? 'Admin' : 'Somebody' ); echo "User1 $name ($id) is $message: gid($group), access($aid), type($type)<br/>"; $user2 = new JUser(); $user2->load(63); $id = $user2->get('id'); $name = $user2->get('name'); $aid = $user2->get('aid'); $group = $user2->get('gid'); $guest = $user2->get('guest'); $admin = $user2->get('admin'); $type = $user2->get('usertype'); $message= $guest ? 'Visitor' : ( $admin ? 'Admin' : 'Somebody' ); echo "User2 $name ($id) is $message: gid($group), access($aid), type($type)<br/>"; $user3 = new JUser(); $user3->load(62); $id = $user3->get('id'); $name = $user3->get('name'); $aid = $user3->get('aid'); $group = $user3->get('gid'); $guest = $user3->get('guest'); $admin = $user3->get('admin'); $type = $user3->get('usertype'); $message= $guest ? 'Visitor' : ( $admin ? 'Admin' : 'Somebody' ); echo "User3 $name ($id) is $message: gid($group), access($aid), type($type)<br/>"; It produces the results that I would expect. Code: User1 (0) is Visitor: gid(0), access(0), type(Public Frontend) User2 tcp (63) is Somebody: gid(19), access(2), type(Author) User3 Administrator (62) is Admin: gid(25), access(2), type(Super Administrator) After looking at and working with the code, I can say that there is still a lot of work to do and it should be interesting to see an ACL implementation in J 1.6. In the meantime, the current framework is excellent. Feedback always appreciated. tcp Edit: Forgot to mention that I added a method named getGroupData() which returns a Stdclass object with group information ( basically jinx's code from the user plugin). Although this can work ok as a protected method, what I would really like to see is a simple method ( eg, JUser::getGroup() ) that returns group information for the given user. The information returned could be an object of JTableAroGroup or "JGroup". Even an initial implementation may be out of the scope for 1.5, but it would be nice to have an interface to JAuthorization where I could code something like the following. Code: $user = new Juser(); $user->load(#); $group1 = $user->getGroup(); $group2 = $group1->getParentGroup(); $name = $group2->get('name'); Probably a can of worms. Well, food for thought. |
|
| Page 1 of 1 | All times are UTC |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|