Esempio n. 1
0
def test_string():
    chain = validator.Chain()
    chain.add(validator.String(min_len=3))
    chain.add(validator.String(max_len=6, trim=True))
    assert chain('xxx') == 'xxx'
    assert chain('xxxx    ') == 'xxxx'
    with pytest.raises(ValueError):
        chain('x')
    with pytest.raises(ValueError):
        chain('xxxxxxxxxx')
Esempio n. 2
0
class AccountQuarantineListResource(Resource):
    """Quarantines for a single account."""

    account_quarantines_filter = api.parser()
    account_quarantines_filter.add_argument(
        'context',
        type=validator.String(),
        location=['form', 'json'],
        help='Consider locked status based on context.')

    @api.marshal_with(AccountQuarantineList)
    @api.doc(parser=account_quarantines_filter)
    @auth.require()
    def get(self, name):
        """Get account quarantines."""
        args = self.account_quarantines_filter.parse_args()

        spreads = None
        if args.context:
            try:
                spreads = [int(db.const.Spread(args.context))]
            except Errors.NotFoundError:
                abort(404, message='Unknown context {!r}'.format(
                    args.context))

        ac = find_account(name)

        qh = QuarantineHandler.check_entity_quarantines(
            db=db.connection,
            entity_id=ac.entity_id,
            spreads=spreads)
        locked = qh.is_locked()

        # TODO: Replace with list of hrefs to quarantines resource?
        quarantines = []
        for q in ac.get_entity_quarantine(only_active=True):
            quarantines.append(_format_quarantine(q))

        return {
            'locked': locked,
            'quarantines': quarantines
        }
Esempio n. 3
0
class ContextListResource(Resource):
    """Resource for contexts."""

    context_search_filter = api.parser()
    context_search_filter.add_argument('entity_types',
                                       type=validator.String(),
                                       action='append',
                                       help='Filter by entity type(s)')

    @api.marshal_list_with(Context)
    @api.doc(parser=context_search_filter)
    @auth.require()
    def get(self):
        """List contexts"""
        args = self.context_search_filter.parse_args()
        filters = {
            key: value
            for (key, value) in args.items() if value is not None
        }

        entity_types = None

        if 'entity_types' in filters:
            etypes = []
            for etype in filters['entity_types']:
                try:
                    entity_type = db.const.EntityType(etype)
                    int(entity_type)
                    etypes.append(entity_type)
                except Errors.NotFoundError:
                    abort(404,
                          message='Unknown entity type for '
                          'entity_types={}'.format(etype))
            entity_types = etypes or None

        es = EntitySpread(db.connection)
        contexts = es.list_spreads(entity_types=entity_types)
        return contexts
Esempio n. 4
0
class AccountPasswordResource(Resource):
    """Resource for account password change."""

    new_password_parser = api.parser()
    new_password_parser.add_argument(
        'password',
        type=validator.String(),
        required=False,
        location=['form', 'json'],
        help='Password, leave empty to generate one',
    )

    @db.autocommit
    @auth.require()
    @api.expect(new_password_parser)
    @api.response(200, 'Password changed', PasswordChanged)
    @api.response(400, 'Invalid password')
    def post(self, name):
        """Change the password for this account."""
        ac = find_account(name)
        data = self.new_password_parser.parse_args()
        password = data.get('password', None)
        if password is None:
            password = ac.make_passwd(ac.account_name)
        assert isinstance(password, text_type)
        try:
            check_password(password, account=ac, structured=False)
        except PasswordNotGoodEnough as e:
            abort(400, 'Bad password: {}'.format(e))
        ac.set_password(password)
        # Remove "weak password" quarantine
        for q in (db.const.quarantine_autopassord,
                  db.const.quarantine_svakt_passord):
            ac.delete_entity_quarantine(q)
        ac.write_db()
        return {'password': password}
