Bug into fosuserbundle when double click on confirmation link? - fosuserbundle

I just begin to use fosuserbundle, today I activate the confirmation register link.
It works great, but if the user click a second time on the confirmation link in the email, he get that error :
The user with confirmation token "3hiqollkisg0s4ck4w8g0gw4soc0wwoo8ko084o4ww4sss8o4" does not exist
404 Not Found - NotFoundHttpException
I think this error should be handle by the bundle, no ?
Thanks

Here's the code for overriding the action. Basically just copied part of the actual FOS action and modded.
Create a RegistrationController.php file in your user bundle's controller folder and put the overriding RegistrationController class in there.
Assuming your user bundle is Acme\UserBundle:
<?php
// Acme\UserBundle\RegistrationController.php
namespace Acme\UserBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\RegistrationController as BaseController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RegistrationController extends BaseController
{
/**
* Receive the confirmation token from user email provider, login the user
*/
public function confirmAction(Request $request, $token)
{
$userManager = $this->container->get('fos_user.user_manager');
$user = $userManager->findUserByConfirmationToken($token);
if (null === $user) {
/* ************************************
*
* User with token not found. Do whatever you want here
*
* e.g. redirect to login:
*
* return new RedirectResponse($this->container->get('router')->generate('fos_user_security_login'));
*
**************************************/
}
else{
// Token found. Letting the FOSUserBundle's action handle the confirmation
return parent::confirmAction($request, $token);
}
}
}

Related

Form::setData([]) to remove input values of a contact form after sending email not working in CakePHP?

I've created a contact form in Cakephp 4 refering to the doc (https://book.cakephp.org/4/en/core-libraries/form.html).
I have a problem to remove input values after the email has been sent.
Here's my ContactController.php :
<?php
namespace App\Controller;
use App\Controller\AppController;
use App\Form\ContactForm;
class ContactController extends AppController
{
public function index()
{
$contact = new ContactForm();
if ($this->request->is('post')) {
if ($contact->execute($this->request->getData())) {
$this->Flash->success('We will get back to you soon.');
$contact->setData([]); // I want to remove data in contact form after the email has been sent, but it doesn't work
} else {
$this->Flash->error('There was a problem submitting your form.');
}
}
$this->set('contact', $contact);
}
}
Why is $contact->setData([]); in the code abode not removing data in my contact form ?
The form helper will prefer request data, eg the POST data from your form submit, otherwise the input would always get lost when a validation error occurs.
If you want to show the form page again after successful submit, then you should redirect to the current page, that's called the PRG (Post-Redirect-Get) pattern.
So instead of $contact->setData([]);, do:
return $this->redirect(['action' => 'index']);
That's also what your baked controllers will do for add and edit actions.
See also
Cookbook > Controllers > Redirecting to Other Pages

How to disable authorization middleware in cakePHP4?

By default, the authorization plugin is apply to a global scope. For some controllers that I did not want to apply any authorization. I have to use the skipAuthorization config manually for each action. For authentication plugin, I can just only load the authentication component for each controller that requires authentication. However, the authorization middleware seems will always work even if I did not load the authorization component in the controller. So, why is that? And is there a way I can disable the authorization process for the entire controller?
You probably mean Authentication and not Authorization. In any case, from the Docs:
// in src/Controller/AppController.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Authentication.Authentication');
}
By default the component will require an authenticated user for all
actions. You can disable this behavior in specific controllers using
allowUnauthenticated():
// in a controller beforeFilter or initialize // Make view and index not require a logged in user.
$this->Authentication->allowUnauthenticated(['view', 'index']);
More information: The Authentication plugin in the Cake Book.
I think you are not doing it in the right way. For authorization, you have to write a request policy. Whenever you bake controller just add --prefix Admin or whatever you want to.
cake bake controller Users --prefix Admin
Put all admin controllers in one place.
Add routes in your routes file
$builder->prefix('Admin',['_namePrefix' => 'admin:'], function (RouteBuilder $builder) {
$builder->connect('/', ['controller' => 'Users', 'action' => 'Index']);
$builder->fallbacks(DashedRoute::class);
});
`
Request Policy. Create a role table and add column role_id in the Users table and the rest you will understand with code below.
<?php
namespace App\Policy;
use Authorization\IdentityInterface;
use Authorization\Policy\RequestPolicyInterface;
use Cake\Http\ServerRequest;
class RequestPolicy implements RequestPolicyInterface
{
/**
* Method to check if the request can be accessed
*
* #param IdentityInterface|null Identity
* #param ServerRequest $request Server Request
* #return bool
*/
public function canAccess($identity, ServerRequest $request)
{
$role = 0;
if(!empty($identity)){
$data = $identity->getOriginalData();
$role = $data['role_id'];
}
if(!empty($request->getParam('prefix'))){
switch($request->getParam('prefix')){
case 'User' : return (bool)($role === 3);
case 'Admin': return (bool)($role === 1) || (bool)($role === 2);
}
}else{
return true;
}
return false;
}
}
`
and then implements AuthorizationServiceProviderInterface to the Application
use App\Policy\RequestPolicy;
use Authorization\AuthorizationServiceProviderInterface;
use Authorization\AuthorizationService;
use Authorization\Policy\MapResolver;
use Cake\Http\ServerRequest;
use Psr\Http\Message\ServerRequestInterface;
class Application extends BaseApplication implements AuthorizationServiceProviderInterface{
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
{
$mapResolver = new MapResolver();
$mapResolver->map(ServerRequest::class, RequestPolicy::class);
return new AuthorizationService($mapResolver);
}
}

How to use the middleware for restricting other content based on the role? Using React Js and Laravel

