cakephp 3.8.13 add admad/cakephp-jwt-auth - authentication

This question is asked many times in the stack overflow but I tried every accepted solution.
I'm new to cake PHP and I was assigned to add JWT in our application. Previously the team used the default cake sessions. In order to integrate, I used admad/cakephp-jwt-auth. So In the AppController
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Recurring');
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'user_name',
'password' => 'password',
],
'contain' => ['Roles']
],
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'CbEmployees',
'fields' => [
'username' => 'id'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
]);
}
I have to use CbEmployees which is our user model.
Then in my custom controller, I add my login function
public function login()
{
$user = $this->Auth->identify();
if (!$user) {
$data = "Invalid login details";
} else {
$tokenId = base64_encode(32);
$issuedAt = time();
$key = Security::salt();
$data = JWT::encode(
[
'alg' => 'HS256',
'id' => $user['id'],
'sub' => $user['id'],
'iat' => time(),
'exp' => time() + 86400,
],
$key
);
}
$this->ApiResponse([
"data" => $data
]);
}
Then I call this function using postman with body
{
"username": "developer",
"password": "dev2020"
}
I always get the response as Invalid login details. So the suggested solution is to check the password data type and length. The password is varchar(255). Another solution is to check the password in the entity. In the entity I have
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return Security::hash($password, 'sha1', true);
// return (new DefaultPasswordHasher)->hash($password);
}
}
I specifically asked why the team is using Security::hash($password, 'sha1', true); due to migration from cake 2 to cake 3 they have to use the same.
Why I'm getting always Invalid login details? What I'm doing wrong here? I can log in the using the same credentials when I'm using the application.

Related

Cakephp 4 logintest

I'm doing the test for my UserController and I'm having trouble with my login test. I'm using cakephp4 with phpunit.
The test I'm doing is this:
public function testLogin(): void
{
$this->enableSecurityToken();
$this->enableCsrfToken();
$this->get('/user/login');
$this->assertResponseOk();
$this->post('/user/login', [
'DNI_CIF' => '22175395Z',
'password' => '$2y$10$ND67aMGqm.qK86MW1wuW9OQLC9vyJQGUn2HnLuSInwrFbXQKBT.V.'
]);
$this->assertResponseCode(302); //Si correcto redirige
// $this->assertSession(1, 'Auth.User.id');
}
My UserController:
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
// regardless of POST or GET, redirect if user is logged in
if ($result && $result->isValid()) {
return $this->redirect('/');
}
// display error if user submitted and authentication failed
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('Alias de usuario o contraseƱa incorrecta.'));
}
}
My Application:
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => Router::url('/user/login'),
'queryParam' => 'redirect',
]);
// Load identifiers, ensure we check email and password fields
$authenticationService->loadIdentifier('Authentication.Password', [
'resolver' => [
'className' => 'Authentication.Orm',
'userModel' => 'User',
],
'fields' => [
'username' => 'DNI_CIF',
'password' => 'password',
]
]);
// Load the authenticators, you want session first
$authenticationService->loadAuthenticator('Authentication.Session');
// Configure form data check to pick email and password
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'DNI_CIF',
'password' => 'password',
],
'loginUrl' => Router::url('/user/login'),
]);
return $authenticationService;
}
But I'm having this error:
.......object(Authentication\Authenticator\Result)#826 (3) {
["_status":protected]=>
string(27) "FAILURE_CREDENTIALS_MISSING"
["_data":protected]=>
NULL
["_errors":protected]=>
array(1) {
[0]=>
string(27) "Login credentials not found"
}
}
Can someone tell my what I'm doing wrong?
I tried several combinations like:
'username' => '22175395Z',
'password' => '$2y$10$ND67aMGqm.qK86MW1wuW9OQLC9vyJQGUn2HnLuSInwrFbXQKBT.V.'
or:
'DNI_CIF' => '22175395Z',
'password' => 'prueba'
or
'username' => '22175395Z',
'password' => 'prueba'
but nothing works.
In order to validate against a password stored in the database, the stored password must be hashed, and the submitted password must not be.
A want to add, in case of someone having the same problem, to be careful if you are using a user added in Fixture to login because it's password may not be hashed and login test will not work. I added a user and used it in the login test.

Laravel 5.1 Guzzle - Undefined offset: 0

I need to access an API so I use guzzle6 and I write a function:
public function test()
{
$client = new GuzzleHttp\Client(['defaults' => ['verify' => false]]);
try {
$res = $client->post('https://example.com/api/v2/oauth/token?grant_type=client_credentials', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'auth' => [
'Username' => 'user_5639',
'Password' => 'pass_asdhbas67yausihd7qaw8'
]
]);
$res = json_decode($res->getBody()->getContents(), true);
}
catch (GuzzleHttp\Exception\ClientException $e) {
$response = $e->getResponse();
$result = json_decode($response->getBody()->getContents());
return response()->json(['data' => $result]);
}
}
but I got error:
ErrorException in Client.php line 346: Undefined offset: 0
When I try at POSTMAN the same request everything is fine:
How to solve my problem?
If you have a look at the Guzzle Manual for the auth-option, you'll see it expects a numerically indexed array, with the username on index 0 and the password on index 1.
So this should work:
$res = $client->post('https://example.com/api/v2/oauth/token?grant_type=client_credentials', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
'auth' => [
'user_xxxx', 'pass_xxxxx'
]
]);

