Laravel 8 Jetstream how to redirect user to custom route after resetting password - laravel-8

I am using Laravel 8 jetstream for authentication. My question is, how can I redirect the user after resetting the password to the custom route? I don't want to redirect the user to the login page. I didn't find the route in all Fortify classes; I am sure it should override.
protected $redirectTo
But I don't know in which file I have to do this change.

Here’s what I ended up doing to have a redirect back to the login route after a user submits a password reset action:
Copy the file SuccessfulPasswordResetLinkRequestResponse.php from \vendor\laravel\fortify\Http\Responses\ to a folder on your project at app\Http\Responses.
In your new file SuccessfulPasswordResetLinkRequestResponse.php, change the namespace to:
namespace App\Http\Responses;
Open app\Providers\FortifyServiceProvider.php
Inside the boot() function add:
public function boot()
{
...
$this->app->singleton(SuccessfulPasswordResetLinkRequestResponseContract::class, SuccessfulPasswordResetLinkRequestResponse::class);
}
In this same FortifyServiceProvider.php file, add the namespaces:
use App\Http\Responses\SuccessfulPasswordResetLinkRequestResponse;
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse as SuccessfulPasswordResetLinkRequestResponseContract;
In your new SuccessfulPasswordResetLinkRequestResponse.php file, edit the toResponse() function:
public function toResponse($request)
{
return $request->wantsJson()
? new JsonResponse(['message' => trans($this->status)], 200)
: redirect()->route('login')->with('status', trans($this->status));
}
Here's a helpful link that shows all of the response classes that Fortify uses at the time of this writing:
Overriding other Jetstream and Fortify functionality

