예제 #1
0
    def to_representation(self, data):
        ret = super(ListingSerializer, self).to_representation(data)

        anonymize_identifiable_data = system_anonymize_identifiable_data(self.context['request'].user.username)
        request_user = generic_model_access.get_profile(self.context['request'].user)  # TODO: Get the profile from view request instead of getting it from db again

        if anonymize_identifiable_data:
            ret['contacts'] = []
        check_failed = []
        # owners
        if 'owners' in ret and not anonymize_identifiable_data:
            for owner in ret['owners']:
                user_dict = owner.get('user')
                user_username = None if user_dict is None else user_dict.get('username')

                # if not user_username:
                # raise serializers.ValidationError('Owner field requires correct format')

                owner_profile = generic_model_access.get_profile(user_username)
                # if not owner_profile:
                #    raise serializers.ValidationError('Owner Profile not found')

                # Don't allow user to select a security marking that is above
                # their own access level\
                try:
                    if system_has_access_control(owner_profile.user.username, ret.get('security_marking')) is False:
                        check_failed.append(owner_profile.user.username)
                        # raise serializers.ValidationError(owner_profile.user.username + 'User certificate is invalid')
                except Exception:
                    check_failed.append(owner_profile.user.username)

        ret['cert_issues'] = check_failed
        ret['feedback'] = self._feedback(request_user, data)
        ret['is_bookmarked'] = self._is_bookmarked(request_user, data)
        return ret
    def for_user(self, username):
        objects = super(AccessControlRecommendationFeedbackManager,
                        self).get_queryset()

        profile_instance = Profile.objects.get(user__username=username)
        # filter out private listings
        exclude_orgs = get_user_excluded_orgs(profile_instance)

        objects = objects.filter(
            target_profile=profile_instance,
            target_listing__is_enabled=True,
            target_listing__approval_status=Listing.APPROVED,
            target_listing__is_deleted=False)

        objects = objects.exclude(target_listing__is_private=True,
                                  target_listing__agency__in=exclude_orgs)

        # Filter out listings by user's access level
        ids_to_exclude = []
        for recommend_feedback_obj in objects:
            if not recommend_feedback_obj.target_listing.security_marking:
                logger.debug('Listing {0!s} has no security_marking'.format(
                    recommend_feedback_obj.target_listing.title))
            if not system_has_access_control(
                    username,
                    recommend_feedback_obj.target_listing.security_marking):
                ids_to_exclude.append(recommend_feedback_obj.target_listing.id)
        objects = objects.exclude(target_listing__pk__in=ids_to_exclude)
        return objects
예제 #3
0
def suggest(request_username, search_param_parser):
    """
    Suggest

    It must respects restrictions
     - Private apps (apps only from user's agency)
     - User's max_classification_level

    Args:
        request_username(string)
        search_param_parser(SearchParamParser): Parsed Request Search Object

    Returns:
        listing titles in a list
    """
    # Create ES client
    es_client = elasticsearch_factory.get_client()

    elasticsearch_factory.check_elasticsearch()

    if search_param_parser.search_string is None:
        return []

    user_exclude_orgs = get_user_exclude_orgs(request_username)

    # Override Limit - Only 15 results should come if limit was not set
    if search_param_parser.limit_set is False:
        search_param_parser.limit = constants.ES_SUGGEST_LIMIT

    search_query = elasticsearch_util.make_search_query_obj(
        search_param_parser, exclude_agencies=user_exclude_orgs)
    # Only Retrieve ['title', 'security_marking', 'id'] fields from Elasticsearch for suggestions
    search_query['_source'] = ['title', 'security_marking', 'id']

    # print(json.dumps(search_query, indent=4))  #  Print statement for debugging output
    res = es_client.search(index=settings.ES_INDEX_NAME, body=search_query)

    hits = res.get('hits', {}).get('hits', None)
    if not hits:
        return []

    hit_titles = []

    for hit in hits:
        source = hit.get('_source')

        exclude_bool = False
        if not source.get('security_marking'):
            exclude_bool = True
            logger.debug('Listing {0!s} has no security_marking'.format(
                source.get('title')))
        if not system_has_access_control(request_username,
                                         source.get('security_marking')):
            exclude_bool = True

        if exclude_bool is False:
            temp = {'title': source['title'], 'id': source['id']}
            hit_titles.append(temp)

    return hit_titles
예제 #4
0
    def process_next_start(self):
        """
        execute security_marking check on each listing
        """
        while True:
            listing = self.starts.next()

            if not listing['security_marking']:
                logger.debug('Listing {0!s} has no security_marking'.format(
                    listing['title']))
            else:
                if self.featured:
                    if listing['is_featured'] is True:
                        if system_has_access_control(
                                self.username, listing['security_marking']):
                            return listing
                else:
                    if system_has_access_control(self.username,
                                                 listing['security_marking']):
                        return listing
