server/sources/native.py
changeset 9512 88dc96fc9fc1
parent 9487 88a092a665f4
child 9543 39f981482e34
equal deleted inserted replaced
9511:241b1232ed7f 9512:88dc96fc9fc1
   437             return not rtype in NONSYSTEM_RELATIONS
   437             return not rtype in NONSYSTEM_RELATIONS
   438         # due to current multi-sources implementation, the system source
   438         # due to current multi-sources implementation, the system source
   439         # can't claim not supporting a relation
   439         # can't claim not supporting a relation
   440         return True #not rtype == 'content_for'
   440         return True #not rtype == 'content_for'
   441 
   441 
   442     def authenticate(self, session, login, **kwargs):
   442     def authenticate(self, cnx, login, **kwargs):
   443         """return CWUser eid for the given login and other authentication
   443         """return CWUser eid for the given login and other authentication
   444         information found in kwargs, else raise `AuthenticationError`
   444         information found in kwargs, else raise `AuthenticationError`
   445         """
   445         """
   446         for authentifier in self.authentifiers:
   446         for authentifier in self.authentifiers:
   447             try:
   447             try:
   448                 return authentifier.authenticate(session, login, **kwargs)
   448                 return authentifier.authenticate(cnx, login, **kwargs)
   449             except AuthenticationError:
   449             except AuthenticationError:
   450                 continue
   450                 continue
   451         raise AuthenticationError()
   451         raise AuthenticationError()
   452 
   452 
   453     def syntax_tree_search(self, session, union, args=None, cachekey=None,
   453     def syntax_tree_search(self, session, union, args=None, cachekey=None,
  1448         if 'CWUser' in schema: # probably an empty schema if not true...
  1448         if 'CWUser' in schema: # probably an empty schema if not true...
  1449             # rql syntax trees used to authenticate users
  1449             # rql syntax trees used to authenticate users
  1450             self._passwd_rqlst = self.source.compile_rql(self.passwd_rql, self._sols)
  1450             self._passwd_rqlst = self.source.compile_rql(self.passwd_rql, self._sols)
  1451             self._auth_rqlst = self.source.compile_rql(self.auth_rql, self._sols)
  1451             self._auth_rqlst = self.source.compile_rql(self.auth_rql, self._sols)
  1452 
  1452 
  1453     def authenticate(self, session, login, password=None, **kwargs):
  1453     def authenticate(self, cnx, login, password=None, **kwargs):
  1454         """return CWUser eid for the given login/password if this account is
  1454         """return CWUser eid for the given login/password if this account is
  1455         defined in this source, else raise `AuthenticationError`
  1455         defined in this source, else raise `AuthenticationError`
  1456 
  1456 
  1457         two queries are needed since passwords are stored crypted, so we have
  1457         two queries are needed since passwords are stored crypted, so we have
  1458         to fetch the salt first
  1458         to fetch the salt first
  1459         """
  1459         """
  1460         args = {'login': login, 'pwd' : None}
  1460         args = {'login': login, 'pwd' : None}
  1461         if password is not None:
  1461         if password is not None:
  1462             rset = self.source.syntax_tree_search(session, self._passwd_rqlst, args)
  1462             rset = self.source.syntax_tree_search(cnx, self._passwd_rqlst, args)
  1463             try:
  1463             try:
  1464                 pwd = rset[0][0]
  1464                 pwd = rset[0][0]
  1465             except IndexError:
  1465             except IndexError:
  1466                 raise AuthenticationError('bad login')
  1466                 raise AuthenticationError('bad login')
  1467             if pwd is None:
  1467             if pwd is None:
  1468                 # if pwd is None but a password is provided, something is wrong
  1468                 # if pwd is None but a password is provided, something is wrong
  1469                 raise AuthenticationError('bad password')
  1469                 raise AuthenticationError('bad password')
  1470             # passwords are stored using the Bytes type, so we get a StringIO
  1470             # passwords are stored using the Bytes type, so we get a StringIO
  1471             args['pwd'] = Binary(crypt_password(password, pwd.getvalue()))
  1471             args['pwd'] = Binary(crypt_password(password, pwd.getvalue()))
  1472         # get eid from login and (crypted) password
  1472         # get eid from login and (crypted) password
  1473         rset = self.source.syntax_tree_search(session, self._auth_rqlst, args)
  1473         rset = self.source.syntax_tree_search(cnx, self._auth_rqlst, args)
  1474         try:
  1474         try:
  1475             user = rset[0][0]
  1475             user = rset[0][0]
  1476             # If the stored hash uses a deprecated scheme (e.g. DES or MD5 used
  1476             # If the stored hash uses a deprecated scheme (e.g. DES or MD5 used
  1477             # before 3.14.7), update with a fresh one
  1477             # before 3.14.7), update with a fresh one
  1478             if pwd.getvalue():
  1478             if pwd.getvalue():
  1479                 verify, newhash = verify_and_update(password, pwd.getvalue())
  1479                 verify, newhash = verify_and_update(password, pwd.getvalue())
  1480                 if not verify: # should not happen, but...
  1480                 if not verify: # should not happen, but...
  1481                     raise AuthenticationError('bad password')
  1481                     raise AuthenticationError('bad password')
  1482                 if newhash:
  1482                 if newhash:
  1483                     session.system_sql("UPDATE %s SET %s=%%(newhash)s WHERE %s=%%(login)s" % (
  1483                     cnx.system_sql("UPDATE %s SET %s=%%(newhash)s WHERE %s=%%(login)s" % (
  1484                                         SQL_PREFIX + 'CWUser',
  1484                                         SQL_PREFIX + 'CWUser',
  1485                                         SQL_PREFIX + 'upassword',
  1485                                         SQL_PREFIX + 'upassword',
  1486                                         SQL_PREFIX + 'login'),
  1486                                         SQL_PREFIX + 'login'),
  1487                                        {'newhash': self.source._binary(newhash),
  1487                                        {'newhash': self.source._binary(newhash),
  1488                                         'login': login})
  1488                                         'login': login})
  1489                     session.commit(free_cnxset=False)
  1489                     cnx.commit(free_cnxset=False)
  1490             return user
  1490             return user
  1491         except IndexError:
  1491         except IndexError:
  1492             raise AuthenticationError('bad password')
  1492             raise AuthenticationError('bad password')
  1493 
  1493 
  1494 
  1494 
  1495 class EmailPasswordAuthentifier(BaseAuthentifier):
  1495 class EmailPasswordAuthentifier(BaseAuthentifier):
  1496     def authenticate(self, session, login, **authinfo):
  1496     def authenticate(self, cnx, login, **authinfo):
  1497         # email_auth flag prevent from infinite recursion (call to
  1497         # email_auth flag prevent from infinite recursion (call to
  1498         # repo.check_auth_info at the end of this method may lead us here again)
  1498         # repo.check_auth_info at the end of this method may lead us here again)
  1499         if not '@' in login or authinfo.pop('email_auth', None):
  1499         if not '@' in login or authinfo.pop('email_auth', None):
  1500             raise AuthenticationError('not an email')
  1500             raise AuthenticationError('not an email')
  1501         rset = session.execute('Any L WHERE U login L, U primary_email M, '
  1501         rset = cnx.execute('Any L WHERE U login L, U primary_email M, '
  1502                                'M address %(login)s', {'login': login},
  1502                                'M address %(login)s', {'login': login},
  1503                                build_descr=False)
  1503                                build_descr=False)
  1504         if rset.rowcount != 1:
  1504         if rset.rowcount != 1:
  1505             raise AuthenticationError('unexisting email')
  1505             raise AuthenticationError('unexisting email')
  1506         login = rset.rows[0][0]
  1506         login = rset.rows[0][0]
  1507         authinfo['email_auth'] = True
  1507         authinfo['email_auth'] = True
  1508         return self.source.repo.check_auth_info(session, login, authinfo)
  1508         return self.source.repo.check_auth_info(cnx, login, authinfo)
  1509 
  1509 
  1510 
  1510 
  1511 class DatabaseIndependentBackupRestore(object):
  1511 class DatabaseIndependentBackupRestore(object):
  1512     """Helper class to perform db backend agnostic backup and restore
  1512     """Helper class to perform db backend agnostic backup and restore
  1513 
  1513