Ejemplo n.º 1
0
    def VerifyUserInfo(self):
        ''' Verify user information: check for LocalUserId and add VOName and ReportableVOName if necessary'''

        id_info = {}  # Store attributes of already-present information
        interesting_keys = ['LocalUserId', 'VOName', 'ReportableVOName']
        for wanted_key in interesting_keys:  # Loop over wanted keys
            item_index = 0
            for id_item in self.UserId:  # Loop over existing entries in UserId block

                # Look for key

                match = re.search(
                    r'<\s*(?:[^:]*:)?' + wanted_key +
                    r'\s*>\s*(?P<Value>.*?)\s*<\s*/', id_item, re.IGNORECASE)

                # Store info

                if match:
                    id_info[wanted_key] = {
                        'Value': match.group('Value'),
                        'Index': item_index
                    }
                    break

                item_index += 1

        if 'LocalUserId' not in id_info or len(id_info) == len(
                interesting_keys):  # Nothing to do
            return

        # Obtain user->VO info from reverse gridmap file.

        vo_info = vo.VOfromUser(id_info['LocalUserId']['Value'])
        if vo_info != None:

            # If we already have one of the two, update both to remain consistent.

            for key in ('VOName', 'ReportableVOName'):
                if key in id_info:  # Replace existing value
                    self.UserId[id_info[key]['Index']] = re.sub(
                        r'(>\s*)' + re.escape(id_info[key]['Value']) +
                        r'(\s*<)', r'\1' + vo_info[key] + r'\2',
                        self.UserId[id_info[key]['Index']], 1)
                else:

                    # Add new

                    self.UserId = self.AddToList(self.UserId, key, r'',
                                                 vo_info[key])
