Exemple #1
0
    def delete_trait(self, code):
        """Remove the entity's trait identified by code value."""

        code = _EntityTraitCode(code)
        # get_traits populates __traits as a side effect
        if code not in self.get_traits():
            raise Errors.NotFoundError(code)
        if code in self.__trait_updates:
            if self.__trait_updates[code] == 'INSERT':
                del self.__trait_updates[code]
                del self.__traits[code]
                return
            del self.__trait_updates[code]
        params = self._pickle_fixup(self.__traits[code])
        binds = {'entity_id': self.entity_id, 'code': int(code)}
        exists_stmt = """
        SELECT EXISTS (
          SELECT 1
          FROM [:table schema=cerebrum name=entity_trait]
          WHERE entity_id=:entity_id AND code=:code
        )
        """
        if not self.query_1(exists_stmt, binds):
            # False positive
            return
        delete_stmt = """
        DELETE FROM [:table schema=cerebrum name=entity_trait]
        WHERE entity_id=:entity_id AND code=:code
        """
        self.execute(delete_stmt, binds)
        self._db.log_change(self.entity_id,
                            self.clconst.trait_del,
                            None,
                            change_params=params)
        del self.__traits[code]
Exemple #2
0
 def get_free_uid(self):
     """Returns the next free uid from ``posix_uid_seq``"""
     while 1:
         # We pick an UID
         uid = self.nextval("posix_uid_seq")
         # We check if the UID is in any of the reserved ranges.
         # If it is, we'll skip past the range (call setval), and
         # pick a new UID that is past the reserved range.
         for x in sorted(cereconf.UID_RESERVED_RANGE):
             # TODO: Move this check to some unit-testing stuff sometime
             if x[1] < x[0]:
                 raise Errors.ProgrammingError(
                     'Wrong order in cereconf.UID_RESERVED_RANGE')
             if uid >= x[0] and uid <= x[1]:
                 self._db.setval('posix_uid_seq', x[1])
                 uid = self.nextval("posix_uid_seq")
         # If the UID is not in use, we return it, else, we try over.
         try:
             self.query_1(
                 """
             SELECT posix_uid
             FROM [:table schema=cerebrum name=posix_user]
             WHERE posix_uid=:uid""", locals())
         except Errors.NotFoundError:
             return int(uid)
Exemple #3
0
    def __init__(self, config=None, *args, **kw):
        """
        Constructs a PasswordGenerator.

        :param Cerebrum.config.configuration.Configuration config:
            The Configuration object for the password_generator module.
        """
        try:
            if config is None:
                self.config = load_config()
            else:
                self.config = load_config(filepath=config)
            # Create a local random object for increased randomness
            # "Use os.urandom() or SystemRandom if you require a
            # cryptographically secure pseudo-random number generator."
            # docs.python.org/2.7/library/random.html#random.SystemRandom
            self.lrandom = random.SystemRandom()
            self.dict_words = []
            if self.config.passphrase_dictionary:
                with open(self.config.passphrase_dictionary) as fp:
                    for line in fp:
                        try:
                            # assume UTF-8 encoded text-file
                            self.dict_words.append(
                                line.strip().decode('utf-8'))
                        except:
                            continue
        except Exception as e:
            raise Errors.CerebrumError('Unable to create a PasswordGenerator '
                                       'instance: {error}'.format(error=e))
Exemple #4
0
    def _autopick_homeMDB(self):
        """Return a valid homeMDB value to be used for the account.

        If the account has previously had a HomeMDB, this is reused, but only
        as long the MDB value is valid today, see
        L{cereconf.EXCHANGE_HOMEMDB_VALID}. Otherwise a random HomeMDB is
        selected. We don't care about the weight of the MDBs, ØFK wants
        everyone to be equally assigned.

        @rtype: string
        @return: One of the HomeMDB values from
            L{cereconf.EXCHANGE_HOMEMDB_VALID}.

        """
        mdb_candidates = cereconf.EXCHANGE_HOMEMDB_VALID
        # Check if account had homeMDB earlier. If so use that, as long as it
        # is in one of today's valid MDBs.
        mdb_choice = self._get_old_homeMDB()
        if mdb_choice and mdb_choice in mdb_candidates:
            return mdb_choice
        # Choose a random HomeMDB, and don't care about weights:
        mdb_choice = random.choice(mdb_candidates.keys())
        if mdb_choice is None:
            raise Errors.CerebrumError("Couldn't assign mdb for %s" %
                                       self.entity_id)
        return mdb_choice
