"""Authenticate against ADSI.

One thing to note -- getting a user roles via ADSI was *very* slow,
and this slowed down logins a lot. So instead, I load all user's roles
once and cache them in memory. This probably is not very efficient
if you have more than a few hundred users...
"""

from win32com import adsi
import win32com, pythoncom, win32security, win32con
import thread

_tmap_={}

def ensure_init():
    # waaa - make sure CoInitialize has been
    # called for this thread...
    id=thread.get_ident()
    if _tmap_.get(id, None) is not None:
        # this thread has been done already!
        return
    # otherwise we need to do it...
    pythoncom.CoInitialize()
    _tmap_[id]=1
    return


# utility methods for making the roles cache

def allUsers():
    """Return a list of all user names."""
    result = []
    ensure_init()
    o = adsi.ADsGetObject("WinNT://Mainnt")
    for r in o:
        if str(r.Class) == 'User': result.append(str(r.Name))
    return result

def cacheUsersRoles():
    """Install all the users' roles into the roles cache."""
    for username in allUsers():
        pythoncom.roles_cache[username] = getUserGroups(username)

def getUserGroups(username):
    """Get the roles for a specific user."""
    roles = []
    ensure_init()
    o = adsi.ADsGetObject("WinNT://Mainnt/%s" % username)
    if str(o.Class) == 'User':
        for r in o.Groups(): roles.append(str(r.Name))
    return roles

# we store the roles cache in win32com so it's persistent across
# extension reloads.
# don't erase cache if it already exists
if not hasattr(pythoncom, "roles_cache"):
    pythoncom.roles_cache = {}
    cacheUsersRoles() # load users into cache


# interfaces for user source

def userExists(client=None, REQUEST=None, username=""):
    """ Check if user exists """
    try:
        ensure_init()
        o = adsi.ADsGetObject("WinNT://Mainnt/%s" % username)
        if str(o.Class) == 'User': return 1
    except:
        pass
    return 0

def userAuthenticate(client=None, REQUEST=None, username="", password=""):
    """ Authenticate user/password pair """
    try:
        handel=win32security.LogonUser(username,'mandelschool.org.il',password ,win32con.LOGON32_LOGON_INTERACTIVE,win32con.LOGON32_PROVIDER_DEFAULT)
        result = 1
    except:
        result = 0
    return result

def userRoles(client=None, REQUEST=None, username=""):
    """Return a user's roles from the cache."""
    try:
        return pythoncom.roles_cache[username]
    except KeyError:
        return []


# test code

def getCache():
    """Return role cache."""
    import time
    return "cache at %s is %s" % (time.time(), str(pythoncom.roles_cache))

def test(username):
    ensure_init()
    import win32com.client
    ns = win32com.client.Dispatch("ADsNameSpaces")
    ntNS = ns.getobject("","WinNT:")
    o = ntNS.OpenDSObject("WinNT://Mainnt/%s" % username, "itamar", "spoon", 0)
    return str(o.Class)

if __name__=='__main__':
    print "Testing 'userExists', 'userRoles':"
    for name in ["maxima", "Administrator", "haimc", "Users"]:
        print "User %s" % name,
        if userExists(None, None, username=name):
            print "exists, with roles %s." % userRoles(None, None, username=name)
        else: print "does not exist."
    print
    print "Testing 'userAuthenticate':"
    for u, p in (("itamar", "spoon"), ("foo", "fsa"), ("fsa", "fas")):
        print "%s / %s is" % (u, p),
        if userAuthenticate(None, None, username=u, password=p): print "auth."
        else: print "not auth."
    print
    #print "All users:", allUsers()