예제 #1
0
파일: JobPolicy.py 프로젝트: TaykYoku/DIRAC
    def getControlledUsers(self, right):
        """Get users and groups which jobs are subject to the given access right"""

        userGroupList = "ALL"
        # If allInfo flag is defined we can see info for any job
        if right == RIGHT_GET_INFO and self.allInfo:
            return S_OK(userGroupList)

        # Administrators can do everything
        if Properties.JOB_ADMINISTRATOR in self.userProperties:
            return S_OK(userGroupList)

        # Inspectors can see info for all the jobs
        if Properties.JOB_MONITOR in self.userProperties and right == RIGHT_GET_INFO:
            return S_OK(userGroupList)

        userGroupList = []
        # User can do many things with his jobs
        if Properties.NORMAL_USER in self.userProperties and right in OWNER_RIGHTS:
            result = getGroupsForUser(self.userName)
            if not result["OK"]:
                return result
            groups = result["Value"]
            for group in groups:
                if "NormalUser" in getPropertiesForGroup(group, []):
                    userGroupList.append((self.userName, group))

        # User can do many things with the jobs in the shared group
        if Properties.JOB_SHARING in self.userProperties and right in SHARED_GROUP_RIGHTS:
            sharedUsers = getUsersInGroup(self.userGroup)
            for user in sharedUsers:
                userGroupList.append((user, self.userGroup))

        userGroupList = list(set(userGroupList))
        return S_OK(userGroupList)
예제 #2
0
파일: JobPolicy.py 프로젝트: afalabel/DIRAC
  def getControlledUsers( self, right ):
    """ Get users and groups which jobs are subject to the given access right
    """
    
    userGroupList = 'ALL'
    # If allInfo flag is defined we can see info for any job
    if right == RIGHT_GET_INFO and self.allInfo:
      return S_OK( userGroupList ) 
    
    # Administrators can do everything
    if Properties.JOB_ADMINISTRATOR in self.userProperties:
      return S_OK( userGroupList )
    
    # Inspectors can see info for all the jobs
    if Properties.JOB_MONITOR in self.userProperties and right == RIGHT_GET_INFO:
      return S_OK( userGroupList )  
    
    userGroupList = []
    # User can do many things with his jobs
    if Properties.NORMAL_USER in self.userProperties and right in OWNER_RIGHTS:
      result = getGroupsForUser( self.userName )
      if not result['OK']:
        return result
      groups = result['Value']
      for group in groups:
        if 'NormalUser' in getPropertiesForGroup( group, [] ):
          userGroupList.append( ( self.userName, group ) )
          
    # User can do many things with the jobs in the shared group
    if Properties.JOB_SHARING in self.userProperties and right in SHARED_GROUP_RIGHTS:
      sharedUsers = getUsersInGroup( self.userGroup )
      for user in sharedUsers:
        userGroupList.append( ( user, self.userGroup ) )
        
    userGroupList = list( set( userGroupList ) )    
    return S_OK( userGroupList )  
            
      

      