cakePHP3 Form Authentication fails on identify() and manual DefaultPasswordHasher check()

I copied code from examples to create a basic login screen based on the table individuals with email and password. My AppController has this:
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email', 'password' => 'password'],
'userModel' => 'Individuals']
],
'loginAction' => [
'controller' => 'Individuals',
'action' => 'login'
],
'loginRedirect' => [
'controller' => 'Associations',
'action' => 'login'
],
'logoutRedirect' => [
'controller' => 'Association',
'action' => 'login',
'home'
]
]);
Password resets are done via a token emailed to the user. The controller saves the unencrypted value and /src/Model/Entity/Individual.php has _setPassword that ensures the database has an encrypted value. Every save for the same password is different but that, I gather, is normal.
protected function _setPassword($password) {
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
My login function started with the standard stuff, but it always returns false
$user = $this->Auth->identify();
My login function now has this debug code that always gets a "no match"
debug($this->request->data);
$email = $this->request->data['email'];
$pwd = $this->request->data['password'];
$user = $this->Individuals->find()
->select(['Individuals.id', 'Individuals.email', 'Individuals.password'])
->where(['Individuals.email' => $email])
->first();
if ($user) {
if ((new DefaultPasswordHasher)->check($pwd, $user->password)) {
debug('match');
}
else{
debug('no match');
}
if ($user->password == (new DefaultPasswordHasher)->hash($pwd)) {
debug('match2');
}
else {
debug('no match2');
}
}
There's a lot more code in and around that and I'm pretty confident I've got it right. Let me know if you need more. I'm keen to crack this.
thanks in advance.

Laravel 5.5 BroadcastException with Pusher

I have create the chat application in laravel with Brodecast+Vue so when trying to my test broadcast class its getting error "BroadcastException in PusherBroadcaster.php (line 106)" I have double checked all configurations and api authentications are correct. but getting error and pusher debug console do not display and request.
driver :
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => 'ap1',
'encrypted' => true
],
],
event :
public $message;
public $user;
public function __construct($message, User $user)
{
$this->message = $message;
$this->user = $user;
}
test function :
public function test()
{
$user = User::find(Auth::id());
event(new ChatEvent('Hello pusher', $user));
return response('done');
}
i think you need to make encrypted = false.
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => 'ap1',
'encrypted' => false
],
],

CakePHP 2, how to AuthComponent::login() with plain-text password?

I would like to implement CakePHP 2 website over existing database with plain-text password field.
This is my AppController
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'home'),
'authError' => 'You cannot view this page',
'authorize' => array('Controller'),
'authenticate' => array(
'Form' => array(
'userModel' => 'User',
'fields' => array('username' => 'user_id', 'password' => 'user_password')
)
)
)
);
public function isAuthorized($user) {
return true;
}
function beforeFilter() {
$this->Auth->allow('home');
//$this->Auth->authenticate = $this->User;
parent::beforeFilter();
}
This is my UserController.
class UsersController extends AppController {
public $paginate = array(
'fields' => array('user_id', 'user_desc', 'user_password'),
'limit' => 25,
'order' => array(
'user_id' => 'asc'
)
);
function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Cannot Login');
}
}
}
}
This is my User model
class User extends AppModel {
public $name = 'User';
public $primaryKey = 'user_id';
public $belongsTo = 'Group';
}
According to those files above, when I pressed the Login button on login.ctp, I saw
select * from users where user_password = 'this_is_hashing_password'
on the sql dump section.
So, how to turn-off the automatic hashing algorithm, so the login() will compare the user input to the database stored password as plain-text???
I have tried lots of reading on the CakePHP book but I cannot find any, also using hashPasswords($data) technique which found from the internet is not working.
Please help.
Kongthap.
The best answer really is to batch-process your stored passwords so they are hashed, however there are cases where you may be adding a Cake app to an existing application that hashes passwords differently (say by not hashing them at all), so the question is valid even if the goal in this case is not.
Try these resources for modifying Cake's password hashing function, depending on your Cake version:
Cake 2.x
Cake 1.3
I got plain text password working in Cakephp 3, this should only be use for DEVELOPMENT purpose, you should never store password in plain text in production.
That being said, during development, plain text password allows me to focus on login instead of implementing a fully functional user encrypt/decrypt logic. Which is going to be replaced by an OAuth / SAML module anyway...
OK here comes the source code:
ROOT/src/Auth/PlainTextPasswordHasher.php
<?php
namespace App\Auth;
use Cake\Auth\AbstractPasswordHasher;
/**
* Plain text password for demo use, DO NOT PUSTH THIS TO PROD
*/
class PlainTextPasswordHasher extends AbstractPasswordHasher
{
public function hash($password)
{
return $password;
}
public function check($password, $hashedPassword)
{
return $password === $hashedPassword;
}
}
ROOT/src/Controller/PagesController.php
<?php
class PagesController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'passwordHasher' => [
'className' => 'PlainText',
],
'userModel' => 'YourUsers',
]
],
'loginAction' => [
'controller' => 'Logins',
'action' => 'login'
]
]);
}
}
Source: This video https://www.youtube.com/watch?v=eASSNS1f3V4 and this section of the official doc: https://book.cakephp.org/3.0/en/controllers/components/authentication.html#creating-custom-password-hasher-classes