예제 #5
0
    def validate_security_marking(self, value):
        # don't allow user to select a security marking that is above
        # their own access level
        username = self.context['request'].user.username

        if value:
            if not system_has_access_control(username, value):
                raise serializers.ValidationError(
                    'Security marking too high for current user')

        return value
예제 #6
0
 def process_next_start(self):
     """
     execute security_marking check on each listing
     """
     while True:
         listing = self.starts.next()
         if not listing.security_marking:
             logger.debug('Listing {0!s} has no security_marking'.format(
                 listing.title))
         if system_has_access_control(self.username,
                                      listing.security_marking):
             return listing
예제 #7
0
    def validate_security_marking(self, value):
        # don't allow user to select a security marking that is above
        # their own access level
        profile = generic_model_access.get_profile(
            self.context['request'].user.username)

        if value:
            if not system_has_access_control(profile.user.username, value):
                raise serializers.ValidationError(
                    'Security marking too high for current user')
        else:
            raise serializers.ValidationError('Security marking is required')
        return value
예제 #8
0
    def for_user(self, username):
        objects = super(AccessControlListingManager, self).get_queryset()
        profile_instance = Profile.objects.get(user__username=username)
        # filter out private listings
        exclude_orgs = get_user_excluded_orgs(profile_instance)

        objects = objects.exclude(is_private=True, agency__in=exclude_orgs)
        objects = self.apply_select_related(objects)

        # Filter out listings by user's access level
        ids_to_exclude = []
        for i in objects:
            if not i.security_marking:
                logger.debug('Listing {0!s} has no security_marking'.format(
                    i.title))
            if not system_has_access_control(username, i.security_marking):
                ids_to_exclude.append(i.id)
        objects = objects.exclude(pk__in=ids_to_exclude)

        return objects
예제 #9
0
    def for_user(self, username):
        """
        This method causes:
        sqlite3.OperationalError: too many SQL variables
        To fix this error, post filtering in memory needs to happen

        Example Code:
            serializer = serializers.ImageSerializer(queryset, many=True, context={'request': request})
            serializer_iterator = recommend_utils.ListIterator(serializer.data)
            pipeline_list = [pipes.ListingDictPostSecurityMarkingCheckPipe(request.user.username)]

            recommended_listings = pipeline.Pipeline(serializer_iterator, pipeline_list).to_list()
        """
        objects = super(AccessControlImageManager, self).get_queryset()

        # filter out listings by user's access level
        images_to_exclude = []
        for i in objects:
            if not system_has_access_control(username, i.security_marking):
                images_to_exclude.append(i.id)
        objects = objects.exclude(id__in=images_to_exclude)

        return objects
예제 #10
0
def search(request_username, search_param_parser):
    """
    Filter Listings
    Too many variations to cache results

    Users shall be able to search for listings'
     - title
     - description
     - description_short
     - tags__name

    Filter by
     - category
     - agency
     - listing types
     - exportable

    Users shall only see what they are authorized to see
      'is_private': false,
      'approval_status': 'APPROVED',
      'is_deleted': false,
      'is_enabled': true,
      'security_marking': 'UNCLASSIFIED',

    Sorted by Relevance
      'avg_rate': 0,
      'total_votes': 0,
      'total_rate5': 0,
      'total_rate4': 0,
      'total_rate3': 0,
      'total_rate2': 0,
      'total_rate1': 0,
      'total_reviews': 0,
      'is_featured': true,

    It must respects restrictions
     - Private apps (apps only from user's agency)
     - User's max_classification_level

    Args:
        username(str): username
        search_param_parser(SearchParamParser): parameters
    """
    elasticsearch_factory.check_elasticsearch()
    # Create ES client
    es_client = elasticsearch_factory.get_client()

    user_exclude_orgs = get_user_exclude_orgs(request_username)
    search_query = elasticsearch_util.make_search_query_obj(
        search_param_parser, exclude_agencies=user_exclude_orgs)

    # print(json.dumps(search_query, indent=4))
    res = es_client.search(index=settings.ES_INDEX_NAME, body=search_query)

    hits = res.get('hits', {})
    inner_hits = hits.get('hits', None)
    if not hits:
        return []

    hit_titles = []

    excluded_count = 0

    for current_innter_hit in inner_hits:
        source = current_innter_hit.get('_source')
        source['_score'] = current_innter_hit.get('_score')

        # Add URLs to icons
        image_keys_to_add_url = [
            'large_icon', 'small_icon', 'banner_icon', 'large_banner_icon'
        ]

        for image_key in image_keys_to_add_url:
            if source.get(image_key) is not None:
                if search_param_parser.base_url:
                    source[image_key]['url'] = '{!s}/api/image/{!s}/'.format(
                        search_param_parser.base_url, source[image_key]['id'])
                else:
                    source[image_key]['url'] = '/api/image/{!s}/'.format(
                        source[image_key]['id'])

        exclude_bool = False
        if not source.get('security_marking'):
            exclude_bool = True
            logger.debug('Listing {0!s} has no security_marking'.format(
                source.get('title')))
        if not system_has_access_control(request_username,
                                         source.get('security_marking')):
            exclude_bool = True

        if exclude_bool is False:
            hit_titles.append(source)
        else:
            excluded_count = excluded_count + 1

    # Total Records in Elasticsearch
    final_count = hits.get('total')
    # Total Records minus what the user does not have access to see, this count should never be below zero
    # TODO: Figure out smarter logic for excluded_count compensation (rivera 11/14/2016)
    final_count_with_excluded = final_count - excluded_count

    final_results = {'count': final_count_with_excluded, 'results': hit_titles}

    final_results['previous'] = None
    final_results['next'] = None

    # if final_count_with_excluded < 0 then previous and next should be None
    if final_count_with_excluded < 0:
        return final_results

    previous_offset_prediction = search_param_parser.offset - search_param_parser.limit
    next_offset_prediction = search_param_parser.offset + search_param_parser.limit

    final_results['next_offset_prediction'] = next_offset_prediction

    # Previous URL - previous_offset_prediction is less than zero, previous should be None
    if previous_offset_prediction >= 0:
        final_results['previous'] = generate_link(search_param_parser,
                                                  previous_offset_prediction)

    # Next URL
    if next_offset_prediction <= final_count_with_excluded:
        final_results['next'] = generate_link(search_param_parser,
                                              next_offset_prediction)

    return final_results
