#!/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.exception import Duplicate

from VOMSAdmin.VOMSCommands import VOMSAdminProxy


os.environ['X509_USER_PROXY'] = '/opt/rucio/etc/ddmadmin.proxy.nagios'
cert, key = os.environ['X509_USER_PROXY'], os.environ['X509_USER_PROXY']

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__':

    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')
    # print cert, key
    # print res
    if isinstance(res, types.ListType):
        for user in res:
            nbusers += 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
                # print dn, ca, email, nickname
                # nickname = None
                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:
                            # print 'Account %(account)s already added' % locals()
                            pass
                        try:
                            c.add_identity(account=account, identity=dn, authtype='X509', email=email, default=True)
                            print 'Identity %(dn)s added' % locals()
                        except Duplicate:
                            # print 'Identity %(account)s already added' % locals()
                            pass
                        try:
                            scope = 'user.' + account
                            c.add_scope(account, scope)
                            print 'Scope %(scope)s added' % locals()
                        except Duplicate:
                            # print 'Scope %(scope)s already added' % locals()
                            pass
                else:
                    nonicknames.append(user._DN)
            except:
                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)