def CheckAndExtendUserIdentity(
    xmlDoc,
    userIdentityNode,
    namespace,
    prefix,
):
    '''Check the contents of the UserIdentity block and extend if necessary
    - if Local user ID is not in the XML, then abort and return {}
    - if there are multiple (>1) VOName or ReportableVOName nodes then the XML is malformed,
      abort and return {}
    - otherwise get VOName, ReportableVOName from existing XML (if FQAN), certinfo file, Condor-CE, 
      existing XML (also if not FQAN), reverse map file; update the values in XML and return them
    - result, dictionary w/ VOName, ReportableVOName and has_certinfo
    '''

    result = {}
    jobIdType, jobId = None, None

    # LocalUserId, used in log messages or to guess VO if all else fails
    localUserIdNodes = userIdentityNode.getElementsByTagNameNS(
        namespace, 'LocalUserId')
    if not localUserIdNodes or localUserIdNodes.length != 1 or not (
            localUserIdNodes[0].firstChild
            and localUserIdNodes[0].firstChild.data):
        [jobIdType, jobId] = FindBestJobId(userIdentityNode.parentNode,
                                           namespace)
        DebugPrint(
            0, 'Warning: UserIdentity block does not have exactly ',
            'one populated LocalUserId node in ' + jobIdType + ' ' + jobId)
        return result

    LocalUserId = localUserIdNodes[0].firstChild.data

    # VOName

    VONameNodes = userIdentityNode.getElementsByTagNameNS(namespace, 'VOName')
    if VONameNodes and VONameNodes.length == 1:
        if VONameNodes[0].hasChildNodes():
            if not VONameNodes[0].firstChild.data:
                [jobIdType, jobId] = FindBestJobId(userIdentityNode.parentNode,
                                                   namespace)
                DebugPrint(
                    0,
                    'Warning: UserIdentity block has VOName node, but value is set to None  in '
                    + jobIdType + ' ' + jobId)
                VONameNodes = None
        else:
            VONameNodes = None
    if not VONameNodes:
        DebugPrint(4, 'DEBUG: Creating VONameNodes elements')
        VONameNodes = []
        VONameNodes.append(xmlDoc.createElementNS(namespace,
                                                  prefix + 'VOName'))
        textNode = xmlDoc.createTextNode(r'')
        VONameNodes[0].appendChild(textNode)
        userIdentityNode.appendChild(VONameNodes[0])
        DebugPrint(4, 'DEBUG: Creating VONameNodes elements DONE')
    elif VONameNodes.length > 1:
        [jobIdType, jobId] = FindBestJobId(userIdentityNode.parentNode,
                                           namespace)
        DebugPrint(
            0, 'Warning: UserIdentity block has multiple VOName nodes in ' +
            jobIdType + ' ' + jobId)
        return result

    # ReportableVOName

    ReportableVONameNodes = userIdentityNode.getElementsByTagNameNS(
        namespace, 'ReportableVOName')
    if not ReportableVONameNodes:
        DebugPrint(4, 'DEBUG: Creating ReortableVONameNodes elements')
        ReportableVONameNodes.append(
            xmlDoc.createElementNS(namespace, prefix + 'ReportableVOName'))
        textNode = xmlDoc.createTextNode(r'')
        ReportableVONameNodes[0].appendChild(textNode)
        userIdentityNode.appendChild(ReportableVONameNodes[0])
        DebugPrint(4, 'DEBUG: Creating ReortableVONameNodes elements DONE')
    elif len(ReportableVONameNodes) > 1:
        [jobIdType, jobId] = FindBestJobId(userIdentityNode.parentNode,
                                           namespace)
        DebugPrint(0, 'Warning: UserIdentity block has multiple ',
                   'ReportableVOName nodes in ' + jobIdType + ' ' + jobId)
        return result

    # ###################################################################
    # Priority goes as follows:
    #
    # 1. Existing VOName if FQAN.
    #
    # 2. Certinfo.
    #
    # 3. Condor-CE direct query
    #
    # 4. Existing VOName if not FQAN.
    #
    # 5. VOName from reverse map file.
    #
    # If 1 has no value or invalid values, the first one of 2, 3, 4, 5 assigns the value (and other ar enot checked)

    vo_info = None
    no_initial_values = True
    real_fqan = False

    # 1. Initial values

    DebugPrint(4, 'DEBUG: reading initial VOName')
    VOName = VONameNodes[0].firstChild.data
    DebugPrint(4, 'DEBUG: current VOName = ' + VONameNodes[0].firstChild.data)

    DebugPrint(4, 'DEBUG: reading initial ReportableVOName')
    ReportableVOName = ReportableVONameNodes[0].firstChild.data
    DebugPrint(
        4, 'DEBUG: current ReportableVOName = ' +
        ReportableVONameNodes[0].firstChild.data)

    # 2. Certinfo (if initial values are not OK)

    if VOName and VOName[0] == r'/':
        # Initial values are valid (1)
        # Information is available and is FQAN (starts with /)
        # Must delete possible certinfo file also when all information is available
        DebugPrint(4, 'DEBUG: Calling removeCertInfoFile')
        certinfo.removeCertInfoFile(xmlDoc, userIdentityNode, namespace)
        # Must set has_certinfo (to avoid to be considered local)
        result['has_certinfo'] = 1
        no_initial_values = False
    else:
        # Use certinfo
        DebugPrint(4, 'DEBUG: Calling verifyFromCertInfo')
        # look for vo_info and delete certinfo file
        vo_info = certinfo.verifyFromCertInfo(xmlDoc, userIdentityNode,
                                              namespace)
        DebugPrint(4, 'DEBUG: Calling verifyFromCertInfo: DONE')
        if vo_info:
            result['has_certinfo'] = 1
            if not (vo_info['VOName'] or vo_info['ReportableVOName']):
                DebugPrint(4, 'DEBUG: No VOName data from verifyFromCertInfo')
                vo_info = None  # Reset if no output.

        # need this because vo_info could have been reset above or may not have been set
        if vo_info:
            DebugPrint(
                4, 'DEBUG: Received values VOName: ' + str(vo_info['VOName']) +
                ' and ReportableVOName: ' + str(vo_info['ReportableVOName']))
            tmpVOName = vo_info['VOName']
            if vo_info['ReportableVOName'] == None:
                if tmpVOName[0] == r'/':
                    vo_info['ReportableVOName'] = string.split(VOName, r'/')[1]
                else:
                    vo_info['ReportableVOName'] = tmpVOName

    # 3. Condor-CE query

    if no_initial_values and not vo_info:
        DebugPrint(4, "Querying the Condor-CE directly")
        jobIdentityNode = certinfo.GetNode(
            xmlDoc.getElementsByTagNameNS(namespace, 'JobIdentity'))
        if jobIdentityNode:
            localJobId = certinfo.GetNodeData(
                jobIdentityNode.getElementsByTagNameNS(namespace,
                                                       'LocalJobId'))
            if localJobId:
                job_certinfo = condor_ce.queryJob(localJobId)
                if job_certinfo:
                    vo_info = certinfo.populateFromCertInfo(
                        job_certinfo, xmlDoc, userIdentityNode, namespace)

    try:
        if vo_info['VOName'][0] == r'/':
            real_fqan = True
    except:
        # Could be NameError, TypeError, KeyError, IndexError
        pass

    # 4. & 5.

    if no_initial_values and not vo_info:
        DebugPrint(4, 'DEBUG: Calling VOfromUser')
        vo_info = vo.VOfromUser(LocalUserId)
        if Config.get_MapUnknownToGroup() and not vo_info:
            fromuserid = LocalUserId
            groupid = "unknown"
            try:
                gid = pwd.getpwnam(LocalUserId)[3]
                fromuserid = grp.getgrgid(gid)[0]
                groupid = fromuserid
            except:
                pass

            # Check the differen VO mapping methods
            if Config.get_MapGroupToRole() and Config.get_VOOverride():
                # TODO: FQAN syntax is  <group>[/Role=[<role>][/Capability=<capability>]]
                # Group is part of the path, otherwise there are Role and Capability, no LocalGroup
                vo_info = {
                    'VOName':
                    "/%s/LocalGroup=%s" % (Config.get_VOOverride(), groupid),
                    'ReportableVOName':
                    Config.get_VOOverride()
                }
            elif Config.get_VOOverride():
                vo_info = {
                    'VOName': Config.get_VOOverride(),
                    'ReportableVOName': Config.get_VOOverride()
                }
            else:
                vo_info = {
                    'VOName': fromuserid,
                    'ReportableVOName': fromuserid
                }

    # Resolve.

    if vo_info:
        DebugPrint(
            4,
            'DEBUG: Deciding wether to use the new vo_info (%s, %s, %s, %s)' %
            (VOName, ReportableVOName, no_initial_values, real_fqan))
        if not (VOName and ReportableVOName) or VOName == 'Unknown' or (
                no_initial_values and real_fqan):
            # Update the VO values if:
            # 1. one of the initial VOName, ReportableVOName was null or empty OR
            # 2. the initial VOName is 'Unknown' OR
            # 3. the initial VOName is not a FQAN and vo_info['VOName'] is a real FQAN (from certinfo or HTCondor-CE)
            if vo_info['VOName'] == None:
                vo_info['VOName'] = r''
            if vo_info['ReportableVOName'] == None:
                vo_info['ReportableVOName'] = r''
            DebugPrint(
                4, 'DEBUG: Updating VO info: (' + vo_info['VOName'] + r', ' +
                vo_info['ReportableVOName'] + ')')

            # VO info from reverse mapfile only overrides missing or
            # inadequate data.

            VONameNodes[0].firstChild.data = vo_info['VOName']
            ReportableVONameNodes[0].firstChild.data = vo_info[
                'ReportableVOName']

    VOName = VONameNodes[0].firstChild.data
    ReportableVOName = ReportableVONameNodes[0].firstChild.data

    DebugPrint(4, 'DEBUG: final VOName = ' + VOName)
    DebugPrint(4, 'DEBUG: final ReportableVOName = ' + ReportableVOName)

    # ###################################################################

    # Clean up.

    if not VOName:
        userIdentityNode.removeChild(VONameNodes[0])
        VONameNodes[0].unlink()

    if not ReportableVOName:
        userIdentityNode.removeChild(ReportableVONameNodes[0])
        ReportableVONameNodes[0].unlink()

    result['VOName'] = VOName
    result['ReportableVOName'] = ReportableVOName

    return result