This repository has been archived by the owner on Jul 10, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added in almost full support for password reminders.
- Loading branch information
Showing
7 changed files
with
500 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
src/Ollieread/Multiauth/Reminders/DatabaseReminderRepository.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
<?php namespace Ollieread\Multiauth\Reminders; | ||
|
||
use Carbon\Carbon; | ||
use Illuminate\Database\Connection; | ||
use Illuminate\Auth\Reminders\RemindableInterface; | ||
|
||
class DatabaseReminderRepository implements ReminderRepositoryInterface { | ||
|
||
/** | ||
* The database connection instance. | ||
* | ||
* @var \Illuminate\Database\Connection | ||
*/ | ||
protected $connection; | ||
|
||
/** | ||
* The reminder database table. | ||
* | ||
* @var string | ||
*/ | ||
protected $table; | ||
|
||
/** | ||
* The hashing key. | ||
* | ||
* @var string | ||
*/ | ||
protected $hashKey; | ||
|
||
/** | ||
* The number of seconds a reminder should last. | ||
* | ||
* @var int | ||
*/ | ||
protected $expires; | ||
|
||
/** | ||
* Create a new reminder repository instance. | ||
* | ||
* @param \Illuminate\Database\Connection $connection | ||
* @param string $table | ||
* @param string $hashKey | ||
* @param int $expires | ||
* @return void | ||
*/ | ||
public function __construct(Connection $connection, $table, $hashKey, $expires = 60) | ||
{ | ||
$this->table = $table; | ||
$this->hashKey = $hashKey; | ||
$this->expires = $expires * 60; | ||
$this->connection = $connection; | ||
} | ||
|
||
/** | ||
* Create a new reminder record and token. | ||
* | ||
* @param \Illuminate\Auth\Reminders\RemindableInterface $user | ||
* @return string | ||
*/ | ||
public function create(RemindableInterface $user, $type) | ||
{ | ||
$email = $user->getReminderEmail(); | ||
|
||
// We will create a new, random token for the user so that we can e-mail them | ||
// a safe link to the password reset form. Then we will insert a record in | ||
// the database so that we can verify the token within the actual reset. | ||
$token = $this->createNewToken($user); | ||
|
||
$this->getTable()->insert($this->getPayload($email, $token, $type)); | ||
|
||
return $token; | ||
} | ||
|
||
/** | ||
* Build the record payload for the table. | ||
* | ||
* @param string $email | ||
* @param string $token | ||
* @return array | ||
*/ | ||
protected function getPayload($email, $token, $type) | ||
{ | ||
return array('type' => $type, 'email' => $email, 'token' => $token, 'created_at' => new Carbon); | ||
} | ||
|
||
/** | ||
* Determine if a reminder record exists and is valid. | ||
* | ||
* @param \Illuminate\Auth\Reminders\RemindableInterface $user | ||
* @param string $token | ||
* @return bool | ||
*/ | ||
public function exists(RemindableInterface $user, $token, $type) | ||
{ | ||
$email = $user->getReminderEmail(); | ||
|
||
$reminder = $this->getTable()->where('email', $email)->where('token', $token)->where('type', $type)->first(); | ||
|
||
return $reminder && ! $this->reminderExpired($reminder); | ||
} | ||
|
||
/** | ||
* Determine if the reminder has expired. | ||
* | ||
* @param object $reminder | ||
* @return bool | ||
*/ | ||
protected function reminderExpired($reminder) | ||
{ | ||
$createdPlusHour = strtotime($reminder->created_at) + $this->expires; | ||
|
||
return $createdPlusHour < $this->getCurrentTime(); | ||
} | ||
|
||
/** | ||
* Get the current UNIX timestamp. | ||
* | ||
* @return int | ||
*/ | ||
protected function getCurrentTime() | ||
{ | ||
return time(); | ||
} | ||
|
||
/** | ||
* Delete a reminder record by token. | ||
* | ||
* @param string $token | ||
* @return void | ||
*/ | ||
public function delete($token, $type) | ||
{ | ||
$this->getTable()->where('token', $token)->where('type', $type)->delete(); | ||
} | ||
|
||
/** | ||
* Delete expired reminders. | ||
* | ||
* @return void | ||
*/ | ||
public function deleteExpired() | ||
{ | ||
$expired = Carbon::now()->subSeconds($this->expires); | ||
|
||
$this->getTable()->where('created_at', '<', $expired)->delete(); | ||
} | ||
|
||
/** | ||
* Create a new token for the user. | ||
* | ||
* @param \Illuminate\Auth\Reminders\RemindableInterface $user | ||
* @return string | ||
*/ | ||
public function createNewToken(RemindableInterface $user) | ||
{ | ||
$email = $user->getReminderEmail(); | ||
|
||
$value = str_shuffle(sha1($email.spl_object_hash($this).microtime(true))); | ||
|
||
return hash_hmac('sha1', $value, $this->hashKey); | ||
} | ||
|
||
/** | ||
* Begin a new database query against the table. | ||
* | ||
* @return \Illuminate\Database\Query\Builder | ||
*/ | ||
protected function getTable() | ||
{ | ||
return $this->connection->table($this->table); | ||
} | ||
|
||
/** | ||
* Get the database connection instance. | ||
* | ||
* @return \Illuminate\Database\Connection | ||
*/ | ||
public function getConnection() | ||
{ | ||
return $this->connection; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
<?php namespace Ollieread\Multiauth\Reminders; | ||
|
||
use Closure; | ||
use Illuminate\Mail\Mailer; | ||
use Illuminate\Auth\UserProviderInterface; | ||
use Illuminate\Auth\Reminders\RemindableInterface; | ||
use Illuminate\Auth\Reminders\PasswordBroker as OriginalPasswordBroker; | ||
|
||
class PasswordBroker extends OriginalPasswordBroker { | ||
|
||
protected $type; | ||
|
||
public function __construct($type, | ||
ReminderRepositoryInterface $reminders, | ||
UserProviderInterface $users, | ||
Mailer $mailer, | ||
$reminderView) | ||
{ | ||
$this->users = $users; | ||
$this->mailer = $mailer; | ||
$this->reminders = $reminders; | ||
$this->reminderView = $reminderView; | ||
$this->type = $type; | ||
} | ||
|
||
/** | ||
* Send a password reminder to a user. | ||
* | ||
* @param array $credentials | ||
* @param Closure $callback | ||
* @return string | ||
*/ | ||
public function remind(array $credentials, Closure $callback = null) | ||
{ | ||
// First we will check to see if we found a user at the given credentials and | ||
// if we did not we will redirect back to this current URI with a piece of | ||
// "flash" data in the session to indicate to the developers the errors. | ||
$user = $this->getUser($credentials); | ||
|
||
if (is_null($user)) | ||
{ | ||
return self::INVALID_USER; | ||
} | ||
|
||
// Once we have the reminder token, we are ready to send a message out to the | ||
// user with a link to reset their password. We will then redirect back to | ||
// the current URI having nothing set in the session to indicate errors. | ||
$token = $this->reminders->create($user, $this->type); | ||
|
||
$this->sendReminder($user, $token, $callback); | ||
|
||
return self::REMINDER_SENT; | ||
} | ||
|
||
/** | ||
* Send the password reminder e-mail. | ||
* | ||
* @param \Illuminate\Auth\Reminders\RemindableInterface $user | ||
* @param string $token | ||
* @param Closure $callback | ||
* @return void | ||
*/ | ||
public function sendReminder(RemindableInterface $user, $token, Closure $callback = null) | ||
{ | ||
// We will use the reminder view that was given to the broker to display the | ||
// password reminder e-mail. We'll pass a "token" variable into the views | ||
// so that it may be displayed for an user to click for password reset. | ||
$view = $this->reminderView; | ||
$type = $this->type; | ||
|
||
return $this->mailer->send($view, compact('token', 'user', 'type'), function($m) use ($user, $token, $type, $callback) | ||
{ | ||
$m->to($user->getReminderEmail()); | ||
|
||
if ( ! is_null($callback)) call_user_func($callback, $m, $user, $type, $token); | ||
}); | ||
} | ||
|
||
/** | ||
* Reset the password for the given token. | ||
* | ||
* @param array $credentials | ||
* @param Closure $callback | ||
* @return mixed | ||
*/ | ||
public function reset(array $credentials, Closure $callback) | ||
{ | ||
// If the responses from the validate method is not a user instance, we will | ||
// assume that it is a redirect and simply return it from this method and | ||
// the user is properly redirected having an error message on the post. | ||
$user = $this->validateReset($credentials); | ||
|
||
if ( ! $user instanceof RemindableInterface) | ||
{ | ||
return $user; | ||
} | ||
|
||
$pass = $credentials['password']; | ||
|
||
// Once we have called this callback, we will remove this token row from the | ||
// table and return the response from this callback so the user gets sent | ||
// to the destination given by the developers from the callback return. | ||
call_user_func($callback, $user, $pass); | ||
|
||
$this->reminders->delete($credentials['token'], $this->type); | ||
|
||
return self::PASSWORD_RESET; | ||
} | ||
|
||
/** | ||
* Validate a password reset for the given credentials. | ||
* | ||
* @param array $credentials | ||
* @return \Illuminate\Auth\Reminders\RemindableInterface | ||
*/ | ||
protected function validateReset(array $credentials) | ||
{ | ||
if (is_null($user = $this->getUser($credentials))) | ||
{ | ||
return self::INVALID_USER; | ||
} | ||
|
||
if ( ! $this->validNewPasswords($credentials)) | ||
{ | ||
return self::INVALID_PASSWORD; | ||
} | ||
|
||
if ( ! $this->reminders->exists($user, $credentials['token'], $this->type)) | ||
{ | ||
return self::INVALID_TOKEN; | ||
} | ||
|
||
return $user; | ||
} | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
src/Ollieread/Multiauth/Reminders/PasswordBrokerManager.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php namespace Ollieread\Multiauth\Reminders; | ||
|
||
use Illuminate\Mail\Mailer; | ||
|
||
class PasswordBrokerManager { | ||
|
||
protected $brokers = array(); | ||
|
||
public function __construct(ReminderRepositoryInterface $reminders, | ||
Mailer $mailer, | ||
$reminderView, | ||
$providers) | ||
{ | ||
foreach($providers as $type => $provider) { | ||
$this->brokers[$type] = new PasswordBroker($type, $reminders, $provider, $mailer, $reminderView); | ||
} | ||
} | ||
|
||
public function __call($name, $arguments = array()) { | ||
if(array_key_exists($name, $this->brokers)) { | ||
return $this->brokers[$name]; | ||
} | ||
} | ||
|
||
|
||
|
||
} |
Oops, something went wrong.