Example #1
0
    def check_answer(self, given_answer, timestamp, signature):
        """ check if the given answer to the question is correct and within the correct timeframe"""
        if self.is_enabled():
            reason = 'ok'
            if self.answer_re is not None:
                success = self.answer_re.match(given_answer.strip()) is not None
                if not success:
                    reason = 'answer_re did not match'
            else:
                # someone trying to cheat!?
                success = False
                reason = 'answer_re is None'
            if not timestamp or timestamp + self.expiry_time < time():
                success = False
                reason = 'textcha expired'
            try:
                if not safe_str_equal(self._compute_signature(self.question, timestamp), signature):
                    success = False
                    reason = 'signature mismatch'
            except TypeError:
                success = False
                reason = 'TypeError during signature check'

            success_status = success and u"success" or u"failure"
            logging.info(u"TextCha: %s (u='%s', a='%s', re='%s', q='%s', rsn='%s')" % (
                             success_status,
                             self.user_info,
                             given_answer,
                             self.answer_regex,
                             self.question,
                             reason,
                             ))
            return success
        else:
            return True
Example #2
0
 def apply_recovery_token(self, tok, newpass):
     parts = tok.split('-')
     if len(parts) != 2:
         return False
     try:
         stamp = int(parts[0])
     except ValueError:
         return False
     # only allow it to be valid for twelve hours
     if stamp + 12*60*60 < time.time():
         return False
     # check hmac
     # key must be of type string
     h = hmac_new(str(self.recoverpass_key), str(stamp)).hexdigest()
     if not safe_str_equal(h, parts[1]):
         return False
     self.recoverpass_key = ""
     self.enc_password = encodePassword(self._cfg, newpass)
     self.save()
     return True
Example #3
0
 def apply_recovery_token(self, tok, newpass):
     parts = tok.split('-')
     if len(parts) != 2:
         return False
     try:
         stamp = int(parts[0])
     except ValueError:
         return False
     lifetime = self._request.cfg.recovery_token_lifetime * 3600
     if time.time() > stamp + lifetime:
         return False
     # check hmac
     # key must be of type string
     h = hmac_new(str(self.recoverpass_key), str(stamp)).hexdigest()
     if not safe_str_equal(h, parts[1]):
         return False
     self.recoverpass_key = ""
     self.enc_password = encodePassword(self._cfg, newpass)
     self.save()
     return True
Example #4
0
 def apply_recovery_token(self, tok, newpass):
     parts = tok.split('-')
     if len(parts) != 2:
         return False
     try:
         stamp = int(parts[0])
     except ValueError:
         return False
     lifetime = self._request.cfg.recovery_token_lifetime * 3600
     if time.time() > stamp + lifetime:
         return False
     # check hmac
     # key must be of type string
     h = hmac_new(str(self.recoverpass_key), str(stamp)).hexdigest()
     if not safe_str_equal(h, parts[1]):
         return False
     self.recoverpass_key = ""
     self.enc_password = encodePassword(self._cfg, newpass)
     self.save()
     return True
Example #5
0
 def apply_recovery_token(self, tok, newpass):
     parts = tok.split('-')
     if len(parts) != 2:
         return False
     try:
         stamp = int(parts[0])
     except ValueError:
         return False
     # only allow it to be valid for twelve hours
     if stamp + 12 * 60 * 60 < time.time():
         return False
     # check hmac
     # key must be of type string
     h = hmac_new(str(self.recoverpass_key), str(stamp)).hexdigest()
     if not safe_str_equal(h, parts[1]):
         return False
     self.recoverpass_key = ""
     self.enc_password = encodePassword(self._cfg, newpass)
     self.save()
     return True