예제 #3
0
    def __researchDIRACGroup(self, extSession, chooseScope, state):
        """Research DIRAC groups for authorized user

        :param dict extSession: ended authorized external IdP session

        :return: -- will return (None, response) to provide error or group selector
                    will return (grant_user, request) to contionue authorization with choosed group
        """
        # Base DIRAC client auth session
        firstRequest = createOAuth2Request(extSession["firstRequest"])
        # Read requested groups by DIRAC client or user
        firstRequest.addScopes(chooseScope)
        # Read already authed user
        username = extSession["authed"]["username"]
        # Requested arguments in first request
        provider = firstRequest.provider
        self.log.debug("Next groups has been found for %s:" % username, ", ".join(firstRequest.groups))

        # Researche Group
        result = getGroupsForUser(username)
        if not result["OK"]:
            return None, self.server.handle_response(
                payload=getHTML("server error", theme="error", info=result["Message"]), delSession=True
            )
        groups = result["Value"]

        validGroups = [
            group for group in groups if (getIdPForGroup(group) == provider) or ("proxy" in firstRequest.scope)
        ]
        if not validGroups:
            return None, self.server.handle_response(
                payload=getHTML(
                    "groups not found.",
                    theme="error",
                    info=f"No groups found for {username} and for {provider} Identity Provider.",
                ),
                delSession=True,
            )

        self.log.debug("The state of %s user groups has been checked:" % username, pprint.pformat(validGroups))

        # If group already defined in first request, just return it
        if firstRequest.groups:
            return extSession["authed"], firstRequest

        # If not and we found only one valid group, apply this group
        if len(validGroups) == 1:
            firstRequest.addScopes(["g:%s" % validGroups[0]])
            return extSession["authed"], firstRequest

        # Else give user chanse to choose group in browser
        with dom.div(cls="row mt-5 justify-content-md-center align-items-center") as tag:
            for group in sorted(validGroups):
                vo, gr = group.split("_")
                with dom.div(cls="col-auto p-2").add(dom.div(cls="card shadow-lg border-0 text-center p-2")):
                    dom.h4(vo.upper() + " " + gr, cls="p-2")
                    dom.a(href="%s?state=%s&chooseScope=g:%s" % (self.currentPath, state, group), cls="stretched-link")

        html = getHTML(
            "group selection..",
            body=tag,
            icon="users",
            info="Dirac use groups to describe permissions. " "You will need to select one of the groups to continue.",
        )

        return None, self.server.handle_response(payload=html, newSession=extSession)