Esempio n. 5
0
class GroupResource(Resource):
    """ Resource for a single group. """
    @staticmethod
    def group_info(group):
        return {
            'name': utils._db_decode(group.group_name),
            'id': group.entity_id,
            'created_at': group.created_at,
            'expire_date': group.expire_date,
            'visibility': group.visibility,
            'description': utils._db_decode(group.description),
            'contexts': [row['spread'] for row in group.get_spread()],
        }

    @staticmethod
    def visibility_type(vis):
        lut = {
            'all': db.const.GroupVisibility('A'),
            'internal': db.const.GroupVisibility('I'),
            'none': db.const.GroupVisibility('N')
        }
        return lut[vis.lower()]

    # Either this or import undecorated other places
    @staticmethod
    def _get(name, idtype='name'):
        """ Undecorated get(). """
        group = find_group(name, idtype)
        return GroupResource.group_info(group)

    # GET /<group>
    #
    @auth.require()
    @api.response(200, 'Group found', Group)
    @api.response(404, 'Group not found')
    @api.marshal_with(Group)
    def get(self, name):
        """ Get group information. """
        return self._get(name)

    # PUT /<group>
    #
    new_group_parser = reqparse.RequestParser()
    new_group_parser.add_argument(
        'visibility',
        choices=GroupVisibility._rev_map.keys(),
        required=True,
        location='form',
        case_sensitive=False,
        nullable=False,
        help='{error_msg}',
    )
    new_group_parser.add_argument(
        'description',
        type=validator.String(min_len=0, max_len=512),
        location='form',
        nullable=True,
        help='{error_msg}',
    )

    @db.autocommit
    @auth.require()
    @api.expect(new_group_parser)
    @api.response(200, 'Group updated', Group)
    @api.response(201, 'Group created', Group)
    @api.response(400, 'Illegal group name')
    @api.marshal_with(Group)
    def put(self, name):
        """ Create or update group. """
        args = self.new_group_parser.parse_args()
        args['visibility'] = GroupVisibility.unserialize(args['visibility'])
        name = name.encode(db.encoding)

        result_code = 200
        try:
            # find and update all attributes
            group = utils.get_group(name, 'name', 'Group')
            changes = False
            if group.visibility != args['visibility']:
                group.visibility = args['visibility']
                changes = True
            if group.description != args['description']:
                group.description = args['description'].encode(db.encoding)
                changes = True
            if changes:
                group.write_db()
        except utils.EntityLookupError:
            # create group
            group = Factory.get('Group')(db.connection)
            bad_name = group.illegal_name(name)
            if bad_name:
                abort(400, message="Illegal group name: {!s}".format(bad_name))
            group.new(auth.account.entity_id, args['visibility'], name,
                      args['description'])
            result_code = 201
        return self.group_info(group), result_code

    # TODO: Do we want PATCH?
    #
    #   # PATCH /<group>
    #   #
    #   update_group_parser = new_group_parser.copy()
    #
    #   @db.autocommit
    #   @auth.require()
    #   @api.expect(update_group_parser)
    #   @api.response(200, 'group updated', Group)
    #   @api.response(404, 'group not found')
    #   @api.marshal_with(Group)
    #   def patch(self, name):
    #       """ Alter group attributes. """
    #       args = self.update_group_parser.parse_args()
    #       group = find_group(name)
    #
    #       changes = False
    #       if group.description != args['description']:
    #           group.description = args['description']
    #           changes = True
    #       if group.visibility != args['visibility']:
    #           group.visibility = args['visibility']
    #           changes = True
    #       if changes:
    #           group.write_db()
    #
    #       return self.group_info(group)

    # DELETE /<group>
    #
    @db.autocommit
    @auth.require()
    @api.response(204, 'group deleted')
    @api.response(404, 'group not found')
    def delete(self, name):
        """ Delete group. """
        # TODO: Find out if any user has group as dfg?
        #       If so, 409 CONFLICT?
        name = name.encode(db.encoding)
        group = find_group(name)
        group.delete()
Esempio n. 6
0
class GroupListResource(Resource):
    """Resource for list of groups."""

    # GET /
    #
    group_search_filter = api.parser()
    group_search_filter.add_argument(
        'name',
        type=validator.String(),
        help='Filter by name. Accepts * and ? as wildcards.')
    group_search_filter.add_argument(
        'description',
        type=validator.String(),
        help='Filter by description. Accepts * and ? as wildcards.')
    group_search_filter.add_argument('context',
                                     type=validator.String(),
                                     dest='spread',
                                     help='Filter by context.')
    group_search_filter.add_argument(
        'member_id',
        type=int,
        action='append',
        help='Filter by memberships. Only groups that have member_id as a '
        'member will be returned. If member_id is a sequence, the group '
        'is returned if any of the IDs are a member of it.')
    group_search_filter.add_argument(
        'indirect_members',
        type=bool,
        help='If true, alter the behavior of the member_id filter to also '
        'include groups where member_id is an indirect member.')
    group_search_filter.add_argument('filter_expired',
                                     type=bool,
                                     help='If false, include expired groups.')
    group_search_filter.add_argument(
        'expired_only',
        type=bool,
        help='If true, only include expired groups.')
    group_search_filter.add_argument('creator_id',
                                     type=int,
                                     help='Filter by creator entity ID.')

    @auth.require()
    @api.marshal_with(GroupListItem, as_list=True, envelope='groups')
    @api.doc(parser=group_search_filter)
    def get(self):
        """List groups."""
        args = self.group_search_filter.parse_args()
        filters = {
            key: value
            for (key, value) in args.items() if value is not None
        }

        if 'spread' in filters:
            try:
                group_spread = db.const.Spread(filters['spread'])
                filters['spread'] = int(group_spread)
            except Errors.NotFoundError:
                abort(404,
                      message='Unknown context={}'.format(filters['spread']))

        gr = Factory.get('Group')(db.connection)

        groups = list()
        for row in gr.search(**filters):
            group = dict(row)
            group.update({
                'id': group['name'],
                'name': group['name'],
            })
            groups.append(group)
        return groups
