This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
mandaye/mandaye/backends/ldap_back.py

156 lines
6.7 KiB
Python

import json
import ldap
import ldap.modlist
import random
from datetime import datetime
from mandaye import config
from mandaye.log import logger
from mandaye.backends.default import storage_conn
def cmp_reverse_last_connection_date(x, y):
return -cmp(x[1]['lastConnectionDate'][0], y[1]['lastConnectionDate'][0])
class Association(object):
"""
association dictionary return by the following methods:
{
'id': '', # identifier of your association (must be unique)
'sp_name': '', # name of the service provider (defined in the mappers)
'sp_login': '', # login on the service provider
'sp_post_values': '', # the post values for sp login form
'idp_unique_id:': '', # the unique identifier of the identity provider (ex.: a saml NameID)
'idp_name': '', # identity provide name
'last_connection': datetime.datetime, # last connection with this association
'creation_date': datetime.datetime, # creation date of this association
}
"""
@staticmethod
def ldap2association(ldap_object):
return {
'id': ldap_object['uniqueID'][0],
'sp_name': ldap_object['spName'][0],
'sp_login': ldap_object['spLogin'][0],
'sp_post_values': json.loads(ldap_object['spPostValues'][0]),
'idp_unique_id': ldap_object['idpUniqueID'][0],
'idp_name': ldap_object['idpName'][0],
'last_connection': datetime.strptime(
ldap_object['lastConnectionDate'][0][:14],
'%Y%m%d%H%M%S'),
'creation_date': datetime.strptime(
ldap_object['creationDate'][0][:14],
'%Y%m%d%H%M%S'),
}
@staticmethod
def get(sp_name, idp_unique_id, idp_name='default'):
""" return a list of dict with associations matching all of this options """
associations = []
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(spName=%s)(idpUniqueID=%s)(idpName=%s))' % (sp_name, idp_unique_id, idp_name))
for result in results:
associations.append(Association.ldap2association(result[1]))
return associations
@staticmethod
def get_by_id(asso_id):
""" return a dict of the association with the id or None if it doesn't exist """
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(uniqueID=%s))' %\
(asso_id))
if results:
return Association.ldap2association(results[0][1])
return None
@staticmethod
def has_id(asso_id):
""" check the given user is present in the directory """
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(uniqueID=%s))' %\
(asso_id))
if results:
return True
return False
@staticmethod
def update_or_create(sp_name, sp_login, sp_post_values, idp_unique_id,
idp_name='default', creation_date=None, last_connection_date=None):
""" update or create an associtaion which match the following values
return the association id
"""
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(spName=%s)(spLogin=%s)(idpUniqueID=%s)(idpName=%s))' %\
(sp_name, sp_login, idp_unique_id, idp_name))
if not results:
creation_date = creation_date or datetime.utcnow()
last_connection_date = last_connection_date or datetime.utcnow()
association = {'spName': str(sp_name),
'spLogin': str(sp_login),
'spPostValues': json.dumps(sp_post_values),
'idpUniqueID': str(idp_unique_id),
'idpName': str(idp_name),
'creationDate': creation_date.strftime('%Y%m%d%H%M%SZ'),
'lastConnectionDate': last_connection_date.strftime('%Y%m%d%H%M%SZ'),
'objectClass': 'MandayeUser'
}
mod_list = ldap.modlist.addModlist(association)
while True:
unique_id = random.randint(1, 5000000)
dn = "uniqueID=%s,%s" % (unique_id, config.ldap_base_dn)
try:
result = storage_conn.add_s(dn, mod_list)
except ldap.ALREADY_EXISTS:
continue
break
logger.info("New association %r with %r", sp_login, idp_unique_id)
return unique_id
else:
results.sort(cmp_reverse_last_connection_date)
dn = results[0][0]
mod_list = [(ldap.MOD_REPLACE, 'spPostValues', json.dumps(sp_post_values))]
storage_conn.modify_s(dn, mod_list)
logger.info("Update post values for %r (%r)", sp_login, idp_unique_id)
return results[0][1]['uniqueID'][0]
@staticmethod
def delete(asso_id):
""" delete the association which has the following asso_id """
dn = "uniqueID=%s,%s" % (asso_id, config.ldap_base_dn)
storage_conn.delete_s(dn)
logger.info('Delete %r association', dn)
@staticmethod
def get_last_connected(sp_name, idp_unique_id, idp_name='default'):
""" get the last connecting association which match the parameters
return a dict of the association
"""
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(spName=%s)(idpUniqueID=%s)(idpName=%s))' % (sp_name, idp_unique_id, idp_name))
if results:
results.sort(cmp_reverse_last_connection_date)
return Association.ldap2association(results[0][1])
return None
@staticmethod
def update_last_connection(asso_id):
""" update the association last connection time with the current time
return a dict of the association
"""
last_connection = datetime.utcnow().strftime("%Y%m%d%H%M%SZ")
dn = "uniqueID=%s,%s" % (asso_id, config.ldap_base_dn)
mod_list = [(ldap.MOD_REPLACE, 'lastConnectionDate', last_connection)]
storage_conn.modify_s(dn, mod_list)
@staticmethod
def has_sp_login(sp_login, sp_name):
results = storage_conn.search_s(config.ldap_base_dn, ldap.SCOPE_ONELEVEL,
filterstr='(&(objectClass=MandayeUser)(spName=%s)(spLogin=%s))' %\
(sp_name, sp_login))
if results:
return True
return False