Exemple #5
0
    def get_group(db, id_type, group):
        """Fetch a group by id.

        :type db: <Cerebrum.Database.Database>
        :param db: A Cerebrum database object.

        :type id_type: str
        :param id_type: The identifier type, 'name' or 'id'

        :type group: str or int
        :param group: The group identifier

        :rtype: Group or None
        """
        gr = Factory.get('Group')(db)

        # Determine lookup type
        if id_type == 'name':
            lookup = gr.find_by_name
        elif id_type == 'id':
            lookup = gr.find
        else:
            raise Errors.CerebrumRPCException('Invalid id_type.')

        # Perform actual lookup
        # TODO: How do we handle NotFoundErrors? Is this correct?
        try:
            lookup(group)
        except Errors.NotFoundError:
            return None
        return gr
Exemple #6
0
    def get_account(db, id_type, account):
        """Fetch a group by id.

        :type db: <Cerebrum.Database.Database>
        :param db: A Cerebrum database object.

        :type id_type: str
        :param id_type: The identifier type, 'name' or 'id'

        :type id_type: str or int
        :param group: The account identifier

        :rtype: Account or None
        """
        ac = Factory.get('Account')(db)

        if id_type == 'name':
            lookup = ac.find_by_name
        elif id_type == 'id':
            lookup = ac.find
        else:
            raise Errors.CerebrumRPCException('Invalid id_type.')

        try:
            lookup(account)
        except Errors.NotFoundError:
            return None
        return ac
Exemple #7
0
    def create_project(self, project_name):
        """Create a new project in TSD.

        Note that this method calls `write_db`.

        :param str project_name:
            A unique, short project name to use to identify the project.
            This is not the *project ID*, which is created automatically.

        :return str:
            The generated project ID for the new project.
        """
        # Check if given project name is already in use:
        if tuple(self.search_tsd_projects(name=project_name,
                                          exact_match=True)):
            raise Errors.CerebrumError(
                'Project name already taken: %s' % project_name)
        self.populate()
        self.write_db()
        # Set a generated project ID
        self.affect_external_id(self.const.system_cached,
                                self.const.externalid_project_id)
        pid = self.get_next_free_project_id()
        self.populate_external_id(self.const.system_cached,
                                  self.const.externalid_project_id, pid)
        self.write_db()
        # Set the project name
        self.add_name_with_language(name_variant=self.const.ou_name_acronym,
                                    name_language=self.const.language_en,
                                    name=project_name)
        self.write_db()
        return pid
Exemple #8
0
    def _get_affiliate_trait(self, etype):
        """Get trait used to affiliate an entity with this project.

        :type etype:
            Constants.EntityType, int, str
        :param entity_type:
            The entity type
        """
        type2trait = {
            self.const.entity_group:
                self.const.trait_project_group,
            self.const.entity_dns_owner:
                self.const.trait_project_host,
            self.const.entity_dns_subnet:
                self.const.trait_project_subnet,
            self.const.entity_dns_ipv6_subnet:
                self.const.trait_project_subnet6,
        }
        entity_type = (
            etype if isinstance(etype, self.const.EntityType)
            else self.const.human2constant(etype, self.const.EntityType))
        try:
            return type2trait[entity_type]
        except KeyError:
            raise Errors.CerebrumError(
                u"Entity type %s (%r) cannot be affilated with project." %
                (entity_type, etype))