EDIT: It is not recommended to edit a file in vendor, use BillD's solution.
Check out vendor\laravel\fortify\src\Http\Responses\PasswordResetResponse.php
You should be able to modify the response in the method:
/**
* Create an HTTP response that represents the object.
*
* #param \Illuminate\Http\Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
return $request->wantsJson()
? new JsonResponse(['message' => trans($this->status)], 200)
: redirect()->route('login')->with('status', trans($this->status));
}

I had the same issue using jetstream and found the accepted solution is better especially if there are admin and user models each has reset password functionality,
You don't need to edit PasswordResetResponse.php in vendor but simply:
copy it to App\Http\Responses
then as you can find /vendor/laravel/fortify/routes/routes.php
Route::post('/reset-password', [NewPasswordController::class, 'store'])
->middleware(['guest:' . config('fortify.guard')])
->name('password.update');
It points to /laravel/fortify/src/Http/Controllers/NewPasswordController.php.
Store function has the default PasswordResetResponse.php.
public function store(Request $request): Responsable
{
$request->validate([
'token' => 'required',
Fortify::email() => 'required|email',
'password' => 'required',
]);
$status = $this->broker()->reset(
$request->only(Fortify::email(), 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
app(ResetsUserPasswords::class)->reset($user, $request->all());
app(CompletePasswordReset::class)($this->guard, $user);
}
);
return $status == Password::PASSWORD_RESET
? app(PasswordResetResponse::class, ['status' => $status])
: app(FailedPasswordResetResponse::class, ['status' => $status]);
}
So only need to change is the namespace in NewPasswordController.php file to point to your PasswordResetResponse.php you've made.
use Laravel\Fortify\Contracts\PasswordResetResponse;
To--
use App\Http\Responses\PasswordResetResponse;

Related

How to send user login credentials after user registers

I am using laravel's default login and registration. I have successfully set up authentication, however I would like to send user's username and password to the emails they used during registration. How can I achieve this?
You can initiate a mail to user after you validated input received and before your create functions of your register controller present in
$email = new UserRegisterData(new User(['password' => $user->password, 'name' => $user->name]));
To do this you need to rewrite
protected function validator(array $data)
function in your register controller and modify that with this mail. as
protected function validator(array $data)
{
$email = new UserRegisterData(new User(['password' => $user->password, 'name' => $user->name]));
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:customers',
'password' => 'required|min:6|confirmed',
]);
}
once you hashed your password in create function, i think it can't be read. Also check if any security issue it may generate. Also you need to create mail as 'UserRegisterData' and add necessary code in it.

phpBB 3.1+ Authentication Plugin

I could really use some help with this.
BACKGROUND:
I've got phpBB 3.0 installed and have working external authentication from my own site's database. My working is an implementation of this excellent worked example: https://github.com/nzeyimana/PhpBBAuthDbExt/blob/master/auth_dbext.php
I now want to upgrade my Forum to 3.2 (current version).
PROBLEM:
Trying to follow the example in the documentation https://area51.phpbb.com/docs/dev/32x/extensions/tutorial_authentication.html#authentication-providers and also phpBB community/viewtopic.php?f=461&t=2272371
I've copied the class file from the example documentation, calling it db2.php and placed in "ext/acme/demo/auth/provider/"
I've also copied the service file from the example documentation, calling it services.yml and placed in "ext/acme/demo/config/"
Copies of both file contents at bottom below.
According to the documentation, I should then see db2 in the list of authentication methods in the Authentication part of Access Control Panel (ACP) - but nothing appears. I've flushed the forum cache, flushed my browsers cache etc, to no avail.
Am I missing something? Any help REALLY appreciated.
Kevin
This is the content of the db2.php file:
#
<?php
namespace acme\demo\auth\provider;
/**
* Database authentication provider for phpBB3
*
* This is for authentication via the integrated user table
*/
class db2 extends \phpbb\auth\provider\base
{
/** #var \phpbb\db\driver\driver_interface $db */
protected $db;
/**
* Database Authentication Constructor
*
* #param \phpbb\db\driver\driver_interface $db
*/
public function __construct(\phpbb\db\driver\driver_interface $db)
{
$this->db = $db;
}
/**
* {#inheritdoc}
*/
public function login($username, $password)
{
// Auth plugins get the password untrimmed.
// For compatibility we trim() here.
$password = trim($password);
// do not allow empty password
if (!$password)
{
return array(
'status' => LOGIN_ERROR_PASSWORD,
'error_msg' => 'NO_PASSWORD_SUPPLIED',
'user_row' => array('user_id' => ANONYMOUS),
);
}
if (!$username)
{
return array(
'status' => LOGIN_ERROR_USERNAME,
'error_msg' => 'LOGIN_ERROR_USERNAME',
'user_row' => array('user_id' => ANONYMOUS),
);
}
$username_clean = utf8_clean_string($username);
$sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts
FROM ' . USERS_TABLE . "
WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'";
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
// Successful login... set user_login_attempts to zero...
return array(
'status' => LOGIN_SUCCESS,
'error_msg' => false,
'user_row' => $row,
);
}
}
#
This is the content of the services.yml file:
#
services:
auth.provider.db2:
class: acme\demo\auth\provider\db2
arguments:
- '#dbal.conn'
tags:
- { name: auth.provider }
#
Unfortunately, the documentation is missing an important part - every extension should have its composer.json file in order to identify the extension - link.
You can refer to OneAll phpBB extension to see its structure and code. Use it as an example.
Once you have your composer.json, you should see you extension in the extension management list. Then enable your extension and you should see it in the Authentication section in your Access Control Panel (ACP)
I hope this helps.

Passport - "Unauthenticated." - Laravel 5.3

