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

import re
import subprocess
import syslog
import xml.etree.ElementTree

from django.conf import settings
from django.contrib import messages

from authentic2.authsaml2 import signals
from sp import pfconfigxml

COMMENT=re.compile('^\s*($|#)')

def user_login_cb(sender, request, attributes={}, **kwargs):
    if request and request.user.is_anonymous():
        return

    cpzone = request.META.get('HTTP_X_PFSENSE_CPZONE') or '';
 
    if 'displayName' in attributes:
        request.session['display_name'] = attributes['displayName'][0]

    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
    username = eduPersonTargetedID + '|' + eduPersonTargetedID_NameQualifier

    ip = request.META['REMOTE_ADDR']

    # user blacklist
    try:
        nameid_bl = pfconfigxml.get_blacklists('nameid')
        for line in nameid_bl.splitlines(True):
            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::], username):
                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" % (username, ip))
                return False
            elif userbl.strip() == username:
                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" % (username, ip))
                return False
    except:
        pass

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

    cmd = [ c % {
            'cpzone': cpzone,
            'ip': ip,
            'username': username,
            'nameid': nameid,
            'multiple': multiple,
            } for c in settings.UNIVNAUTES_CP_ALLOW_CMD ]

    if settings.DEBUG:
        syslog.openlog("sp/auth", syslog.LOG_PID)
        syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_DEBUG , 'meta: %r' % request.META)
        syslog.syslog(syslog.LOG_LOCAL4 | syslog.LOG_DEBUG , "cmd: %r" % ' '.join(cmd))

    # open the firewall for this client
    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 : OSError %s" % e)
        syslog.openlog("sp/auth", 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 : returncode=%d" % p.returncode)
        syslog.openlog("sp/auth", 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
    request.session['prefered_idp'] = attributes['__issuer']
    return True

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

