comparison src/memory/memory.py @ 1591:0df9c6247474

core: profile session starting and connection are now separated. Moved profile session starting/authentication to memory module
author Goffi <goffi@goffi.org>
date Sat, 14 Nov 2015 19:18:10 +0100
parents 698d6755d62a
children a3d0cfa5b7a6
comparison
equal deleted inserted replaced
1590:ab54af2a9ab2 1591:0df9c6247474
35 from sat.memory.sqlite import SqliteStorage 35 from sat.memory.sqlite import SqliteStorage
36 from sat.memory.persistent import PersistentDict 36 from sat.memory.persistent import PersistentDict
37 from sat.memory.params import Params 37 from sat.memory.params import Params
38 from sat.memory.disco import Discovery 38 from sat.memory.disco import Discovery
39 from sat.memory.crypto import BlockCipher 39 from sat.memory.crypto import BlockCipher
40 from sat.memory.crypto import PasswordHasher
40 from sat.tools import config as tools_config 41 from sat.tools import config as tools_config
41 42
42 43
43 PresenceTuple = namedtuple("PresenceTuple", ('show', 'priority', 'statuses')) 44 PresenceTuple = namedtuple("PresenceTuple", ('show', 'priority', 'statuses'))
44 MSG_NO_SESSION = "Session id doesn't exist or is finished" 45 MSG_NO_SESSION = "Session id doesn't exist or is finished"
314 @param profile: %(doc_profile)s""" 315 @param profile: %(doc_profile)s"""
315 return self.params.loadIndParams(profile) 316 return self.params.loadIndParams(profile)
316 317
317 ## Profiles/Sessions management ## 318 ## Profiles/Sessions management ##
318 319
319 def startProfileSession(self, profile): 320 def _startSession(self, password, profile_key):
321 profile = self.getProfileName(profile_key)
322 return self.startSession(password, profile)
323
324 def startSession(self, password, profile):
320 """"Iniatialise session for a profile 325 """"Iniatialise session for a profile
321 @param profile: %(doc_profile)s""" 326
322 log.info(_("[%s] Profile session started" % profile)) 327 @param password(unicode): profile session password
323 self._entities_cache[profile] = {} 328 or empty string is no password is set
329 @param profile: %(doc_profile)s
330 """
331 def createSession(dummy):
332 """Called once params are loaded."""
333 self._entities_cache[profile] = {}
334 log.info(u"[{}] Profile session started".format(profile))
335 return False
336
337 def backendInitialised(dummy):
338 def doStartSession(dummy=None):
339 if self.isSessionStarted(profile):
340 log.info("Session already started!")
341 return True
342 try:
343 # if there is a value at this point in self._entities_cache,
344 # it is the loadIndividualParams Deferred, the session is starting
345 session_d = self._entities_cache[profile]
346 except KeyError:
347 # else we do request the params
348 session_d = self._entities_cache[profile] = self.loadIndividualParams(profile)
349 session_d.addCallback(createSession)
350 finally:
351 return session_d
352
353 auth_d = self.profileAuthenticate(password, profile)
354 auth_d.addCallback(doStartSession)
355 return auth_d
356
357 return self.host.initialised.addCallback(backendInitialised)
358
359 def _isSessionStarted(self, profile_key):
360 return self.isSessionStarted(self.getProfileName(profile_key))
361
362 def isSessionStarted(self, profile):
363 try:
364 # XXX: if the value in self._entities_cache is a Deferred,
365 # the session is starting but not started yet
366 return not isinstance(self._entities_cache[profile], defer.Deferred)
367 except KeyError:
368 return False
369
370 def profileAuthenticate(self, password, profile):
371 """Authenticate the profile.
372
373 @param password (unicode): the SàT profile password
374 @param profile: %(doc_profile)s
375 @return (D): a deferred None in case of success, a failure otherwise.
376 """
377 session_data = self.auth_sessions.profileGetUnique(profile)
378 if not password and session_data:
379 # XXX: this allows any frontend to connect with the empty password as soon as
380 # the profile has been authenticated at least once before. It is OK as long as
381 # submitting a form with empty passwords is restricted to local frontends.
382 return defer.succeed(None)
383
384 def check_result(result):
385 if not result:
386 log.warning(u'Authentication failure of profile {}'.format(profile))
387 raise exceptions.PasswordError(u"The provided profile password doesn't match.")
388 if not session_data: # avoid to create two profile sessions when password if specified
389 return self.newAuthSession(password, profile)
390
391 d = self.asyncGetParamA(C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile)
392 d.addCallback(lambda sat_cipher: PasswordHasher.verify(password, sat_cipher))
393 return d.addCallback(check_result)
324 394
325 def newAuthSession(self, key, profile): 395 def newAuthSession(self, key, profile):
326 """Start a new session for the authenticated profile. 396 """Start a new session for the authenticated profile.
327 397
328 The personal key is loaded encrypted from a PersistentDict before being decrypted. 398 The personal key is loaded encrypted from a PersistentDict before being decrypted.