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
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
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
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
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
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