Old users can't login after changing password validation rule - regex

i am using symfony 2 to build a web platform for my company. Recently, i have changed the validation rule inside my User entity by adding the following code:
/**
* #Assert\Regex(
* pattern="/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,127}$/",
* message="edit.personnal_info.udpate.message.password_info_regex",
* groups={"registration"}
* )
*/
protected $plainPassword;
After this change, all my old created users can't login anymore. Just new users, with valid password can get connected.
I don't want to change all old passwords. So, if there is a way to skip validation rules while login, it will be OK.
Ps: i'm using FOSUserBundle.

Solution if your issue is that old users used shorter passwords and you want to support them until next password change
Instead of adding this constrain to entity you could add it to your registration and change password forms
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('plainPassword', PasswordType::class, [
'constraints' => [
new Regex([
'pattern' => '/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,127}$/'
]),
new NotBlank()
]
]);
}
this way you can enforce new password policy for new users without breaking logic for old users.

Related

Why running a Laravel 9 test is deleting my database?

I am usgin Laravel 9 test tool.
I dropped the database, recreated and imported using SQL statement.
With all the database set, I used the browser to log in with my user, and everything worded just fine.
Then I ran the php artisan test --filter HomeControllerTest and all the database was deleted! HOW COME?????
here is the test code:
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class HomeControllerTest extends TestCase
{
use RefreshDatabase;
public function test_home_view_requires_authentication()
{
// Log in as the created user and try to access the home page
$response = $this->postJson('/login', [
'email' => 'test#example.com',
'password' => 'password',
]);
$response->assertStatus(302);
$response->assertRedirect(route('home'));
$response = $this->get(route('home'));
$response->assertOk();
$response->assertViewIs('home');
$response->assertViewHasAll(['corretora', 'propostas']);
}
/**
* Test if home page can be accessed by a guest user.
*
* #return void
*/
public function test_home_view_requires_guest()
{
$response = $this->get(route('home'));
$response->assertStatus(302);
$response->assertRedirect(route('login'));
}
}
Why my database was deleted? i do have a backup, of course, but should test do it?
There was not an error. The use of the use RefreshDatabase; do the erasing.
I remove it and now is working good.

Location of auth:api Middleware

Can somebody please tell the location of auth:api middleware?
As per the auth:api middleware, the api routes are protected by not null users.
I have a boolean field in user table called Is_Admin_Url_Accessible. I want to add a condition in the auth:api middleware for some routes to make user that only those user access such routes whoever are permitted to access the admin area.
I checked the class here but could not help.
\app\Http\Middleware\Authenticate.php
You can add a middleware that makes control user accessible, and you can set it as middleware to your route group like auth:api
Please run php artisan make:middleware UserAccessible on your terminal.
After run above artisan command, you will see generated a file named UserAccessible.php in the App/Http/Middleware folder.
UserAccessible.php Contents
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class UserAccessible
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if(!$user->accesible){
// redirect page or error.
}
return $next($request);
}
}
Then, you must define a route middleware via App/Http/Kernel.php
Kernel.php Contents
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
...
'user_accessible' => \App\Http\Middleware\UserAccessible::class
];
And finally, you can define route middleware to your route group;
api.php Contents
Route::group(['middleware' => ['auth:api', 'user_accessible']], function () {
// your protected routes.
});
I hope this solve your problem.

Using SitecoreUser.Profile with Forms Authentication