Esempio n. 7
0
class GroupMemberListResource(Resource):
    """Resource for list of members of groups."""

    # GET /<group>/members/
    #
    group_member_filter = api.parser()
    group_member_filter.add_argument('type',
                                     type=validator.String(),
                                     dest='member_type',
                                     help='Filter by entity type.')
    group_member_filter.add_argument(
        'context',
        type=validator.String(),
        dest='member_spread',
        help='Filter by context. Accepts * and ? as wildcards.')
    group_member_filter.add_argument(
        'filter_expired',
        type=bool,
        dest='member_filter_expired',
        help='If false, include members that are expired.')

    @auth.require()
    @api.marshal_with(GroupMember, as_list=True, envelope='members')
    @api.doc(parser=group_member_filter)
    @api.doc(params={'name': 'group name'})
    def get(self, name):
        """List members of a group."""
        args = self.group_member_filter.parse_args()
        filters = {
            key: value
            for (key, value) in args.items() if value is not None
        }

        if 'member_type' in filters:
            try:
                member_type = db.const.EntityType(filters['member_type'])
                filters['member_type'] = int(member_type)
            except Errors.NotFoundError:
                abort(404,
                      message='Unknown entity type for type={}'.format(
                          filters['member_type']))

        if 'member_spread' in filters:
            try:
                member_spread = db.const.Spread(filters['member_spread'])
                filters['member_spread'] = int(member_spread)
            except Errors.NotFoundError:
                abort(404,
                      message='Unknown context for context={}'.format(
                          filters['member_spread']))

        gr = find_group(name)

        filters['group_id'] = gr.entity_id
        filters['include_member_entity_name'] = True

        members = list()
        for row in gr.search_members(**filters):
            member = dict(row)
            member.update({
                'id':
                row['member_id'],
                'name':
                row['member_name'],
                'href':
                utils.href_from_entity_type(entity_type=row['member_type'],
                                            entity_id=row['member_id'],
                                            entity_name=row['member_name']),
            })
            members.append(member)
        return members

    # PUT /<group>/members
    #
    group_members_parser = api.parser()
    group_members_parser.add_argument(
        'members',
        type=validator.Integer(min_val=0),
        location=['form', 'json'],
        nullable=False,
        required=False,
        default=[],
        action='append',
        help='{error_msg}',
    )

    @db.autocommit
    @auth.require()
    @api.expect(group_members_parser)
    @api.response(200, 'members added')
    @api.response(404, 'group or member not found')
    def put(self, name):
        """ Ensure that the supplied member list are the only members of the group. """
        args = self.group_members_parser.parse_args()

        group = find_group(name)
        members = set(row['member_id'] for row in group.search_members(
            group_id=group.entity_id, member_filter_expired=False))
        to_remove = members - set(args['members'])
        to_add = set(args['members']) - members

        for entity_id in to_remove:
            member = find_entity(entity_id)
            group.remove_member(member.entity_id)
        for entity_id in to_add:
            member = find_entity(entity_id)
            group.add_member(member.entity_id)