I hope someone could explain why I'm unauthenticated when already has performed a successfull Oauth 2 authentication process.
I've set up the Passport package like in Laravel's documentation and I successfully get authenticated, receives a token value and so on. But, when I try to do a get request on, let say, /api/user, I get a Unauthenticated error as a response. I use the token value as a header with key name Authorization, just as described in the docs.
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware("auth:api");
This function is suppose to give back my self as the authenticated user, but I'm only getting Unauthenticated. Likewise, if I just return the first user, I'm again getting Unauthenticated.
Route::get('/test', function(Request $request) {
return App\User::whereId(1)->first();
})->middleware("auth:api");
In a tutorial from Laracast, guiding through the setup of Passport, the guider doesn't have the ->middleware("auth:api") in his routes. But if its not there, well then there's no need for authentication at all!
Please, any suggestions or answers are more then welcome!
You have to set an expiration date for the tokens you are generating,
set the boot method in your AuthServiceProvider to something like the code below and try generating a new token. Passports default expiration returns a negative number
public function boot()
{
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
}
Check your user model and the database table, if you have modified the primary id field name to say something other than "id" or even "user_id" you MIGHT run into issues. I debugged an issue regarding modifying the primary id field in my user model and database table to say "acct_id" instead of keeping it as just "id" and the result was "Unauthenticated" When I tried to get the user object via GET /user through the auth:api middleware. Keep in mind I had tried every other fix under the sun until I decided to debug it myself.
ALSO Be sure to UPDATE your passport. As it has had some changes made to it in recent weeks.
I'll link my reference below, it's VERY detailed and well defined as to what I did and how I got to the solution.
Enjoy!
https://github.com/laravel/passport/issues/151
I had this error because of that I deleted passport mysql tables(php artisan migrate:fresh), php artisan passport:install helps me. Remember that after removing tables, you need to re-install passport!
I had exactly the same error because I forgot to put http before the project name.
use Illuminate\Http\Request;
Route::get('/', function () {
$query = http_build_query([
'client_id' => 3,
'redirect_uri' => 'http://consumer.dev/callback',
'response_type' => 'code',
'scope' => '',
]);
// The redirect URL should start with http://
return redirect('passport.dev/oauth/authorize?'.$query);
});
Route::get('/callback', function (Request $request) {
$http = new GuzzleHttp\Client;
$response = $http->post('http://passport.dev/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 3,
'client_secret' => 'M8y4u77AFmHyYp4clJrYTWdkbua1ftPEUbciW8aq',
'redirect_uri' => 'http://consumer.dev/callback',
'code' => $request->code,
],
]);
return json_decode((string) $response->getBody(), true);
});

Zend 2 and auth configuration routing

