I am building the application using cakephp.
I have choosed the cakephp2.3.
User would be authenticated using either 'email' OR 'username'.
I found one option with Auth component "scope", but with this we can set static conditions.
LIKE: if user is active,, is_active => 1
But I want that while authenticating auth component should check either 'email' or 'username' field and other is password.
Is there any way?
This needs some code. You can easily find it through Users/CakeDC plugin found here
This plugin Uses the auth component below for login with multiple columns.
https://github.com/CakeDC/users/blob/master/Controller/Component/Auth/MultiColumnAuthenticate.php
It also includes an example of how to use. If you don't want the whole plugin you can just copy the MultiColumnAuthenticate.php to the folder app/Controllers/Components/Auth/.
if you copy only the file then in beforeFilter method inside your AppController you must write:
class AppController extends Controller {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->authenticate = array(
'MultiColumn' => array( //With no plugin
'fields' => array(
'username' => 'username',
'password' => 'password'
),
'columns' => array('username', 'email'),
)
);
}
}
according to cakephp documentation.
FormAuthenticate allows you to authenticate users based on form POST data. Usually this is a login form that users enter information into
By default AuthComponent uses FormAuthenticate
you can try this:
// Pass settings in $components array
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email', 'password' => 'password')
)
)
)
);
Related
I'm using this JWTAuth adapter to use JWT authentication instead of cookie-based auth in my CakePHP 2.8 app. It works great, except for one hitch:
Normally for one of my REST endpoints, I can use $this->Auth->user("id") to get the currently logged-in users' ID.
When I try to make a controller action accessible to non-members using $this->Auth->allow(), a problem occurs. If I do this, using $this->Auth->loggedIn() in the controller returns false, meaning I can not add additional logic for logged-in users.
When using standard cookie auth:
$this->Auth->user('id') is available in
Controller::beforeFilter().
$this->Auth->loggedIn() is true in
Controller::beforeFilter().
$this->Auth->user('id') is available in controller actions, public
and members-only.
$this->Auth->loggedIn() is true in controller actions, public
and members-only.
When using JWT auth:
$this->Auth->user('id') is null in Controller::beforeFilter().
$this->Auth->loggedIn() is false in
Controller::beforeFilter().
$this->Auth->user('id') is available in members-only controller actions, and null in public controller actions.
$this->Auth->loggedIn() is true in members-only controller actions, and false in public controller actions.
Is there any way I can get Auth to include information returned by the JWTAuth component on actions that have been made public by $this->Auth->allow()?
Example controller here:
public function visible(){
// This will always be false, even if a valid JWT token is sent
$this->set("loggedIn", $this->Auth->loggedIn());
}
public function members_only(){
// This will be unavailable if not logged in, and a true if logged in
$this->set("loggedIn", $this->Auth->loggedIn());
}
public function beforeFilter($options = array()){
parent::beforeFilter();
$this->Auth->allow("visible");
}
And for reference, my AppController::components array;
public $components = array(
'DebugKit.Toolbar',
'Auth' => array(
'authorize' => array(
'Actions' => array(
'actionPath' => 'controllers'
),
),
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email'),
'contain' => array(
'UserProfile',
)
),
'JwtAuth.JwtToken' => array(
'fields' => array(
'username' => 'email',
'token' => 'password',
),
'header' => 'AuthToken',
'userModel' => 'User',
),
),
'unauthorizedRedirect' => false
),
"Acl",
"RequestHandler",
"Session"
);
For stateless adapters authentication process is triggerd in AuthComponent::startup(). Component's startup() methods are run after Controller::beforeFilter(), that is why AuthComponent::user() doesn't return any info.
For other adapters when user is authenticated the identity info is stored in session. Getting that info doesn't require any authentication process which is why AuthComponent::user() give you the user info in case of standard cookie based auth.
I'm a bit late, but I found a solution to this problem, but (warning!) it involved updating the code for AuthComponent.
I took a copy of Lib/Controller/Component/AuthComponent.php and placed it under app/Controller/Component/AuthComponent.php.
I then added one line to the file:
public function startup(Controller $controller) {
$methods = array_flip(array_map('strtolower', $controller->methods));
$action = strtolower($controller->request->params['action']);
// One-line modification from the ordinary CakePHP file.
// This lets us have info on the logged-in user in public actions when using stateless auth.
$this->_getUser();
Voila, you can now access user info on the server while accessing a non-protected controller function with stateless auth!
CakePHP v.2.4...
I'm following this documentation trying to set up the Auth component to use my custom password hashing class:
App::uses('PHPassPasswordHasher', 'Controller/Component/Auth');
class AppController extends Controller {
// auth needed stuff
public $components = array(
'Session',
'Cookie',
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username'=>'email', 'password'=>'password'),
'passwordHasher' => 'PHPass'
)
),
Inside my UsersController::login() I debug the return from $this->Auth->login(); and it always returns false, even when I submit the correct email / password.
(NOTE: It looks strange to me that the login() takes no parameters, but the docs seem to imply that it looks into the the request data automatically. And this would make sense if my configurations aren't correctly causing it to check the User.email field instead username.)
The post data from the submitted login form looks like this:
array(
'User' => array(
'password' => '*****',
'email' => 'whatever#example.com'
)
)
What am I missing?
Update2
I'm starting to suspect that the default hashing algorithm is getting used instead of my custom class. I tried to match the examples in the docs but they're quite vague on how to do this.
Here's the contents of app/Controller/Component/Auth/PHPassPasswordHasher.php
<?php
App::import('Vendor', 'PHPass/class-phpass'); //<--this exists and defines PasswordHash class
class PHPassPasswordHasher extends AbstractPasswordHasher {
public function hash($password) {
$hasher = new new PasswordHash( 8, true );
return $hasher->HashPassword($password);
}
public function check($password, $hashedPassword) {
debug('PHPassHasher'); die('Using custom hasher'); //<--THIS NEVER HAPPENS!
$hasher = new new PasswordHash( 8, true );
return $hasher->CheckPassword($password, $hashedPassword);
}
}
AHA! The debug() never appears... so I'm pretty sure the problem is with my custom hasher configuration(s).
Update3
Additional clue: I experimented by setting various default hashing algorithms (Ex: "Simple", "Blowfish") and creating users. The hashes which show up in the DB are all the same which tells me that my config settings are getting ignored completely.
Update4
I debugged $this->settings inside the constructor of /lib/Cake/Controller/Component/Auth/BaseAuthenticate.php and my custom hasher settings are in there:
array(
'fields' => array(
'password' => 'password',
'username' => 'email'
),
'userModel' => 'User',
'scope' => array(),
'recursive' => (int) 0,
'contain' => null,
'passwordHasher' => 'PHPass'
)
You need to rename your password hasher class to have the suffix "PasswordHasher", and only provide the non-suffixed name in the 'className' argument.
eg:
<?php
App::import('Vendor', 'PHPass/class-phpass'); //<--this exists and defines PasswordHash class
class PHPassHasherPasswordHasher extends AbstractPasswordHasher {
// functions
}
The example from the docs sets the classname to 'Simple', which then loads 'SimplePasswordHasher'.
You might find that having a name of PHPassHasherPasswordHasher is a bit silly, it's up to you what you want to call it. Perhaps PHPassPasswordHasher might be a bit more appropriate (and then use the classname argument 'PHPass').
EDIT: It seems as if Cake has issues when multiple capital letters are used one after the other (eg. PHPass), so the right way to do it is to change the password hasher class to the following:
<?php
App::import('Vendor', 'PHPass/class-phpass'); //<--this exists and defines PasswordHash class
class PhpassPasswordHasher extends AbstractPasswordHasher {
// functions
}
... and make sure the filename matches the classname: PhpassPasswordHasher.php.
Thanks to SDP for the discussion, I learnt something today!
According to the docs:
To configure different fields for user in $components array:
// Pass settings in $components array
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array(
'username' => 'email',
'password' => 'password'
)
)
)
)
);
Source
I finally got this working. We were on the right track by renaming the file/class to comply with Cake conventions. I had to go one step further and change the capitalization as well:
PHPassPasswordHasher.php --> PhpassPasswordHasher.php
class PHPassPasswordHasher... --> class PhpassPasswordHasher...
Phew!
ps: Many many thanks to #Ben Hitchcock for support on this.
I am developing an application using cakephp 2.3.9 .It got a users table to save user credentials .How do i use a different field in User table other than password field to save password.
You can try this:
public $components = array(
'Auth' => array(
'loginAction' => array(
......
),
'authError' => '...',
'authenticate' => array(
'Form' => array(
'fields' =>
array(
'password' => 'YOUR_CUSTOM_FIELD' // set custom field
// as password field
)
)
)
)
);
in AppController.php.
And in your Form set type="password" to that field. e.g.
$this->Form->input('YOUR_CUSTOM_FIELD', array('type' => 'password'));
Referencing comment, to encrypt the password field you need to do manual approach in your controller or model. e.g. in controller you can do like:
$this->request->data['User']['YOUR_CUSTOM_FIELD'] = AuthComponent::password( $this->request->data['User']['YOUR_CUSTOM_FIELD']);
Also you can do model beforeSave() function also by proper checking in case of add/edit action.
Ref:
CakePHP Auth Password Hash
For detail about CakePHP Auth
I have a mongo db structure for users with "username" and "password". I am trying to use the Auth in cakephp login but it seems like its not working for me. I tried removing the $this->data but still it did not work.
My password is hashed using Security::hash($this->data['User']['password'])
if(!empty($this->data))
{
if($this->Auth->login($this->data))
{
echo "yes";
}
else{
echo "no";
}
}
In my app controller I have this:
public $components = array('DebugKit.Toolbar', 'Session', 'Auth' => array(
'loginAction' => array(
'controller' => 'pages',
'action' => 'home'
),
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'username', 'password' => 'password')
)
)
));
Here is the result when I debug the login method:
array(
'User' => array(
'password' => '*****',
'username' => 'test#test.com',
'remember' => '0',
'auto_login' => '0'
)
)
I don't know why I cannot use Auth with mongodb. Thanks for the help in advance.
EDIT:
When i tried and take away the layout, it shows me a query at the bottom of the page saying:
db.users.find( {"username":"test#test.com","password":"2fdf49ffc396453960802df8fc2417655d1e8fca"}, [] ).sort( [] ).limit( 1 ).skip( 0 )
The hashed value of the password that I inputted from the form is different from the hash value that is being queried. The hashed value should be "a2374c309ab7823dcd9b4e21dae7511f7a9c7ec5". Why is it that cakephp is converting the password into another hash value?
There are two ways of using $this->Auth->login(). The CakePHP API documentation explains it:
If a $user is provided that data will be stored as the logged in user. If $user is empty or not specified, the request will be used to identify a user.
The manual also mentions:
In 2.0 $this->Auth->login($this->request->data) will log the user in with whatever data is posted ...
So for the login method of the users controller you shouldn't pass anything:
if($this->Auth->login()) {
// user is now logged in
}
Should you need to manually login a user you can pass the user data as an array:
if($this->Auth->login($this->request->data['User'])) {
// user is now logged in
}
Where $this->request->data['User'] is something like:
array(
'id' => 1,
'username' => 'admin',
'password' => '1234',
);
Note: In both cases you don't need to hash the password as it is done automatically.
I was able to find out the answer. Its because cakephp is automatically hashing the password when searching in the database.
The problem that I had was when I was saving the users' password, I am was using
Security::hash($this->data['User']['password'])
I should have used this one instead:
AuthComponent::password($this->data['User']['password'])
Thank you for all the help especially to #xgalvin
with cake 1.3 for autologin facebook users i get the user info from database:
$userInfo = $this->User->find('first', array(
'fields' =>array('User.username','User.password'),
'conditions' => array(
'source_id' => $fb_user_id,
'source' => "facebook",
)
));
password comming from this select is hashed.
and i use this method for authentication
$this->Auth->login($userInfo);
but now with cake 2
var_dump($this->Auth->login($userInfo));
always return false;
i 'm not sure but i think that now the login() method need a clear password??
any solution? and excuse my English
Try $this->Auth->login($userInfo['User']), to login user in cakephp 2.0 you should use array with users data, without mention model
If its will not help then check if your Auth component configuration is right...
I use
$this->Auth->authenticate = array(
'all' => array(
'userModel' => 'User',
),
'Form'
);
$this->Auth->loginAction = {url};
$this->Auth->logoutAction = {url}