You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
6.2 KiB

4 years ago
4 years ago
  1. #!/usr/bin/env python3
  2. import ldap
  3. import ldap.modlist
  4. import string
  5. from random import SystemRandom
  6. # LDAP Server Configuration
  7. LDAP_URI = "ldap://ldap1.dmz.lilik.it"
  8. LDAP_STARTTLS = True
  9. LDAP_BASEDN = "dc=lilik,dc=it"
  10. MAIL_DOMAIN = "lilik.it"
  11. NEW_PW_LEN = 10
  12. # Manager Account
  13. # Required privileges:
  14. # - New user creation in `ou=People`
  15. # - User search in `ou=People`
  16. # All other action are performed as the logged-in user, and must be
  17. # allowed by LDAP ACLs
  18. LDAPMANAGER_BINDDN = "cn=,ou=Server,dc=lilik,dc=it"
  19. LDAPMANAGER_BINDPW = ""
  20. def ldapmanager_check_uid_exists(uid):
  21. conn = ldap.initialize(LDAP_URI)
  22. if(LDAP_STARTTLS):
  23. conn.start_tls_s()
  24. conn.simple_bind_s(LDAPMANAGER_BINDDN, LDAPMANAGER_BINDPW)
  25. results = conn.search_s('ou=People,{}'.format(LDAP_BASEDN),
  26. ldap.SCOPE_SUBTREE,
  27. 'uid={}'.format(uid),
  28. ['uid'])
  29. conn.unbind_s()
  30. return len(results) > 0
  31. def ldapmanager_create_uid(uid, group_cn, req_attrs):
  32. dn="uid={},ou=People,{}".format(uid, LDAP_BASEDN)
  33. # New user template
  34. attrs = {
  35. 'objectClass': [b'top', b'inetOrgPerson', b'authorizedServiceObject'],
  36. 'uid': uid.encode('utf-8'),
  37. 'mail': "{}@{}".format(uid, MAIL_DOMAIN).encode('utf-8'),
  38. 'manager': "cn={},ou=Group,{}".format(group_cn, LDAP_BASEDN).encode('utf-8'),
  39. 'cn': req_attrs['cn'].encode('utf-8'),
  40. 'sn': req_attrs['sn'].encode('utf-8'),
  41. 'authorizedService': [b'nextcloud', b'matrix', b'gitea']
  42. }
  43. conn = ldap.initialize(LDAP_URI)
  44. if(LDAP_STARTTLS):
  45. conn.start_tls_s()
  46. conn.simple_bind_s(LDAPMANAGER_BINDDN, LDAPMANAGER_BINDPW)
  47. conn.add_s(dn, ldap.modlist.addModlist(attrs))
  48. conn.unbind_s()
  49. return
  50. class Group(object):
  51. def __init__(self, admin_uid, admin_pass):
  52. self.admin_uid = admin_uid
  53. self.conn = self.bind(admin_uid, admin_pass)
  54. def bind(self, admin_uid, admin_pass):
  55. conn = ldap.initialize(LDAP_URI)
  56. if(LDAP_STARTTLS):
  57. conn.start_tls_s()
  58. conn.simple_bind_s("uid={},ou=People,{}".format(admin_uid, LDAP_BASEDN), admin_pass)
  59. return conn
  60. def group_list(self):
  61. results = self.conn.search_s('ou=Group,{}'.format(LDAP_BASEDN),
  62. ldap.SCOPE_SUBTREE,
  63. 'owner=uid={},ou=People,{}'.format(self.admin_uid, LDAP_BASEDN),
  64. ['cn', 'description'])
  65. return [ (group["cn"][0].decode('utf-8'),
  66. group["description"][0].decode('utf-8')) for key, group in results ]
  67. def member_list(self, group_cn):
  68. results = self.conn.search_s('cn={},ou=Group,{}'.format(group_cn, LDAP_BASEDN),
  69. ldap.SCOPE_BASE,
  70. 'owner=uid={},ou=People,{}'.format(self.admin_uid, LDAP_BASEDN),
  71. ['member'])
  72. return [ ldap.dn.str2dn(member)[0][0][1] for member in results[0][1]["member"] ]
  73. def add_member(self, group_cn, uid):
  74. self.conn.modify_s('cn={},ou=Group,{}'.format(group_cn, LDAP_BASEDN),
  75. [ (ldap.MOD_ADD, 'member', ["uid={},ou=People,{}".format(uid, LDAP_BASEDN).encode('utf-8')]) ])
  76. return
  77. def reset_password(self, uid):
  78. valid_chars = (string.ascii_uppercase
  79. + string.ascii_lowercase
  80. + string.digits)
  81. rng = SystemRandom()
  82. passwd = "".join([rng.choice(valid_chars) for _ in range(NEW_PW_LEN)])
  83. result = self.conn.passwd_s('uid={},ou=People,{}'.format(uid, LDAP_BASEDN),
  84. None,
  85. passwd)
  86. return passwd
  87. from flask import Flask
  88. from flask import request, jsonify
  89. app = Flask(__name__)
  90. @app.route('/get_list', methods=['POST'])
  91. def display_list():
  92. try:
  93. g = Group(request.form['username'], request.form['password'])
  94. result = [
  95. { "cn": group[0],
  96. "description": group[1],
  97. "members": g.member_list(group[0])
  98. }
  99. for group in g.group_list()
  100. ]
  101. except Exception as e:
  102. return jsonify({"failed": True, "reason": str(e)})
  103. return jsonify(result)
  104. @app.route('/group/<group_cn>/create/<new_uid>', methods=['POST'])
  105. def new_user(group_cn, new_uid):
  106. try:
  107. g = Group(request.json['username'], request.json['password'])
  108. if group_cn not in [ group[0] for group in g.group_list() ]:
  109. result = { "failed": True,
  110. "reason": "User {} is not an administrator for group {}".format(request.json['username'], group_cn) }
  111. elif ldapmanager_check_uid_exists(new_uid):
  112. result = { "failed": True,
  113. "reason": "User {} already exists, choose another name.".format(new_uid) }
  114. else:
  115. ldapmanager_create_uid(new_uid, group_cn, request.json['newEntry'])
  116. g.add_member(group_cn, new_uid)
  117. if 'memberOf' in request.json['newEntry']:
  118. for extra_group in request.json['newEntry']['memberOf']:
  119. g.add_member(extra_group, new_uid)
  120. new_passwd = g.reset_password(new_uid)
  121. result = { "failed": False,
  122. "newPasswd": new_passwd }
  123. except Exception as e:
  124. return jsonify({ "failed": True, "reason": str(e) })
  125. return jsonify(result)
  126. @app.route('/groups', methods=['POST'])
  127. def group_list():
  128. try:
  129. g = Group(request.json['username'], request.json['password'])
  130. result = {
  131. "failed": False,
  132. "groups": { group[0]: group[1] for group in g.group_list() }
  133. }
  134. except Exception as e:
  135. return jsonify({"failed": True, "reason": str(e)})
  136. return jsonify(result)
  137. @app.route('/reset_password/<target_user>', methods=['POST'])
  138. def reset_password(target_user):
  139. try:
  140. g = Group(request.form['username'], request.form['password'])
  141. newpasswd = g.reset_password(target_user)
  142. except Exception as e:
  143. return jsonify({"failed": True, "reason": str(e)})
  144. return jsonify({"failed": False, "passwd": newpasswd})
  145. if __name__ == "__main__":
  146. app.run(host='127.0.0.1')