예제 #1
0
    async def login(self, user: RemoteUser):
        """
        Persist a user id and a backend in the request. This way a user doesn't
        have to reauthenticate on every request. Note that data set during
        the anonymous session is retained when the user logs in.
        """
        session_auth_hash = ''
        if user is None:
            user = self.current_user
        if hasattr(user, 'get_session_auth_hash'):
            session_auth_hash = user.get_session_auth_hash()

        if SESSION_KEY in self.session:
            if _get_user_session_key(self) != user.id or (
                    session_auth_hash and not constant_time_compare(
                        self.session.get(HASH_SESSION_KEY, ''),
                        session_auth_hash)):
                # To avoid reusing another user's session, create a new, empty
                # session if the existing session corresponds to a different
                # authenticated user.
                self.session.flush()
        else:
            self.session.cycle_key()

        self.session[SESSION_KEY] = user.id
        self.session[HASH_SESSION_KEY] = session_auth_hash
        # noinspection PyAttributeOutsideInit
        self.current_user = user
예제 #2
0
 def unsign(self, signed_value):
     if self.sep not in signed_value:
         raise BadSignature('No "%s" found in value' % self.sep)
     value, sig = signed_value.rsplit(self.sep, 1)
     if constant_time_compare(sig, self.signature(value)):
         return value
     raise BadSignature('Signature "%s" does not match' % sig)
예제 #3
0
    async def get_user(self):
        """
        Return the user model instance associated with the given session.
        If no user is retrieved, return an instance of `AnonymousUser`.
        """
        user = None
        try:
            user_id = _get_user_session_key(self)
            backend_path = self.session[BACKEND_SESSION_KEY]
        except KeyError:
            pass
        else:
            if backend_path in settings.AUTHENTICATION_BACKENDS:
                backend = load_backend(backend_path)
                user = await backend.get_user(user_id)
                # Verify the session
                if hasattr(user, 'get_session_auth_hash'):
                    session_hash = self.session.get(HASH_SESSION_KEY)
                    session_hash_verified = session_hash and constant_time_compare(
                        session_hash, user.get_session_auth_hash())
                    if not session_hash_verified:
                        self.session.flush()
                        user = None

        return user or AnonymousUser()
예제 #4
0
 def decode(self, session_data):
     encoded_data = base64.b64decode(force_bytes(session_data))
     try:
         # could produce ValueError if there is no ':'
         hash, serialized = encoded_data.split(b':', 1)
         expected_hash = self._hash(serialized)
         if not constant_time_compare(hash.decode(), expected_hash):
             raise SuspiciousSession("Session data corrupted")
         else:
             return self.serializer().loads(serialized)
     except Exception as e:
         # ValueError, SuspiciousOperation, unpickling exceptions. If any of
         # these happen, just return an empty dictionary (an empty session).
         if isinstance(e, SuspiciousOperation):
             logger = logging.getLogger('anthill.application')
             logger.warning(str(e))
         return {}
예제 #5
0
    def login(self, user, backend=None):
        """
        Persist a user id and a backend in the request. This way a user doesn't
        have to reauthenticate on every request. Note that data set during
        the anonymous session is retained when the user logs in.
        """
        session_auth_hash = ''
        if user is None:
            user = self.current_user
        if hasattr(user, 'get_session_auth_hash'):
            session_auth_hash = user.get_session_auth_hash()

        if SESSION_KEY in self.session:
            if _get_user_session_key(self) != user.id or (
                    session_auth_hash and not constant_time_compare(
                        self.session.get(HASH_SESSION_KEY, ''),
                        session_auth_hash)):
                # To avoid reusing another user's session, create a new, empty
                # session if the existing session corresponds to a different
                # authenticated user.
                self.session.flush()
        else:
            self.session.cycle_key()

        try:
            backend = backend or user.backend
        except AttributeError:
            backends = _get_backends(return_tuples=True)
            if len(backends) == 1:
                _, backend = backends[0]
            else:
                raise ValueError(
                    'You have multiple authentication backends configured and '
                    'therefore must provide the `backend` argument or set the '
                    '`backend` attribute on the user.')
        else:
            if not isinstance(backend, str):
                raise TypeError(
                    'backend must be a dotted import path string (got %r).' %
                    backend)

        self.session[SESSION_KEY] = user.id
        self.session[BACKEND_SESSION_KEY] = backend
        self.session[HASH_SESSION_KEY] = session_auth_hash
        self.current_user = user
예제 #6
0
    async def get_user(self):
        """
        Return the user model instance associated with the given session.
        If no user is retrieved, return an instance of `AnonymousUser`.
        """
        user = None
        try:
            user_id = _get_user_session_key(self)
        except KeyError:
            pass
        else:
            user = await RemoteUser(id=user_id).get()
            # Verify the session
            if hasattr(user, 'get_session_auth_hash'):
                session_hash = self.session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user.get_session_auth_hash())
                if not session_hash_verified:
                    self.session.flush()
                    user = None

        return user or AnonymousUser()
예제 #7
0
 def verify(self, password, encoded):
     crypt = self._load_library()
     algorithm, salt, data = encoded.split('$', 2)
     assert algorithm == self.algorithm
     return constant_time_compare(data, crypt.crypt(password, data))
예제 #8
0
 def verify(self, password, encoded):
     if len(encoded) == 37 and encoded.startswith('md5$$'):
         encoded = encoded[5:]
     encoded_2 = self.encode(password, '')
     return constant_time_compare(encoded, encoded_2)
예제 #9
0
 def verify(self, password, encoded):
     encoded_2 = self.encode(password, '')
     return constant_time_compare(encoded, encoded_2)
예제 #10
0
 def verify(self, password, encoded):
     algorithm, salt, hash = encoded.split('$', 2)
     assert algorithm == self.algorithm
     encoded_2 = self.encode(password, salt)
     return constant_time_compare(encoded, encoded_2)
예제 #11
0
 def verify(self, password, encoded):
     algorithm, data = encoded.split('$', 1)
     assert algorithm == self.algorithm
     encoded_2 = self.encode(password, force_bytes(data))
     return constant_time_compare(encoded, encoded_2)