예제 #1
0
 /**
  * Attempts to automatically login using the auto login cookie
  * 
  * @see SimpleID\API\AuthHooks::autoAuthHook()
  * @return SimpleID\Models\User the user object, or NULL
  */
 public function autoAuthHook()
 {
     if (!$this->f3->exists('COOKIE.' . $this->cookie_name)) {
         return null;
     }
     $cookie = $this->f3->get('COOKIE.' . $this->cookie_name);
     $token = new SecurityToken();
     $data = $token->getPayload($cookie);
     if ($data === null) {
         $this->logger->log(LogLevel::NOTICE, 'Automatic login: Invalid token - clearing');
         $this->logoutHook();
         return null;
     }
     if ($data['typ'] != 'rememberme') {
         return NULL;
     }
     $this->logger->log(LogLevel::DEBUG, 'Automatic login token detected', $data);
     if ($data['exp'] < time()) {
         // Cookie expired
         $this->logger->log(LogLevel::NOTICE, 'Automatic login: Expired - clearing');
         $this->logoutHook();
         return NULL;
     }
     if ($data['uaid'] != $this->auth->assignUAID()) {
         $this->logger->log(LogLevel::WARNING, 'Automatic login: User agent ID does not match - clearing');
         $this->logoutHook();
         return NULL;
     }
     $store = StoreManager::instance();
     // Load the user, tag it as an auto log in
     $test_user = $store->loadUser($data['uid']);
     if ($test_user != NULL) {
         $this->logger->log(LogLevel::INFO, 'Automatic login token accepted for ' . $data['uid']);
         return $test_user;
     } else {
         $this->logger->log(LogLevel::WARNING, 'Automatic login token accepted for ' . $data['uid'] . ', but no such user exists');
         return NULL;
     }
 }
예제 #2
0
 /**
  * Applies the upgrade.
  */
 function complete()
 {
     global $upgrade_access_check;
     $cache = \Cache::instance();
     $token = new SecurityToken();
     if (!$this->f3->exists('GET.tk')) {
         $this->f3->status(401);
         $this->fatalError($this->t('SimpleID detected a potential security attack.  Please try again.'));
         return;
     }
     $payload = $token->getPayload($this->f3->get('POST.step'));
     if ($payload == null) {
         $this->f3->status(401);
         $this->fatalError($this->t('SimpleID detected a potential security attack.  Please try again.'));
         return;
     }
     $upgid = $payload['upgid'];
     $upgrade = $cache->get($upgid . '.upgrade');
     $cache->reset('.upgrade');
     if ($upgrade === false) {
         $this->f3->status(500);
         $this->fatalError($this->t('Upgrade not found'));
     }
     if (!$upgrade_access_check) {
         $this->f3->set('edit_upgrade_php', $this->t('Remember to edit upgrade.php to check <code>$upgrade_access_check</code> back to <code>TRUE</code>.'));
     }
     $this->f3->set('results', $upgrade['results']);
     $this->f3->set('upgrade_complete', $this->t('Your SimpleID installation has been upgraded.  Please check the results below for any errors.'));
     $this->f3->set('title', $this->t('Upgrade'));
     $this->f3->set('page_class', 'dialog-page');
     $this->f3->set('layout', 'upgrade_results.html');
     print $tpl->render('page.html');
 }
예제 #3
0
 /**
  * Processes a user response from the {@link consentForm()} function.
  *
  * @since 2.0
  */
 function consent()
 {
     $auth = AuthManager::instance();
     $token = new SecurityToken();
     $store = StoreManager::instance();
     if (!$auth->isLoggedIn()) {
         $auth_module = $this->mgr->getModule('SimpleID\\Auth\\AuthModule');
         $auth_module->loginForm();
         return;
     }
     $user = $auth->getUser();
     $form_state = $token->getPayload($this->f3->get('POST.fs'));
     $request = $form_state['rq'];
     $response = $form_state['rs'];
     if (!$token->verify($this->f3->get('POST.tk'), 'oauth_consent')) {
         $this->logger->log(LogLevel::WARNING, 'Security token ' . $this->f3->get('POST.tk') . ' invalid.');
         $this->f3->set('message', $this->t('SimpleID detected a potential security attack.  Please try again.'));
         $this->consentForm($request, $response);
         return;
     }
     if ($this->f3->get('POST.op') == $this->t('Deny')) {
         $response->setError('access_denied')->renderRedirect();
         return;
     } else {
         $this->mgr->invokeRefAll('oAuthConsentFormSubmit', $form_state);
         $client = $store->loadClient($request['client_id'], 'SimpleID\\Protocols\\OAuth\\OAuthClient');
         $cid = $client->getStoreID();
         $now = time();
         $consents = array('oauth' => $this->f3->get('POST.prefs.consents.oauth'));
         if (isset($user->clients[$cid])) {
             $prefs = $user->clients[$cid];
         } else {
             $prefs = array('oauth' => array(), 'store_id' => $client->getStoreID(), 'display_name' => $client->getDisplayName(), 'display_html' => $client->getDisplayHTML(), 'first_time' => $now, 'consents' => array());
         }
         $prefs['last_time'] = $now;
         $prefs['consents'] = array_merge($prefs['consents'], $consents);
         if ($this->f3->exists('POST.prefs.oauth.prompt_none') && $this->f3->exists('POST.prefs.oauth.prompt_none') == 'true') {
             $prefs['oauth']['prompt_none'] = true;
         }
         $user->clients[$cid] = $prefs;
         $store->saveUser($user);
     }
     $this->processAuthRequest($request, $response);
 }