We use sitecore to manage our registered users (extranet domain) and when creating new virtual users we give it an email using the Profile.Email property and then call the Profile.Save() method.
Another property somewhere else reads the userProfile.Email, everything is fine at the beginning.
Plus we use Forms authentication with the remember me feature.
The problem is when we close the browser and reopen it Sitecore.Context.User contains info about the actual user who clicked remember me but the User.Profile always has the Email null.
I tried Reload() and initialize() they don't work. I also tried getting the user again via the username (User.FromName()) but the returned user object also doesn't have the Profile Email.
What is being done wrong?
There is one very important remark in Security API Cookbook. It is related to Sitecore 6 but as far as I know it should work with Sitecore 8 as there was no important changes in Security model. It worked for Sitecore 7.
Important You must log in a virtual user only after you assign Roles and Profile properties to them. The Roles and Profile properties that are assigned after logging in are lost upon subsequent request.
Sitecore.Security.Accounts.User user =
Sitecore.Security.Authentication.AuthenticationManager.BuildVirtualUser(#"domain\user"
, true);
if (user != null)
{
string domainRole = #"domain\role";
if (Sitecore.Security.Accounts.Role.Exists(domainRole))
{
user.Roles.Add(Role.FromName(domainRole));
}
user.Profile.Email = "user#domain.com";
user.Profile[“Custom Property”] = “Custom Value”;
user.Profile.Save();
Sitecore.Security.Authentication.AuthenticationManager.LoginVirtualUser(user);
}

Facebook PHP SDK 4.0 - Cannot re-ask read permissions once denied