Esempio n. 8
0
class ExternalIdResource(Resource):
    """Resource for external ID searches."""

    # GET /
    #
    extid_search_filter = api.parser()
    extid_search_filter.add_argument(
        'source_system',
        type=validator.String(),
        action='append',
        help='Filter by one or more source systems.')
    extid_search_filter.add_argument('id_type',
                                     type=validator.String(),
                                     action='append',
                                     help='Filter by one or more ID types.')
    extid_search_filter.add_argument('external_id',
                                     type=validator.String(),
                                     required=True,
                                     help='Filter by external ID.')

    @auth.require()
    @api.doc(parser=extid_search_filter)
    @api.marshal_with(ExternalIdItem, as_list=True, envelope='external_ids')
    def get(self):
        """Get external IDs"""
        args = self.extid_search_filter.parse_args()
        filters = {
            key: value
            for (key, value) in args.items() if value is not None
        }
        filters['entity_type'] = db.const.entity_person
        eei = EntityExternalId(db.connection)

        if 'source_system' in filters:
            source_systems = []
            if not isinstance(filters['source_system'], list):
                filters['source_system'] = [filters['source_system']]
            for entry in filters['source_system']:
                try:
                    code = int(db.const.AuthoritativeSystem(entry))
                    source_systems.append(code)
                except Errors.NotFoundError:
                    abort(404,
                          message='Unknown source_system={}'.format(entry))
            filters['source_system'] = source_systems

        if 'id_type' in filters:
            id_types = []
            if not isinstance(filters['id_type'], list):
                filters['id_type'] = [filters['id_type']]
            for entry in filters['id_type']:
                try:
                    if entry not in models.ExternalIdType.valid_types():
                        raise Errors.NotFoundError
                    code = int(models.ExternalIdType.unserialize(entry))
                    id_types.append(code)
                except Errors.NotFoundError:
                    abort(404, message='Unknown id_type={}'.format(entry))
            filters['id_type'] = id_types

        strip_wildcards = {ord(c): '' for c in '*?%_'}
        if 'external_id' in filters:
            filters['external_id'] = filters['external_id'].translate(
                strip_wildcards)

        results = list()
        for row in eei.search_external_ids(**filters):
            entry = dict(row)
            # id for the href builder, won't be shown in output
            entry['id'] = entry['entity_id']
            results.append(entry)
        return results
def test_string_validator_normalizes_unicode():
    assert validator.String()(OHM_SIGN) == LETTER_OMEGA
Esempio n. 10
0
class AccountListResource(Resource):
    """Resource for list of accounts."""

    account_search_filter = api.parser()
    account_search_filter.add_argument(
        'name',
        type=validator.String(),
        help='Filter by account name. Accepts * and ? as wildcards.')
    account_search_filter.add_argument(
        'context',
        type=validator.String(),
        dest='spread',
        help='Filter by context. Accepts * and ? as wildcards.')
    account_search_filter.add_argument(
        'owner_id',
        type=int,
        help='Filter by owner entity ID.')
    account_search_filter.add_argument(
        'owner_type',
        type=validator.String(),
        help='Filter by owner entity type.')
    account_search_filter.add_argument(
        'expire_start',
        type=validator.String(),
        help='Filter by expiration start date.')
    account_search_filter.add_argument(
        'expire_stop',
        type=validator.String(),
        help='Filter by expiration end date.')

    @api.marshal_with(AccountList)
    @api.doc(parser=account_search_filter)
    @auth.require()
    def get(self):
        """List accounts."""
        args = self.account_search_filter.parse_args()
        filters = {key: value for (key, value) in args.items()
                   if value is not None}

        if 'owner_type' in filters:
            try:
                owner_type = db.const.EntityType(filters['owner_type'])
                filters['owner_type'] = int(owner_type)
            except Errors.NotFoundError:
                abort(404,
                      message='Unknown entity type for owner_type={}'.format(
                          filters['owner_type']))

        ac = Factory.get('Account')(db.connection)

        accounts = list()
        for row in ac.search(**filters):
            account = dict(row)
            account.update({
                'id': account['name'],
                'owner': {
                    'id': account['owner_id'],
                    'type': account['owner_type'],
                }
            })
            accounts.append(account)
        return {'accounts': accounts}
Esempio n. 11
0
        ctype='AccountHomeStatus',
        description='Home status'),
    'disk_id': fields.base.Integer(
        description='Disk entity ID'),
})

AccountHomeList = api.model('AccountHomeList', {
    'homes': fields.base.List(
        fields.base.Nested(AccountHome),
        description='Home directories'),
})

password_parser = api.parser()
password_parser.add_argument(
    'password',
    type=validator.String(),
    required=True,
    location=['form', 'json'],
    help='Password',
)

PasswordChanged = api.model('PasswordChanged', {
    'password': fields.base.String(
        description='New password')
})

PasswordVerification = api.model('PasswordVerification', {
    'verified': fields.base.Boolean(
        description='Did the password match?')
})