forked from jeanGaston/RF-AD
194 lines
7.1 KiB
Python
194 lines
7.1 KiB
Python
from datetime import datetime
|
|
import ldap
|
|
import sqlite3
|
|
import threading
|
|
import schedule
|
|
from env import DOOR_ACCESS_GROUPS_DN, LDAPPASS, LDAPUSER, LDAP_SERVER, USERS_DN
|
|
|
|
|
|
# Function to initialize LDAP connection
|
|
def initialize_ldap_connection():
|
|
"""
|
|
## Settings :
|
|
None
|
|
## Behavior
|
|
Init the connection to the LDAP server.
|
|
Return LDAPobjet instance when connected
|
|
if it fail, return None and print error code
|
|
"""
|
|
try:
|
|
connect = ldap.initialize(LDAP_SERVER)
|
|
connect.set_option(ldap.OPT_REFERRALS, 0)
|
|
connect.simple_bind_s(LDAPUSER, LDAPPASS)
|
|
print(f"[{datetime.now()}] LDAP connection successful.")
|
|
return connect
|
|
except ldap.LDAPError as e:
|
|
print(f"[{datetime.now()}] LDAP Error: {e}")
|
|
return None
|
|
|
|
|
|
# Function to retrieve users from LDAP
|
|
def retrieve_users_from_ldap(ldap_connection):
|
|
"""
|
|
## Settings :
|
|
- ldap_connection : LDAPobjet instance
|
|
## Behavior
|
|
retrieve the users in the specified OU
|
|
Return result when it success
|
|
if it fail, return empty list and print error code
|
|
"""
|
|
try:
|
|
result = ldap_connection.search_s(
|
|
USERS_DN, ldap.SCOPE_SUBTREE, "(objectClass=user)"
|
|
)
|
|
return result
|
|
except ldap.LDAPError as e:
|
|
print(f"[{datetime.now()}] LDAP Error: {e}")
|
|
return []
|
|
|
|
|
|
# Function to retrieve groups from LDAP
|
|
def retrieve_groups_from_ldap(ldap_connection):
|
|
"""
|
|
## Settings :
|
|
- ldap_connection : LDAPobjet instance
|
|
## Behavior
|
|
retrieve the groups in the specified OU
|
|
Return result when it success
|
|
if it fail, return empty list and print error code
|
|
"""
|
|
try:
|
|
result = ldap_connection.search_s(
|
|
DOOR_ACCESS_GROUPS_DN, ldap.SCOPE_SUBTREE, "(objectClass=group)"
|
|
)
|
|
return result
|
|
except ldap.LDAPError as e:
|
|
print(f"[{datetime.now()}]LDAP Error: {e}")
|
|
return []
|
|
|
|
|
|
# Function to add user to the database or update if already exists
|
|
def add_user_to_database(conn, cursor, upn, rfid_uid, member_of):
|
|
try:
|
|
cursor.execute("SELECT * FROM Users WHERE upn=?", (upn,))
|
|
existing_user = cursor.fetchone()
|
|
if existing_user:
|
|
# User already exists, check if data needs to be updated
|
|
if existing_user[1] != rfid_uid or existing_user[2] != member_of:
|
|
cursor.execute(
|
|
"UPDATE Users SET rFIDUID=?, MemberOf=? WHERE upn=?",
|
|
(rfid_uid, member_of, upn),
|
|
)
|
|
conn.commit()
|
|
print(f"[{datetime.now()}] User '{upn}' updated in the database.")
|
|
else:
|
|
print(
|
|
f"[{datetime.now()}] User '{upn}' already exists in the database with the same data."
|
|
)
|
|
else:
|
|
# User doesn't exist, insert new user
|
|
cursor.execute(
|
|
"INSERT INTO Users (upn, rFIDUID, MemberOf) VALUES (?, ?, ?)",
|
|
(upn, rfid_uid, member_of),
|
|
)
|
|
conn.commit()
|
|
print(f"[{datetime.now()}] User '{upn}' added to the database.")
|
|
except sqlite3.Error as e:
|
|
print(f"SQLite Error: {e}")
|
|
|
|
|
|
# Function to add group to the database or update if already exists
|
|
def add_group_to_database(conn, cursor, cn):
|
|
try:
|
|
cursor.execute("SELECT * FROM Groups WHERE cn=?", (cn,))
|
|
existing_group = cursor.fetchone()
|
|
if existing_group:
|
|
# Group already exists, no need to update
|
|
print(f"[{datetime.now()}] Group '{cn}' already exists in the database.")
|
|
else:
|
|
# Group doesn't exist, insert new group
|
|
cursor.execute("INSERT INTO Groups (cn) VALUES (?)", (cn,))
|
|
conn.commit()
|
|
print(f"[{datetime.now()}] Group '{cn}' added to the database.")
|
|
except sqlite3.Error as e:
|
|
print(f"SQLite Error: {e}")
|
|
|
|
|
|
# Function to sync LDAP users and groups to the database
|
|
def sync_ldap_to_database(db_file):
|
|
"""
|
|
Syncs LDAP users and groups to the SQLite database.
|
|
|
|
Args:
|
|
db_file (str): The path to the SQLite database file.
|
|
|
|
Returns:
|
|
None
|
|
|
|
This function connects to the LDAP server, retrieves user and group information,
|
|
and synchronizes it with the SQLite database. It checks if users are disabled in
|
|
LDAP and removes them from the database if necessary. It also ensures that users
|
|
and groups are added or updated in the database according to the LDAP information.
|
|
|
|
Note:
|
|
The LDAP connection must be properly configured and the LDAP server accessible
|
|
from the machine running this script.
|
|
"""
|
|
ldap_conn = initialize_ldap_connection()
|
|
if ldap_conn:
|
|
conn = sqlite3.connect(db_file)
|
|
cursor = conn.cursor()
|
|
|
|
# Retrieve users from LDAP and add them to the database
|
|
users = retrieve_users_from_ldap(ldap_conn)
|
|
for dn, user_info in users:
|
|
upn = user_info.get("userPrincipalName", [""])[0]
|
|
rfid_uid = user_info.get("rFIDUID", [""])[0]
|
|
member_of = [
|
|
group.decode("utf-8").split(",")[0].split("=")[1]
|
|
for group in user_info.get("memberOf", [])
|
|
]
|
|
|
|
# Check if the user is disabled in LDAP
|
|
user_account_control = user_info.get("userAccountControl", [0])[0]
|
|
if (
|
|
user_account_control == b"514" or user_account_control == b"66050"
|
|
): # Check if the 9th bit is set (ADS_UF_ACCOUNTDISABLE flag)
|
|
# User is disabled, check if user exists in the database and remove if present
|
|
cursor.execute("SELECT * FROM Users WHERE upn=?", (upn,))
|
|
existing_user = cursor.fetchone()
|
|
if existing_user:
|
|
cursor.execute("DELETE FROM Users WHERE upn=?", (upn,))
|
|
conn.commit()
|
|
print(
|
|
f"[{datetime.now()}] User '{upn}' disabled in LDAP and removed from the database."
|
|
)
|
|
else:
|
|
print(
|
|
f"[{datetime.now()}] User '{upn}' disabled in LDAP but not present in the database."
|
|
)
|
|
continue # Skip adding the disabled user to the database
|
|
|
|
# User is not disabled, add or update user in the database
|
|
add_user_to_database(conn, cursor, upn, rfid_uid, ", ".join(member_of))
|
|
|
|
# Retrieve groups from LDAP and add them to the database
|
|
groups = retrieve_groups_from_ldap(ldap_conn)
|
|
for dn, group_info in groups:
|
|
cn = group_info.get("cn", [""])[0].decode("utf-8")
|
|
add_group_to_database(conn, cursor, cn)
|
|
|
|
# Close connections
|
|
conn.close()
|
|
ldap_conn.unbind()
|
|
|
|
|
|
def run_sync_ldap_to_database_thread(db_file):
|
|
print(f"[{datetime.now()}] Running LDAP sync")
|
|
threading.Thread(target=sync_ldap_to_database, args=(db_file,), daemon=True).start()
|
|
|
|
|
|
def schedule_sync_ldap_to_database(db_file):
|
|
run_sync_ldap_to_database_thread(db_file) # Run immediately
|
|
schedule.every(5).minutes.do(run_sync_ldap_to_database_thread, db_file)
|