Exemple #9
0
    def _get_ou(self, ou_id=None, stedkode=None):
        """ Fetch a specified OU instance.

        Either ou_id or stedkode must be provided.

        @type ou_id: int or None
        @param ou_id:
          ou_id (entity_id) if not None.

        @type stedkode: string (DDDDDD, where D is a digit)
        @param stedkode:
          Stedkode for OU if not None.
        """
        ou = self.OU_class(self.db)
        ou.clear()
        try:
            if ou_id is not None:
                ou.find(ou_id)
            else:
                if len(stedkode) != 6 or not stedkode.isdigit():
                    raise CerebrumError("Expected 6 digits in stedkode %r" %
                                        stedkode)
                ou.find_stedkode(stedkode[:2], stedkode[2:4], stedkode[4:],
                                 institusjon=cereconf.DEFAULT_INSTITUSJONSNR)
            return ou
        except Errors.NotFoundError:
            raise CerebrumError("Unknown OU (%s)" %
                                (ou_id and ("id=%r" % ou_id) or
                                 ("sko=%r" % stedkode)))
        raise Errors.UnreachableCodeError("_get_ou")
Exemple #10
0
 def search_members_flat(self, groupname):
     # TODO: add access control for who is allowed to get the members. Only
     # moderators of the given group?
     #if not self.ba.is_superuser(self.operator_id):
     #    raise NotAuthorizedError('Only for superusers')
     # Raises Cerebrum.modules.bofh.errors.PermissionDenied - how to handle
     # these?
     #self.ba.can_set_trait(self.operator_id)
     try:
         self.grp.clear()
         self.grp.find_by_name(groupname)
     except Errors.NotFoundError:
         raise Errors.CerebrumRPCException("Group %s not found." % groupname)
     grp_id = self.grp.entity_id
     self.grp.clear()
     type_account = str(self.co.entity_account)
     member_rows = self.grp.search_members(group_id=grp_id,
                                         indirect_members=True,
                                         include_member_entity_name=True)
     return [{   'member_type': type_account,
                 'member_id': str(row['member_id']),
                 'uname': row['member_name']
             }
                 for row in member_rows
                 if row['member_type'] == self.co.entity_account]
Exemple #11
0
 def _get_gid(self):
     """Returns the next free GID from 'posix_gid_seq'"""
     while True:
         # Pick a new GID
         gid = self.nextval('posix_gid_seq')
         # We check if the GID is in any of the reserved ranges.
         # If it is, we'll skip past the range (call setval), and
         # pick a new GID that is past the reserved range.
         for x in sorted(cereconf.GID_RESERVED_RANGE):
             # TODO: Move this check to some unit-testing stuff sometime
             if x[1] < x[0]:
                 raise Errors.ProgrammingError(
                     'Wrong order in cereconf.GID_RESERVED_RANGE')
             if x[0] <= gid <= x[1]:
                 self._db.setval('posix_gid_seq', x[1])
                 gid = self.nextval('posix_gid_seq')
         # We check if the GID is in use, if not, return, else start over.
         try:
             self.query_1(
                 """
             SELECT posix_gid
             FROM [:table schema=cerebrum name=posix_group]
             WHERE posix_gid=:gid""", locals())
         except Errors.NotFoundError:
             return gid
Exemple #12
0
    def __init__(self, config=None, logger=None, *args, **kw):
        """ Constructs a PasswordGenerator.

        :param Cerebrum.config.configuration.Configuration config:
            The Configuration object for the password_generator module.

        :param logging.Logger logger:
            Logger object to use. If `None`, this object will fetch a new
            logger with `Factory.get_logger('crontab')`. This is the default.
        """
        try:
            if config is None:
                self.config = load_config()
            else:
                self.config = load_config(filepath=config)
            # Create a local random object for increased randomness
            # "Use os.urandom() or SystemRandom if you require a
            # cryptographically secure pseudo-random number generator."
            # docs.python.org/2.7/library/random.html#random.SystemRandom
            self.lrandom = random.SystemRandom()
            self.logger = logger or Utils.Factory.get_logger('console')
            self.dict_words = []
            if self.config.passphrase_dictionary:
                with open(self.config.passphrase_dictionary) as fp:
                    for line in fp:
                        try:
                            # assume UTF-8 encoded text-file
                            self.dict_words.append(
                                line.strip().decode('utf-8'))
                        except:
                            continue
            self.logger.debug('PasswordGenerator initialized')
        except Exception as e:
            raise Errors.CerebrumError('Unable to create a PasswordGenerator '
                                       'instance: {error}'.format(error=e))