Example #6
0
    def _validatePassword(self, data, password):
        """
        Check user password.

        This is a private method and should not be used by clients.

        @param data: dict with user data (from storage)
        @param password: password to verify [unicode]
        @rtype: 2 tuple (bool, bool)
        @return: password is valid, enc_password changed
        """
        epwd = data['enc_password']

        # If we have no password set, we don't accept login with username
        if not epwd:
            return False, False

        # require non empty password
        if not password:
            return False, False

        password_correct = recompute_hash = False
        wanted_scheme = self._cfg.password_scheme

        # Check password and upgrade weak hashes to strong default algorithm:
        for scheme in config.password_schemes_supported:
            if epwd.startswith(scheme):
                is_passlib = False
                d = epwd[len(scheme):]

                if scheme == '{PASSLIB}':
                    # a password hash to be checked by passlib library code
                    if not self._cfg.passlib_support:
                        logging.error('in user profile %r, password hash with {PASSLIB} scheme encountered, but passlib_support is False' % (self.id, ))
                    else:
                        pwd_context = self._cfg.cache.pwd_context
                        try:
                            password_correct = pwd_context.verify(password, d)
                        except ValueError, err:
                            # can happen for unknown scheme
                            logging.error('in user profile %r, verifying the passlib pw hash crashed [%s]' % (self.id, str(err)))
                        if password_correct:
                            # check if we need to recompute the hash. this is needed if either the
                            # passlib hash scheme / hash params changed or if we shall change to a
                            # builtin hash scheme (not recommended):
                            recompute_hash = pwd_context.hash_needs_update(d) or wanted_scheme != '{PASSLIB}'

                else:
                    # a password hash to be checked by legacy, builtin code
                    if scheme == '{SSHA}':
                        d = base64.decodestring(d)
                        salt = d[20:]
                        hash = hash_new('sha1', password.encode('utf-8'))
                        hash.update(salt)
                        enc = base64.encodestring(hash.digest() + salt).rstrip()

                    elif scheme == '{SHA}':
                        enc = base64.encodestring(
                            hash_new('sha1', password.encode('utf-8')).digest()).rstrip()

                    elif scheme == '{APR1}':
                        # d is of the form "$apr1$<salt>$<hash>"
                        salt = d.split('$')[2]
                        enc = md5crypt.apache_md5_crypt(password.encode('utf-8'),
                                                        salt.encode('ascii'))
                    elif scheme == '{MD5}':
                        # d is of the form "$1$<salt>$<hash>"
                        salt = d.split('$')[2]
                        enc = md5crypt.unix_md5_crypt(password.encode('utf-8'),
                                                      salt.encode('ascii'))
                    elif scheme == '{DES}':
                        if crypt is None:
                            return False, False
                        # d is 2 characters salt + 11 characters hash
                        salt = d[:2]
                        enc = crypt.crypt(password.encode('utf-8'), salt.encode('ascii'))

                    else:
                        logging.error('in user profile %r, password hash with unknown scheme encountered: %r' % (self.id, scheme))
                        raise NotImplementedError

                    if safe_str_equal(epwd, scheme + enc):
                        password_correct = True
                        recompute_hash = scheme != wanted_scheme

                if recompute_hash:
                    data['enc_password'] = encodePassword(self._cfg, password)
                return password_correct, recompute_hash
Example #7
0
    def _validatePassword(self, data, password):
        """
        Check user password.

        This is a private method and should not be used by clients.

        @param data: dict with user data (from storage)
        @param password: password to verify [unicode]
        @rtype: 2 tuple (bool, bool)
        @return: password is valid, enc_password changed
        """
        epwd = data['enc_password']

        # If we have no password set, we don't accept login with username
        if not epwd:
            return False, False

        # require non empty password
        if not password:
            return False, False

        password_correct = recompute_hash = False
        wanted_scheme = self._cfg.password_scheme

        # Check password and upgrade weak hashes to strong default algorithm:
        for scheme in config.password_schemes_supported:
            if epwd.startswith(scheme):
                is_passlib = False
                d = epwd[len(scheme):]

                if scheme == '{PASSLIB}':
                    # a password hash to be checked by passlib library code
                    if not self._cfg.passlib_support:
                        logging.error(
                            'in user profile %r, password hash with {PASSLIB} scheme encountered, but passlib_support is False'
                            % (self.id, ))
                    else:
                        pwd_context = self._cfg.cache.pwd_context
                        try:
                            password_correct = pwd_context.verify(password, d)
                        except ValueError, err:
                            # can happen for unknown scheme
                            logging.error(
                                'in user profile %r, verifying the passlib pw hash crashed [%s]'
                                % (self.id, str(err)))
                        if password_correct:
                            # check if we need to recompute the hash. this is needed if either the
                            # passlib hash scheme / hash params changed or if we shall change to a
                            # builtin hash scheme (not recommended):
                            recompute_hash = pwd_context.hash_needs_update(
                                d) or wanted_scheme != '{PASSLIB}'

                else:
                    # a password hash to be checked by legacy, builtin code
                    if scheme == '{SSHA}':
                        d = base64.decodestring(d)
                        salt = d[20:]
                        hash = hash_new('sha1', password.encode('utf-8'))
                        hash.update(salt)
                        enc = base64.encodestring(hash.digest() +
                                                  salt).rstrip()

                    elif scheme == '{SHA}':
                        enc = base64.encodestring(
                            hash_new(
                                'sha1',
                                password.encode('utf-8')).digest()).rstrip()

                    elif scheme == '{APR1}':
                        # d is of the form "$apr1$<salt>$<hash>"
                        salt = d.split('$')[2]
                        enc = md5crypt.apache_md5_crypt(
                            password.encode('utf-8'), salt.encode('ascii'))
                    elif scheme == '{MD5}':
                        # d is of the form "$1$<salt>$<hash>"
                        salt = d.split('$')[2]
                        enc = md5crypt.unix_md5_crypt(password.encode('utf-8'),
                                                      salt.encode('ascii'))
                    elif scheme == '{DES}':
                        if crypt is None:
                            return False, False
                        # d is 2 characters salt + 11 characters hash
                        salt = d[:2]
                        enc = crypt.crypt(password.encode('utf-8'),
                                          salt.encode('ascii'))

                    else:
                        logging.error(
                            'in user profile %r, password hash with unknown scheme encountered: %r'
                            % (self.id, scheme))
                        raise NotImplementedError

                    if safe_str_equal(epwd, scheme + enc):
                        password_correct = True
                        recompute_hash = scheme != wanted_scheme

                if recompute_hash:
                    data['enc_password'] = encodePassword(self._cfg, password)
                return password_correct, recompute_hash