#!/usr/bin/env python
# Copyright European Organization for Nuclear Research (CERN)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#                       http://www.apache.org/licenses/LICENSE-2.0
#
# Authors:
# - Vincent Garonne, <vincent.garonne@cern.ch>, 2012-2013
# - Cedric Serfon, <cedric.serfon@cern.ch>, 2014

import commands
import os
import re
import sys
import types


from rucio.client import Client
from rucio.common.config import config_get
from rucio.common.exception import Duplicate

from VOMSAdmin.VOMSCommands import VOMSAdminProxy


UNKNOWN = 3
CRITICAL = 2
WARNING = 1
OK = 0


def validate_nickname(nickname, email, dn, debug=False):
    # Check bad characters
    badCharacters = ['.', ' ', '@', '#', ' ']
    for c in badCharacters:
        if c in nickname:
            reason = 'Bad Characters in nickname %(nickname)s for %(dn)s' % locals()
            if debug:
                print reason
            return False

    # return True

    # Check lowercase
    if nickname.lower() != nickname:
        reason = 'VOMS nickname %(nickname)s should be lowercase for %(dn)s' % locals()
        if debug:
            print reason
        return False

    # Check CERN account
    cmd = "/usr/bin/ldapsearch -x -h xldap.cern.ch -b 'OU=Users,OU=Organic Units,DC=cern,DC=ch' '(&(objectClass=user) (CN=%(nickname)s))'" % locals()
    status, output = commands.getstatusoutput(cmd)
    ad_email = re.search('mail: (.*)\n', output)
    ad_name = re.search('displayName: (.*)\n', output)
    ad_dn = re.search('dn: (.*)\n', output)

    if not ad_email:
        reason = "VOMS nickname %(nickname)s for %(dn)s doesn't exist as CERN account" % locals()
        if debug:
            print reason
        return False

    # Check mail address
    ad_email = ad_email.groups()[0]
    ad_name = ad_name.groups()[0].replace(' ', '.')+'@cern.ch'
    is_service_Account = 'memberOf: CN=cern-accounts-service,OU=e-groups,OU=Workgroups,DC=cern,DC=ch' in output

    if is_service_Account:
        return False

    if not is_service_Account and email.lower().replace('@mail.cern.ch', '@cern.ch') not in (ad_email.lower(), ad_name.lower(), nickname + '@cern.ch'):
        reason = "Mail mismatch for VOMS nickname %(nickname)s-%(dn)s: %(email)s vs. %(ad_email)s " % locals()
        if debug:
            print reason
        return False

    return True

if __name__ == '__main__':
    try:
        proxy = config_get('nagios', 'proxy')
        os.environ["X509_USER_PROXY"] = proxy
        cert, key = os.environ['X509_USER_PROXY'], os.environ['X509_USER_PROXY']
    except Exception as e:
        print "Failed to get proxy from rucio.cfg"
        sys.exit(CRITICAL)
    status = OK
    nbusers = 0
    nonicknames = []
    c = Client()
    admin = VOMSAdminProxy(vo='atlas', host='voms.cern.ch', port=8443,
                           user_cert=cert, user_key=key)
    res = admin.call_method('list-users')
    if isinstance(res, types.ListType):
        for user in res:
            nbusers += 1
            attempts = 0
            totattemps = 3
            for attempts in xrange(0, totattemps):
                if (attempts < totattemps - 1):
                    try:
                        dn = user._DN
                        ca = user._CA
                        email = user._mail
                        result = admin.call_method('list-user-attributes', dn, ca)
                        nickname = None
                        try:
                            nickname = result[0]._value
                        except TypeError, e:
                            print e
                            pass
                        if nickname:
                            if validate_nickname(nickname=nickname, email=email, dn=dn, debug=True):
                                account = nickname
                                try:
                                    c.add_account(account=account, type='USER')
                                    print 'Account %(account)s added' % locals()
                                except Duplicate:
                                    pass
                                try:
                                    c.add_identity(account=account, identity=dn, authtype='X509', email=email, default=True)
                                    print 'Identity %(dn)s added' % locals()
                                except Duplicate:
                                    pass
                                try:
                                    scope = 'user.' + account
                                    c.add_scope(account, scope)
                                    print 'Scope %(scope)s added' % locals()
                                except Duplicate:
                                    pass
                            else:
                                break
                        elif user._DN not in nonicknames:
                            nonicknames.append(user._DN)
                    except:
                        pass
                else:
                    print 'ERROR getting info for %s' % (user._DN)
                    status = WARNING
    else:
        sys.exit(CRITICAL)
    print '%i users extracted from VOMS' % nbusers
    if nonicknames != []:
        print 'Users with no nickname :'
        print nonicknames

    sys.exit(status)