I currently setup the role based and content authorization. However i got problem when I try the to access the route of super admin still accessible. I used this instruction https://medium.com/justlaravel/how-to-use-middleware-for-content-restriction-based-on-user-role-in-laravel-2d0d8f8e94c6 - but still no working well.
to understand well, I will share to you what suppose to be the output and my sample coding on my middleware and api.php
I have Middleware of CheckRoleRouter.php
I create a unauthorized.blade.php file for new response if the user role access wrong route.
I already set the middleware to the kernel.php
Role: I have Super Admin = 0 and Admin = 1
Middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class CheckRoleRouter
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
//Role of users
//Super Admin = 0
//Admin = 1
// how to make a middleware to prevent accessing other router based on their role.
if ($request->user() && $request->user()->role != 0)
{
return new Response(view('unauthorized')->with('role', 'SUPERADMIN'));
}
return $next($request);
}
}
Api:
Route::group(['middleware' => 'App\Http\Middleware\CheckRoleRouter'], function()
{
Route::get('list_offers','Api\BusinessOffersController#list_offers');
});
Kernel:
'checker' => \App\Http\Middleware\CheckRoleRouter::class,
Session: - it means i used the admin role so the logic is the router of super_admin is not accessible anymore because i used the admin.
Page:

Cucumber doesn't found step file "implement missing steps with the snippets"

I have designed my FW and I have exactly placed runner and step files in the package. But I am not able to run the TC, it saying Test pending though steps are defined.
PFA my project structure.
enter image description here
My step file:
package com.reThink.steps;
import net.thucydides.core.annotations.Steps;
import com.reThink.helper.LoginHelper;
import com.reThink.util.CBTestProperties;
import com.reThink.util.Constants;
import com.reThink.util.Log;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class LoginSteps {
#Steps
LoginHelper loginHelper;
private String username = null;
private String password = null;
/**
* Method to navigate to login page
*
* #param
* #return
*/
#Given("^I am on the reThink Login page$")
public void givenIamonthehomepage() throws Exception {
loginHelper.openLoginPage();
}
/**
* Method to login as a Admin user
*
* #param
* #return
*/
#When("^I login as an Admin user$")
public void loginWithAdminUser() throws Exception {
loginHelper.openLoginPage();
username = CBTestProperties.Instance
.getTestProperty(Constants.ADMINUSERNAME);
password = CBTestProperties.Instance
.getTestProperty(Constants.ADMINPASSWORD);
loginHelper.loginToRethink(username, password);
}
/**
* I should be login successfully
*
* #param
* #return
*/
#Then("^I should be logged in successfully$")
public void thenItShouldBeLoggedIn() throws Exception {
// assertThat(homePageHelper.isLoginSuccessful(username));
Log.info("Successfully logged in");
}
}
Feature file
#Logon_Admin_User
Scenario: Login to reThink with Admin User credentials
Given I am on the reThink Login page
When I login as an Admin user
Then I should be logged in successfully
You are missing glue path in cucumber options of runner class. Please try with followings.
#RunWith(CucumberWithSerenity.class)
#CucumberOptions(features="src/test/resources/features",tags="#Logon_Admin_user",glue = { "com.reThink.steps" })
public class TestRunnerSuite{}

Laravel: resetting password without getting redirect response

I am building an angular application and want to implement password reset. However, default laravel config doesn't appear to allow one to do this using purely XMLHttpRequest ($http.post) requests and responds with a 302 redirect.
I managed to get postLogin and postRegister to work without issuing redirects by implementing said methods in authController class and returning a json response, doing this overrides the default laravel implementation of said methods. No such luck with postEmail and it appears the method is not hit at all, I just get a 302 response back immediately.
Ideally, other than to check their E-mail, I don't want the user to leave the single page angular application at all.
So 1. User posts E-mail to postEmail -> Email with reset link or better 'reset code' is sent to E-mail address -> User then inputs the reset token code into the already open web app or if it can't be done, browse to reset password page opened in new tab.
I tried implementing postEmail method as such:
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
});
switch ($response) {
case Password::RESET_LINK_SENT:
return response()->json(['msg' => 'A reset link has been sent to your E-mail'], 200);
case Password::INVALID_USER:
return response()->json(['msg' => 'This E-mail cannot be found in our system'], 200);
}
}
Also, where is template for the E-mail with the reset link that laravel sends out ?
You can create a PasswordController within the App\Http\Controllers\Auth namespace to extend the password reset methods.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller
{
use ResetsPasswords;
public function postEmail(Request $request)
{
}
}
To overwrite the email templates you can create a reminder.blade.php in the app/views/emails/auth directory, or change the location of the template file in the app/config/auth.php config.
while the accepted answer is completely valid, another solution without overriding the original notification class is as follows, ResetPassword provides a static method called createUrlUsing which accepts a Closure, So we can override the URL as something like the below:
use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Notifications\ResetPassword;
...
$status = Password::sendResetLink(
['email' => $args['email']],
function ($user, $token) {
ResetPassword::createUrlUsing(function ($notifiable, $token) {
// This is where you override the URL, you can also take a look at
// the `url`, `action` and `route` functions in Laravel and skip
// `sprintf` if you prefer to stick to Laravel functions only.
return sprintf(
"%s/%s/?token=%s&email=%s",
config('your.optional.frontend_url'),
config('your.optional.password_reset'),
$token,
$notifiable->getEmailForPasswordReset(),
); // frontend_url/password_url/?token=TOKEN&email=EMAIL
});
return $user->notify(new ResetPassword($token));
}
);
// This is an optional way to handle the final response, you can convert it to
// JSON or ignore it.
return $status === Password::RESET_LINK_SENT
? ['status' => __($status)]
: throw new Error(__($status));
This piece of code should be placed at a new route to handle password reset requests instead of using the default Laravel one.

Resources