Security fixes

* clear all password reset request once user get login.
* clear all password reset request once user change his/her email.
* added redirection on password forgot page ( only oauth2 clients ).

Change-Id: I5a9f57a87ff54e0509ff2dc23a25ac96fad34fb9
Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
smarcet 2020-02-29 00:07:05 -03:00
parent 94ba72402c
commit 83f0a8e2dd
11 changed files with 298 additions and 137 deletions

View File

@ -0,0 +1,44 @@
<?php namespace App\Events;
/**
* Copyright 2020 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Illuminate\Queue\SerializesModels;
/**
* Class UserEmailUpdated
* @package App\Events
*/
class UserEmailUpdated
{
use SerializesModels;
/**
* @var int
*/
private $user_id;
/**
* UserEmailVerified constructor.
* @param int $user_id
*/
public function __construct(int $user_id)
{
$this->user_id = $user_id;
}
/**
* @return int
*/
public function getUserId(): int
{
return $this->user_id;
}
}

View File

@ -11,13 +11,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Http\Controllers\Controller;
use App\Services\Auth\IUserService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request as LaravelRequest;
use models\exceptions\ValidationException;
use OAuth2\Repositories\IClientRepository;
/**
* Class ForgotPasswordController
* @package App\Http\Controllers\Auth
@ -29,30 +32,64 @@ final class ForgotPasswordController extends Controller
*/
private $user_service;
/**
* @var IClientRepository
*/
private $client_repository;
/**
* ForgotPasswordController constructor.
* @param IClientRepository $client_repository
* @param IUserService $user_service
*/
public function __construct(IUserService $user_service)
public function __construct
(
IClientRepository $client_repository,
IUserService $user_service
)
{
$this->middleware('guest');
$this->user_service = $user_service;
$this->client_repository = $client_repository;
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
* @param LaravelRequest $request
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showLinkRequestForm()
public function showLinkRequestForm(LaravelRequest $request)
{
return view('auth.passwords.email');
try {
$params = [
"redirect_uri" => '',
"client_id" => '',
];
// check if we have explicit params at query string
if ($request->has("redirect_uri") && $request->has("client_id")) {
$redirect_uri = $request->get("redirect_uri");
$client_id = $request->get("client_id");
$client = $this->client_repository->getClientById($client_id);
if (is_null($client))
throw new ValidationException("client does not exists");
if (!$client->isUriAllowed($redirect_uri))
throw new ValidationException(sprintf("redirect_uri %s is not allowed on associated client", $redirect_uri));
$params['redirect_uri'] = $redirect_uri;
$params['client_id'] = $client_id;
}
return view('auth.passwords.email', $params);
} catch (\Exception $ex) {
Log::warning($ex);
}
return view("auth.passwords.email_error");
}
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
public function sendResetLinkEmail(LaravelRequest $request)
@ -63,24 +100,44 @@ final class ForgotPasswordController extends Controller
if (!$validator->passes()) {
return back()
->withInput($request->only('email'))
->withInput($request->only('email', 'client_id', 'redirect_uri'))
->withErrors($validator);
}
$this->user_service->requestPasswordReset($payload);
return $this->sendResetLinkResponse("Reset link sent");
}
catch (ValidationException $ex){
$params = [
'client_id' => '',
'redirect_uri' => '',
];
// check redirect uri with associated client
if($request->has("redirect_uri") && $request->has("client_id")){
$redirect_uri = $request->get("redirect_uri");
$client_id = $request->get("client_id");
$client = $this->client_repository->getClientById($client_id);
if(is_null($client))
throw new ValidationException("client does not exists");
if(!$client->isUriAllowed($redirect_uri))
throw new ValidationException(sprintf("redirect_uri %s is not allowed on associated client", $redirect_uri));
$params['client_id'] = $client_id;
$params['redirect_uri'] = $redirect_uri;
}
$params['status'] = 'Reset link sent';
return back()->with($params);
} catch (ValidationException $ex) {
Log::warning($ex);
foreach ($ex->getMessages() as $message){
foreach ($ex->getMessages() as $message) {
$validator->getMessageBag()->add('validation', $message);
}
return back()
->withInput($request->only('email'))
->withInput($request->only(['email', 'client_id', 'redirect_uri']))
->withErrors($validator);
}
catch(\Exception $ex){
} catch (\Exception $ex) {
Log::warning($ex);
}
return view("auth.passwords.email_error");
@ -89,7 +146,7 @@ final class ForgotPasswordController extends Controller
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
@ -102,25 +159,12 @@ final class ForgotPasswordController extends Controller
/**
* Get the response for a successful password reset link.
*
* @param string $response
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkResponse($response)
{
return back()->with('status', trans($response));
}
/**
* Get the response for a failed password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkFailedResponse(LaravelRequest $request, $response)
{
return back()
->withInput($request->only('email'))
->withErrors(['email' => trans($response)]);
}
}

View File

@ -93,7 +93,6 @@ final class RegisterController extends Controller
if ($oauth_auth_request->isValid()) {
$redirect_uri = $oauth_auth_request->getRedirectUri();
$client_id = $oauth_auth_request->getClientId();
@ -189,7 +188,6 @@ final class RegisterController extends Controller
'redirect_uri' => '',
];
// check if we have a former oauth2 request
if ($this->memento_service->exists()) {

View File

@ -12,6 +12,7 @@
* limitations under the License.
**/
use App\Events\OAuth2ClientLocked;
use App\Events\UserEmailUpdated;
use App\Events\UserLocked;
use App\Events\UserPasswordResetRequestCreated;
use App\Events\UserPasswordResetSuccessful;
@ -78,14 +79,22 @@ final class EventServiceProvider extends ServiceProvider
Mail::queue(new WelcomeNewUserEmail($user));
if(!$user->isEmailVerified() && !$user->hasCreator())
$user_service->sendVerificationEmail($user);
});
Event::listen(UserEmailUpdated::class, function($event)
{
$repository = App::make(IUserRepository::class);
$user = $repository->getById($event->getUserId());
if(is_null($user)) return;
if(! $user instanceof User) return;
$user_service = App::make(IUserService::class);
$user_service->sendVerificationEmail($user);
});
Event::listen(UserPasswordResetRequestCreated::class, function($event){
$repository = App::make(IUserPasswordResetRequestRepository::class);
$request = $repository->find($event->getId());
if(is_null($request)) return;
});
Event::listen(UserLocked::class, function($event){

View File

@ -230,11 +230,12 @@ final class UserService extends AbstractService implements IUserService
{
return $this->tx_service->transaction(function() use($payload) {
$user = $this->user_repository->getByEmailOrName(trim($payload['email']));
if(is_null($user))
throw new EntityNotFoundException("user not found");
if(is_null($user) || !$user->isEmailVerified())
throw new EntityNotFoundException("User not found.");
$request = new UserPasswordResetRequest();
$request->setOwner($user);
do{
$token = $request->generateToken();
$former_request = $this->request_reset_password_repository->getByToken($token);

View File

@ -11,17 +11,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Events\UserEmailUpdated;
use App\libs\Auth\Factories\UserFactory;
use App\libs\Auth\Repositories\IGroupRepository;
use App\Services\AbstractService;
use Auth\IUserNameGeneratorService;
use Auth\Repositories\IUserRepository;
use Auth\User;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\utils\IEntity;
use OpenId\Services\IUserService;
use phpDocumentor\Reflection\Types\Parent_;
use Utils\Db\ITransactionService;
use Utils\Services\ILogService;
use Utils\Services\IServerConfigurationService;
@ -225,6 +227,7 @@ final class UserService extends AbstractService implements IUserService
if(is_null($user) || !$user instanceof User)
throw new EntityNotFoundException("user not found");
$former_email = $user->getEmail();
if(isset($payload["email"])){
$former_user = $this->repository->getByEmailOrName(trim($payload["email"]));
if(!is_null($former_user) && $former_user->getId() != $id)
@ -249,6 +252,12 @@ final class UserService extends AbstractService implements IUserService
}
}
if($former_email != $user->getEmail()){
Log::debug(sprintf("UserService::update use id %s - email changed old %s - email new %s", $id, $former_email , $user->getEmail()));
$user->clearEmailVerification();
Event::fire(new UserEmailUpdated($user->getId()));
}
return $user;
});

View File

@ -151,6 +151,7 @@ class CustomAuthProvider implements UserProvider
$user->setLastLoginDate(new \DateTime('now', new \DateTimeZone('UTC')));
$user->setLoginFailedAttempt(0);
$user->setActive(true);
$user->clearResetPasswordRequests();
$auth_extensions = $this->auth_extension_service->getExtensions();

View File

@ -45,8 +45,10 @@ final class UserFactory
$user->setFirstName(trim($payload['first_name']));
if(isset($payload['last_name']))
$user->setLastName(trim($payload['last_name']));
if(isset($payload['email']))
$user->setEmail(strtolower(trim($payload['email'])));
if(isset($payload['second_email']))
$user->setSecondEmail(strtolower(trim($payload['second_email'])));
if(isset($payload['third_email']))

View File

@ -11,6 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Events\UserCreated;
use App\Events\UserLocked;
use App\libs\Auth\Models\IGroupSlugs;
@ -33,6 +34,7 @@ use Illuminate\Auth\Passwords\CanResetPassword as CanResetPasswordTrait;
use Doctrine\Common\Collections\ArrayCollection;
use App\Models\Utils\BaseEntity;
use Doctrine\ORM\Mapping AS ORM;
/**
* @ORM\Entity(repositoryClass="App\Repositories\DoctrineUserRepository")
* @ORM\Table(name="users")
@ -348,21 +350,21 @@ class User extends BaseEntity
$this->public_profile_show_photo = false;
$this->public_profile_show_email = false;
$this->public_profile_show_fullname = false;
$this->password = "";
$this->identifier = "";
$this->password = "";
$this->identifier = "";
$this->gender_specify = "";
$this->password_enc = AuthHelper::AlgNative;
$this->password_salt = AuthHelper::generateSalt(self::SaltLen, $this->password_enc);
$this->password_enc = AuthHelper::AlgNative;
$this->password_salt = AuthHelper::generateSalt(self::SaltLen, $this->password_enc);
$this->login_failed_attempt = 0;
$this->access_tokens = new ArrayCollection();
$this->access_tokens = new ArrayCollection();
$this->refresh_tokens = new ArrayCollection();
$this->clients = new ArrayCollection();
$this->trusted_sites = new ArrayCollection();
$this->consents = new ArrayCollection();
$this->actions = new ArrayCollection();
$this->groups = new ArrayCollection();
$this->affiliations = new ArrayCollection();
$this->scope_groups = new ArrayCollection();
$this->clients = new ArrayCollection();
$this->trusted_sites = new ArrayCollection();
$this->consents = new ArrayCollection();
$this->actions = new ArrayCollection();
$this->groups = new ArrayCollection();
$this->affiliations = new ArrayCollection();
$this->scope_groups = new ArrayCollection();
$this->reset_password_requests = new ArrayCollection();
}
@ -400,7 +402,7 @@ class User extends BaseEntity
/**
* @return string
*/
public function getIdentifier():?string
public function getIdentifier(): ?string
{
return $this->identifier;
}
@ -410,7 +412,7 @@ class User extends BaseEntity
return $this->email;
}
public function getFullName():?string
public function getFullName(): ?string
{
return $this->getFirstName() . " " . $this->getLastName();
}
@ -422,15 +424,15 @@ class User extends BaseEntity
public function getLastName()
{
return $this->last_name;
return $this->last_name;
}
public function getNickName():?string
public function getNickName(): ?string
{
return $this->getIdentifier();
}
public function getGender():?string
public function getGender(): ?string
{
return $this->gender;
}
@ -440,14 +442,14 @@ class User extends BaseEntity
return $this->country_iso_code;
}
public function getLanguage():?string
public function getLanguage(): ?string
{
return $this->language;
}
public function getDateOfBirth():?\DateTime
public function getDateOfBirth(): ?\DateTime
{
return $this->birthday;
return $this->birthday;
}
/**
@ -455,7 +457,7 @@ class User extends BaseEntity
*/
public function getDateOfBirthNice(): ?string
{
if(is_null($this->birthday)) return null;
if (is_null($this->birthday)) return null;
return $this->birthday->format("Y-m-d H:i:s");
}
@ -470,7 +472,7 @@ class User extends BaseEntity
*/
public function getShowProfileFullName()
{
return $this->public_profile_show_fullname > 0 ;
return $this->public_profile_show_fullname > 0;
}
/**
@ -497,7 +499,7 @@ class User extends BaseEntity
return $this->public_profile_show_email > 0;
}
public function getBio():?string
public function getBio(): ?string
{
return $this->bio;
}
@ -505,13 +507,13 @@ class User extends BaseEntity
/**
* @return Client[]
*/
public function getAvailableClients():array
public function getAvailableClients(): array
{
$own_clients = $this->clients->filter(function(Client $client){
$own_clients = $this->clients->filter(function (Client $client) {
return !$client->hasResourceServer();
})->toArray();
$managed_clients = $this->managed_clients->filter(function(Client $client){
$managed_clients = $this->managed_clients->filter(function (Client $client) {
return !$client->hasResourceServer() && !$client->isOwner($this);
})->toArray();
@ -520,7 +522,7 @@ class User extends BaseEntity
public function getManagedClients()
{
return $this->managed_clients->filter(function(Client $client){
return $this->managed_clients->filter(function (Client $client) {
return !$client->hasResourceServer() && !$client->isOwner($this);
});
}
@ -529,9 +531,9 @@ class User extends BaseEntity
* Could use system scopes on registered clients
* @return bool
*/
public function canUseSystemScopes():bool
public function canUseSystemScopes(): bool
{
if($this->isSuperAdmin()) return true;
if ($this->isSuperAdmin()) return true;
return $this->belongToGroup(IOAuth2User::OAuth2SystemScopeAdminGroup);
}
@ -541,23 +543,24 @@ class User extends BaseEntity
*/
public function isOAuth2ServerAdmin(): bool
{
if($this->isSuperAdmin()) return true;
if ($this->isSuperAdmin()) return true;
return $this->belongToGroup(IOAuth2User::OAuth2ServerAdminGroup);
}
/**
* @return bool
*/
public function isOpenIdServerAdmin():bool
public function isOpenIdServerAdmin(): bool
{
if($this->isSuperAdmin()) return true;
if ($this->isSuperAdmin()) return true;
return $this->belongToGroup(IOpenIdUser::OpenIdServerAdminGroup);
}
/**
* @return bool
*/
public function isSuperAdmin():bool{
public function isSuperAdmin(): bool
{
return $this->belongToGroup(IGroupSlugs::SuperAdminGroup);
}
@ -565,7 +568,8 @@ class User extends BaseEntity
* @param string $slug
* @return bool
*/
public function belongToGroup(string $slug):bool{
public function belongToGroup(string $slug): bool
{
$criteria = new Criteria();
$criteria->where(Criteria::expr()->eq('slug', $slug));
return $this->groups->matching($criteria)->count() > 0;
@ -574,8 +578,9 @@ class User extends BaseEntity
/**
* @param Group $group
*/
public function addToGroup(Group $group){
if($this->groups->contains($group)) return;
public function addToGroup(Group $group)
{
if ($this->groups->contains($group)) return;
$this->groups->add($group);
$group->addUser($this);
}
@ -583,25 +588,27 @@ class User extends BaseEntity
/**
* @param Group $group
*/
public function removeFromGroup(Group $group){
if(!$this->groups->contains($group)) return;
public function removeFromGroup(Group $group)
{
if (!$this->groups->contains($group)) return;
$this->groups->removeElement($group);
$group->removeUser($this);
}
public function clearGroups():void{
public function clearGroups(): void
{
$this->groups->clear();
}
public function getStreetAddress()
{
return $this->address1.' '.$this->address2;
return $this->address1 . ' ' . $this->address2;
}
public function getRegion()
{
return $this->state;
return $this->state;
}
public function getLocality()
@ -622,8 +629,9 @@ class User extends BaseEntity
/**
* @param OpenIdTrustedSite $site
*/
public function addTrustedSite(OpenIdTrustedSite $site) {
if($this->trusted_sites->contains($site)) return;
public function addTrustedSite(OpenIdTrustedSite $site)
{
if ($this->trusted_sites->contains($site)) return;
$this->trusted_sites->add($site);
$site->setOwner($this);
}
@ -656,25 +664,25 @@ class User extends BaseEntity
*/
public function getFormattedAddress()
{
$street = $this->getStreetAddress();
$region = $this->getRegion();
$city = $this->getLocality();
$street = $this->getStreetAddress();
$region = $this->getRegion();
$city = $this->getLocality();
$zip_code = $this->getPostalCode();
$country = $this->getCountry();
$country = $this->getCountry();
$complete = $street;
if(!empty($city))
$complete .= ', '.$city;
if (!empty($city))
$complete .= ', ' . $city;
if(!empty($region))
$complete .= ', '.$region;
if (!empty($region))
$complete .= ', ' . $region;
if(!empty($zip_code))
$complete .= ', '.$zip_code;
if (!empty($zip_code))
$complete .= ', ' . $zip_code;
if(!empty($country))
$complete .= ', '.$country;
if (!empty($country))
$complete .= ', ' . $country;
return $complete;
}
@ -693,16 +701,15 @@ class User extends BaseEntity
public function getGroupScopes()
{
$scopes = [];
$map = [];
$map = [];
$criteria = new Criteria();
$criteria->where(Criteria::expr()->eq('active', true));
$active_scope_groups = $this->scope_groups->matching($criteria);
foreach($active_scope_groups as $group){
foreach($group->getScopes() as $scope)
{
if(!isset($map[$scope->getId()]))
foreach ($active_scope_groups as $group) {
foreach ($group->getScopes() as $scope) {
if (!isset($map[$scope->getId()]))
$scopes[] = $scope;
}
}
@ -715,17 +722,22 @@ class User extends BaseEntity
* @return bool
* @throws ValidationException
*/
public function isGroupScopeAllowed(ApiScope $scope):bool{
if(!$scope->isAssignedByGroups()) throw new ValidationException("scope is not assigned by groups!");
public function isGroupScopeAllowed(ApiScope $scope): bool
{
if (!$scope->isAssignedByGroups()) throw new ValidationException("scope is not assigned by groups!");
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('active', true));
$active_scope_groups = $this->scope_groups->matching($criteria);
foreach($active_scope_groups as $group){
if($group->hasScope($scope)) return true;
foreach ($active_scope_groups as $group) {
if ($group->hasScope($scope)) return true;
}
return false;
}
public function clearEmailVerification(){
$this->email_verified = false;
$this->email_verified_date = null;
}
/**
* @return bool
@ -735,7 +747,8 @@ class User extends BaseEntity
return $this->email_verified;
}
public function clearTrustedSites():void{
public function clearTrustedSites(): void
{
$this->trusted_sites->clear();
}
@ -752,7 +765,7 @@ class User extends BaseEntity
/**
* @return string
*/
public function getPic():string
public function getPic(): string
{
return $this->getGravatarUrl();
}
@ -760,22 +773,24 @@ class User extends BaseEntity
/**
* Get either a Gravatar URL or complete image tag for a specified email address.
*/
private function getGravatarUrl( ):string {
private function getGravatarUrl(): string
{
$url = 'https://www.gravatar.com/avatar/';
$url .= md5( strtolower( trim( $this->email ) ) );
$url .= md5(strtolower(trim($this->email)));
return $url;
}
/**
* @param string $password
* @return bool
* @throws \Exception
*/
public function checkPassword(string $password):bool
public function checkPassword(string $password): bool
{
return AuthHelper::check($password, $this->password, $this->password_enc, $this->password_salt);
}
public function canLogin():bool
public function canLogin(): bool
{
return $this->isEmailVerified() && $this->isActive();
}
@ -1118,7 +1133,7 @@ class User extends BaseEntity
public function setPassword(string $password): void
{
$this->password_salt = AuthHelper::generateSalt(self::SaltLen, $this->password_enc);
$this->password = AuthHelper::encrypt_password($password, $this->password_salt, $this->password_enc);
$this->password = AuthHelper::encrypt_password($password, $this->password_salt, $this->password_enc);
}
/**
@ -1236,8 +1251,9 @@ class User extends BaseEntity
/**
* @param UserAction $action
*/
public function addUserAction(UserAction $action){
if($this->actions->contains($action)) return;
public function addUserAction(UserAction $action)
{
if ($this->actions->contains($action)) return;
$this->actions->add($action);
$action->setOwner($this);
}
@ -1268,7 +1284,7 @@ class User extends BaseEntity
$criteria = new Criteria();
$criteria->where(Criteria::expr()->eq("client", $client));
$consents = $this->consents->matching($criteria);
if($consents->count() == 0 ) return null;
if ($consents->count() == 0) return null;
$scope_set = explode(' ', $scopes);
sort($scope_set);
@ -1289,12 +1305,12 @@ SQL;
$query->setParameter("scopes", join(' ', $scope_set));
$consent = $query->getOneOrNullResult();
if(!is_null($consent)) return $consent;
if (!is_null($consent)) return $consent;
foreach($consents as $consent){
foreach ($consents as $consent) {
$former_scope_set = explode(' ', $consent->getScope());
// check if the requested scopes are included on the former consent present
if(count(array_diff($scope_set, $former_scope_set)) == 0){
if (count(array_diff($scope_set, $former_scope_set)) == 0) {
return $consent;
}
}
@ -1304,21 +1320,24 @@ SQL;
/**
* @param UserConsent $consent
*/
public function addConsent(UserConsent $consent){
if($this->consents->contains($consent)) return;
public function addConsent(UserConsent $consent)
{
if ($this->consents->contains($consent)) return;
$this->consents->add($consent);
$consent->setOwner($this);
}
public function updateLastLoginDate():void{
public function updateLastLoginDate(): void
{
$this->last_login_date = new \DateTime('now', new \DateTimeZone('UTC'));
}
/**
* @return int
*/
public function updateLoginFailedAttempt():int {
$this->login_failed_attempt = $this->login_failed_attempt +1 ;
public function updateLoginFailedAttempt(): int
{
$this->login_failed_attempt = $this->login_failed_attempt + 1;
return $this->login_failed_attempt;
}
@ -1343,6 +1362,10 @@ SQL;
*/
public function setEmail(string $email): void
{
if (!empty($this->email) && $email != $this->email) {
//we are setting a new email
$this->clearResetPasswordRequests();
}
$this->email = $email;
}
@ -1365,8 +1388,9 @@ SQL;
/**
* @return $this
*/
public function verifyEmail(){
if(!$this->email_verified) {
public function verifyEmail()
{
if (!$this->email_verified) {
$this->email_verified = true;
$this->active = true;
$this->lock = false;
@ -1382,10 +1406,10 @@ SQL;
/**
* @return String
*/
public function generateEmailVerificationToken():string
public function generateEmailVerificationToken(): string
{
$generator = new RandomGenerator();
$token = strval($this->id).$generator->randomToken();
$generator = new RandomGenerator();
$token = strval($this->id) . $generator->randomToken();
$this->email_verified_token_hash = self::createConfirmationTokenHash($token);
return $token;
}
@ -1394,7 +1418,7 @@ SQL;
* @param string $token
* @return string
*/
public static function createConfirmationTokenHash(string $token):string
public static function createConfirmationTokenHash(string $token): string
{
return md5($token);
}
@ -1403,7 +1427,7 @@ SQL;
* @param string $token
* @return bool
*/
public function checkConfirmationTokenHash(string $token):bool
public function checkConfirmationTokenHash(string $token): bool
{
return md5($token) == $this->email_verified_token_hash;
}
@ -1419,14 +1443,16 @@ SQL;
/**
* @param string $identifier
*/
public function setIdentifier(string $identifier){
public function setIdentifier(string $identifier)
{
$this->identifier = $identifier;
}
/**
* @ORM\PostPersist
*/
public function inserted($args){
public function inserted($args)
{
Event::fire(new UserCreated($this->getId(), $args));
}
@ -1434,14 +1460,15 @@ SQL;
* @param $name
* @return mixed
*/
public function __get($name) {
if($name == "fullname")
public function __get($name)
{
if ($name == "fullname")
return $this->getFullName();
if($name == "pic")
if ($name == "pic")
return $this->getPic();
$res = $this->{$name};
$res = $this->{$name};
return $res;
}
@ -1464,8 +1491,9 @@ SQL;
/**
* @param UserPasswordResetRequest $request
*/
public function addPasswordResetRequest(UserPasswordResetRequest $request){
if($this->reset_password_requests->contains($request)) return;
public function addPasswordResetRequest(UserPasswordResetRequest $request)
{
if ($this->reset_password_requests->contains($request)) return;
$this->reset_password_requests->add($request);
}
@ -1488,14 +1516,16 @@ SQL;
/**
* @return bool
*/
public function hasCreator():bool{
public function hasCreator(): bool
{
return $this->getCreatedById() > 0;
}
/**
* @return int
*/
public function getCreatedById():int{
public function getCreatedById(): int
{
try {
return !is_null($this->created_by) ? $this->created_by->getId() : 0;
} catch (\Exception $ex) {
@ -1519,4 +1549,9 @@ SQL;
$this->twitter_name = $twitter_name;
}
public function clearResetPasswordRequests(): void
{
$this->reset_password_requests->clear();
}
}

View File

@ -26,6 +26,15 @@
return true;
});
$(document).ready(function($){
var redirect = $('#redirect_url');
if(redirect.length > 0){
var href = $(redirect).attr('href');
setTimeout(function(){ window.location = href; }, 3000);
}
});
});
// End of closure.

View File

@ -20,6 +20,9 @@
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
{{ session('status') }}
</div>
@if($redirect_uri)
<p>Now you will be redirected to <a id="redirect_url" name="redirect_url" href="{{$redirect_uri}}">{{$redirect_uri}}</a></p>
@endif
@endif
@if ($errors->any())
<div class="alert alert-danger alert-dismissible" role="alert">
@ -48,6 +51,12 @@
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{{ __('Send Password Reset Link') }}</button>
</div>
@if($redirect_uri)
<input type="hidden" id="redirect_uri" name="redirect_uri" value="{{$redirect_uri}}"/>
@endif
@if($client_id)
<input type="hidden" id="client_id" name="client_id" value="{{$client_id}}"/>
@endif
</form>
</div>
</div>