예제 #4
0
    def syncCSWithVOMS(self):
        """Performs the synchronization of the DIRAC registry with the VOMS data. The resulting
          CSAPI object containing modifications is returned as part of the output dictionary.
          Those changes can be applied by the caller depending on the mode (dry or a real run)


        :return: S_OK with a dictionary containing the results of the synchronization operation
        """
        resultDict = defaultdict(list)

        # Get DIRAC group vs VOMS Role Mappings
        result = getVOMSRoleGroupMapping(self.vo)
        if not result["OK"]:
            return result

        vomsDIRACMapping = result["Value"]["VOMSDIRAC"]
        diracVOMSMapping = result["Value"]["DIRACVOMS"]
        noVOMSGroups = result["Value"]["NoVOMS"]
        noSyncVOMSGroups = result["Value"]["NoSyncVOMS"]

        vomsSrv = VOMSService(self.vo)

        # Get VOMS users
        result = vomsSrv.getUsers()
        if not result["OK"]:
            self.log.error("Could not retrieve user information from VOMS", result["Message"])
            return result

        self.vomsUserDict = result["Value"]
        message = "There are %s user entries in VOMS for VO %s" % (len(self.vomsUserDict), self.vomsVOName)
        self.adminMsgs["Info"].append(message)
        self.log.info("VOMS user entries", message)
        self.log.debug(self.vomsUserDict)

        # Get DIRAC users
        result = self.getVOUserData(self.vo)
        if not result["OK"]:
            return result
        diracUserDict = result["Value"]
        self.adminMsgs["Info"].append(
            "There are %s registered users in DIRAC for VO %s" % (len(diracUserDict), self.vo)
        )
        self.log.info(
            "Users already registered", ": there are %s registered users in DIRAC VO %s" % (len(diracUserDict), self.vo)
        )

        # Find new and obsoleted user DNs
        existingDNs = []
        obsoletedDNs = []
        newDNs = []
        for user in diracUserDict:
            dn = diracUserDict[user]["DN"]
            # We can have users with more than one DN registered
            dnList = fromChar(dn)
            existingDNs.extend(dnList)
            for dn in dnList:
                if dn not in self.vomsUserDict:
                    obsoletedDNs.append(dn)

        for dn in self.vomsUserDict:
            if dn not in existingDNs:
                newDNs.append(dn)

        allDiracUsers = getAllUsers()
        nonVOUserDict = {}
        nonVOUsers = list(set(allDiracUsers) - set(diracUserDict))
        if nonVOUsers:
            result = self.csapi.describeUsers(nonVOUsers)
            if not result["OK"]:
                self.log.error("Could not retrieve CS User description")
                return result
            nonVOUserDict = result["Value"]

        # Process users
        defaultVOGroup = getVOOption(self.vo, "DefaultGroup", "%s_user" % self.vo)
        # If a user is (previously put by hand) in a "QuarantineGroup",
        # then the default group will be ignored.
        # So, this option is only considered for the case of existing users.
        quarantineVOGroup = getVOOption(self.vo, "QuarantineGroup")

        newAddedUserDict = {}
        for dn in self.vomsUserDict:
            newDNForExistingUser = ""
            diracName = ""
            if dn in existingDNs:
                for user in diracUserDict:
                    if dn in fromChar(diracUserDict[user]["DN"]):
                        diracName = user
                        break

            if dn in newDNs:
                # Find if the DN is already registered in the DIRAC CS
                for user in nonVOUserDict:
                    if dn in fromChar(nonVOUserDict[user]["DN"]):
                        diracName = user
                        diracUserDict[diracName] = nonVOUserDict[user]
                        break

                # Check the nickName in the same VO to see if the user is already registered
                # with another DN
                nickName = self.vomsUserDict[dn].get("nickname")
                if nickName in diracUserDict or nickName in newAddedUserDict:
                    diracName = nickName
                    # This is a flag for adding the new DN to an already existing user
                    newDNForExistingUser = dn

                # We have a real new user
                if not diracName:
                    if nickName:
                        newDiracName = nickName
                    else:
                        newDiracName = self.getUserName(dn)

                    # Do not consider users with Suspended status in VOMS
                    if self.vomsUserDict[dn]["suspended"] or self.vomsUserDict[dn]["certSuspended"]:
                        resultDict["SuspendedUsers"].append(newDiracName)
                        continue

                    # If the chosen user name exists already, append a distinguishing suffix
                    ind = 1
                    trialName = newDiracName
                    while newDiracName in allDiracUsers:
                        # We have a user with the same name but with a different DN
                        newDiracName = "%s_%d" % (trialName, ind)
                        ind += 1

                    # We now have everything to add the new user
                    userDict = {"DN": dn, "CA": self.vomsUserDict[dn]["CA"], "Email": self.vomsUserDict[dn]["mail"]}
                    groupsWithRole = []
                    for role in self.vomsUserDict[dn]["Roles"]:
                        groupList = vomsDIRACMapping.get(role, [])
                        for group in groupList:
                            if group not in noSyncVOMSGroups:
                                groupsWithRole.append(group)
                    userDict["Groups"] = list(set(groupsWithRole + [defaultVOGroup]))

                    # Run the sync plugins for extra info and/or validations
                    if self.syncPlugin:
                        try:
                            self.syncPlugin.verifyAndUpdateUserInfo(newDiracName, userDict)
                        except ValueError as e:
                            self.log.error("Error validating new user", "nickname %s\n error %s" % (newDiracName, e))
                            self.adminMsgs["Errors"].append(
                                "Error validating new user %s: %s\n  %s" % (newDiracName, userDict, e)
                            )
                            continue

                    message = "\n  Added new user %s:\n" % newDiracName
                    for key in userDict:
                        message += "    %s: %s\n" % (key, str(userDict[key]))
                    self.adminMsgs["Info"].append(message)
                    self.voChanged = True
                    if self.autoAddUsers:
                        self.log.info("Adding new user %s: %s" % (newDiracName, str(userDict)))
                        result = self.csapi.modifyUser(newDiracName, userDict, createIfNonExistant=True)
                        if not result["OK"]:
                            self.log.warn("Failed adding new user %s" % newDiracName)
                        resultDict["NewUsers"].append(newDiracName)
                        newAddedUserDict[newDiracName] = userDict
                    continue

            # We have an already existing user
            modified = False
            suspendedInVOMS = self.vomsUserDict[dn]["suspended"] or self.vomsUserDict[dn]["certSuspended"]
            suspendedVOList = getUserOption(diracName, "Suspended", [])
            knownEmail = getUserOption(diracName, "Email", None)
            userDict = {
                "DN": diracUserDict[diracName]["DN"],
                "CA": diracUserDict[diracName]["CA"],
                "Email": self.vomsUserDict[dn].get("mail", self.vomsUserDict[dn].get("emailAddress")) or knownEmail,
            }

            # Set Suspended status for the user for this particular VO
            if suspendedInVOMS and self.vo not in suspendedVOList:
                suspendedVOList.append(self.vo)
                userDict["Suspended"] = ",".join(suspendedVOList)
                modified = True

            # Remove the lifted Suspended status
            if not suspendedInVOMS and self.vo in suspendedVOList and self.autoLiftSuspendedStatus:
                newList = []
                for vo in suspendedVOList:
                    if vo != self.vo:
                        newList.append(vo)
                if not newList:
                    newList = ["None"]
                userDict["Suspended"] = ",".join(newList)
                modified = True

            if newDNForExistingUser:
                userDict["DN"] = ",".join([dn, diracUserDict.get(diracName, newAddedUserDict.get(diracName))["DN"]])
                userDict["CA"] = ",".join(
                    [self.vomsUserDict[dn]["CA"], diracUserDict.get(diracName, newAddedUserDict.get(diracName))["CA"]]
                )
                modified = True
            existingGroups = diracUserDict.get(diracName, {}).get("Groups", [])
            nonVOGroups = list(set(existingGroups) - set(diracVOMSMapping))
            groupsWithRole = []
            for role in self.vomsUserDict[dn]["Roles"]:
                groupList = vomsDIRACMapping.get(role, [])
                for group in groupList:
                    if group not in noSyncVOMSGroups:
                        groupsWithRole.append(group)
            keepGroups = nonVOGroups + groupsWithRole
            if not quarantineVOGroup or quarantineVOGroup not in existingGroups:
                keepGroups += [defaultVOGroup]
            if quarantineVOGroup and quarantineVOGroup in existingGroups:
                keepGroups = [quarantineVOGroup]
            for group in existingGroups:
                if group in nonVOGroups:
                    continue
                role = diracVOMSMapping.get(group, "")
                # Among already existing groups for the user keep those without a special VOMS Role
                # because this membership is done by hand in the CS
                if "Role" not in role:
                    keepGroups.append(group)
                # Keep existing groups with no VOMS attribute if any
                if group in noVOMSGroups:
                    keepGroups.append(group)
                # Keep groups for which syncronization with VOMS is forbidden
                if group in noSyncVOMSGroups:
                    keepGroups.append(group)
            userDict["Groups"] = list(set(keepGroups))
            # Merge together groups for the same user but different DNs
            if diracName in newAddedUserDict:
                otherGroups = newAddedUserDict[diracName].get("Groups", [])
                userDict["Groups"] = list(set(keepGroups + otherGroups))
                modified = True
            if not existingGroups and diracName in allDiracUsers:
                groups = getGroupsForUser(diracName)
                if groups["OK"]:
                    self.log.info("Found groups for user %s %s" % (diracName, groups["Value"]))
                    userDict["Groups"] = list(set(groups["Value"] + keepGroups))
                    addedGroups = list(set(userDict["Groups"]) - set(groups["Value"]))
                    modified = True
                    message = "\n  Modified user %s:\n" % diracName
                    message += "    Added to group(s) %s\n" % ",".join(addedGroups)
                    self.adminMsgs["Info"].append(message)

            # Check if something changed before asking CSAPI to modify
            if diracName in diracUserDict:
                message = "\n  Modified user %s:\n" % diracName
                modMsg = ""
                for key in userDict:
                    if key == "Groups":
                        addedGroups = set(userDict[key]) - set(diracUserDict.get(diracName, {}).get(key, []))
                        removedGroups = set(diracUserDict.get(diracName, {}).get(key, [])) - set(userDict[key])
                        if addedGroups:
                            modMsg += "    Added to group(s) %s\n" % ",".join(addedGroups)
                        if removedGroups:
                            modMsg += "    Removed from group(s) %s\n" % ",".join(removedGroups)
                    elif key == "Suspended":
                        if userDict["Suspended"] == "None":
                            modMsg += "    Suspended status removed\n"
                        else:
                            modMsg += "    User Suspended in VOs: %s\n" % userDict["Suspended"]
                    else:
                        oldValue = str(diracUserDict.get(diracName, {}).get(key, ""))
                        if str(userDict[key]) != oldValue:
                            modMsg += "    %s: %s -> %s\n" % (key, oldValue, str(userDict[key]))
                if modMsg:
                    self.adminMsgs["Info"].append(message + modMsg)
                    modified = True

            if self.autoModifyUsers and modified:
                result = self.csapi.modifyUser(diracName, userDict)
                if result["OK"] and result["Value"]:
                    self.log.info("Modified user %s: %s" % (diracName, str(userDict)))
                    self.voChanged = True
                    resultDict["ModifiedUsers"].append(diracName)

        # Check if there are potentially obsoleted users
        oldUsers = set()
        for user in diracUserDict:
            dnSet = set(fromChar(diracUserDict[user]["DN"]))
            if not dnSet.intersection(set(self.vomsUserDict)) and user not in nonVOUserDict:
                existingGroups = diracUserDict.get(user, {}).get("Groups", [])
                nonVOGroups = list(set(existingGroups) - set(diracVOMSMapping))
                removedGroups = list(set(existingGroups) - set(nonVOGroups))
                if removedGroups:
                    self.log.info("Checking user for deletion", "%s: %s" % (user, existingGroups))
                    self.log.info("User has groups in other VOs", "%s: %s" % (user, nonVOGroups))
                    userDict = diracUserDict[user]
                    userDict["Groups"] = nonVOGroups
                    if self.autoModifyUsers:
                        result = self.csapi.modifyUser(user, userDict)
                        if result["OK"] and result["Value"]:
                            self.log.info("Modified user %s: %s" % (user, str(userDict)))
                            self.voChanged = True
                            message = "\n  Modified user %s:\n" % user
                            modMsg = "    Removed from group(s) %s\n" % ",".join(removedGroups)
                            self.adminMsgs["Info"].append(message + modMsg)
                            resultDict["ModifiedUsers"].append(user)
                    continue
                if not any(group in noVOMSGroups for group in existingGroups):
                    oldUsers.add(user)

        # Check for obsoleted DNs
        for user in diracUserDict:
            dnSet = set(fromChar(diracUserDict[user]["DN"]))
            for dn in dnSet:
                if dn in obsoletedDNs and user not in oldUsers:
                    existingGroups = diracUserDict.get(user, {}).get("Groups", [])
                    nonVOGroups = list(set(existingGroups) - set(diracVOMSMapping))
                    if nonVOGroups:
                        self.log.verbose("User has groups in other VOs", "%s: %s" % (user, nonVOGroups))
                        continue
                    self.log.verbose("Modified user %s: dropped DN %s" % (user, dn))
                    if self.autoModifyUsers:
                        userDict = diracUserDict[user]
                        modDNSet = dnSet - set([dn])
                        if modDNSet:
                            userDict["DN"] = ",".join(modDNSet)
                            result = self.csapi.modifyUser(user, userDict)
                            if result["OK"] and result["Value"]:
                                self.log.info("Modified user %s: dropped DN %s" % (user, dn))
                                self.adminMsgs["Info"].append("Modified user %s: dropped DN %s" % (user, dn))
                                self.voChanged = True
                                resultDict["ModifiedUsers"].append(diracName)
                        else:
                            oldUsers.add(user)

        if oldUsers:
            self.voChanged = True
            if self.autoDeleteUsers:
                self.log.info("The following users will be deleted: %s" % str(oldUsers))
                result = self.csapi.deleteUsers(oldUsers)
                if result["OK"]:
                    self.adminMsgs["Info"].append("The following users are deleted from CS:\n  %s\n" % str(oldUsers))
                    resultDict["DeletedUsers"] = oldUsers
                else:
                    self.adminMsgs["Errors"].append("Error in deleting users from CS:\n  %s" % str(oldUsers))
                    self.log.error("Error while user deletion from CS", result)
            else:
                self.adminMsgs["Info"].append(
                    "The following users to be checked for deletion:\n\t%s" % "\n\t".join(sorted(oldUsers))
                )
                self.log.info("The following users to be checked for deletion:", "\n\t".join(sorted(oldUsers)))

        resultDict["CSAPI"] = self.csapi
        resultDict["AdminMessages"] = self.adminMsgs
        resultDict["VOChanged"] = self.voChanged
        return S_OK(resultDict)
