Exception while calling authenticate method of Zend Authentication Service - php

I'm migrating my ZF2 app to ZF3.
While calling the authenticate method, getting this exception
An error occurred
An error occurred during execution; please try again later.
No Exception available
This is how I' calling the method,
public function __construct($authService, $sessionManager, $config)
{
$this->authService = $authService;//Getting the Zend\Authentication\AuthenticationService object (no error here)
$this->sessionManager = $sessionManager;
$this->config = $config;
}
public function login($email, $password, $rememberMe)
{
if ($this->authService->getIdentity() != null) {
throw new \Exception('Already logged in');
}
// Authenticate with login/password.
$authAdapter = $this->authService->getAdapter();
$authAdapter->setEmail($email);//abc.gmail.com
$authAdapter->setPassword($password);//sha1 password
$this->authService->authenticate();//Exception is generating here
}
What is I'm doing wrong?

Your exception message is not enough,
you should check php_error.log for details.
I assume that you are not registered Auth Service in the config.
So in config/autoload/global.php add
'service_manager' => [
'invokables' => [
Zend\Authentication\AuthenticationService::class => Zend\Authentication\AuthenticationService::class,
]
],

Related

How to use CakePHP3 "Authentication" Plugin with JWT

I have installed CakePhp 3.8 and i need use JWT authentication.
I have tryed installing and configuring CakePHP/Authentication (https://book.cakephp.org/authentication/1.1/en/index.html) but can not configure this.
My configuration:
PHP 7.2.19
MySQL 5.7.27
Apache 2.4.29
CakePHP 3.8
Authentication Plugin 1.1
firebase/php-jwt
I followed the guide configurations, and have add at AppController.php
// /src/Controller/Appcontroller.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Authentication.Authentication', [
'logoutRedirect' => '/administrators/login' // Default is false
]);
....
In Application.php
// /src/application.php
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
....
public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
{
$service = new AuthenticationService();
$service->loadIdentifier('Authentication.JwtSubject');
$service->loadAuthenticator('Authentication.Jwt', [
'returnPayload' => false
]);
return $service;
}
....
public function middleware($middlewareQueue)
{
....
// Add the authentication middleware
$authentication = new AuthenticationMiddleware($this);
// Add the middleware to the middleware queue
$middlewareQueue->add($authentication);
return $middlewareQueue;
}
How i can login for first time and retrive JWT token?
-------------------EDIT-------------------
Thankyou, your solutions workly perfectly.
But now i have CORS problem with Angular FE GET request, befor GET this try one OPTIONS request whit CORS error.
I have this CORS policy in my AppController
// Accepted all CORS
$this->response = $this->response->cors($this->request)
->allowOrigin(['*'])
->allowMethods(['GET','POST','PUT','DELETE','OPTIONS','PATCH']) // edit this with more method
->allowHeaders(['X-CSRF-Token']) //csrf protection for cors
->allowCredentials()
->exposeHeaders(['Link'])
->maxAge(60)
->build();
You'd have to handle that on your own, ie create an endpoint that handles login requests, and upon successful authentication creates a JWT token containing the required identifier.
For username/password authentication for example you can use the Form authenticator and the Password identifier:
$service->loadIdentifier('Authentication.Password');
$service->loadIdentifier('Authentication.JwtSubject');
$service->loadAuthenticator('Authentication.Form', [
'loginUrl' => '/users/login'
]);
$service->loadAuthenticator('Authentication.Jwt', [
'returnPayload' => false
]);
With that example in UsersController create a login() action like this (that's just a very basic, hopefully self-explanatory example), check the authentication status, if valid generate a token, if invalid generate an error:
public function login()
{
if ($this->Authentication->getResult()->isValid()) {
$userId = $this->Authentication->getIdentityData('id');
$token = \Firebase\JWT\JWT::encode(
['sub' => $userId],
\Cake\Utility\Security::getSalt()
);
$status = 200;
$response = [
'token' => $token,
];
} else {
$status = 403;
$response = [
'error' => 'Authentication required',
];
}
return $this
->getResponse()
->withStatus($status)
->withType('json')
->withStringBody(json_encode($response));
}
It probably wouldn't hurt if the cookbook would have a complete example for token authentication.
See also
Authentication Cookbook > Migration from the AuthComponent > Login action
Authentication Cookbook > Quick Start > Checking the login status
Authentication Cookbook > Quick Start > Using Stateless Authenticators with other Authenticators

Login with any password in laravel in development mode

We have auth() function in laravel and call it like this:
auth()->attempt(['email' => 'hello#gmail.com', 'password' => 123456]);
I want to set new provider for session guard and config it at config/auth.php too login user with any password in auth() function in development mode .
But i can't find a way to do it in my provider file!
This is a bad idea as you could inadvertently introduce a security risk into your production code. But in the interests of experimentation...
One way would be to overwrite the validation in the default session guard, but I think this is too risky. So I would duplicate your existing production guard and and force it to die if not in development mode. Here's an example assuming you're using the session guard.
In /app/Providers/AuthServiceProvider.php register a new guard:
use App\Services\Auth\SillyGuard;
...
public function boot()
{
$this->registerPolicies();
Auth::extend('silly', function ($app, $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard...
return new SillyGuard(Auth::createUserProvider($config['provider']));
});
}
Add it to your /config/auth.php - you'll want to overwrite your existing web guard otherwise you'd have to redefine all your routes when you switch from development to production. You must switch this guard back to your original driver when you go to production mode
'guards' => [
//others
'web' => [
'driver' => 'silly',
'provider' => 'users',
],
],
Copy the file ...src/Illuminate/Auth/SessionGuard.php to app/Services/Auth/SillyGuard.php and make the following changes:
//namespace Illuminate\Auth;
namespace App\Services\Auth;
...
public function __construct($name,
UserProvider $provider,
SessionInterface $session,
Request $request = null)
{
if (!\App::environment('local') || !config('app.debug')) {
die("This guard only works in local debug mode");
}
$this->name...
...
protected function hasValidCredentials($user, $credentials)
{
//return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
return ! is_null($user);
}

How to trigger laravel jobs failed() method when job fails?

Currently I'm calling task Report.php and generating report using generateReport() method. I have checked that the jobs have been executed using CLI command php artsan queue:listen. If anything goes wrong while calling Artisan::call() the error message will be displayed in terminal. So I want to catch the exception in failed() and I want to log the error into logs.
I have tried with try catch in handle() method but it's not catching the exception.
protected $options;
public function __construct($options)
{
$this->options = array_merge(
[
'task' => 'Report',
'do' => 'generateReport',
'limit' => '10000'
],
$options
);
}
public function handle()
{
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
}
public function failed()
{
//
}
How can I trigger the failed() and get the error into logs?
Artisan::call is actually just calling the execute console class so if you throw an Exception in there it should automatically end up in the failed method.
However, in 5.2 the Exception object is not passed to the failed method (this was added in 5.3).
Laravel 5.2
So if you need the Exception object passed to the failed method then you will need to do something like this in 5.2:
public function handle()
{
try {
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
} catch (\Exception $e) {
$this->failed($e)
}
}
public function failed(\Exception $e = null)
{
//handle error
}
Laravel 5.3+
In 5.3 the Exception is automatically passed to failed so your code would be like this:
public function handle()
{
Artisan::call('execute', [
'--task' => $this->options['task'],
'--do' => $this->options['do'],
'--parameters' => $this->options,
]);
}
public function failed(\Exception $e = null)
{
//handle error
}

How can I intercept exceptions in ZendFramework 3

I'm using ZendFramework 3 in my REST API project. So there are few modules and a plugin which checks an authorization status. If the authorization fails it throws an Exception.
There is no way to handle it in each controller separately using try .. catch. How can I intercept and handle the Exception and generate JSON output like this?
{
message: "Access denied",
reason: "Your token is incorrect"
}
I'm a newbie in ZendFramework, that's why I have no idea how to do this. And official documentation didn't say a word about this.
There are default framework Events that are triggered including the event MvcEvent::EVENT_DISPATCH_ERROR. So, all you should do is to attach listener on that error event and return JSON response.
First, you need to register your Listener in module.config.php
// In my case module name is Api
'listeners' => [
Api\Listener\ApiListener::class // Register the class listener
],
'service_manager' => [
'invokables' => [
// Register the class (of course you can use Factory)
Api\Listener\ApiListener::class => Api\Listener\ApiListener::class
],
],
Second, create the file class Api/Listener/ApiListener.php
<?php
namespace Api\Listener;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;
use Zend\Console\Request as ConsoleRequest;
use Zend\View\Model\JsonModel;
class ApiListener extends AbstractListenerAggregate
{
public function attach(EventManagerInterface $events, $priority = 1)
{
// Registr the method which will be triggered on error
$this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR,
[$this, 'handleError'], 0);
}
/**
* Return JSON error on API URI(s)
*/
public function handleError(MvcEvent $e)
{
$request = $e->getParam('application')->getRequest();
if($request instanceof ConsoleRequest){
return;
}
//If you want to convert Response only on some URIs
//$uri = $request->getUri()->getPath();
//if(0 !== strpos($uri, '/api')){
// return;
//}
$response = $e->getResponse();
$exception = $e->getResult()->exception;
$errorType = $e->getError();
$errorCode = $exception && $exception->getCode() ? $exception->getCode() : 500;
$errorMsg = $exception ? $exception->getMessage() : $errorType;
$json = new JsonModel(['message' => $errorMsg]);
$json->setTerminal(true);
$response->setStatusCode($errorCode);
$e->setResult($json);
$e->setViewModel($json);
}
}
That's all. Now on every error, your custom logics will be executed.

Laravel test connection to SOAP WDSL and exception handling

I use the laravel framework and I want to check if a connection to Soap server was successful or not, without the app dying with fatal error.
Both this:
$this->client = #new SoapClient("http://some.url/test.wsdl");
$this->session = $this->client->login("username", "password");
if (is_soap_fault($this->session)) {
return "Error";
}
And this:
try {
$this->client = #new SoapClient("http://some.url/test.wsdl");
$this->session = $this->client->login("username", "password");
} catch (SoapFault $e) {
return "Error";
}
Result in a fatal error:
Symfony \ Component \ Debug \ Exception \ FatalErrorException
SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://some.url/test.wsdl' : failed to load external entity "http://some.url/test.wsdl"
Thanks
I struggled with this issue today as well. The problem is the Laravel error handler is interpreting this catchable error as a fatal error, and aborting the program as a result.
To counter this, you need to intercept the error prior to Laravel's internal error handler. This method varies depending on your Laravel version:
Laravel 4.*
Go to your globals.php file. This should be in your app\start\ folder.
Add the following code (Thanks dmgfjaved):
App::fatal(function($exception)
{ //If SOAP Error is found, we don't want to FATALLY crash but catch it instead
if(strpos($exception->getMessage(), 'SOAP-ERROR') !== FALSE)
{
return '';
}
});
Laravel 5.*
There is no globals.php file. All IoC calls are handled via ServiceProviders. Go to app\Providers\AppServiceProvider.php.
Find the render() function.
Add the following code before the return parent::render($request, $e);
if(strpos($e->getMessage(), 'SOAP-ERROR') !== false)
{
return false;
}
This will remove the SoapFault error type from your error handler. Remember to catch the SoapFault as Laravel won't!
Try this:
try {
$this->client = #new SoapClient("http://some.url/test.wsdl");
$this->session = $this->client->login("username", "password");
} catch (\Throwable $e) {
return "Error";
}
The solution is to actually ask the Soap client to throw a SoapFault instead of reporting an E_ERROR.
When the Soap client reports an E_ERROR, there is nothing for you to catch.
To fix this initialise you SoapClient like this:
$clientOptions = array(
'exceptions' => true,
);
try {
$client = new \SoapClient("foo.wsdl", $clientOptions);
} catch (\SoapFault $e) {
// Do what you need to do!;
}
try {
$result = $client->__soapCall($method, $data);
} catch (\SoapFault $e) {
// Do what you need to do!;
}
This is how I got soap to work in Laravel 5.1
clean install laravel 5.1
install artisaninweb/laravel-soap
create a controller SoapController.php
<?php
namespace App\Http\Controllers;
use Artisaninweb\SoapWrapper\Facades\SoapWrapper;
class SoapController extends Controller {
public function demo()
{
// Add a new service to the wrapper
SoapWrapper::add(function ($service) {
$service
->name('currency')
->wsdl('http://currencyconverter.kowabunga.net/converter.asmx?WSDL')
->trace(true);
});
$data = [
'CurrencyFrom' => 'USD',
'CurrencyTo' => 'EUR',
'RateDate' => '2014-06-05',
'Amount' => '1000'
];
// Using the added service
SoapWrapper::service('currency', function ($service) use ($data) {
var_dump($service->getFunctions());
var_dump($service->call('GetConversionAmount', [$data])->GetConversionAmountResult);
});
}
}
Create a route in your routes.php
Route::get('/demo', ['as' => 'demo', 'uses' => 'SoapController#demo']);
#Adam Link provided a good hint, but in Laravel 5.1, it appear stha tthere is not longer a render method in AppServiceProvider.
Instead, it has been moved to app\Exceptions\Handler.php

Categories