# -*- encoding: utf-8 -*-

import subprocess
import settings
from django.contrib import messages

from authentic2.authsaml2 import signals

import xml.etree.ElementTree
import re
COMMENT=re.compile('^\s*($|#)')
import syslog

def user_login_cb(sender, request, attributes={}, **kwargs):
    if request and request.user.is_anonymous():
        return
    nameid = 'nameID:%s' % attributes['__nameid']
    # use eduPersonTargetedID (OID 1.3.6.1.4.1.5923.1.1.1.10), fallback to __nameid/__issuer
    try:
        if 'eduPersonTargetedID' in attributes:
            attrkey = 'eduPersonTargetedID'
        else:
            attrkey = ('urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri')
        eduPersonTargetedID_xml = xml.etree.ElementTree.fromstring(attributes[attrkey][0])
        eduPersonTargetedID = 'eduPersonTargetedID:%s' % eduPersonTargetedID_xml.text
        eduPersonTargetedID_NameQualifier = eduPersonTargetedID_xml.attrib['NameQualifier']
    except:
        eduPersonTargetedID = nameid
        eduPersonTargetedID_NameQualifier = attributes['__issuer']

    # log needs eduPersonTargetedID + transientID + idp
    user = eduPersonTargetedID + '|' + eduPersonTargetedID_NameQualifier

    ip = request.META['REMOTE_ADDR']

    # user blacklist
    try:
        userblfile = open( settings.USERBL, 'r' )
        for line in userblfile:
            if COMMENT.match(line):
                continue
            userbl = line.strip()
            # if the line starts with ~, it's a regex
            if userbl[0] == '~' and re.match(userbl[1::], user):
                userblfile.close()
                request.session['pfsenseid'] = 'BLACKLISTED'
                messages.error(request, u"Connexion refusée (règle dans une liste noire).")
                syslog.openlog("logportalauth", syslog.LOG_PID)
                syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_INFO , "BLACKLISTED-REGEX: %s,,%s" % (user, ip))
                return False
            elif userbl.strip() == user:
                userblfile.close()
                request.session['pfsenseid'] = 'BLACKLISTED'
                messages.error(request, u"Connexion refusée (présent dans une liste noire).")
                syslog.openlog("logportalauth", syslog.LOG_PID)
                syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_INFO , "BLACKLISTED: %s,,%s" % (user, ip))
                return False
        userblfile.close()
    except:
        pass

    # univnautes idp returns univnautesPrivileges attribute (a list)
    privileges = attributes.get((u'univnautesPrivileges', u'urn:oasis:names:tc:SAML:2.0:attrname-format:basic'), [])

    # open the firewall for this client
    if 'univnautes-idp-multiple' in privileges:
        cmd = ['cp_allow', 'ip=%s' % ip, 'username=%s' % user, 'nameid=%s' % nameid, 'univnautes_concurrentlogins=1']
        syslog.openlog("logportalauth", syslog.LOG_PID)
        syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_INFO ,
                "INFO: %s with privilege univnautes-idp-multiple (multiple connexions)" % user)
    else:
        cmd = ['cp_allow', 'ip=%s' % ip, 'username=%s' % user, 'nameid=%s' % nameid]
    try:
        p = subprocess.Popen(cmd, close_fds=True,
                        stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
    except OSError, e:
        request.session['pfsenseid'] = 'ERROR'
        messages.error(request, u"Erreur lors de l'autorisation sur le pare-feu (OSError %s)." % e)
        syslog.openlog("logportalauth", syslog.LOG_PID)
        syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_INFO , "ERROR: OSError %s" % e)
        return False
    stdout, stderr = p.communicate()
    if p.returncode != 0:
        request.session['pfsenseid'] = 'ERROR'
        messages.error(request, u"Erreur lors de l'autorisation sur le pare-feu (returncode=%d)." % p.returncode)
        syslog.openlog("logportalauth", syslog.LOG_PID)
        syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_INFO , "ERROR: returncode=%d" % p.returncode)
        return False
    # cp_allow returns the pfsense CP sessionid on stdout
    # store it in django session
    request.session['pfsenseid'] = stdout
    # also store some informations about the user (for views)
    request.session['prefered_idp'] = attributes['__issuer']
    if 'displayName' in attributes:
        request.session['display_name'] = attributes['displayName'][0]
    return True

def user_logout_cb(sender, user, **kwargs):
    # note : cp_disconnect is called by views.logout (it needs request)
    pass

signals.auth_login.connect(user_login_cb, dispatch_uid='authentic2.idp')
signals.auth_logout.connect(user_logout_cb, dispatch_uid='authentic2.idp')

