/** * Enable the Two-factor Authentication. * * @return \Cake\Network\Response|void */ public function enable() { if (!$this->request->is('post')) { return $this->redirect(['action' => 'configure']); } $this->loadModel('UsersTwoFactorAuth'); $userTfa = $this->UsersTwoFactorAuth->find()->where(['UsersTwoFactorAuth.user_id' => $this->Auth->user('id')])->first(); if (is_null($userTfa) || empty($userTfa->secret) || !isset($this->request->data['code'])) { $this->Flash->error(__('Two-factor secret verification failed. Please verify your secret and try again.')); return $this->redirect(['action' => 'configure']); } $tfa = new TwoFactorAuth('Xeta'); if ($tfa->verifyCode($userTfa->secret, $this->request->data['code']) === true && $this->request->data['code'] != $userTfa->current_code) { $this->loadModel('Users'); $user = $this->Users->find()->where(['Users.id' => $this->Auth->user('id')])->select(['id', 'username', 'two_factor_auth_enabled'])->first(); $user->two_factor_auth_enabled = true; $this->Users->save($user); $data = ['session' => $this->request->clientIp() . $this->request->header('User-Agent') . gethostbyaddr($this->request->clientIp()), 'current_code' => $this->request->data['code'], 'recovery_code' => $this->_generateNewRecoveryCode($userTfa->username)]; $this->UsersTwoFactorAuth->patchEntity($userTfa, $data); $this->UsersTwoFactorAuth->save($userTfa); //Logs Event. $this->eventManager()->attach(new Logs()); $event = new Event('Log.User', $this, ['user_id' => $user->id, 'username' => $user->username, 'user_ip' => $this->request->clientIp(), 'user_agent' => $this->request->header('User-Agent'), 'action' => '2FA.enabled']); $this->eventManager()->dispatch($event); $this->Flash->success(__('Two-factor authentication successfully enabled !')); $this->set(compact('user', 'userTfa')); } else { $this->Flash->error(__('Two-factor secret verification failed. Please verify your secret and try again.')); return $this->redirect(['action' => 'configure']); } }
public function testKnownTestVectors_sha512() { //Known test vectors for SHA512: https://tools.ietf.org/html/rfc6238#page-15 $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNA'; //== base32encode('1234567890123456789012345678901234567890123456789012345678901234') $tfa = new TwoFactorAuth('Test', 8, 30, 'sha512'); $this->assertEquals('90693936', $tfa->getCode($secret, 59)); $this->assertEquals('25091201', $tfa->getCode($secret, 1111111109)); $this->assertEquals('99943326', $tfa->getCode($secret, 1111111111)); $this->assertEquals('93441116', $tfa->getCode($secret, 1234567890)); $this->assertEquals('38618901', $tfa->getCode($secret, 2000000000)); $this->assertEquals('47863826', $tfa->getCode($secret, 20000000000)); }
<!doctype html> <html> <head> <title>Demo</title> </head> <body> <ol> <?php require_once 'loader.php'; Loader::register('../lib', 'RobThree\\Auth'); use RobThree\Auth\TwoFactorAuth; $tfa = new TwoFactorAuth('MyApp'); echo '<li>First create a secret and associate it with a user'; $secret = $tfa->createSecret(); echo '<li>Next create a QR code and let the user scan it:<br><img src="' . $tfa->getQRCodeImageAsDataUri('My label', $secret) . '"><br>...or display the secret to the user for manual entry: ' . chunk_split($secret, 4, ' '); $code = $tfa->getCode($secret); echo '<li>Next, have the user verify the code; at this time the code displayed by a 2FA-app would be: <span style="color:#00c">' . $code . '</span> (but that changes periodically)'; echo '<li>When the code checks out, 2FA can be / is enabled; store (encrypted?) secret with user and have the user verify a code each time a new session is started.'; echo '<li>When aforementioned code (' . $code . ') was entered, the result would be: ' . ($tfa->verifyCode($secret, $code) === true ? '<span style="color:#0c0">OK</span>' : '<span style="color:#c00">FAIL</span>'); ?> </ol> <p>Note: Make sure your server-time is <a href="http://en.wikipedia.org/wiki/Network_Time_Protocol">NTP-synced</a>! Depending on the $discrepancy allowed your time cannot drift too much from the users' time!</p> </body> </html>
/* * Made by Samerton * http://worldscapemc.co.uk * * License: MIT */ $page = 'tfa'; // Two factor auth // Ensure user is logged in if (!$user->isLoggedIn()) { Redirect::to('/'); die; } use RobThree\Auth\TwoFactorAuth; $tfa = new TwoFactorAuth('NamelessMC'); if (!isset($_GET['s'])) { // Generate secret $secret = $tfa->createSecret(); if ($user->data()->tfa_secret) { Redirect::to('/user/settings'); die; } $queries->update('users', $user->data()->id, array('tfa_secret' => $secret)); ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1">
$siteemail = $siteemail[0]->value; $to = $user_query[0]->email; $subject = $sitename . ' - ' . $user_language['two_factor_authentication']; $message = $email_language['greeting'] . PHP_EOL . $user_language['tfa_email_contents'] . PHP_EOL . PHP_EOL . $code . PHP_EOL . PHP_EOL . $email_language['thanks'] . PHP_EOL . $sitename; $headers = 'From: ' . $siteemail . "\r\n" . 'Reply-To: ' . $siteemail . "\r\n" . 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, $headers); } } // Ask user to input code now require 'core/includes/tfa_signin.php'; die; } else { // Verify code if ($user_query[0]->tfa_type == 1) { // App $tfa = new TwoFactorAuth('NamelessMC'); if ($tfa->verifyCode($user_query[0]->tfa_secret, $_POST['tfa_code']) !== true) { Session::flash('tfa_signin', '<div class="alert alert-danger">' . $user_language['invalid_tfa'] . '</div>'); require 'core/includes/tfa_signin.php'; die; } } else { // Email // Get the code $code = $user_query[0]->tfa_secret; $code = explode(':', $code); // Check it hasn't expired if ($code[1] < strtotime("-10 minutes")) { // Expired Session::flash('signin', '<div class="alert alert-danger">' . $user_language['invalid_tfa'] . '</div>'); Redirect::to('/signin');
/** * getQRCodeImageAsDataUri * @return string base64 string containing QR code for shared secret */ public function getQRCodeImageAsDataUri($issuer, $secret) { return $this->tfa->getQRCodeImageAsDataUri($issuer, $secret); }
/** * Ask to the user the 2FA code and verify it. * * @return \Cake\Network\Response|void */ public function tfa() { if ($this->Auth->user()) { return $this->redirect($this->Auth->redirectUrl()); } if ($this->request->is('post')) { $this->loadModel('UsersTwoFactorAuth'); $id = $this->Cookie->read('CookieTfa'); if (empty($id) || $id == false) { $this->Cookie->delete('CookieTfa'); return $this->redirect($this->Auth->config('loginAction')); } try { $id = Security::decrypt(base64_decode($id), Configure::read('Security.key')); } catch (\Exception $e) { $this->Flash->error(__('The link used for the Two-factor Authentication is incorrect.')); return $this->redirect($this->Auth->config('loginAction')); } $userTfa = $this->UsersTwoFactorAuth->find()->where(['user_id' => $id])->first(); $tfa = new TwoFactorAuth('Xeta'); $isAuthorized = false; $recoveryCodeUsed = false; if ($tfa->verifyCode($userTfa->secret, $this->request->data['code']) === true && $this->request->data['code'] !== $userTfa->current_code) { $isAuthorized = true; //Check recovery code and verify if the recovery code is not already used. } elseif ($userTfa->recovery_code === $this->request->data['code'] && $userTfa->recovery_code_used == false && $this->request->data['code'] !== $userTfa->current_code) { $isAuthorized = true; $recoveryCodeUsed = true; } if ($isAuthorized === true) { $data = ['session' => $this->request->clientIp() . $this->request->header('User-Agent') . gethostbyaddr($this->request->clientIp()), 'current_code' => $recoveryCodeUsed === true ? 'recovery' : $this->request->data['code'], 'recovery_code_used' => $recoveryCodeUsed === true ? 1 : $userTfa->recovery_code_used]; $this->UsersTwoFactorAuth->patchEntity($userTfa, $data); $this->UsersTwoFactorAuth->save($userTfa); //Login the user. $userLogin = $this->Users->find()->where(['id' => $id])->hydrate(false)->first(); unset($userLogin['password']); $this->_handleLogin($userLogin); $this->Cookie->delete('CookieTfa'); //Logs Event. $this->eventManager()->attach(new Logs()); $event = new Event('Log.User', $this, ['user_id' => $userLogin['id'], 'username' => $userLogin['username'], 'user_ip' => $this->request->clientIp(), 'user_agent' => $this->request->header('User-Agent'), 'action' => '2FA.recovery_code.used']); $this->eventManager()->dispatch($event); return $this->redirect(['controller' => 'pages', 'action' => 'home']); } else { $this->Flash->error(__('Two-factor secret verification failed. Please verify your code and try again.')); } } $id = $this->Cookie->read('CookieTfa'); if (empty($id) || $id == false) { $this->Cookie->delete('CookieTfa'); return $this->redirect($this->Auth->config('loginAction')); } }