othAuth 0.5 documentation
the long awaited documentation of othAuth, this article covers the new version of othAuth 0.5
Introduction
OthAuth is written by othman ouahbi aka CraZyLeGs, email for bugs, enhancements, etc crazylegs AT gmail DOT com
thanks to Dieter@be for helping getting this document done.
OthAuth uses the MIT-license, which is what the cakePHP framework uses.
OthAuth is both an authentication system (a system that tries to make sure that it only logs in allowed users who are who they claim to be),
and a permission system (a system that regulates the access to pages or actions depending on the permissions of the (logged-in) users or groups)
It is initially designed to work with CakePHP v1.1.x but newer versions of cakePHP will ofcourse be followed by newer versions of othAuth if some incompatibility is detected.
While it's one of the first( along with gwoo's rdAuth ) othAuth is certainly not the only player in this field, there are several other similar projects (some inspired by othAuth ) developed or in development for CakePHP
(there are even much more out there not specifically written for cakephp, but you better write one from scratch for cakephp then trying to port a "foreign" one)
While trying to not give a subjective judgement about any of these projects' quality, we think you should consider giving them a try:
To say short, we could say that othAuth is probably the most advanced (in terms of features), however it is still in heavy development!
(there is no such thing as the perfect solution ;-) )
The coolest features of othAuth are probably user-habtm-groups support, integration with cake's acl (not entirely finished),
mass login (brute-force) detection & blocking, user-defineable encryption algorythm (md5, sha-1, crc, or a combinations of them), etc.
However, othAuth has a to-do list. These are some jobs that could use some good taking care of:
* Enhanced Deny/Allow Logic
* Improve acl mode
Starting from 0.5, othAuth has support for modes. right now there are 3 modes:
* oth: This is the default old mode, it allows a user to have only one group, this is not a limitation, there are systems that need a user to belong to only one group
* nao: This mode was originally written by Naonak thus I called it nao, he had made the effort to make othAuth work with user HMBTM groups, I actually rewrote the code, but he made the 1st effort so this mode is dedicated to him ;)
* acl: This is the ACL mode, it's really in developement so if you have ideas feel free to contribute
(for an upcomming version: * sim: This is the simple mode, in this mode you don't have access groups, users are linked to permissions directly, use it if you don't need groups.)
Installation
The initial installation consists of 5 steps:
1) create the right tables in your database. depending on the mode you plan to use ( currently only the oth mode is documented ).
2) download the helper http://bakery.cakephp.org/articles/view/149 and save it as <yourproject>/views/helpers/oth_auth.php ( optional )
3) download the component http://bakery.cakephp.org/articles/view/99 and save it as <yourproject>/controllers/components/oth_auth.php
4) create the right models in <yourproject>/models. (you might need some tables depending on the features you have enabled)
5) install the unbind-all-except-some function. this is actually needed by the component to be able to unbind All models associated with the main Models except some you may want to keep in the session data ( e.g. User hasOne Profile )
DB tables
these are the basic tables for the oth mode, other features may require additional tables
Download code
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(50) NOT NULL default '',
`passwd` varchar(32) NOT NULL default '',
`name` varchar(50) NOT NULL default '',
`email` varchar(100) NOT NULL default '',
`last_visit` datetime NOT NULL default '0000-00-00 00:00:00',
`group_id` int(10) unsigned NOT NULL default '0',
`active` tinyint(1) unsigned NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`,`username`),
KEY `group_id` (`group_id`)
);
CREATE TABLE `groups` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) character set utf8 collate utf8_unicode_ci NOT NULL,
`level` int(11) NOT NULL,
`redirect` varchar(50) character set utf8 collate utf8_unicode_ci NOT NULL,
`perm_type` enum('allow','deny') NOT NULL default 'allow',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
);
CREATE TABLE `groups_permissions` (
`group_id` int(10) unsigned NOT NULL default '0',
`permission_id` int(10) unsigned NOT NULL default '0',
KEY `group_id` (`group_id`,`permission_id`)
);
CREATE TABLE `permissions` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL default '',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
);
next comes saving the php code to files in the right directories as mentioned above. if you doubt about anything, check cake's convention page: http://manual.cakephp.org/appendix/conventions
The helper
Grab this code and save it as <yourappfolder>/views/helpers/oth_auth.php
The component
grab the php code and save it as <yourappfolder>/controllers/components/oth_auth.php
The models
Create the right models for your mode or use Bake to do it quickly ( not that writing by hand isn't quick, it's Cake! )
I'll the basic models here if you are lazy:
Model Class:
Download code
<?php
class User extends AppModel
{
var $name = 'User';
var $belongsTo = 'Group';
//var $recursive = 2;
}
?>
Model Class:
Download code
<?php
class Group extends AppModel
{
var $name = 'Group';
var $hasMany = 'User';
var $hasAndBelongsToMany = array('Permission' =>
array('className' => 'Permission',
'joinTable' => 'groups_permissions'));
}
?>
Model Class:
Download code
<?php
class Permission extends AppModel
{
var $name = 'Permission';
var $hasAndBelongsToMany = array('Group' =>
array('className' => 'Group',
'joinTable' => 'groups_permissions'));
}
?>
The unbind all associations except some function
For increased performance, othAuth uses an other function, which unbinds all unneeded associations.
If you don't have the file <yourapp>/app_model.php just create it, and put this in it:
(otherwise just put the function unbindAll in there, except if you have it already ofcourse)
Download code
<?php
class AppModel extends Model{
function unbindAll($params = array())
{
foreach($this->__associations as $ass)
{
if(!empty($this->{$ass}))
{
$this->__backAssociation[$ass] = $this->{$ass};
if(isset($params[$ass]))
{
foreach($this->{$ass} as $model => $detail)
{
if(!in_array($model,$params[$ass]))
{
$this->__backAssociation = array_merge($this->__backAssociation, $this->{$ass});
unset($this->{$ass}[$model]);
}
}
}else
{
$this->__backAssociation = array_merge($this->__backAssociation, $this->{$ass});
$this->{$ass} = array();
}
}
}
return true;
}
}
?>
You can find more information about this function @ http://othy.wordpress.com/2006/06/03/unbind-all-associations-except-some/
DB tables
This configuration is meant for the "oth" mode, there are other modes available as well (see below)
Keep in mind that you can change the configuration any time you want, and the results will be immediatly visible (or, at the next page-request)
e.g. if you want to add an extra group or user, or change a permission in the database, or in the php files, if you save the database/file, these new
rules will become active.
The fundamental subjects of authentication come down to dividing your users into groups, each group having its own permissions or rights. If you doubt about creating
an extra group, don't hesitate to do so, because it gives you more flexibility to finetune the permissions. Here is an example sql code:
Download code
INSERT INTO groups VALUES (1,'webmasters',100,'','allow');
INSERT INTO groups VALUES (2,'editors',200,'','allow');
INSERT INTO groups VALUES (3,'members',300,'','allow');
the first argument is the id, ofcourse this has to be unique, next comes the name for the groups, choose a clear name!
the 3rd option defines the level for the group, this gives the group a value, so that it's easier to reference, also it gives groups values which become important when users have more then 1 group (but that's not in the default "oth" mode, that's for "nao" mode)
next comes the redirect, this allows you to set a redirect-to page in case the login fails, specifically for each group! (you don't have to , ofcourse)
in my case it's empty, so othAuth uses access_page, but you could let it redirect back to the login form, or whatever.
The last argument (called perm_type) is a very handy switch that lets you define how to filter the permission rules. If set to allow, it allows its users to do all the actions that
the permissions that are linked to this group define. However, if you set this to deny, then all the permissions that are linked to this group are denied for the users!
(there are 2 more fields, created and modified specific to cake)
After that, it's a good idea to enter some users, like this:
Download code
INSERT INTO users VALUES (1,'root','e10adc3949ba59abbe56e057f20f883e','Firstname Lastname','user@example.com','0000-00-00 00:00:00',1,1);
Again the first argument is the user id, the username (this is the name that the user types as the login), then comes the md5 checksum of the password ( or sha-1 etc..depeding what you told othAuth to use).
Use an online md5 calculator like http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-MD5.html (or you could write your own in cake very easily ofcourse)
to find out what the hash is of your password. the hash above is for the password 123456. Never write passwords in cleartext in the database,
not only is that insecure, also it won't work with othAuth!
After that comes the full (real) user name (first name and last name), and his email address. those aren't used by othAuth, they are optional and aim to be an example
Next comes the group_id. this is very important, we want to make root a member of the webmasters group (see above), so we put id 1 there.
The last 1 makes the user active, if this would be 0, the user would be inactive and unable to login.
Enter as many users as you wish, just remember their passwords, and keep in mind to pass the right group_id, to make sure they have the right permissions (see later on)
Next you have to insert all the permissions and link them too the groups, like this:
Download code
INSERT INTO permissions VALUES (1,'*');
INSERT INTO permissions VALUES (2,'news');
INSERT INTO permissions VALUES (3,'userprofiles');
INSERT INTO permissions VALUES (4,'userprofiles/view');
INSERT INTO permissions VALUES (5,'userprofiles/add');
INSERT INTO groups_permissions VALUES (1,1);
INSERT INTO groups_permissions VALUES (2,2);
INSERT INTO groups_permissions VALUES (2,3);
INSERT INTO groups_permissions VALUES (3,4);
INSERT INTO groups_permissions VALUES (3,5);
The permissions will be checked against the restricted actions variable (see later) to check whether users are allowed to do something or not.
The first argument is their id, the 2nd is the name of the permission.
The name deserves special attention: '*' means _all_ possible actions for all possible controllers in your application. (you probably only want to give this to the webmaster/root)
If the name is just '<controllername>', then the permission means _all_ possible actions for this one single controller.
if the name is '<controllername>/<actionname>', then the permission only means that one single action on that one single controller.
of course you can go up to whatever param you want e.g controller/action/p/a/r/a/m/s
The next queries just link group_id's to permission_id's. the first query means that the group with id 1, is linked to permission with id 1.
This means that all the webmasters are allowed to do everything. keep in mind, if you would have passed 'deny' as perm_type, the webmasters wouldnt be allowed to do anything. (not implemented at the moment)
The next 2 queries link permissions 2 and 3 to group_id 2. This means that users of the editor group will be allowed to do any action on news or userprofiles.
The last one, links permission_id 4 and 5 to group_id 3, so that members of the 'members' group are allowed to view a single userprofile, or add one.
(but they can't see a list of all the userprofiles, that would require 'userprofiles/index' or 'userprofiles'
see also $othAuthRestrictions in chapter 5
Configuration: The component.
After this comes the configuration of the component.
The ones at the top (form vars and DB vars) normally don't need any editing, the defaults should work perfectly.
Below those, there are the "Internals you don't normally need to edit those" variables. As the comment says, you don't have to edit these,
but it's a nice place to globally store any preferences, which you would have otherwise have to pass at every login() call.
Explanations:
* $gid
* $strict_gid_check
* $gid_order
These three variables are used in conjunction. The $gid variable defines a limit of which group_id's are allowed to login.
$strict_gid_check is a variable that defines how that limit is used. if set to true, it means "$gid only", if false, it means
"$gid or any gid $gid_order that". $gid_order can have two values 'asc' and 'desc', and it defines the order of importance of the groups,
asc : the most important group is the group with smallest value, desc: the most important group is the group with greatest value
for example:
* $gid = 3 && $strict_gid_check = true;
only users with level 3 are allowed to login
* $gid = 3 && $strict_gid_check = false; && $gid_order = 'asc'
users with level 1,2 or 3 are allowed to login
* $gid = 3 && $strict_gid_check = false; && $gid_order = 'desc'
users with level 3 and above ( 4, 70,..)are allowed to login
The reason why this is useful, is that you can define loginforms that only allow to login a specific range of users. it defines the concept of Point of Login.
(this is something else then allowing users to actions)
For example you could have an "admin area login", that has $gid=1 and the strict check to true, to only allow webmasters to login at that point.
However, if you would allow other users to login, that wouldn't be a problem either, if you defined good permissions.
* $redirect_page
use this var to globally define a redirect page (page to redirect to, when the login fails),but...
* $auto_redirect
...only when this is set to true. otherwise no redirect will occur.
* $hashkey
a hash key for this login point, also used in different hashing operations internally
* $login_page
define the page/url/action where users need to login. with auto_redirect true, users trying to acces restricted
actions are redirected to this page when they don't have enough credentials.
* $logout_page
redirect to this when they want to logout.
* $access_page
here the page that they tried to acces is temporarily stored so they can be returned back to this page
after they succesfully logged in and have enough permissions.
* $noaccess_page
people that are logged in, but don't have enough permissions for the request actions, are sent to this page (notice the subtle difference with $login_page)
* $mode
this is a _very_ important variable. It controls the working of the whole othauth system.
There are several options:
- "oth": the default. This gives each user 1 group (and thus n permissions for that group)
- "nao": this is more advanced. it allows a user to have multiple groups.
- "acl": this mode tries to complement cakePHP's acl functions, but this is still in heavy development.
* $cookie_active
* $cookie_lifetime
Use cookies , and define how long they are valid.
* $gid_order
Remember the "levels" that you entered when defining groups? Well, if you use the nao mode,
where one user can have more groups, you can use this setting to define the order of importance of several groups.
"asc" means the most importang group is the one with the smallest level, "desc" is the other way around. This is necessary because each group
can have different permissions, and when a user has multiple groups, these permissions (or better: groups) must be weighted against each other
so that othAuth can know what a user is allowed to do.
* $kill_old_login
when true, the form can do another login with the same hash and delete the old one.
Making it work.
Every controller that you want to use othauth, must have the right settings and beforefilter code. But since we don't like to DRY
(don't repeat yourself), and because it's more convenient, we can just place the code in the app_controller. All the other controllers inherit
from it, so they also "get" the othAuth coverage! :)
define these 3 variables (inside the AppController):
Download code
<?php
var $components = array('othAuth'); // necessary, we need to have the othauth component so it can do it's business logic
var $helpers = array('Html', 'OthAuth'); // html is always needed, othauth helper is not a must, but you can do some cool things with it (see later on)
var $othAuthRestrictions = array( 'add','edit','delete'); // these are the global restrictions, they are very important. all the permissions defined above
are weighted against these restrictions to calculate the total allow or deny for a specific request.
?>
It should be obvious that if you have Access to show/admins/1
you don't necessarily have access to show/admins or show.
but if you have access to show, you do automatically have access to show/admin
a deny, allow logic will be added in a future release.
to ignore auth check on a controller just set $othAuthRestrictions = null;
for overall controller auth check set $othAuthRestrictions = "*";
for CAKE_ADMIN restrictions set $othAuthRestrictions to CAKE_ADMIN or the string you defined in "core.php"
Next, put this in the beforeFilter:
Download code
<?php
function beforeFilter()
{
$auth_conf = array(
'mode' => 'oth',
'login_page' => '/admin/login',
'logout_page' => '/admin/logout',
'access_page' => '/admin/index',
'hashkey' => 'MySEcEeTHaSHKeYz',
'noaccess_page' => '/admin/noaccess',
'strict_gid_check' => false);
$this->othAuth->controller = &$this;
$this->othAuth->init($auth_conf);
$this->othAuth->check();
}
?>
you will probably recognize some variables that we also have setup globaly in the components setup. Well, here you can override these :)
The 3 function calls inside it are mandatory to let othauth do it's job.
Now you just need to have some place where you can login and logout. users/login and users/logout seems like logical choice, so add this to your users controller:
Download code
<?php
function login()
{
if(isset($this->params['data']))
{
$auth_num = $this->othAuth->login($this->params['data']['User']);
$this->set('auth_msg', $this->othAuth->getMsg($auth_num));
}
}
function logout()
{
$this->othAuth->logout();
$this->flash('You are now logged out!','/users/login');
}
function noaccess()
{
$this->flash("You don't have permissions to access this page.",'/admin/login');
}
?>
Now, create a view for the login function (views/users/login.thtml)
Download code
<h1>Log In:</h1>
<form action="<?php echo $html->url('/users/login'); ?>" method="post">
<div class="required">
<label for="user_username">Username</label>
<?php echo $html->input('User/username', array('id' => 'user_username', 'size' => '40')) ?>
<?php echo $html->tagErrorMsg('User/username', 'Please enter your username') ?>
</div>
<div class="required">
<label for="user_password">Password</label>
<?php echo $html->input('User/passwd', array('id' => 'user_passwd', 'size' => '40', 'type'=>"password")) ?>
<?php echo $html->tagErrorMsg('User/passwd', 'Please enter your password!') ?>
</div>
<?php echo $html->checkbox("User/cookie");?>
<div class="submit"><input type="submit" value="Login" /></div>
</form>
The last item (the checkbox) is used to store the information in a cookie, so that the user can choose to be remembered for the next visit!
you can configure cookie Remember me feature with these two self-explainatory variables in the Component:
<?php
var $cookie_active = true;
var $cookie_lifetime = '+1 day';
?>
Everything should work by now, but you probably want to know what cool thingies that othauth has to offer for you to use? read on !
Cool tricks you can do with othAuth.
Redirecting back after login when the session timeouts
this feature is activated by default, suppose you work on a page, and the session timeouts
or you accessed a page that you don't have enough permissions to access, you are in a normal behaviour redirected to the login page,
after login, if this feature is activated, othAuth redirects back to that page.
to disable it, simply comment $auth_url_redirect_var, simply change the value of this var to change the url var ( if it's used by something else )
Getting information about the user, group, etc.
You can interact with the component (when doing business logic), or with the helper (which aids in presentational stuff).
The component and the helper work very similarly. the most important aspects come down to these 4 functions:
* user() <-- user information
* group() <-- group information
* permission() <-- permission information
* getData() <--- getData gets the whole othAuth session data, it's up to you to parse it, ( print_r can be useful )
Offcourse, the helper is available in the view as $othAuth, while the component in the controller is called $this->othAuth
Other then that, they work the same:
Component:
Download code
<?php
$fullname = $this->othAuth->user('name');
$last_visit = $this->othAuth->user('last_visit');
$groupname = $this->othAuth->group('name');
?>
Helper:
Download code
<?php
$fullname = $othAuth->user('name');
$last_visit = $othAuth->user('last_visit');
$groupname = $othAuth->group('name');
?>
The helper even has a 5th function called sessionValid, you could use the helper like this in your view:
Download code
<?php
if ($othAuth->sessionValid())
{
echo '<li>'.$html->link('logout', '/users/logout').'</li>';
}
else
{
echo '<li>'.$html->link('login','/users/login').'</li>';
}
?>
Limit login attempts
Starting from version 0.5, othAuth offers a mechanism to limit login attempts, using ip and cookie.
This Feature if enabled ( it is actually enabled by default ) protects your login form mass login, after a configurable amount of tries the user is ip and cookie banned.
( Another method is instead of banning you generate a hash image in the form not supported within othAuth atm but it's a snap to do )
to control it, use these variables in the component:
Download code
<?php
$login_limit // flag to toggle login attempts feature
$login_attempts_model // the name of the model that interfaces the table where login attemps are stored
$login_attempts_num // number of login attempts before an action is taken ( ban, image auth,..)
$login_attempts_timeout // time in minutes to reset already stored attempts of this user
$login_locked_out // Time to lock out/ban the user
?>
db table:
Download code
CREATE TABLE `login_attempts` (
`ip` varchar(15) collate utf8_unicode_ci NOT NULL,
`num` int(11) NOT NULL default '1',
`expire` datetime NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`ip`)
);
Model login_attempts.php
Model Class:
Download code
<?php
class LoginAttempts extends AppModel
{
var $name = 'LoginAttempts';
var $primaryKey = 'ip';
var $useTable = 'login_attempts';
}
?>
Keeping track of logins
I initially wrote this for a project I was working on and plugged it in othAuth, I kept it because it might be useful for others.
This feature saves history of logins in a db table in case you want to do some statistics etc.
Use these two variables in the Component to control it:
Download code
<?php
$history_active // flag to activate/deactivate this feature
$history_model // model name to store info thro
?>
an example table:
Download code
CREATE TABLE `user_histories` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(32) NOT NULL,
`fullname` varchar(64) NOT NULL,
`groupname` varchar(32) NOT NULL,
`visitdate` datetime NOT NULL,
PRIMARY KEY (`id`)
);
Slipping some additional associations through othAuth's data
By default, othAuth strips the data-array to include only the information it uses (user, group, etc)
But you can add additional association data
For example suppose you have the User model, and it's associated with the Profile model. You can include the profile information inside the session data so it can be used by the component or the helper
This is how:
In the component configuration alter these 3 arrays (which are empty by default)
* $allowedAssocUserModels
* $allowedAssocGroupModels
* $allowedAssocPermissionModels
for example if you define $allowedAssocUserModels as array('hasOne'=>array('Profile')) any data residing in your $data array with index 'Profile' will be
kept through-out the session!
other encryption functions
By default , othAuth uses md5, but this isn't an obligation, you can tell othAuth to use, sha1, crypt or even your own method!
Use the following vars to configure it:
Download code
<?php
$pass_crypt_method = 'md5'; // md5, sha1, crypt, crc32,callback
$pass_crypt_callback = null; // if you have a callback function, set its name here
$pass_crypt_callback_file = ''; // file where the function is declared ( in vendors )
?>
Hope this article helped frustrated people, sorry again for the long delay.
Don't forget that othAuth is a community stuff, feel free to improve it ( docs too )
Cake!
Comments
Bug
1 password or passwd
I did run into a problem, however. In the component code, it sets the user table password column to be 'passwd', but in the SQL you provide to build the table you use 'password'. So I got an error saying that User.passwd didn't exist.
I fixed the error by changing the login.thtml file to reference "Users/password" instead of "Users/passwd" then in the component file, I chaned any of the config variables that referred to "passwd" to instead refer to "password".
Unless, it should be "passwd" and the database scheme is wrong?
Comment
2 Correct and corrected
Question
3 Editing only own Objects
this is a very nice helper. the right for which i am searching.
bt i wonder if its possible to grant users ony access to edit their own objects (posts etc) without adding a new ACO for each post?
kind regards,
alex
Comment
4 othAuth is abstract
I'm not sure I understand correctly what you mean but anyway, othAuth is abstract thing, which means it doesn't have the notion of objects that belong to a user or even the notion of edit. it's up to use to grant useful permissions to less abstract things
Regards
Question
5 aco mod and change gropu
http://cake-php.googlegroups.com/web/othauth.php?gda=ctzDdEEAAAAHrv8IS8nhNsvUTvIFd3GaH-5x9hkpgjHywALnK9jx2hVJVT3hrgKrn_IySc8la3L2GiaXqyOPbAkqeyr49WeedCJfaee7TamSXSOlVydL_w
Othman please tell me how is best way to change group user's in login session
Comment
6 using sha1
Comment
7 access page var
Bug
8 default route and restricted login logout actions
also i noticed another oddity: if your login/out actions are in users_controller, then if you place a '*' restriction in that controller, you will still be able to access the login page AND the logout page, but any other action in that controller, will redirect you to login. if, however, you explicitly list the restricted actions: array('login', 'logout', etc) then you can still access the login page but NOT the logout page (it will redirect you to login). this is true if your restrictions are declared as described in app-controller instead of a specific controller too. another oddity, just wondering if anyone else noticed.
anyone implemented a form of 'challenge-response authentication' into othAuth to make it the ultimate cake auth package?
Comment
9 restrictions declared as strings
Question
10 Problem with group permissions
I have completed the five steps in Othman's article.. after the installation I got the following errors: 'Undefined property: Group::$Permission in..' and 'Fatal error: Call to a member function unbindAll()'. I have made the following models: group, group_permissons, login_attempts, permissions, users and user_histories. Can somebody help me, I'm new to CakePHP.
Question
11 About Adding new User using the OTH model
I am just wondering, using your AUTH Model, how would I be able to create a new User?
Say i have an array $signupdata in the form
Array (
[User] => Array ( [username] => asdf => asdf@asdf [password] => asdf [how] => asdf [credit] => 100 [dob] => 2006-07-07 00:00:00 ) )
and in my controller, i did ($this->User->save($signupdata))
This returns me 0 which I suppose it failed. Anything I am doing that is wrong here?
Question
12 nao mode
I hope you or somebody expands the article to include the nao mode because having users belong to multiple groups is really needed by lots of applications, especially intranet apps where the groups are named after different departments of the company and the directors need to be assigned to all of them for example..
Thanks.
Comment
13 How to make this work for 1.1.11.4064
In \app\controllers\components\oth_auth.php, lines 750-751 need to be modified.
Original:
$this->Session->write('othAuth.frompage',$this->controller->params['url']['url']);
$page .= "?".$this->auth_url_redirect_var."=".$this->controller->params['url']['url'];
Revised:
if(isset($this->controller->params['url']['url'])) {
$this->Session->write('othAuth.frompage',$this->controller->params['url']['url']);
$page .= "?".$this->auth_url_redirect_var."=".$this->controller->params['url']['url'];
}
Comment
14 How to make this work for 1.1.11.4064 (revised)
The correct path is:
\app\controllers\components\oth_auth.php
Bug
15 Fatal Error when Cookie is Set.
"Fatal error: Class 'User' not found in mypath\app\controllers\components\oth_auth.php on line 1334"
Relevant line (1334) is "$UserModel =& new $this->user_model;" in the _createModel() function.
Sorry if there is an easy fix to this, I am really new to Cake so just learning the ins and outs.
Please note: by "close the browser", i mean completely close it and restart it. Not simply navigating away from the application and coming back.
Question
16 NAO Mode
Bug
17 loginattempts
Comment
18 a permission checking function
Then use it like this:
View Template:
if($othAuth->hasPermission('items/delete')){ ... }
Helper Class:
<?php
function hasPermission($val,$arg='name')
{
$perms = $this->permission($arg);
if (in_array('*',$perms))
{
return true;
}
if (in_array($val,$perms))
{
return true;
}
$vals = explode('/',$val);
$val = '';
for ($i=0; $i<count($vals); $i++)
{
if ($i)
{
$val .= '/';
}
$val .= $vals[$i];
if (in_array($val,$perms))
{
return true;
}
}
return false;
}
?>
Question
19 Session Problems
Here is the error I get:
Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at cake\app\controllers\components\oth_auth.php:1450) in D:\www\public_html\CincyWebSolutions-2.0\cake\libs\session.php on line 131
Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at cake\app\controllers\components\oth_auth.php:1450) in D:\www\public_html\CincyWebSolutions-2.0\cake\libs\session.php on line 131
The last line of oth_auth.php is line #1450. Where else would cake be outputting anything?
Any help would be greatly appreciated.
Thanks, Jeremy
Bug
20 cookies
After a failed login attempt:
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/sandbox/cake/app/models/user.php:10) in /var/www/html/sandbox/cake/app/controllers/components/oth_auth.php on line 716
Line 716: setcookie('othAuth.login_attempts',$cdata,$time,'/');
After a successful login:
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/sandbox/cake/app/models/user.php:10) in /var/www/html/sandbox/cake/app/controllers/components/oth_auth.php on line 603
Line 603: setcookie('othAuth.login_attempts','',time() - 31536000,'/');
I guess turning off tracking login attempts might fix this problem. But I really need that feature.
And, if I check the "remember me" checkbox, and log in succesfully, in addition to the error on line 603 I get this one too:
Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/sandbox/cake/app/models/user.php:10) in /var/www/html/sandbox/cake/app/controllers/components/oth_auth.php on line 549
Line 549: setcookie('othAuth',$data,$time,'/');
Comment
21 sigh...nevermind...
Jeremy, you probably have the same issue. Delete any blank spaces and/or lines at the end of the file (after the closing php tag) which is accused of outputting headers. In your case that would be at the end of oth_auth.php.
The same error can occur if there are blank lines/spaces before the opening php tag.
Comment
22 Login Attempts
}if($this->login_attempts_timeout > 0)
{
$timeout = $this->login_attempts_timeout * 60;
// $del_sql .= " OR ( UNIX_TIMESTAMP(created) > UNIX_TIMESTAMP(NOW()) - $timeout )";
Otherwise, it was always deleting the entries in the login attempts table, making the number of tries always 1, and so never rejecting people based on too many login attempts. I don't know why, but commenting out that line did the trick.
Question
23 NAO mode and Password hashing
BTW, I think md5 or sha1 with a salt should be used as default to avoid dictionary bruteforce. Well, users can use a callback function but I believe that feature should be default.
Question
24 Authorization
If I put the beforeFilter as above in app_controller.php, then it seems to apply to every controller, and I cannot see how I can do make a few actions public. Surely there must be a better way for me make a few actions public than to add the beforeFilter to each indivdual controller?
I guess I don't really understand the permissions system.
Bug
25 Field name difference.
$data[$this->history_model]['fullname'] = $row[$this->user_model]['fullname'];
Using the code above, the users table uses 'name' not 'fullname'. So, Line 503 should be:
$data[$this->history_model]['fullname'] = $row[$this->user_model]['name'];
Thanks for all the great work.
Question
26 getData on Helper
waiting reply... thanks!!!!
Question
27 Certaint groups access
<?
class AppController extends Controller {
var $components = array('othAuth');
var $helpers = array('html', 'othAuth');
//var $othAuthRestrictions = array('*');
var $othAuthRestrictions = array('admin');
function beforeFilter()
{
$auth_conf = array(
'mode' => 'oth',
'login_page' => '/users/login',
'logout_page' => '/users/logout',
'access_page' => '/users/index',
'hashkey' => 'hello',
'noaccess_page' => '/users/noaccess',
'strict_gid_check' => true);
$this->othAuth->controller = &$this;
$this->othAuth->init($auth_conf);
$this->othAuth->check();
}
}
?>
and the sql stuff...
table: permissions
| id | name | created | modified |
+----+-------+---------------------+---------------------+
| 1 | * | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
| 2 | foros | 0000-00-00 00:00:00 | 0000-00-00 00:00:00
table: group_permissions
+----------+---------------+
| group_id | permission_id |
+----------+---------------+
| 1 | 1 |
| 2 | 2 |
mysql> select id, name, level, redirect, perm_type from groups;
+----+---------+-------+----------+-----------+
| id | name | level | redirect | perm_type |
+----+---------+-------+----------+-----------+
| 1 | prepas | 100 | | allow |
| 2 | alumnos | 200 | | allow |
+----+---------+-------+----------+-----------+
SO, any action named "admin_action" asks for the user to login, but, when i access to foros action, it doesnt ask login to user :S
Comment
28 action restrictions
You have to add restrictions to other actions.
var $othAuthRestrictions = array('admin', 'view', 'edit', 'delete');
Question
29 OthAuth downloads broken
just wanted to start using othAuth, but the download links seem broken.
Both,
- the component: http://bakery.cakephp.org/articles/view/99 and
- the helper: http://bakery.cakephp.org/articles/view/149
are down (Bakery flashes 'Invalid article').
Could U please re-provide the pages?
Thx a lot & keep up the great work!
carsten
Bug
30 Small bug
if((count($perm_parts) > 1) &&
($perm_parts[0] == CAKE_ADMIN) &&
($perm_parts[1] == $c) &&
($perm_parts[2] == "*"))
{
return true;
}
but it should be
if((count($perm_parts) > 2) &&
($perm_parts[0] == CAKE_ADMIN) &&
($perm_parts[1] == $c) &&
($perm_parts[2] == "*"))
{
return true;
}
i.e. count($perm_parts) > 2 in the if clause.
Bug
31 redirect fails when link has parameters
To save the parameters, you will need to modify redirect function..here is the new redirect function
function redirect($page = "",$back = false)
{
if($page == "")
//$page = $this->redirect_page;
$page = $this->logout_page;
if(isset($this->auth_url_redirect_var))
{
if(!isset($this->controller->params['url'][$this->auth_url_redirect_var]))
{
if($back == true)
{
// this is where i modified the function...
$frompage = '/';
if(isset($this->controller->params['url']['url'])){
$frompage = $this->controller->params['url']['url'];
$parameters = $this->controller->params['url'];
unset($parameters['url']);
$para = array();
foreach($parameters as $key => $value)
$para[] = $key . '=' . $value;
if(count($para) > 0){
$frompage .= '?' . implode('&',$para);
}
}
// end of modification
$this->Session->write('othAuth.frompage',$frompage);
$page .= "?".$this->auth_url_redirect_var."=".$frompage;
}
else
{
if($this->Session->check('othAuth.frompage'))
{
$page = $this->Session->read('othAuth.frompage');
$this->Session->del('othAuth.frompage');
}
}
}
}
if($this->__notcurrent($page))
{
if($this->__notcurrent($page))
{
if ($this->RequestHandler->isAjax())
{
$this->RequestHandler->setAjax($this->controller);
// Brute force !
echo 'window.location = "'.
$this->url($page).
'"';
exit;
}
else
{
$this->controller->redirect($page);
exit;
}
}
}
}
Comment
32 Using othAuth Helper within another Helper
Finally, in the init() function in the othAuth helper, I changed "$this->view->viewVars['othAuth_data']" to "$this->view->_viewVars['othAuth_data']" and it finally worked.
Hope this helps someone.
Comment
33 Failed login attempts
Bug
34 User Histories
$data[$this->history_model]['fullname'] = $row[$this->user_model]['name'];
or change the column 'name' of users mysql table to 'fullname'.
You nedd to add the user_history model in /app/models/user_history.php:
<?php
class UserHistory extends AppModel
{
var $name = 'UserHistory';
var $useTable = 'user_histories';
}
?>
Comment
35 Login Attempts
if($this->login_attempts_timeout > 0)
{
$timeout = $this->login_attempts_timeout * 60;
$del_sql .= " OR ( UNIX_TIMESTAMP(created) > UNIX_TIMESTAMP(NOW()) - $timeout )";
}
To:
if($this->login_attempts_timeout > 0)
{
$timeout = $this->login_attempts_timeout * 60;
$del_sql .= " OR ( UNIX_TIMESTAMP(created) < UNIX_TIMESTAMP(NOW()) - $timeout )";
}
That's all
Marc - voz ip
www.adamvozip.es
Bug
36 Hashkey and Already Logged In
1. Hashkey - should only be alphanumeric. If you have crazy characters it breaks the session saving. Maybe this is common knowledge? Would help if it was explicitly stated so you others don't waste time :P
2. The login functions return 1 for 'already logged in' and if everything goes smoothly. If you don't have auto-redirect and instead prefer to do your own thing the getMsg function will erroneously tell you 'already logged in.'
Question
37 Notice error
When I try to login with incorrect username or password, return error message like this: "Notice: Only variables should be assigned by reference in d:\webserver\public_html\cakephp\app\controllers\components\oth_auth.php on line 298"
How to fix this?
Thanks
Comment
38 Redundant if statement
if($this->__notcurrent($page))
{
if($this->__notcurrent($page))
{
if ($this->RequestHandler->isAjax())
{
$this->RequestHandler->setAjax($this->controller);
// Brute force ! you've got a better way ?
echo '<script type="text/javascript">window.location = "'.
$this->url($page).
'"</script>';
exit;
}
else
{
$this->controller->redirect($page);
exit;
}
}
}
Surely only one if($this->__notcurrent($page)) statement is needed?
Question
39 Component not available...
The helper is back online, but article 99 is still up for review/not available to public...
Any date or timelapse when we'll be able to taste your goods?
Comment
40 Component not available...
Comment
41 problem
Warning: Cannot modify header information - headers already sent by (output started at C:\AppServ\www\cake\maractivo\controllers\components\oth_auth.php:301) in C:\AppServ\www\cake\cake\libs\controller\controller.php on line 446
php 4.4.5
Comment
42 Controller names in the permissions table
I was entering MyControllerName for controller-wide permissions into the permissions table, but it was expecting my_controller_name instead.
Bug
43 Mistake with table prefix
$del_sql = "DELETE FROM {$Model->useTable} WHERE expire <= NOW()";With :
$del_sql = "DELETE FROM " . $Model->tablePrefix . $Model->useTable . " WHERE expire <= NOW()";For whose are using table prefixes.
(sorry for my english).
Comment
44 bakery comments
also, should the model class name for login_attempts be singular?
Question
45 access othAuth from a given model
I'd like to do something like this
in somemodel.php
function beforeFind(&$q){
$q['conditions'] .= "AND user_id = '".$othAuth->user('user_id')."';
return true;
}
By this, I wont have to rewrite every find/findAll and any find/findall would give me just what i want.
Comment
46 Problem also
I have the same problem and am stuck on PHP 4.4.4 unfortunately. Is there a workaround?
Thanks
Question
47 Fatal error
I'm getting this :
Fatal error: Class 'Permission' not found in H:\xampp\htdocs\myspacefactory.com\cake\libs\model\model_php5.php on line 445
How can I solve it?
Going to look over the code now, but thought I'd post this so long.
Please help.
Comment
48 Cannot Get It To Work
session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at D:wamp3hnappcontrollerscomponentsoth_auth.php:2) [COREcakelibssession.php, line 154]
Cannot modify header information - headers already sent by (output started at D:wamp3hnappcontrollerscomponentsoth_auth.php:2) [COREcakelibssession.php, line 155]
PHP 4.4
Cake 1.2
I don't know. I think I've followed all the directions.
Any help would be greatly appreciated.
Comment
49 Re Cannot Get It To Work
Greetings
Firzair
Bug
50 Recursive UserModel in othLogin
On line 304, you'll see this :
$row = $UserModel->find($conditions);
Problem is...
If you have other models with associatons to the User model on level 0, and the other model might have like a belongsTo association with thousands of items/records...well...you get the idea.
The login on my site kept on timing out. I couldn't figure out what the problem was till I saw this. On every login, it was loading about 4000 records due to associations.
So...in short...
The User model needs to be set to recursive = false; Like this :
$UserModel -> recursive = false;
...on line 303
Question
51 call time pass by reference at component oth auth php line 791
Warning: Call-time pass-by-reference has been deprecated - argument passed by value; If you would like to pass it by reference, modify the declaration of [runtime function name](). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file. However, future versions may not support this any longer. in /var/www/html/cake/2/app/controllers/components/oth_auth.php on line 791
Note that I had to go to extreme lengths to remove all the punctuation from the title of this note before I could post.
Comment
52 Ampersand
It is deprecated.
You can get rid of the error by removing the ampersand on line 791
Comment
53 Noob error
Here's what I have done:
Copy code for othAuth_Compent (http://bakery.cakephp.org/articles/view/99) - save to glx/app/controllers/components/oth_auth.php
Copy code for othAuth_Helper (http://bakery.cakephp.org/articles/view/149) save to glx/app/views/helpers/oth_auth.php
Copy this and execute it mysql:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL auto_increment,
`username` varchar(50) NOT NULL default '',
`passwd` varchar(32) NOT NULL default '',
`name` varchar(50) NOT NULL default '',
`email` varchar(100) NOT NULL default '',
`last_visit` datetime NOT NULL default '0000-00-00 00:00:00',
`group_id` int(10) unsigned NOT NULL default '0',
`active` tinyint(1) unsigned NOT NULL default '0',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`,`username`),
KEY `group_id` (`group_id`)
);
CREATE TABLE `groups` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) character set utf8 collate utf8_unicode_ci NOT NULL,
`level` int(11) NOT NULL,
`redirect` varchar(50) character set utf8 collate utf8_unicode_ci NOT NULL,
`perm_type` enum('allow','deny') NOT NULL default 'allow',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
);
CREATE TABLE `groups_permissions` (
`group_id` int(10) unsigned NOT NULL default '0',
`permission_id` int(10) unsigned NOT NULL default '0',
KEY `group_id` (`group_id`,`permission_id`)
);
CREATE TABLE `permissions` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL default '',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`modified` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
);
INSERT INTO groups VALUES (1,'webmasters',100,'','allow','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO groups VALUES (2,'editors',200,'','allow','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO groups VALUES (3,'members',300,'','allow','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO users VALUES (1,'root','e10adc3949ba59abbe56e057f20f883e','Firstname Lastname','user@example.com','0000-00-00 00:00:00',1,1,'0000-00-00 00:00:00','0000-00-00 00:00:00');INSERT INTO permissions VALUES (1,'*','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO permissions VALUES (2,'news','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO permissions VALUES (3,'userprofiles','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO permissions VALUES (4,'userprofiles/view','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO permissions VALUES (5,'userprofiles/add','0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO groups_permissions VALUES (1,1);
INSERT INTO groups_permissions VALUES (2,2);
INSERT INTO groups_permissions VALUES (2,3);
INSERT INTO groups_permissions VALUES (3,4);
INSERT INTO groups_permissions VALUES (3,5);
glx/app/models/user.php