예제 #4
0
 /**
  * Continues a previously saved request.
  *
  * The request is saved as a <code>SecurityToken</code> which is passed through
  * the <code>token</code> path parameter.  The underlying payload
  * can contain the following keys
  *
  * - mt the HTTP method (e.g. GET, POST)
  * - rt the FatFree routing path
  * - rq an array containing the request parameters
  */
 public function continueRequest($f3, $params)
 {
     $token = new SecurityToken();
     $payload = $token->getPayload($params['token']);
     if ($payload === null) {
         $this->f3->fatalError($this->t('Invalid request.'));
         return;
     }
     if (!isset($payload['mt'])) {
         $payload['mt'] = 'GET';
     }
     if (!isset($payload['rt'])) {
         $payload['rt'] = '/';
     }
     if (!isset($payload['rq'])) {
         $payload['rq'] = array();
     }
     $this->f3->mock($payload['mt'] . ' ' . $payload['rt'], $payload['rq']);
 }
예제 #5
0
 /**
  * Displays the page used to set up login verification using one-time
  * passwords.
  */
 public function setup()
 {
     $auth = AuthManager::instance();
     $store = StoreManager::instance();
     $user = $auth->getUser();
     $tpl = new \Template();
     $token = new SecurityToken();
     // Require HTTPS, redirect if necessary
     $this->checkHttps('redirect', true);
     if (!$auth->isLoggedIn()) {
         $this->f3->reroute('/my/dashboard');
         return;
     }
     if ($this->f3->get('POST.op') == $this->t('Disable')) {
         if ($this->f3->exists('POST.tk') === false || !$token->verify($this->f3->get('POST.tk'), 'otp')) {
             $this->f3->set('message', $this->t('SimpleID detected a potential security attack.  Please try again.'));
             $this->f3->mock('GET /my/dashboard');
             return;
         }
         if (isset($user['otp'])) {
             unset($user['otp']);
             $store->saveUser($user);
         }
         $this->f3->set('message', $this->t('Login verification has been disabled.'));
         $this->f3->mock('GET /my/dashboard');
         return;
     } elseif ($this->f3->get('POST.op') == $this->t('Verify')) {
         $params = $token->getPayload($this->f3->get('POST.otp_params'));
         $this->f3->set('otp_params', $this->f3->get('POST.otp_params'));
         if ($this->f3->exists('POST.tk') === false || !$token->verify($this->f3->get('POST.tk'), 'otp')) {
             $this->f3->set('message', $this->t('SimpleID detected a potential security attack.  Please try again.'));
             page_dashboard();
             return;
         } elseif ($this->f3->exists('POST.otp') === false || $this->f3->get('POST.otp') == '') {
             $this->f3->set('message', $this->t('You need to enter the verification code to complete enabling login verification.'));
         } elseif ($this->verifyOTP($params, $this->f3->get('POST.otp'), 10) === false) {
             $this->f3->set('message', $this->t('The verification code is not correct.'));
         } else {
             $user['otp'] = $params;
             $store->saveUser($user);
             $this->f3->set('message', $this->t('Login verification has been enabled.'));
             $this->f3->mock('GET /my/dashboard');
             return;
         }
     } else {
         $rand = new Random();
         $params = array('type' => 'totp', 'secret' => $rand->bytes(10), 'algorithm' => 'sha1', 'digits' => 6, 'period' => 30, 'drift' => 0, 'remember' => array());
         $this->f3->set('otp_params', $token->generate($params, SecurityToken::OPTION_BIND_SESSION));
     }
     $secret = new BigNum($params['secret'], 256);
     $code = strtr($secret->val(32), '0123456789abcdefghijklmnopqrstuv', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567');
     $code = str_repeat('A', 16 - strlen($code)) . $code;
     for ($i = 0; $i < strlen($code); $i += 4) {
         $this->f3->set('secret' . ($i + 1), substr($code, $i, 4));
     }
     $url = 'otpauth://totp/SimpleID?secret=' . $code . '&digits=' . $params['digits'] . '&period=' . $params['period'];
     $this->f3->set('qr', addslashes($url));
     $this->f3->set('about_otp', $this->t('Login verification adds an extra layer of protection to your account. When enabled, you will need to enter an additional security code whenever you log into SimpleID.'));
     $this->f3->set('otp_warning', $this->t('<strong>WARNING:</strong> If you enable login verification and lose your authenticator app, you will need to <a href="!url">edit your identity file manually</a> before you can log in again.', array('!url' => 'http://simpleid.koinic.net/docs/2/common_problems/#otp')));
     $this->f3->set('setup_otp', $this->t('To set up login verification, following these steps.'));
     $this->f3->set('download_app', $this->t('Download an authenticator app that supports TOTP for your smartphone, such as Google Authenticator.'));
     $this->f3->set('add_account', $this->t('Add your SimpleID account to authenticator app using this key.  If you are viewing this page on your smartphone you can use <a href="!url">this link</a> or scan the QR code to add your account.', array('!url' => $url)));
     $this->f3->set('verify_code', $this->t('To check that your account has been added properly, enter the verification code from your phone into the box below, and click Verify.'));
     $this->f3->set('tk', $token->generate('otp', SecurityToken::OPTION_BIND_SESSION));
     $this->f3->set('otp_label', $this->t('Verification code:'));
     $this->f3->set('submit_button', $this->t('Verify'));
     $this->f3->set('page_class', 'dialog-page');
     $this->f3->set('title', $this->t('Login Verification'));
     $this->f3->set('framekiller', true);
     $this->f3->set('layout', 'auth_otp_setup.html');
     print $tpl->render('page.html');
 }
예제 #6
0
 /**
  * Processes a user response from the {@link simpleid_openid_consent_form()} function.
  *
  * If the user verifies the relying party, an OpenID response will be sent to
  * the relying party.  Otherwise, the dashboard will be displayed to the user.
  */
 public function consent()
 {
     $auth = AuthManager::instance();
     $token = new SecurityToken();
     $store = StoreManager::instance();
     if (!$auth->isLoggedIn()) {
         $auth_module = $this->mgr->getModule('SimpleID\\Auth\\AuthModule');
         $auth_module->loginForm();
         return;
     }
     $user = $auth->getUser();
     $form_state = $token->getPayload($this->f3->get('POST.fs'));
     $request = $form_state['rq'];
     $response = $form_state['rs'];
     $reason = $form_state['code'];
     if (!$token->verify($this->f3->get('POST.tk'), 'openid_consent')) {
         $this->logger->log(LogLevel::WARNING, 'Security token ' . $this->f3->get('POST.tk') . ' invalid.');
         $this->f3->set('message', $this->t('SimpleID detected a potential security attack.  Please try again.'));
         $this->consentForm($request, $response, $reason);
         return;
     }
     $return_to = $response['return_to'];
     if ($return_to == null) {
         $return_to = $request['openid.return_to'];
     }
     if ($this->f3->get('POST.op') == $this->t('Cancel')) {
         $response = $this->createErrorResponse($request, false);
         if (!$return_to) {
             $this->f3->set('message', $this->t('Log in cancelled.'));
         }
     } else {
         $this->mgr->invokeRefAll('openIDConsentFormSubmit', $form_state);
         $consents = array('openid' => $this->f3->exists('POST.prefs.consents.openid') && $this->f3->exists('POST.prefs.consents.openid') == 'true');
         $this->logActivity($request, $consents);
         $this->signResponse($response, isset($response['assoc_handle']) ? $response['assoc_handle'] : NULL);
         if (!$return_to) {
             $this->f3->set('message', $this->t('You were logged in successfully.'));
         }
     }
     if ($return_to) {
         $response->render($return_to);
     } else {
         $this->f3->reroute('/');
     }
 }
예제 #7
0
 /**
  * Attempts to log in a user, using the credentials specified in the
  * HTTP request.
  *
  * @param \Base $f3
  * @param array $params
  */
 public function login($f3, $params)
 {
     $params['destination'] = isset($params[1]) ? $params[1] : '';
     $this->f3->set('PARAMS.destination', $params['destination']);
     $token = new SecurityToken();
     $token->gc();
     // Require HTTPS or return an error
     $this->checkHttps('error', true);
     if ($this->f3->exists('POST.fs') === false) {
         $form_state = array('mode' => AuthManager::MODE_CREDENTIALS);
         if (in_array($this->f3->get('GET.mode'), array(AuthManager::MODE_VERIFY, AuthManager::MODE_REENTER_CREDENTIALS))) {
             $form_state['mode'] = $this->f3->get('GET.mode');
         }
         $this->loginForm($params, $form_state);
         return;
     }
     $form_state = $token->getPayload($this->f3->get('POST.fs'));
     if ($form_state === false) {
         $form_state = array('mode' => AuthManager::MODE_CREDENTIALS);
     }
     $mode = $form_state['mode'];
     if (!in_array($mode, array(AuthManager::MODE_CREDENTIALS, AuthManager::MODE_REENTER_CREDENTIALS, AuthManager::MODE_VERIFY))) {
         $this->f3->set('message', $this->t('SimpleID detected a potential security attack on your log in.  Please log in again.'));
         $this->loginForm($params, $form_state);
         return;
     }
     if ($this->f3->exists('POST.tk') === false) {
         if (isset($params['destination'])) {
             // User came from a log in form.
             $this->f3->set('message', $this->t('You seem to be attempting to log in from another web page.  You must use this page to log in.'));
         }
         $this->loginForm($params, $form_state);
         return;
     }
     if (!$token->verify($this->f3->get('POST.tk'), 'login')) {
         $this->logger->log(LogLevel::WARNING, 'Login attempt: Security token ' . $this->f3->get('POST.tk') . ' invalid.');
         $this->f3->set('message', $this->t('SimpleID detected a potential security attack on your log in.  Please log in again.'));
         $this->loginForm($params, $form_state);
         return;
     }
     if ($this->f3->exists('POST.op') && $this->f3->get('POST.op') == $this->t('Cancel')) {
         $results = $this->mgr->invokeAll('loginFormCancelled', $form_state);
         if (!array_reduce($results, function ($overall, $result) {
             return $result ? true : $overall;
         }, false)) {
             $this->fatalError($this->t('Login cancelled without a proper request.'));
         }
         return;
     }
     // If the user is already logged in, return
     if ($mode == AuthManager::MODE_CREDENTIALS && $this->auth->isLoggedIn()) {
         $this->f3->reroute('/');
     }
     $results = $this->mgr->invokeRefAll('loginFormValidate', $form_state);
     if (!array_reduce($results, function ($overall, $result) {
         return $result !== null && $result === false ? false : $overall;
     }, true)) {
         $this->loginForm($params, $form_state);
         return;
     }
     $modules = $this->mgr->getModules();
     foreach ($modules as $module) {
         $results = $this->mgr->invokeRef($module, 'loginFormSubmit', $form_state);
         if ($results === false) {
             $this->loginForm($params, $form_state);
             return;
         }
         if (is_array($results)) {
             if (isset($results['uid'])) {
                 $form_state['uid'] = $results['uid'];
             }
             if (isset($results['auth_level'])) {
                 $form_state['auth_level'] = isset($form_state['auth_level']) ? max($form_state['auth_level'], $results['auth_level']) : $results['auth_level'];
             }
             if (!isset($form_state['modules'])) {
                 $form_state['modules'] = array();
             }
             $form_state['modules'][] = $module;
         }
     }
     if (!isset($form_state['uid'])) {
         // No user
         $this->loginForm($params, $form_state);
         return;
     }
     if ($mode == AuthManager::MODE_CREDENTIALS) {
         $form_state['mode'] = AuthManager::MODE_VERIFY;
         $forms = $this->mgr->invokeRefAll('loginForm', $form_state);
         if (count($forms) > 0) {
             $this->loginForm($params, $form_state);
             return;
         }
     }
     $this->auth->login($form_state['uid'], $form_state['auth_level'], $form_state['modules'], $form_state);
     $this->f3->reroute('/' . $params['destination']);
 }