예제 #5
0
  sourceSE = sys.argv[2]
  targetSE1 = sys.argv[3]
  targetSE2 = sys.argv[4]

  gLogger.always( "will use '%s' group" % userGroup )

  admin = DiracAdmin()

  userName = admin._getCurrentUser()
  if not userName["OK"]:
    gLogger.error( userName["Message"] )
    sys.exit( -1 )
  userName = userName["Value"]
  gLogger.always( "current user is '%s'" % userName )

  userGroups = getGroupsForUser( userName )
  if not userGroups["OK"]:
    gLogger.error( userGroups["Message"] )
    sys.exit( -1 )
  userGroups = userGroups["Value"]

  if userGroup not in userGroups:
    gLogger.error( "'%s' is not a member of the '%s' group" % ( userName, userGroup ) )
    sys.exit( -1 )

  userDN = getDNForUsername( userName )
  if not userDN["OK"]:
    gLogger.error( userDN["Message"] )
    sys.exit( -1 )
  userDN = userDN["Value"][0]
  gLogger.always( "userDN is %s" % userDN )
예제 #6
0
    sourceSE = sys.argv[2]
    targetSE1 = sys.argv[3]
    targetSE2 = sys.argv[4]

    gLogger.always("will use '%s' group" % userGroup)

    admin = DiracAdmin()

    userName = admin._getCurrentUser()
    if not userName["OK"]:
        gLogger.error(userName["Message"])
        sys.exit(-1)
    userName = userName["Value"]
    gLogger.always("current user is '%s'" % userName)

    userGroups = getGroupsForUser(userName)
    if not userGroups["OK"]:
        gLogger.error(userGroups["Message"])
        sys.exit(-1)
    userGroups = userGroups["Value"]

    if userGroup not in userGroups:
        gLogger.error("'%s' is not a member of the '%s' group" %
                      (userName, userGroup))
        sys.exit(-1)

    userDN = getDNForUsername(userName)
    if not userDN["OK"]:
        gLogger.error(userDN["Message"])
        sys.exit(-1)
    userDN = userDN["Value"][0]
예제 #7
0
  import DIRAC
  from DIRAC import gLogger, gConfig
  from DIRAC.ConfigurationSystem.Client.Helpers.Resources import getSites
  from DIRAC.DataManagementSystem.Client.FTSClient import FTSClient
  from DIRAC.DataManagementSystem.Client.FTSSite import FTSSite
  from DIRAC.Interfaces.API.DiracAdmin import DiracAdmin
  from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getGroupsForUser
  admin = DiracAdmin()

  currentUser = admin._getCurrentUser()
  if not currentUser["OK"]:
    gLogger.error( currentUser["Message"] )
    DIRAC.exit(-1)
  currentUser = currentUser["Value"]
  
  userGroups = getGroupsForUser( currentUser )
  if not userGroups["OK"]:
    gLogger.error( userGroups["Message"] )
    DIRAC.exit( -1 )
  userGroups = userGroups["Value"]
  
  if "diracAdmin" not in userGroups:
    gLogger.error( "you are not allowed to change FTSSites configuration" )
    DIRAC.exit( -1 )

  args = Script.getPositionalArgs()

  maxActiveJobs = 50
  ftsSite = ftsServer = ""
  if not len( args ) == 3:
    Script.showHelp()