I'm currently asking users for two read permissions i.e. email and user_location and one write permssion i.e. publish_actions. Following is the code snippet I'm using to verify if the user has granted all requested permissions:
$facebook = new Facebook(APP_ID, APP_SECRET, REDIRECT_URI);
if ( $facebook->IsAuthenticated() ) {
// Verify if all of the scopes have been granted
if ( !$facebook->verifyScopes( unserialize(SCOPES) ) ) {
header( "Location: " . $facebook->getLoginURL( $facebook->denied_scopes) );
exit;
}
...
}
Facebook is a class I've customly built to wrap the login flow used by various classes in the SDK. IsAuthenticated() makes the use of code get variable to check if the user is authorized. verifyScopes() checks granted permissions against SCOPES and assings an array of denied scopes to denied_scopes property. getLoginURL()` builds a login-dialog URL based on permissions passed as an an array as a only paramter.
Now, the problem is when the user doesn't grant write permissions, publish_actions in this case, write permission dialog is shown until user grants the write permission. But if the user chooses to deny of the read permissions, say email, the read login dialog isn't show. Instead Facebook redirects to the callback URL (that is REDIRECT_URI) creating a redirect loop.
The application I'm builiding requires email to be compulsorily provided but apparently the above approach (which seems to be the only) is failing. So, is there a workaround or a alternative way to achieve this? Or Facebook doesn't allow to ask for read permissions once denied?
As of July 15, 2014, an update has been made to the Facebook PHP SDK 4.x that allows user to re-ask the declined permissions. The function prototype of getLoginUrl() now looks like this.
public function getLoginUrl($redirectUrl, $scope = array(), $rerequest = false, $version = null)
So, to re-ask declined permissions we'd do something like this:
<?php
// ...
$helper = new FacebookRedirectLoginHelper();
if ($PermissionIsDeclined) {
header("Location: " . $helper->getLoginUrl( $redirect_uri, $scopes, true );
exit;
}
// ....
?>
For the time being you can append &auth_type=rerequest to the getLoginUrl return value to enable a rerequest, kind of lame but it works.
$helper = new FacebookRedirectLoginHelper($app_url, $app_id, $app_secret);
$login = $helper->getLoginUrl(array('scope'=>'user_likes', 'user_location'));
print $login."&auth_type=rerequest";
what about getReRequestUrl(); ?
That works just fine.
Read more at https://developers.facebook.com/docs/php/FacebookRedirectLoginHelper/5.0.0

How do I integrate Facebook SDK login with cakephp 2.x?

There seems to be very few to no up to date resources on integration of Facebook login with the cakephp Auth component online. I have found the following resources:
Old Bakery Article using cakephp 1.3? and an older version of Facebook SDK
Cakephp Plugin by webtechnick that seems to be in development
Other than this I found no definitive resources. I wanted the integration to be as flexible (without the use of a magic plugin) as possible. So after much research I finally baked a decent solution which I am sharing here today. Please contribute as I am rather new to cake.
Integration of Cakephp 2.x Auth with Facebook Auth for seamless user authentication
To start off you should read up on the fantastic cakePHP Auth Component and follow the Simple Authentication and Authorization Application tutorial from the cakephp book 2.x (Assuming you have also followed the first two tutorials from the series. After you are done, you should have managed to build a simple cakePHP application with user authentication and authorization.
Next you should download the facebook SDK and obtain an App ID from facebook.
First we will copy the Facebook sdk in to App/Vendors. Then we will import and initialize it in the AppController beforeFilter method.
//app/Controller/AppController.php
public function beforeFilter() {
App::import('Vendor', 'facebook-php-sdk-master/src/facebook');
$this->Facebook = new Facebook(array(
'appId' => 'App_ID_of_facebook',
'secret' => 'App_Secret'
));
$this->Auth->allow('index', 'view');
}
We are initializing the Facebook SDK in AppController so that we will have access to it through out the application. Next we will generate the Facebook login URL using the SDK and pass it to the view. I normally do this in the beforeRender method.
Note: The above configuration details (appId & secret) should preferably be saved in App/Config/facebook.php. You should then use cake Configure.
//app/Controller/AppController.php
public function beforeRender() {
$this->set('fb_login_url', $this->Facebook->getLoginUrl(array('redirect_uri' => Router::url(array('controller' => 'users', 'action' => 'login'), true))));
$this->set('user', $this->Auth->user());
}
We will update our layout so that we can display this link to facebook login for all users who have not logged in. Notice how we have set redirect_uri to our applications User/login action. This is so that once facebook has authenticated a user, we can log him in using cake::Auth as well. There are various benefits to this, including the solution for this question.
<!-- App/Views/Layouts/default.ctp just after <div id="content"> -->
<?php
if($user) echo 'Welcome ' . $user['username'];
else {
echo $this->Html->link('Facebook Login', $fb_login_url) . ' | ';
echo $this->Html->link('Logout', array('controller' => 'user', 'action' => 'logout'));
?>
When the user clicks the login link, facebook SDK will login the user and redirect them to our app Users/login. We will update this action for handling this:
// App/Controller/UsersController.php
// Handles login attempts from both facebook SDK and local
public function login()
{
// If it is a post request we can assume this is a local login request
if ($this->request->isPost()){
if ($this->Auth->login()){
$this->redirect($this->Auth->redirectUrl());
} else {
$this->Session->setFlash(__('Invalid Username or password. Try again.'));
}
}
// When facebook login is used, facebook always returns $_GET['code'].
elseif($this->request->query('code')){
// User login successful
$fb_user = $this->Facebook->getUser(); # Returns facebook user_id
if ($fb_user){
$fb_user = $this->Facebook->api('/me'); # Returns user information
// We will varify if a local user exists first
$local_user = $this->User->find('first', array(
'conditions' => array('username' => $fb_user['email'])
));
// If exists, we will log them in
if ($local_user){
$this->Auth->login($local_user['User']); # Manual Login
$this->redirect($this->Auth->redirectUrl());
}
// Otherwise we ll add a new user (Registration)
else {
$data['User'] = array(
'username' => $fb_user['email'], # Normally Unique
'password' => AuthComponent::password(uniqid(md5(mt_rand()))), # Set random password
'role' => 'author'
);
// You should change this part to include data validation
$this->User->save($data, array('validate' => false));
// After registration we will redirect them back here so they will be logged in
$this->redirect(Router::url('/users/login?code=true', true));
}
}
else{
// User login failed..
}
}
}
And we are done! Most of the heavy lifting is done by this action as you can see. You should preferably move some of the above code in to UserModel. So here's a summary of what is going on.
At first we check if the login request is send from the login form of our application # Users/login. If it is, then we simply log the user in. Otherwise we check if the user exists in our database and if he does log him in or create a new user, and then log him in.
Be careful to verify the user here with more than their email, like their facebook_id. Otherwise there is a chance the user could change their facebook email and hijack another user of your application.
Happy Coding!