Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14475795
D7976.id18046.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D7976.id18046.diff
View Options
Index: resources/sql/autopatches/20140115.auth.2.expires.sql
===================================================================
--- /dev/null
+++ resources/sql/autopatches/20140115.auth.2.expires.sql
@@ -0,0 +1,8 @@
+ALTER TABLE {$NAMESPACE}_user.phabricator_session
+ ADD sessionExpires INT UNSIGNED NOT NULL;
+
+UPDATE {$NAMESPACE}_user.phabricator_session
+ SET sessionExpires = UNIX_TIMESTAMP() + (60 * 60 * 24 * 30);
+
+ALTER TABLE {$NAMESPACE}_user.phabricator_session
+ ADD KEY `key_expires` (sessionExpires);
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1211,6 +1211,7 @@
'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php',
'PhabricatorAuthSession' => 'applications/auth/storage/PhabricatorAuthSession.php',
'PhabricatorAuthSessionEngine' => 'applications/auth/engine/PhabricatorAuthSessionEngine.php',
+ 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php',
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php',
@@ -3791,6 +3792,7 @@
1 => 'PhabricatorPolicyInterface',
),
'PhabricatorAuthSessionEngine' => 'Phobject',
+ 'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthStartController' => 'PhabricatorAuthController',
'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController',
Index: src/applications/auth/engine/PhabricatorAuthSessionEngine.php
===================================================================
--- src/applications/auth/engine/PhabricatorAuthSessionEngine.php
+++ src/applications/auth/engine/PhabricatorAuthSessionEngine.php
@@ -5,11 +5,15 @@
public function loadUserForSession($session_type, $session_key) {
$session_table = new PhabricatorAuthSession();
$user_table = new PhabricatorUser();
- $conn_r = $session_table->establishConnection('w');
+ $conn_r = $session_table->establishConnection('r');
+
+ // NOTE: We're being clever here because this happens on every page load,
+ // and by joining we can save a query.
$info = queryfx_one(
$conn_r,
- 'SELECT u.* FROM %T u JOIN %T s ON u.phid = s.userPHID
+ 'SELECT s.sessionExpires AS _sessionExpires, s.id AS _sessionID, u.*
+ FROM %T u JOIN %T s ON u.phid = s.userPHID
AND s.type LIKE %> AND s.sessionKey = %s',
$user_table->getTableName(),
$session_table->getTableName(),
@@ -20,6 +24,29 @@
return null;
}
+ $expires = $info['_sessionExpires'];
+ $id = $info['_sessionID'];
+ unset($info['_sessionExpires']);
+ unset($info['_sessionID']);
+
+ $ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type);
+
+ // If more than 20% of the time on this session has been used, refresh the
+ // TTL back up to the full duration. The idea here is that sessions are
+ // good forever if used regularly, but get GC'd when they fall out of use.
+
+ if (time() + (0.80 * $ttl) > $expires) {
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $conn_w = $session_table->establishConnection('w');
+ queryfx(
+ $conn_w,
+ 'UPDATE %T SET sessionExpires = UNIX_TIMESTAMP() + %d WHERE id = %d',
+ $session_table->getTableName(),
+ $ttl,
+ $id);
+ unset($unguarded);
+ }
+
return $user_table->loadFromArray($info);
}
@@ -84,6 +111,7 @@
// Consume entropy to generate a new session key, forestalling the eventual
// heat death of the universe.
$session_key = Filesystem::readRandomCharacters(40);
+ $session_ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type);
// Load all the currently active sessions.
$sessions = queryfx_all(
@@ -119,12 +147,14 @@
// care if we race here or not.
queryfx(
$conn_w,
- 'INSERT IGNORE INTO %T (userPHID, type, sessionKey, sessionStart)
- VALUES (%s, %s, %s, 0)',
+ 'INSERT IGNORE INTO %T
+ (userPHID, type, sessionKey, sessionStart, sessionExpires)
+ VALUES (%s, %s, %s, 0, UNIX_TIMESTAMP() + %d)',
$session_table->getTableName(),
$identity_phid,
$establish_type,
- PhabricatorHash::digest($session_key));
+ PhabricatorHash::digest($session_key),
+ $session_ttl);
break;
}
}
@@ -144,10 +174,12 @@
queryfx(
$conn_w,
- 'UPDATE %T SET sessionKey = %s, sessionStart = UNIX_TIMESTAMP()
+ 'UPDATE %T SET sessionKey = %s, sessionStart = UNIX_TIMESTAMP(),
+ sessionExpires = UNIX_TIMESTAMP() + %d
WHERE userPHID = %s AND type = %s AND sessionKey = %s',
$session_table->getTableName(),
PhabricatorHash::digest($session_key),
+ $session_ttl,
$identity_phid,
$establish_type,
$expect_key);
Index: src/applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php
===================================================================
--- /dev/null
+++ src/applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php
@@ -0,0 +1,18 @@
+<?php
+
+final class PhabricatorAuthSessionGarbageCollector
+ extends PhabricatorGarbageCollector {
+
+ public function collectGarbage() {
+ $session_table = new PhabricatorAuthSession();
+ $conn_w = $session_table->establishConnection('w');
+
+ queryfx(
+ $conn_w,
+ 'DELETE FROM %T WHERE sessionExpires <= UNIX_TIMESTAMP() LIMIT 100',
+ $session_table->getTableName());
+
+ return ($conn_w->getAffectedRows() == 100);
+ }
+
+}
Index: src/applications/auth/storage/PhabricatorAuthSession.php
===================================================================
--- src/applications/auth/storage/PhabricatorAuthSession.php
+++ src/applications/auth/storage/PhabricatorAuthSession.php
@@ -10,6 +10,7 @@
protected $type;
protected $sessionKey;
protected $sessionStart;
+ protected $sessionExpires;
private $identityObject = self::ATTACHABLE;
@@ -38,6 +39,18 @@
return $this->assertAttached($this->identityObject);
}
+ public static function getSessionTypeTTL($session_type) {
+ switch ($session_type) {
+ case self::TYPE_WEB:
+ return (60 * 60 * 24 * 30); // 30 days
+ case self::TYPE_CONDUIT:
+ return (60 * 60 * 24); // 24 hours
+ default:
+ throw new Exception(pht('Unknown session type "%s".', $session_type));
+ }
+ }
+
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
Index: src/applications/settings/panel/PhabricatorSettingsPanelSessions.php
===================================================================
--- src/applications/settings/panel/PhabricatorSettingsPanelSessions.php
+++ src/applications/settings/panel/PhabricatorSettingsPanelSessions.php
@@ -60,6 +60,7 @@
substr($session->getSessionKey(), 0, 12),
$session->getType(),
phabricator_datetime($session->getSessionStart(), $viewer),
+ phabricator_datetime($session->getSessionExpires(), $viewer),
);
}
@@ -72,6 +73,7 @@
pht('Session'),
pht('Type'),
pht('Created'),
+ pht('Expires'),
));
$table->setColumnClasses(
array(
@@ -79,6 +81,7 @@
'n',
'',
'right',
+ 'right',
));
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 28, 9:02 PM (5 h, 47 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6940090
Default Alt Text
D7976.id18046.diff (7 KB)
Attached To
Mode
D7976: Expire and garbage collect unused sessions
Attached
Detach File
Event Timeline
Log In to Comment