예제 #11
0
def validate_listing(serializer_instance, data):
    # TODO Put in listing model_access.py
    access_control_instance = plugin_manager.get_system_access_control_plugin()
    profile = generic_model_access.get_profile(serializer_instance.context['request'].user.username)

    # This checks to see if value exist as a key and value is not None
    if not data.get('title'):
        raise serializers.ValidationError('Title is required')

    if 'security_marking' not in data:
        raise serializers.ValidationError('Security Marking is Required')

    # Assign a default security_marking level if none is provided
    if not data.get('security_marking'):
        data['security_marking'] = constants.DEFAULT_SECURITY_MARKING

    if not access_control_instance.validate_marking(data['security_marking']):
        raise serializers.ValidationError('Security Marking Format is Invalid')

    # Don't allow user to select a security marking that is above
    # their own access level
    if not system_has_access_control(profile.user.username, data.get('security_marking')):
        raise serializers.ValidationError('Security marking too high for current user')

    # Don't allow 2nd-party user to be an submit/edit a listing
    if system_anonymize_identifiable_data(profile.user.username):
        raise serializers.ValidationError('Permissions are invalid for current profile')

    # TODO: errors.PermissionDenied instead of serializers.ValidationError

    data['description'] = data.get('description')
    data['launch_url'] = data.get('launch_url')
    data['version_name'] = data.get('version_name')
    data['unique_name'] = data.get('unique_name')
    data['what_is_new'] = data.get('what_is_new')
    data['description_short'] = data.get('description_short')
    data['usage_requirements'] = data.get('usage_requirements')
    data['system_requirements'] = data.get('system_requirements')
    data['is_private'] = data.get('is_private', False)
    data['is_exportable'] = data.get('is_exportable', False)
    data['security_marking'] = data.get('security_marking')

    # only checked on update, not create
    data['is_enabled'] = data.get('is_enabled', False)
    data['is_508_compliant'] = data.get('is_508_compliant', False)
    data['is_featured'] = data.get('is_featured', False)
    data['approval_status'] = data.get('approval_status')

    # Agency
    agency_title = None if data.get('agency') is None else data.get('agency', {}).get('title')
    if agency_title:
        data['agency'] = agency_model_access.get_agency_by_title(agency_title)
        if data['agency'] is None:
            raise serializers.ValidationError('Invalid Agency')
    else:
        data['agency'] = profile.organizations.all()[0]

    # Listing Type
    type_title = None if data.get('listing_type') is None else data.get('listing_type', {}).get('title')
    if type_title:
        data['listing_type'] = model_access.get_listing_type_by_title(type_title)
    else:
        data['listing_type'] = None

    # Images
    image_keys = ['small_icon', 'large_icon', 'banner_icon', 'large_banner_icon']

    for image_key in image_keys:
        current_image_value = data.get(image_key)
        if current_image_value:
            if 'id' not in current_image_value:
                raise serializers.ValidationError('Image({!s}) requires a {!s}'.format(image_key, 'id'))
            if current_image_value.get('security_marking') is None:
                current_image_value['security_marking'] = constants.DEFAULT_SECURITY_MARKING
            if not access_control_instance.validate_marking(current_image_value['security_marking']):
                raise errors.InvalidInput('{!s} Security Marking is invalid'.format(image_key))
        else:
            data[image_key] = None

    # Screenshot
    screenshots = data.get('screenshots')
    if screenshots is not None:
        screenshots_out = []
        image_require_fields = ['id']
        for screenshot_set in screenshots:

            if ('small_image' not in screenshot_set or
                    'large_image' not in screenshot_set):
                raise serializers.ValidationError(
                    'Screenshot Set requires {0!s} fields'.format('small_image, large_icon'))
            screenshot_small_image = screenshot_set.get('small_image')
            screenshot_large_image = screenshot_set.get('large_image')

            for field in image_require_fields:
                if field not in screenshot_small_image:
                    raise serializers.ValidationError('Screenshot Small Image requires a {0!s}'.format(field))

            for field in image_require_fields:
                if field not in screenshot_large_image:
                    raise serializers.ValidationError('Screenshot Large Image requires a {0!s}'.format(field))

            if not screenshot_small_image.get('security_marking'):
                screenshot_small_image['security_marking'] = constants.DEFAULT_SECURITY_MARKING
            if not access_control_instance.validate_marking(screenshot_small_image['security_marking']):
                raise errors.InvalidInput('Security Marking is invalid')

            if not screenshot_large_image.get('security_marking'):
                screenshot_large_image['security_marking'] = constants.DEFAULT_SECURITY_MARKING
            if not access_control_instance.validate_marking(screenshot_large_image['security_marking']):
                raise errors.InvalidInput('Security Marking is invalid')

            screenshots_out.append(screenshot_set)
            data['screenshots'] = screenshots_out
    else:
        data['screenshots'] = None

    # Contacts
    if 'contacts' in data:
        for contact in data['contacts']:
            if 'name' not in contact:
                raise serializers.ValidationError('Contact requires [name] field')
            if 'email' not in contact:
                raise serializers.ValidationError('Contact requires [email] field')
            if 'secure_phone' not in contact:
                contact['secure_phone'] = None
            if 'unsecure_phone' not in contact:
                contact['unsecure_phone'] = None
            if 'contact_type' not in contact:
                raise serializers.ValidationError('Contact requires [contact_type] field')

            contact_type = contact.get('contact_type')
            contact_type_name = None if contact_type is None else contact_type.get('name')

            if not contact_type_name:
                raise serializers.ValidationError('Contact field requires correct format')

            contact_type_instance = contact_type_model_access.get_contact_type_by_name(contact_type_name)
            if not contact_type_instance:
                raise serializers.ValidationError('Contact Type [{}] not found'.format(contact_type_name))

    # owners
    owners = []
    if 'owners' in data:
        for owner in data['owners']:
            user_dict = owner.get('user')
            user_username = None if user_dict is None else user_dict.get('username')

            if not user_username:
                raise serializers.ValidationError('Owner field requires correct format')

            owner_profile = generic_model_access.get_profile(user_username)
            if not owner_profile:
                raise serializers.ValidationError('Owner Profile not found')

            # Don't allow user to select a security marking that is above
            # their own access level
            if not system_has_access_control(owner_profile.user.username, data.get('security_marking')):
                raise serializers.ValidationError('Security marking too high for current owner profile')

            # Don't allow 2nd-party user to be an owner of a listing
            if system_anonymize_identifiable_data(owner_profile.user.username):
                raise serializers.ValidationError('Permissions are invalid for current owner profile')

            owners.append(owner_profile)
    data['owners'] = owners

    # Categories
    categories = []
    if 'categories' in data:
        for category in data['categories']:
            category_title = category.get('title')
            if not category_title:
                raise serializers.ValidationError('Categories field requires correct format')

            category_instance = category_model_access.get_category_by_title(category_title)
            if not category_instance:
                raise serializers.ValidationError('Category [{}] not found'.format(category_title))

            categories.append(category_instance)
    data['categories'] = categories

    # Intents
    intents = []
    if 'intents' in data:
        for intent in data['intents']:
            intent_action = intent.get('action')
            if not intent_action:
                raise serializers.ValidationError('Intent field requires correct format')

            intent_instance = intent_model_access.get_intent_by_action(intent_action)
            if not intent_instance:
                raise serializers.ValidationError('Intent Action [{}] not found'.format(intent_action))

            intents.append(intent_instance)
    data['intents'] = intents

    # doc urls will be created in create()
    if 'doc_urls' in data:
        pass

    # tags will be created (if necessary) in create()
    if 'tags' in data:
        pass

    return data