Exemple #13
0
    def add_relationship(self, relationship_code, target_id):
        """Add a relationship of given type between this role and a target
        component (atom or role).

        @type relationship_code: int
        @param relationship_code:
            The relationship constant that defines the kind of relationship the
            source and target will have.
        """
        if self.illegal_relationship(relationship_code, target_id):
            # TODO: is ProgrammingError the correct exception to raise here?
            # Frontends should be able to give better feedbacks
            raise Errors.ProgrammingError('Illegal relationship')
        self.execute(
            """
            INSERT INTO [:table schema=cerebrum name=hostpolicy_relationship]
              (source_policy, relationship, target_policy)
            VALUES (:source, :rel, :target)""", {
                'source': self.entity_id,
                'rel': int(relationship_code),
                'target': target_id
            })
        self._db.log_change(self.entity_id,
                            self.clconst.hostpolicy_relationship_add,
                            target_id)
Exemple #14
0
def ldif_outfile(tree, filename=None, default=None, explicit_default=False,
                 max_change=None, module=cereconf):
    """(Open and) return LDIF outfile for <tree>.

    Use <filename> if specified,
    otherwise module.LDAP_<tree>['file'] unless <explicit_default>,
    otherwise return <default> (an open filehandle) if that is not None.
    (explicit_default should be set if <default> was opened from a
    <filename> argument and not from module.LDAP*['file'].)

    When opening a file, use SimilarSizeWriter where close() fails if
    the resulting file has changed more than <max_change>, or
    module.LDAP_<tree>['max_change'], or module.LDAP['max_change'].
    If max_change is unset or >= 100, just open the file normally.
    """
    if not (filename or explicit_default):
        filename = getattr(module, 'LDAP_' + tree).get('file')
        if filename:
            filename = os.path.join(module.LDAP['dump_dir'], filename)
    if filename:
        if max_change is None:
            max_change = ldapconf(tree, 'max_change', default=ldapconf(
                None, 'max_change', default=100, module=module),
                module=module)
        if max_change < 100:
            f = SimilarSizeWriter(filename, 'w')
            f.max_pct_change = max_change
        else:
            f = AtomicFileWriter(filename, 'w')
        return f
    if default:
        return default
    raise _Errors.CerebrumError(
        'Outfile not specified and LDAP_{0}["file"] not set'.format(tree))
Exemple #15
0
    def _validate_project_name(self, name):
        """Check if a given project name is valid.

        Project names are used to identify project entities in other systems,
        so we need to enforce some limits to avoid potential problems.

        Requirements
        ------------
        Can not contain spaces
            TODO: Why?

        Can not contain commas.
            This is due to AD's way of identifying objects. Example:
            CN=username,OU=projectname,DC=tsd,DC=uio,DC=no.

        Can not contain the SQL wildcards ? and %.
            This is a convenience limit, to be able to use Cerebrum's existing
            API without modifications.

        Can not contain control characters.

        Can not contain characters outside of ASCII.
            This is to avoid unexpected encoding issues.

        TBD: A maximum length in the name?
            AD probably has a limit. As a prefix, it should be a bit less than
            AD's limit.

        In practice, we only accept regular alphanumeric characters in ASCII,
        in addition to some punctuation characters, like colon, dash and
        question marks. This would need to be extended in the future.

        :param str name:
            The name to check.

        :raise Errors.CerebrumError:
            If the given project name was not accepted
        """
        m = re.search('[^A-Za-z0-9_\-:;\*"\'\#\&\=!\?]', name)
        if m:
            raise Errors.CerebrumError(
                'Invalid characters in projectname: %s' % m.group())
        if len(name) < 3:
            raise Errors.CerebrumError('Project name too short')
        if len(name) > 8:  # TBD: or 6?
            raise Errors.CerebrumError('Project name is too long')
        return True
