checkCode($user['tfa_secret'], $token)) { $_SESSION[SESS_USER_2FA] = time(); // About using the user agent: It's easy to fake it, but it increases the barrier for stealing and reusing cookies nevertheless // and it doesn't do any harm (except that it's invalid after a browser upgrade, but that may be even intented) $cookie = $_SESSION[SESS_USER_2FA] .':'.hash_hmac('sha1', $user['username'].':'. $tfaMins . ':' . $_SESSION[SESS_USER_2FA] .':'.$_SERVER['HTTP_USER_AGENT'], $user['tfa_secret']); cacti_cookie_set(session_name() . '_otp', $cookie, time() + (30 * 24 * 3600)); } else { $_SESSION[SESS_USER_2FA] = false; } } } else { $_SESSION[SESS_USER_2FA] = time(); } /* Process the user */ if ($_SESSION[SESS_USER_2FA]) { if (isset($user['tfa_enabled'])) { cacti_log("LOGIN: User '" . $user['username'] . "' 2FA Authenticated", false, 'AUTH'); $client_addr = get_client_addr(''); db_execute_prepared('INSERT IGNORE INTO user_log (username, user_id, result, ip, time) VALUES (?, ?, 2, ?, NOW())', array($user['username'], $user['id'], $client_addr)); } } else { /* BAD token */ cacti_log("DEBUG: User '" . $user['username'] . "' failed to verify 2fa token", false, 'AUTH', POLLER_VERBOSITY_DEBUG); db_execute_prepared('INSERT IGNORE INTO user_log (username, user_id, result, ip, time) VALUES (?, 0, 3, ?, NOW())', array($user['username'], get_client_addr(''))); $message = __('Failed to verify token'); } } if (empty($user['tfa_enabled'])) { $_SESSION[SESS_USER_2FA] = true; } if (!empty($_SESSION[SESS_USER_2FA])) { auth_login_redirect($user['login_opts']); exit; } if (api_plugin_hook_function('custom_2fa_login', OPER_MODE_NATIVE) == OPER_MODE_RESKIN) { return; } $selectedTheme = get_selected_theme(); html_auth_header('login_2fa', __('2nd Factor Authentication'), __('2FA Verification'), __('Enter your token'), array( 'username' => $user['username'], 'action' => get_nfilter_request_var('action') ) ); ?>