@@ -94,6 +94,7 @@ public function loadUserForSession($session_type, $session_token) {
94
94
s.sessionExpires AS s_sessionExpires,
95
95
s.sessionStart AS s_sessionStart,
96
96
s.highSecurityUntil AS s_highSecurityUntil,
97
+ s.isPartial AS s_isPartial,
97
98
u.*
98
99
FROM %T u JOIN %T s ON u.phid = s.userPHID
99
100
AND s.type = %s AND s.sessionKey = %s ' ,
@@ -159,9 +160,10 @@ public function loadUserForSession($session_type, $session_token) {
159
160
* @{class:PhabricatorAuthSession}).
160
161
* @param phid|null Identity to establish a session for, usually a user
161
162
* PHID. With `null`, generates an anonymous session.
163
+ * @param bool True to issue a partial session.
162
164
* @return string Newly generated session key.
163
165
*/
164
- public function establishSession ($ session_type , $ identity_phid ) {
166
+ public function establishSession ($ session_type , $ identity_phid, $ partial ) {
165
167
// Consume entropy to generate a new session key, forestalling the eventual
166
168
// heat death of the universe.
167
169
$ session_key = Filesystem::readRandomCharacters (40 );
@@ -176,26 +178,32 @@ public function establishSession($session_type, $identity_phid) {
176
178
// This has a side effect of validating the session type.
177
179
$ session_ttl = PhabricatorAuthSession::getSessionTypeTTL ($ session_type );
178
180
181
+ $ digest_key = PhabricatorHash::digest ($ session_key );
182
+
179
183
// Logging-in users don't have CSRF stuff yet, so we have to unguard this
180
184
// write.
181
185
$ unguarded = AphrontWriteGuard::beginScopedUnguardedWrites ();
182
186
id (new PhabricatorAuthSession ())
183
187
->setUserPHID ($ identity_phid )
184
188
->setType ($ session_type )
185
- ->setSessionKey (PhabricatorHash:: digest ( $ session_key ) )
189
+ ->setSessionKey ($ digest_key )
186
190
->setSessionStart (time ())
187
191
->setSessionExpires (time () + $ session_ttl )
192
+ ->setIsPartial ($ partial ? 1 : 0 )
188
193
->save ();
189
194
190
195
$ log = PhabricatorUserLog::initializeNewLog (
191
196
null ,
192
197
$ identity_phid ,
193
- PhabricatorUserLog::ACTION_LOGIN );
198
+ ($ partial
199
+ ? PhabricatorUserLog::ACTION_LOGIN_PARTIAL
200
+ : PhabricatorUserLog::ACTION_LOGIN ));
201
+
194
202
$ log ->setDetails (
195
203
array (
196
204
'session_type ' => $ session_type ,
197
205
));
198
- $ log ->setSession ($ session_key );
206
+ $ log ->setSession ($ digest_key );
199
207
$ log ->save ();
200
208
unset($ unguarded );
201
209
@@ -287,6 +295,12 @@ public function requireHighSecuritySession(
287
295
new PhabricatorAuthTryFactorAction (),
288
296
-1 );
289
297
298
+ if ($ session ->getIsPartial ()) {
299
+ // If we have a partial session, just issue a token without
300
+ // putting it in high security mode.
301
+ return $ this ->issueHighSecurityToken ($ session , true );
302
+ }
303
+
290
304
$ until = time () + phutil_units ('15 minutes in seconds ' );
291
305
$ session ->setHighSecurityUntil ($ until );
292
306
@@ -303,9 +317,6 @@ public function requireHighSecuritySession(
303
317
PhabricatorUserLog::ACTION_ENTER_HISEC );
304
318
$ log ->save ();
305
319
} else {
306
-
307
-
308
-
309
320
$ log = PhabricatorUserLog::initializeNewLog (
310
321
$ viewer ,
311
322
$ viewer ->getPHID (),
@@ -331,11 +342,15 @@ public function requireHighSecuritySession(
331
342
* Issue a high security token for a session, if authorized.
332
343
*
333
344
* @param PhabricatorAuthSession Session to issue a token for.
345
+ * @param bool Force token issue.
334
346
* @return PhabricatorAuthHighSecurityToken|null Token, if authorized.
335
347
*/
336
- private function issueHighSecurityToken (PhabricatorAuthSession $ session ) {
348
+ private function issueHighSecurityToken (
349
+ PhabricatorAuthSession $ session ,
350
+ $ force = false ) {
351
+
337
352
$ until = $ session ->getHighSecurityUntil ();
338
- if ($ until > time ()) {
353
+ if ($ until > time () || $ force ) {
339
354
return new PhabricatorAuthHighSecurityToken ();
340
355
}
341
356
return null ;
@@ -390,4 +405,42 @@ public function exitHighSecurity(
390
405
$ log ->save ();
391
406
}
392
407
408
+
409
+ /**
410
+ * Upgrade a partial session to a full session.
411
+ *
412
+ * @param PhabricatorAuthSession Session to upgrade.
413
+ * @return void
414
+ */
415
+ public function upgradePartialSession (PhabricatorUser $ viewer ) {
416
+ if (!$ viewer ->hasSession ()) {
417
+ throw new Exception (
418
+ pht ('Upgrading partial session of user with no session! ' ));
419
+ }
420
+
421
+ $ session = $ viewer ->getSession ();
422
+
423
+ if (!$ session ->getIsPartial ()) {
424
+ throw new Exception (pht ('Session is not partial! ' ));
425
+ }
426
+
427
+ $ unguarded = AphrontWriteGuard::beginScopedUnguardedWrites ();
428
+ $ session ->setIsPartial (0 );
429
+
430
+ queryfx (
431
+ $ session ->establishConnection ('w ' ),
432
+ 'UPDATE %T SET isPartial = %d WHERE id = %d ' ,
433
+ $ session ->getTableName (),
434
+ 0 ,
435
+ $ session ->getID ());
436
+
437
+ $ log = PhabricatorUserLog::initializeNewLog (
438
+ $ viewer ,
439
+ $ viewer ->getPHID (),
440
+ PhabricatorUserLog::ACTION_LOGIN_FULL );
441
+ $ log ->save ();
442
+ unset($ unguarded );
443
+
444
+ }
445
+
393
446
}
0 commit comments