Exemple #16
0
def add_cname_record(db, cname_record_name, target_name, fail_on_exists=True):
    """
    Creates a CNAME-record.

    If fail_on_exists=False, it will simply return without doing anything,
    if the CNAME-record already exists.
    This is due to the method being used by OU._setup_project_hosts, which
    can be run several times for the same project when it is reconfigured.

    :param db: A Cerebrum-database instance
    :type db: Cerebrum.database.Database
    :param cname_record_name: FQDN of the CNAME-record
    :type cname_record_name: str
    :param target_name: FQDN of the target domain
    :type target_name: str
    :param fail_on_exists: True or False
    :type fail_on_exists: bool
    """

    cname = CNameRecord(db)
    dns_owner = DnsOwner(db)
    constants = Factory.get('Constants')

    try:
        dns_owner.find_by_name(target_name)
        proxy_dns_owner_ref = dns_owner.entity_id
    except Errors.NotFoundError:
        raise Errors.NotFoundError('%s does not exist.' % target_name)

    dns_owner.clear()

    try:
        dns_owner.find_by_name(cname_record_name)
    except Errors.NotFoundError:
        dns_owner.populate(constants.DnsZone(cereconf.DNS_DEFAULT_ZONE),
                           cname_record_name)
        dns_owner.write_db()
    cname_dns_owner_ref = dns_owner.entity_id

    try:
        cname.find_by_cname_owner_id(cname_dns_owner_ref)
        if fail_on_exists:
            raise Errors.RealityError('CNAME %s already exists.' %
                                      cname_record_name)
    except Errors.NotFoundError:
        cname.populate(cname_dns_owner_ref, proxy_dns_owner_ref)
        cname.write_db()
 def get_addresses_by_affiliation(ctx, status=None, skos=None, source=None):
     """Get primary e-mail addresses for persons that match given
     criterias."""
     if not source and not status:
         raise Errors.CerebrumRPCException('Input needed')
     return ctx.udc['postmaster'].get_addresses_by_affiliation(status=status,
                                                               skos=skos,
                                                               source=source)
Exemple #18
0
 def get_project_id(self):
     """Get the project ID of this project"""
     ret = self.get_external_id(id_type=self.const.externalid_project_id)
     if ret:
         return ret[0]['external_id']
     raise Errors.NotFoundError(
         'Mandatory project ID not found for {entity}'.format(
             entity=self.entity_id))
Exemple #19
0
 def get_account(self, uname):
     account = Factory.get('Account')(self.db)
     try:
         account.find_by_name(uname)
     except Errors.NotFoundError:
         log.info("Couldn't find account %s" % uname)
         raise Errors.CerebrumRPCException('person_notfound')
     else:
         return account
Exemple #20
0
 def set_password(self, uname, new_password, token, browser_token):
     if not self.check_token(uname, token, browser_token):
         return False
     account = self.get_account(uname)
     try:
         check_password(new_password, account)
     except PasswordNotGoodEnough as e:
         m = str(e).decode('utf-8')
         raise Errors.CerebrumRPCException('password_invalid', m)
     # All data is good. Set password
     account.set_password(new_password)
     try:
         account.write_db()
         account._db.commit()
         log.info("Password for %s altered." % uname)
     except self.db.DatabaseError, m:
         log.error("Error when setting password for %s: %s" % (uname, m))
         raise Errors.CerebrumRPCException('error_unknown')
