Guest User

Untitled

a guest
Nov 30th, 2018
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.76 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Ejabberd extauth : Authenticate phpbb users against PostgreSQL with Peewee
  4. # Original Author: Lukas Kolbe <lukas@einfachkaffee.de>
  5.  
  6. import sys
  7. import logging
  8. import struct
  9.  
  10. from hashlib import md5
  11. from peewee import PrimaryKeyField, CharField, PostgresqlDatabase, Model,\
  12. DoesNotExist, VarCharColumn, ForeignKeyField
  13.  
  14.  
  15. LOGGER = logging.getLogger('ejabberd-extauth')
  16. # Default to logging to stderr.
  17. formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s ')
  18. stream_handler = logging.StreamHandler()
  19. stream_handler.setFormatter(formatter)
  20. LOGGER.addHandler(stream_handler)
  21.  
  22. CONFIG = {
  23. 'name': 'dbname',
  24. 'args': {'user': 'userdb',
  25. 'password': 'passworddb',
  26. 'host': 'localhost'}
  27. }
  28.  
  29. db = PostgresqlDatabase(CONFIG['name'], **CONFIG['args'])
  30.  
  31.  
  32. class User(Model):
  33. class Meta:
  34. db_table = 'phpbb_users'
  35. database = db
  36.  
  37. id = PrimaryKeyField(db_column='user_id')
  38. username = CharField()
  39. password = CharField(db_column='user_password')
  40.  
  41.  
  42. class Session(Model):
  43. class Meta:
  44. db_table = 'phpbb_sessions'
  45. database = db
  46.  
  47. id = PrimaryKeyField(db_column='session_id', column_class=VarCharColumn)
  48. user = ForeignKeyField(User, db_column='session_user_id',
  49. related_name='id')
  50.  
  51. @classmethod
  52. def authentificate(cls, username, session_id):
  53. sq = cls.filter(id=session_id, user__username=username)
  54. sq = sq.limit(1)
  55. sq = list(sq)
  56. if len(sq) == 1:
  57. return True
  58. return False
  59.  
  60.  
  61. ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  62.  
  63.  
  64. def raw_md5(*args):
  65. m = md5()
  66. for i in args:
  67. m.update(i)
  68. return m.digest()
  69.  
  70.  
  71. def hex_md5(*args):
  72. m = md5()
  73. for i in args:
  74. m.update(i)
  75. return m.hexdigest()
  76.  
  77.  
  78. def phpbb_check_hash(password, password_hash):
  79. if len(password_hash) == 34:
  80. return hash_crypt_private(password, password_hash) == password_hash
  81. return hex_md5(password) == password_hash
  82.  
  83.  
  84. def hash_encode64(raw_hash, count, itoa64=ITOA64):
  85. output = ''
  86. i = 0
  87.  
  88. while True:
  89. value = ord(raw_hash[i])
  90. i += 1
  91.  
  92. output += itoa64[value & 0x3f]
  93.  
  94. if i < count:
  95. value |= ord(raw_hash[i]) << 8
  96.  
  97. output += itoa64[(value >> 6) & 0x3f]
  98.  
  99. i += 1
  100. if i >= count:
  101. break
  102.  
  103. if i < count:
  104. value |= ord(raw_hash[i]) << 16
  105.  
  106. output += itoa64[(value >> 12) & 0x3f]
  107.  
  108. i += 1
  109. if i >= count:
  110. break
  111.  
  112. output += itoa64[(value >> 18) & 0x3f]
  113.  
  114. if not i < count:
  115. break
  116.  
  117. return output
  118.  
  119.  
  120. def hash_crypt_private(password, setting, itoa64=ITOA64):
  121. output = '*'
  122.  
  123. if setting[0:0 + 3] != '$H$':
  124. return output
  125.  
  126. count_log2 = itoa64.find(setting[3])
  127. if count_log2 < 7 or count_log2 > 30:
  128. return output
  129.  
  130. count = 1 << count_log2
  131. salt = setting[4:4 + 8]
  132.  
  133. if len(salt) != 8:
  134. return output
  135.  
  136. raw_hash = raw_md5(salt, password)
  137. for i in xrange(count):
  138. raw_hash = raw_md5(raw_hash, password)
  139.  
  140. output = setting[0:0 + 12]
  141. output += hash_encode64(raw_hash, 16, itoa64)
  142.  
  143. return output
  144.  
  145.  
  146. class EjabberdInputError(Exception):
  147. def __init__(self, value):
  148. self.value = value
  149.  
  150. def __str__(self):
  151. return repr(self.value)
  152.  
  153.  
  154. def ejabberd_out(bool):
  155. LOGGER.debug("Ejabberd gets: %s" % bool)
  156. answer = 0
  157. if bool:
  158. answer = 1
  159. token = struct.pack('>hh', 2, answer)
  160. values = (ord(token[0]), ord(token[1]), ord(token[2]), ord(token[3]))
  161. LOGGER.debug("sent bytes: %#x %#x %#x %#x" % values)
  162. sys.stdout.write(token)
  163. sys.stdout.flush()
  164.  
  165.  
  166. def ejabberd_in():
  167. LOGGER.debug("trying to read 2 bytes from ejabberd:")
  168. try:
  169. input_length = sys.stdin.read(2)
  170. except IOError:
  171. LOGGER.debug("ioerror")
  172. if len(input_length) is not 2:
  173. LOGGER.debug("ejabberd sent us wrong things!")
  174. raise EjabberdInputError('Wrong input from ejabberd!')
  175. LOGGER.debug('got 2 bytes via stdin')
  176.  
  177. (size,) = struct.unpack('>h', input_length)
  178. return sys.stdin.read(size).split(':')
  179.  
  180.  
  181. def get_user(username):
  182. db.connect()
  183. try:
  184. user = User.get(username=username)
  185. except DoesNotExist:
  186. user = None
  187. db.close()
  188. return user
  189.  
  190.  
  191. def auth_pass(username, password):
  192. LOGGER.debug("%s wants authentication ..." % username)
  193. user = get_user(username)
  194. if user is not None:
  195. if phpbb_check_hash(password, user.password):
  196. return True
  197. return False
  198.  
  199.  
  200. def auth_session(username, session_id):
  201. LOGGER.debug("%s wants authentication ..." % username)
  202. return Session.authentificate(username, session_id)
  203.  
  204.  
  205. def isuser(username):
  206. LOGGER.debug("do we know %s?" % username)
  207. return (get_user(username) is not None)
  208.  
  209.  
  210. def log_success(method, username, success):
  211. if success:
  212. LOGGER.info("%s successful for %s" % (method, username))
  213. else:
  214. LOGGER.info("%s unsuccessful for %s" % (method, username))
  215.  
  216.  
  217. # this is our main-loop. I hate infinite loops.
  218. while True:
  219. LOGGER.debug("start of infinite loop")
  220.  
  221. try:
  222. data = ejabberd_in()
  223. except EjabberdInputError, inst:
  224. LOGGER.info("Exception occured: %s", inst)
  225. break
  226.  
  227. LOGGER.debug('Method: %s' % data[0])
  228. success = False
  229.  
  230. if data[0] == "auth":
  231. success = auth_session(data[1], data[3])
  232. if not success:
  233. success = auth_pass(data[1], data[3])
  234. ejabberd_out(success)
  235. log_success("auth", data[1], success)
  236.  
  237. elif data[0] == "isuser":
  238. success = isuser(data[1])
  239. ejabberd_out(success)
  240. log_success("isuser", data[1], success)
  241.  
  242. else:
  243. ejabberd_out(False)
  244.  
  245. LOGGER.debug("end of infinite loop")
  246.  
  247. LOGGER.info('extauth script terminating')
Add Comment
Please, Sign In to add comment