I'm working curently on a Zend2 project where there is an authentifaction system for the whole website, it was fine until we had to develop a module which is an public web service.
I would like to know if it's possible to allow users to access to a specific module/routing of Zend 2 ?
The Zend\Authentication\Adapter\Http provides an easy way for Apache like authentication in Zend Framework 2 applications.
It comes with two implementations Basic and Digest HTTP Authentication, which can be combined with two sub components - the class itself or a FileResolver. We are going to use the FileResolver to read the stored credentials and compare them to the submitted values.
First thing first. There are few important things to know.
Create a folder with name auth in MODULE_NAME/config/. Inside that folder create two files basic.txt and digest.txt. The file formats are smillar to Apache .htpasswd files.
Basic - <username>:<realm>:<credentials>, here credentials should be written in clear text, e.g.: basic:authentication:plaintextpassword.
Digest - <username>:<realm>:<credentials>, where <credentials> is the md5 hash of all 3 parts, e.g.: digest:authentication:dc45122ef294d83e84a8b5a3a6c5356b
In the same module, where we have just created our auth folder, open module.config.php file and place this code.
The code tells us which authentication schemes we accept, the realm (must be the same as the realm in the basic/digest.txt files, digest_domains (only when we use digest authentication) is the URL(s) where we want to apply the same valid information, nonce_timeout sets the number of seconds for which the nonce is valid.
/**
* Used for basic authentication
*/
'authentication_basic' => [
'adapter' => [
'config' => [
'accept_schemes' => 'basic',
'realm' => 'authentication',
'nonce_timeout' => 3600,
],
'basic' => __DIR__.'/auth/basic.txt',
],
],
/**
* Used for digest authentication
*/
'authentication_digest' => [
'adapter' => [
'config' => [
'accept_schemes' => 'digest',
'realm' => 'authentication',
'digest_domains' => '/learn-zf2-authentication/digest',
'nonce_timeout' => 3600,
],
'digest' => __DIR__.'/auth/digest.txt',
],
]
LearnZF2Authentication\Factory\BasicAuthenticationAdapterFactory
$config = $serviceLocator->get('Config');
$authConfig = $config['authentication_basic']['adapter'];
$authAdapter = new HttpAdapter($authConfig['config']);
$basic = new FileResolver();
$basic->setFile($authConfig['basic']);
$authAdapter->setBasicResolver($basic);
return $authAdapter;
LearnZF2Authentication\Factory\DigestAuthenticationAdapterFactory
$config = $serviceLocator->get('Config');
$authConfig = $config['authentication_digest']['adapter'];
$authAdapter = new HttpAdapter($authConfig['config']);
$digest = new FileResolver();
$digest->setFile($authConfig['digest']);
$authAdapter->setDigestResolver($digest);
return $authAdapter;
These are the codes we use to pass the authentication information
Module.php
/**
* #var MvcEvent $e
*/
$request = $e->getRequest();
$response = $e->getResponse();
$view = $e->getApplication()->getMvcEvent()->getViewModel();
$sm = $e->getApplication()->getServiceManager();
$authAdapter = $sm->get('LearnZF2Authentication\BasicAuthenticationAdapter');
/**
* Not HTTP? Stop!
*/
if (!($request instanceof Http\Request && $response instanceof Http\Response)) {
return;
}
/**
* Call the factory class and try to authenticate
*/
if ($e->getRouteMatch()->getParam('action') == 'digest') {
$authAdapter = $sm->get('LearnZF2Authentication\DigestAuthenticationAdapter');
}
$authAdapter->setRequest($request);
$authAdapter->setResponse($response);
if($e->getRouteMatch()->getParam('action') == 'basic' || $e->getRouteMatch()->getParam('action') == 'digest') {
$result = $authAdapter->authenticate();
/**
* Pass the information to the view and see what we got
*/
if ($result->isValid()) {
return $view->identity = $result->getIdentity();
} else {
/**
* Create a log function or just use the one from LearnZF2.
* Also make sure to redirect to another page, 404 for example
*/
foreach ($result->getMessages() as $msg) {
return $view->authProblem = $msg;
}
}
}
This is the code we use to pass the authentication information
One last important thing to note is that you must include a special header called Authorization n your request, replace :
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
with
PHP compiled as CGI does not support apache_response_headers function, but we need this header in order to do basic HTTP authtentication when running with CGI or FastCGI.
RewriteRule ^(.*)$ %{ENV:BASE}index.php [E=HTTP_AUTHORIZATION:% {HTTP:Authorization},L,NC]
and add in top of public/index.php
if (isset($_SERVER["REDIRECT_HTTP_AUTHORIZATION"])) {
$_SERVER["HTTP_AUTHORIZATION"] = $_SERVER["REDIRECT_HTTP_AUTHORIZATION"];
}
Some things to note. The auth folder as well the authentication code from module.config.php is best to be placed in your main config folder, where the global|local.php files are and excluded from commits.

Blocking access via HTTP Authentication with Zend Framework 2

I'm trying to implement HTTP-based authentication through a Zend\Authentication\Adapter\Http as explained in the ZF2 documentation about the HTTP Authentication Adapter.
I want to block every incoming request until the user agent is authenticated, however I'm unsure about how to implement this in my module.
How would I setup my Zend\Mvc application to deny access to my controllers?
What you are looking for is probably a listener attached to the Zend\Mvc\MvcEvent::EVENT_DISPATCH event of your application.
In order, here's what you have to do to block access to any action through an authentication adapter. First of all, define a factory that is responsible for producing your authentication adapter:
namespace MyApp\ServiceFactory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Authentication\Adapter\Http as HttpAdapter;
use Zend\Authentication\Adapter\Http\FileResolver;
class AuthenticationAdapterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
$authConfig = $config['my_app']['auth_adapter'];
$authAdapter = new HttpAdapter($authConfig['config']);
$basicResolver = new FileResolver();
$digestResolver = new FileResolver();
$basicResolver->setFile($authConfig['basic_passwd_file']);
$digestResolver->setFile($authConfig['digest_passwd_file']);
$adapter->setBasicResolver($basicResolver);
$adapter->setDigestResolver($digestResolver);
return $adapter;
}
}
This factory will basically give you a configured auth adapter, and abstract its instantiation logic away.
Let's move on and attach a listener to our application's dispatch event so that we can block any request with invalid authentication headers:
namespace MyApp;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\EventManager\EventInterface;
use Zend\Mvc\MvcEvent;
use Zend\Http\Request as HttpRequest;
use Zend\Http\Response as HttpResponse;
class MyModule implements ConfigProviderInterface, BootstrapListenerInterface
{
public function getConfig()
{
// moved out for readability on SO, since config is pretty short anyway
return require __DIR__ . '/config/module.config.php';
}
public function onBootstrap(EventInterface $event)
{
/* #var $application \Zend\Mvc\ApplicationInterface */
$application = $event->getTarget();
$serviceManager = $application->getServiceManager();
// delaying instantiation of everything to the latest possible moment
$application
->getEventManager()
->attach(function (MvcEvent $event) use ($serviceManager) {
$request = $event->getRequest();
$response = $event->getResponse();
if ( ! (
$request instanceof HttpRequest
&& $response instanceof HttpResponse
)) {
return; // we're not in HTTP context - CLI application?
}
/* #var $authAdapter \Zend\Authentication\Adapter\Http */
$authAdapter = $serviceManager->get('MyApp\AuthenticationAdapter');
$authAdapter->setRequest($request);
$authAdapter->setResponse($response);
$result = $adapter->authenticate();
if ($result->isValid()) {
return; // everything OK
}
$response->setBody('Access denied');
$response->setStatusCode(HttpResponse::STATUS_CODE_401);
$event->setResult($response); // short-circuit to application end
return false; // stop event propagation
}, MvcEvent::EVENT_DISPATCH);
}
}
And then the module default configuration, which in this case was moved to MyModule/config/module.config.php:
return array(
'my_app' => array(
'auth_adapter' => array(
'config' => array(
'accept_schemes' => 'basic digest',
'realm' => 'MyApp Site',
'digest_domains' => '/my_app /my_site',
'nonce_timeout' => 3600,
),
'basic_passwd_file' => __DIR__ . '/dummy/basic.txt',
'digest_passwd_file' => __DIR__ . '/dummy/digest.txt',
),
),
'service_manager' => array(
'factories' => array(
'MyApp\AuthenticationAdapter'
=> 'MyApp\ServiceFactory\AuthenticationAdapterFactory',
),
),
);
This is the essence of how you can get it done.
Obviously, you need to place something like an my_app.auth.local.php file in your config/autoload/ directory, with the settings specific to your current environment (please note that this file should NOT be committed to your SCM):
<?php
return array(
'my_app' => array(
'auth_adapter' => array(
'basic_passwd_file' => __DIR__ . '/real/basic_passwd.txt',
'digest_passwd_file' => __DIR__ . '/real/digest_passwd.txt',
),
),
);
Eventually, if you also want to have better testable code, you may want to move the listener defined as a closure to an own class implementing the Zend\EventManager\ListenerAggregateInterface.
You can achieve the same results by using ZfcUser backed by a Zend\Authentication\Adapter\Http, combined with BjyAuthorize, which handles the listener logic on unauthorized actions.
Answer of #ocramius is accept answer But you forget to describe How to write two files basic_password.txt and digest_passwd.txt
According to Zend 2 Official Doc about Basic Http Authentication:
basic_passwd.txt file contains username, realm(the same realm into your configuration) and plain password -> <username>:<realm>:<credentials>\n
digest_passwd.txt file contains username, realm(the same realm into your configuration) and password hashing Using MD5 hash -> <username>:<realm>:<credentials hashed>\n
Example:
if basic_passwd.txt file:
user:MyApp Site:password\n
Then digest_passwd.txt file:
user:MyApp Site:5f4dcc3b5aa765d61d8327deb882cf99\n
Alternatively you can use Apache Resolver for HTTP Adapter
use Zend\Authentication\Adapter\Http\ApacheResolver;
$path = 'data/htpasswd';
// Inject at instantiation:
$resolver = new ApacheResolver($path);
// Or afterwards:
$resolver = new ApacheResolver();
$resolver->setFile($path);
According to https://zendframework.github.io/zend-authentication/adapter/http/#resolvers