Exemple #21
0
 def __init__(self, db):
     """
     Override __init__ to set up AD spesific constants.
     """
     self.__super.__init__(db)
     # Setup AD spread constants
     if not hasattr(cereconf, 'AD_ACCOUNT_SPREADS'):
         raise Errors.CerebrumError("Missing AD_ACCOUNT_SPREADS in cereconf")
     self.ad_account_spreads = {}
     for spread_str in cereconf.AD_ACCOUNT_SPREADS:
         c = self.const.Spread(spread_str)
         self.ad_account_spreads[int(c)] = c
     # Setup defined ad traits
     if not hasattr(cereconf, 'AD_TRAIT_TYPES'):
         raise Errors.CerebrumError("Missing AD_TRAIT_TYPES in cereconf")
     self.ad_trait_types = []
     for trait_str in cereconf.AD_TRAIT_TYPES:
         self.ad_trait_types.append(self.const.EntityTrait(trait_str))
Exemple #22
0
    def check_token(self, uname, token, browser_token):
        """Check if token and other data from user is correct."""
        try:
            account = self.get_account(uname)
        except Errors.CerebrumRPCException:
            # shouldn't tell what went wrong
            return False

        # Check browser_token. The given browser_token may be "" but if so
        # the stored browser_token must be "" as well for the test to pass.

        bt = account.get_trait(self.co.trait_browser_token)
        if not bt or bt['strval'] != self.hash_token(browser_token, uname):
            log.info("Incorrect browser_token %s for user %s" %
                     (browser_token, uname))
            return False

        # Check password token. Keep track of how many times a token is
        # checked to protect against brute force attack (defaults to 20).
        pt = account.get_trait(self.co.trait_password_token)
        no_checks = int(pt['numval'])
        if no_checks > getattr(cereconf, 'INDIVIDUATION_TOKEN_ATTEMPTS', 20):
            log.info("No. of token checks exceeded for user %s" % uname)
            raise Errors.CerebrumRPCException('toomanyattempts_check')
        # Check if we're within time limit
        time_limit = now() - RelativeDateTime(
            minutes=cereconf.INDIVIDUATION_TOKEN_LIFETIME)
        if pt['date'] < time_limit:
            log.debug("Password token's timelimit for user %s exceeded" %
                      uname)
            raise Errors.CerebrumRPCException('timeout_check')

        if pt and pt['strval'] == self.hash_token(token, uname):
            # All is fine
            return True
        log.debug("Token %s incorrect for user %s" % (token, uname))
        account.populate_trait(self.co.trait_password_token,
                               strval=pt['strval'],
                               date=pt['date'],
                               numval=no_checks + 1)
        account.write_db()
        account._db.commit()
        return False
Exemple #23
0
 def delete_machine(self):
     """Demotes Machine to a normal host"""
     if self.entity_id is None:
         raise Errors.NoEntityAssociationError(
             "Unable to determine which entity to delete.")
     self._db.log_change(self.entity_id, self.const.machine_demote, None)
     self.execute(
         """
     DELETE FROM [:table schema=cerebrum name=machine_info]
     WHERE host_id=:e_id""", {'e_id': self.entity_id})
Exemple #24
0
 def get_fullname(self):
     """The GECOS contains the full name the user wants to be
     associated with POSIX account. This method's return value will
     also be used to generate an email-address if the posix account
     is not owned by an actual person."""
     if self.owner_type != int(self.const.entity_person):
         if self.gecos is not None:
             return self.gecos
         raise Errors.NotFoundError('Name (GECOS) not set for'
                                    'non-personal PosixUser.')
     return self.__super.get_fullname()
