Skip to content

Commit

Permalink
fix session collision issue #61
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewPoppe committed Mar 30, 2022
1 parent 840fe88 commit e7116dc
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 38 deletions.
3 changes: 3 additions & 0 deletions REDCapPRO.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ function redcap_every_page_top($project_id)
if (strpos($_SERVER["PHP_SELF"], "surveys") !== false) {
return;
}
$this::$AUTH->destroySession();
$role = SUPER_USER ? 3 : $this->getUserRole(USERID); // 3=admin/manager, 2=user, 1=monitor, 0=not found
if ($role > 0) {
?>
Expand Down Expand Up @@ -211,9 +212,11 @@ function redcap_survey_page_top(
window.rcpro.module = " . $this->getJavascriptModuleObjectName() . ";
window.rcpro.logo = '" . $this->getUrl("images/RCPro_Favicon.svg") . "';
window.rcpro.logoutPage = '" . $this->getUrl("src/logout.php", true) . "';
window.rcpro.sessionCheckPage = '" . $this->getUrl("src/session_check.php", true) . "';
window.rcpro.timeout_minutes = " . self::$SETTINGS->getTimeoutMinutes() . ";
window.rcpro.warning_minutes = " . self::$SETTINGS->getTimeoutWarningMinutes() . ";
window.rcpro.initTimeout();
window.rcpro.initSessionCheck();
</script>";

// Participant is not logged into their account
Expand Down
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
"src/reset-password",
"src/create-password",
"src/forgot-password",
"src/forgot-username"
"src/forgot-username",
"src/session_check"
],
"framework-version": 5,
"compatibility": {
Expand Down
57 changes: 51 additions & 6 deletions src/classes/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Auth
{

public static $APPTITLE;
public static $SESSION_NAME;
public static $SESSION_NAME = "REDCapPRO_SESSID";

/**
* constructor
Expand All @@ -22,7 +22,6 @@ class Auth
function __construct($title = null)
{
self::$APPTITLE = $title;
self::$SESSION_NAME = "${title}_sessid";
}

/**
Expand All @@ -32,24 +31,50 @@ function __construct($title = null)
*/
public function init()
{
$session_id = $_COOKIE["survey"];
if (isset($_COOKIE["PHPSESSID"])) {
\Session::destroy($_COOKIE["PHPSESSID"]);
// To ensure any REDCap user is logged out
$redcap_session_id = $_COOKIE["PHPSESSID"];
if (isset($redcap_session_id)) {
\Session::destroy($redcap_session_id);
\Session::deletecookie("PHPSESSID");
session_destroy($redcap_session_id);
}

// If we already have a session, use it.
// Otherwise, create a new session.
$session_id = $_COOKIE[self::$SESSION_NAME];
if (!empty($session_id)) {
if ($session_id !== session_id()) {
\Session::destroy(session_id());
session_destroy();
}
session_id($session_id);
} else {
\Session::destroy(session_id());
session_destroy();
$this->createSession();
}

session_name(self::$SESSION_NAME);
session_start();

$this->set_survey_username($_SESSION["username"]);
}

public function createSession()
{
\Session::init("survey");
\Session::init(self::$SESSION_NAME);
$this->set_csrf_token();
}

public function destroySession()
{
$session_id = $_COOKIE[self::$SESSION_NAME];
if (isset($session_id)) {
\Session::destroy($session_id);
}
\Session::deletecookie(self::$SESSION_NAME);
}

public function set_csrf_token()
{
$_SESSION[self::$APPTITLE . "_token"] = bin2hex(random_bytes(24));
Expand Down Expand Up @@ -124,6 +149,9 @@ public function set_survey_active_state($state)

public function set_login_values($participant)
{

$this->set_survey_username($participant["rcpro_username"]);

$_SESSION["username"] = $participant["rcpro_username"];
$_SESSION[self::$APPTITLE . "_participant_id"] = $participant["log_id"];
$_SESSION[self::$APPTITLE . "_username"] = $participant["rcpro_username"];
Expand All @@ -132,4 +160,21 @@ public function set_login_values($participant)
$_SESSION[self::$APPTITLE . "_lname"] = $participant["lname"];
$_SESSION[self::$APPTITLE . "_loggedin"] = true;
}

public function set_survey_username($username)
{
$orig_id = session_id();
$survey_session_id = $_COOKIE["survey"];
if (isset($survey_session_id)) {
session_write_close();
session_name('survey');
session_id($survey_session_id);
session_start();
$_SESSION['username'] = $username;
session_write_close();
session_name(self::$SESSION_NAME);
session_id($orig_id);
session_start();
}
}
}
2 changes: 1 addition & 1 deletion src/forgot-password.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Validate token
if (!$module::$AUTH->validate_csrf_token($_POST['token'])) {
$module->logEvent("Invalid CSRF Token");
$module->logEvent("Invalid CSRF Token", []);
echo $module->tt("error_generic1");
echo "<br>";
echo $module->tt("error_generic2");
Expand Down
2 changes: 1 addition & 1 deletion src/forgot-username.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Validate token
if (!$module::$AUTH->validate_csrf_token($_POST['token'])) {
$module->logEvent("Invalid CSRF Token");
$module->logEvent("Invalid CSRF Token", []);
echo $module->tt("error_generic1");
echo "<br>";
echo $module->tt("error_generic2");
Expand Down
2 changes: 1 addition & 1 deletion src/login.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

// Validate token
if (!$module::$AUTH->validate_csrf_token($_POST['token'])) {
$module->logEvent("Invalid CSRF Token");
$module->logEvent("Invalid CSRF Token", []);
echo $module->tt("error_generic1");
echo "<br>";
echo $module->tt("error_generic2");
Expand Down
38 changes: 21 additions & 17 deletions src/logout.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?php
// Initialize the session
session_start();
$module::$AUTH->init();

// Destroy the session.
$module::$AUTH->destroySession();

// Unset all of the session variables
$_SESSION = array();
session_unset();

// Destroy the session.
session_destroy();
// Whether to cancel showing the popup
$cancelPopup = $_GET['cancelPopup'];

// This method starts the html doc
$module::$UI->ShowParticipantHeader($module->tt("logout_title"));
Expand All @@ -23,16 +26,17 @@
<div style="text-align: center;">
<p><?= $module->tt("ui_close_tab") ?></p>
</div>
<script src="<?= $module->getUrl("lib/sweetalert/sweetalert2.all.min.js"); ?>"></script>
<script>
Swal.fire({
imageUrl: "<?= $module->getUrl("images/RCPro_Favicon.svg") ?>",
imageWidth: '150px',
html: '<strong><?= $module->tt("logout_message1") ?></strong>',
allowOutsideClick: false,
confirmButtonText: "OK",
confirmButtonColor: "#900000"
});
</script>

<?php $module::$UI->EndParticipantPage(); ?>
<?php if (!$cancelPopup) { ?>
<script src="<?= $module->getUrl("lib/sweetalert/sweetalert2.all.min.js"); ?>"></script>
<script>
Swal.fire({
imageUrl: "<?= $module->getUrl("images/RCPro_Favicon.svg") ?>",
imageWidth: '150px',
html: '<strong><?= $module->tt("logout_message1") ?></strong>',
allowOutsideClick: false,
confirmButtonText: "OK",
confirmButtonColor: "#900000"
});
</script>
<?php }
$module::$UI->EndParticipantPage(); ?>
34 changes: 23 additions & 11 deletions src/rcpro_base.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
let rcpro = {
logo:"",
logoutPage:"",
logo: "",
logoutPage: "",
sessionCheckPage: "",
module: null,
timeout_minutes: 0,
warning_minutes: 0,
warningOpen: false,
seconds: 0,
stop: false
}
rcpro.warning_duration = rcpro.timeout_minutes - rcpro.warning_minutes;
rcpro.warning_duration = rcpro.timeout_minutes - rcpro.warning_minutes;
rcpro.initTimeout = function() {
let lastTS = Date.now();
let timeout;
Expand All @@ -18,11 +19,11 @@ rcpro.initTimeout = function() {
return
}
let newTS = Date.now();
rcpro.seconds = Math.floor((newTS - lastTS)/1000);
if (rcpro.seconds >= (rcpro.timeout_minutes*60)) {
rcpro.seconds = Math.floor((newTS - lastTS) / 1000);
if (rcpro.seconds >= (rcpro.timeout_minutes * 60)) {
rcpro.logout();
}
if (rcpro.seconds >= (rcpro.warning_minutes*60) && !rcpro.warningOpen) {
if (rcpro.seconds >= (rcpro.warning_minutes * 60) && !rcpro.warningOpen) {
rcpro.warningOpen = true;
rcpro.logoutWarning();
}
Expand All @@ -42,7 +43,17 @@ rcpro.initTimeout = function() {
});
startTimer();
};


rcpro.initSessionCheck = function() {
setInterval(async function() {
let result = await fetch(rcpro.sessionCheckPage)
.then(resp => resp.json());
if (result.redcap_session_active || !result.redcappro_logged_in) {
rcpro.logout(true);
}
}, 1000);
}

rcpro.logoutWarning = function() {
let timerInterval;
return Swal.fire({
Expand All @@ -56,8 +67,8 @@ rcpro.logoutWarning = function() {
timerInterval = setInterval(() => {
const content = Swal.getHtmlContainer()
if (content) {
let remaining = (rcpro.timeout_minutes*60) - rcpro.seconds;
let rDate = new Date(remaining*1000);
let remaining = (rcpro.timeout_minutes * 60) - rcpro.seconds;
let rDate = new Date(remaining * 1000);
let formatted = `${rDate.getMinutes()}:${String(rDate.getSeconds()).padStart(2,0)}`;
content.innerHTML = `<strong>${rcpro.module.tt("timeout_message1", formatted)}</strong><br>${rcpro.module.tt("timeout_message2")}`;
}
Expand All @@ -69,10 +80,11 @@ rcpro.logoutWarning = function() {
}
});
};
rcpro.logout = function () {
rcpro.logout = function(cancelPopup) {
rcpro.stop = true;
$('body').html('');
location.href = rcpro.logoutPage;
let logoutPage = cancelPopup ? rcpro.logoutPage + "&cancelPopup=true" : rcpro.logoutPage;
location.href = logoutPage;
}

window.rcpro = rcpro;
17 changes: 17 additions & 0 deletions src/session_check.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
session_id($_COOKIE[$module::$AUTH::$SESSION_NAME]);
session_name($module::$AUTH::$SESSION_NAME);
session_start();

$results = [
"redcap_session_active" => false,
"redcappro_logged_in" => $module::$AUTH->is_logged_in()
];

// Check whether there is a current REDCap session (non-survey)
$phpsessid = $_COOKIE["PHPSESSID"];
if (isset($phpsessid)) {
$results["redcap_session_active"] = \Session::read($phpsessid) != false;
}

echo json_encode($results);

0 comments on commit e7116dc

Please sign in to comment.