Exemple #25
0
    def __init__(self, db, logger, u_sprd=None, g_sprd=None, n_sprd=None,
                 fd=None):
        """ Initiate database and import modules.

        Spreads are given in initiation and general constants which is
        used in more than one method.

        """
        timer = make_timer(logger, 'Initing PosixLDIF...')
        from Cerebrum.modules import PosixGroup
        self.db = db
        self.logger = logger
        self.const = Factory.get('Constants')(self.db)
        self.grp = Factory.get('Group')(self.db)
        self.posuser = Factory.get('PosixUser')(self.db)
        self.posgrp = PosixGroup.PosixGroup(self.db)
        self.user_dn = LDIFutils.ldapconf('USER', 'dn', None)
        # This is an odd one -- if set to False, then id2uname should be
        # populated with users exported in the users export -- which makes the
        # group exports filter group members by *actually* exported users...
        self.get_name = True
        self.fd = fd
        self.spread_d = {}
        # Validate spread from arg or from cereconf
        for x, y in zip(['USER', 'FILEGROUP', 'NETGROUP'],
                        [u_sprd, g_sprd, n_sprd]):
            spread = LDIFutils.map_spreads(
                y or getattr(cereconf, 'LDAP_' + x).get('spread'), list)
            if spread:
                self.spread_d[x.lower()] = spread
        if 'user' not in self.spread_d:
            raise Errors.ProgrammingError(
                "Must specify spread-value as 'arg' or in cereconf")
        self.account2name = dict()
        self.group2gid = dict()
        self.groupcache = defaultdict(dict)
        self.group2groups = defaultdict(set)
        self.group2users = defaultdict(set)
        self.group2persons = defaultdict(list)
        self.shell_tab = dict()
        self.quarantines = dict()
        self.user_exporter = UserExporter(self.db)
        if len(self.spread_d['user']) > 1:
            logger.warning('Exporting users with multiple spreads, '
                           'ignoring homedirs from %r',
                           self.spread_d['user'][1:])
        self.homedirs = HomedirResolver(db, self.spread_d['user'][0])
        self.owners = OwnerResolver(db)

        auth_attr = LDIFutils.ldapconf('USER', 'auth_attr', None)
        self.user_password = AuthExporter.make_exporter(
            db,
            auth_attr['userPassword'])
        timer('... done initing PosixLDIF.')
Exemple #26
0
    def find_by_tsd_projectname(self, project_name):
        """Finds Project OU by project name.

        This is a L{find}-method, it will populate this entity with any project
        it finds.

        :param str project_name: The short-name of the project to find.

        :raise NotFoundError:
            If the project is not found.
        :raise TooManyRowsError:
            If multiple projects matches the name (should not be possible).
        """
        matched = self.search_tsd_projects(name=project_name, exact_match=True)
        if not matched:
            raise Errors.NotFoundError(u"Unknown project: %s" % project_name)
        if len(matched) != 1:
            raise Errors.TooManyRowsError(
                u"Found several OUs with given name: %s" % project_name)
        return self.find(matched[0]['entity_id'])
Exemple #27
0
    def get_person(self, id_type, ext_id):
        person = Factory.get('Person')(self.db)
        person.clear()
        if not hasattr(self.co, id_type):
            log.error("Wrong id_type: '%s'" % id_type)
            raise Errors.CerebrumRPCException('person_notfound')
        try:
            person.find_by_external_id(getattr(self.co, id_type), ext_id)
            return person
        except Errors.NotFoundError:
            log.debug("Couldn't find person with %s='%s'" % (id_type, ext_id))

        # Try without leading zeros, as FS use that, and which could confuse
        # students. TODO: Note that this does not help if the external IDs are
        # stored _with_ leading zeros in the database, i.e. the opposite way.
        if ext_id.isdigit():
            try:
                person.find_by_external_id(getattr(self.co, id_type),
                                           str(int(ext_id)))
                log.debug(
                    "Found person %s without leading zeros in ext_id: %s" %
                    (person.entity_id, ext_id))
                return person
            except Errors.NotFoundError:
                pass

            # Still not found? Try to padd with zeros if it's a student number
            # with less than 6 digits:
            if (hasattr(self.co, 'externalid_studentnr') and getattr(
                    self.co, id_type) == self.co.externalid_studentnr
                    and len(ext_id) < 6):
                try:
                    person.find_by_external_id(getattr(self.co, id_type),
                                               '%06d' % int(ext_id))
                    log.debug(
                        "Found person %s with padded zeros in ext_id: %s" %
                        (person.entity_id, ext_id))
                    return person
                except Errors.NotFoundError:
                    pass
        raise Errors.CerebrumRPCException('person_notfound')
Exemple #28
0
 def select_extid(entity_id, id_type):
     """ Get preferred fnr for a given person_id. """
     ext_ids = {
         int(r['source_system']): r['external_id']
         for r in person.search_external_ids(entity_id=entity_id,
                                             source_system=sys_lookup_order,
                                             id_type=id_type)
     }
     for pref in sys_lookup_order:
         if ext_ids.get(int(pref)):
             return ext_ids[int(pref)]
     raise Errors.NotFoundError("No fnr for person_id=%r" % (entity_id, ))
Exemple #29
0
    def group_remove_member(self, group_id_type, group_id,
                            member_id_type, member_id):
        """Remove a member from a group.

        :type group_id_type: str
        :param group_id_type: Group identifier type, 'id' or 'group_name'

        :type group_id: str
        :param group_id: Group identifier

        :type member_id_type: str
        :param member_id_type: Member identifier type, 'id' or 'account_name'

        :type member_id: str
        :param member_id: Member identifier

        :rtype: boolean
        """
        # Get the group
        gr = Utils.get(self.db, 'group', group_id_type, group_id)

        if not gr:
            raise Errors.CerebrumRPCException(
                'Group %s:%s does not exist.' % (group_id_type, group_id))

        # Perform auth check
        self.ba.can_alter_group(self.operator_id, gr)

        # Get the member we want to add
        member = Utils.get(self.db, 'entity', member_id_type, member_id)

        if not member:
            raise Errors.CerebrumRPCException(
                'Entity %s:%s does not exist.' % (member_id_type, member_id))

        if not gr.has_member(member.entity_id):
            return False

        GroupAPI.remove_member(gr, member.entity_id)
        return True
    def ephorte_set_standard_role(self, operator, person_id, role, sko,
                                  arkivdel, journalenhet):
        """
        Set given role as standard role.

        There can be only one standard role, thus if another role is
        marked as standard role, it will no longer be the persons
        standard role.
        """
        # Check operators permissions
        if not self.ba.can_add_ephorte_role(operator.get_entity_id()):
            raise PermissionDenied("Currently limited to ephorte admins")
        try:
            person = self.util.get_target(person_id, restrict_to=['Person'])
        except Errors.TooManyRowsError:
            raise CerebrumError("Unexpectedly found more than one person")
        ou = self._get_ou(stedkode=sko)
        # Check that the person has the given role.
        tmp = self.ephorte_role.get_role(person.entity_id,
                                         self._get_role_type(role),
                                         ou.entity_id,
                                         self._get_arkivdel(arkivdel),
                                         self._get_journalenhet(journalenhet))
        # Some sanity checks
        if not tmp:
            raise CerebrumError("Person has no such role")
        elif len(tmp) > 1:
            raise Errors.TooManyRowsError("Unexpectedly found more than one"
                                          " role")
        new_std_role = tmp[0]
        if new_std_role['standard_role'] == 'T':
            return "Role is already standard role"
        # There can be only one standard role
        for row in self.ephorte_role.list_roles(person_id=person.entity_id):
            if row['standard_role'] == 'T':
                self.logger.debug("Unset role %s at %s as standard_role" % (
                    row['role_type'], row['adm_enhet']))
                self.ephorte_role.set_standard_role_val(person.entity_id,
                                                        row['role_type'],
                                                        row['adm_enhet'],
                                                        row['arkivdel'],
                                                        row['journalenhet'],
                                                        'F')
        # Finally set the new standard role
        self.ephorte_role.set_standard_role_val(
            person.entity_id,
            self._get_role_type(role),
            ou.entity_id,
            self._get_arkivdel(arkivdel),
            self._get_journalenhet(journalenhet),
            'T')
        return "OK, set new standard role"