protected override bool Validate(OrganizationServiceContext context, CrmEntitySearchResult result)
        {
            // With permissions now indexed, invalid results should have been filtered out index time.
            // Monitor whether this is true or whether the permission indexing is missing corner cases.
            if (!base.Validate(context, result))
            {
                return(false);
            }

            if (result.Url == null)
            {
                ADXTrace.Instance.TraceWarning(TraceCategory.Application, string.Format("Search result had invalid URL. Logical name: {0}, ID: {1}", EntityNamePrivacy.GetEntityName(result.EntityLogicalName), result.EntityID));
                return(false);
            }

            if (!ValidateCmsSecurityProvider(context, result))
            {
                ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Search result failed CMS security check. Logical name: {0}, ID: {1}", EntityNamePrivacy.GetEntityName(result.EntityLogicalName), result.EntityID));
                if (!ValidateEntityPermission(context, result))
                {
                    ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Search result failed entity permissions security check. Logical name: {0}, ID: {1}", EntityNamePrivacy.GetEntityName(result.EntityLogicalName), result.EntityID));
                    return(false);
                }
            }

            // Checking products and CALs for a full page of results can be costly
            // Only check if explicitly enabled (e.g. because a customer is having issues with CAL/product indexing)
            if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.CALProductSearchPostFiltering))
            {
                var contentAccessLevelProvider = new ContentAccessLevelProvider();
                var productAccessProvider      = new ProductAccessProvider();

                if (!ValidateContentAccessLevelAndProducts(context, result, contentAccessLevelProvider, productAccessProvider))
                {
                    ADXTrace.Instance.TraceError(TraceCategory.Application, string.Format("Search result failed CAL or product filtering. Logical name: {0}, ID: {1}", EntityNamePrivacy.GetEntityName(result.EntityLogicalName), result.EntityID));
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Validates the content access level and product filtering.
        /// </summary>
        /// <param name="serviceContext">The service context.</param>
        /// <param name="result">The result.</param>
        /// <returns>Boolean</returns>
        private bool ValidateContentAccessLevelAndProducts(OrganizationServiceContext serviceContext, CrmEntitySearchResult result, ContentAccessLevelProvider contentAccessLevelProvider, ProductAccessProvider productAccessProvider)
        {
            if (result == null || result.EntityID == null)
            {
                return(false);
            }

            // Content access levels/products will only filter knowledge articles
            if (result.EntityLogicalName != "knowledgearticle")
            {
                return(true);
            }

            var baseFetch = string.Format(@"
				<fetch mapping='logical'>
					<entity name='knowledgearticle'>
						<filter type='and'>
							<condition attribute='knowledgearticleid' operator='eq' value='{0}' />
						</filter>
					</entity>
				</fetch>"                , result.EntityID);

            if (!contentAccessLevelProvider.IsEnabled() && !productAccessProvider.IsEnabled())
            {
                return(true);
            }

            Fetch filterCheckFetch = Fetch.Parse(baseFetch);

            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, filterCheckFetch);
            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, filterCheckFetch);

            // If there are no results, user didn't have access to products or CALs associated to article
            var response = (RetrieveMultipleResponse)serviceContext.Execute(filterCheckFetch.ToRetrieveMultipleRequest());

            return(response.EntityCollection != null && response.EntityCollection.Entities.Any());
        }
        private bool ValidateEntityPermission(OrganizationServiceContext serviceContext, CrmEntitySearchResult result)
        {
            if (!AdxstudioCrmConfigurationManager.GetCrmSection().ContentMap.Enabled)
            {
                return(false);
            }

            var permissionResult = new CrmEntityPermissionProvider(PortalName).TryAssert(serviceContext, result.Entity);

            return(permissionResult.RulesExist && permissionResult.CanRead);
        }
 private bool ValidateCmsSecurityProvider(OrganizationServiceContext serviceContext, CrmEntitySearchResult result)
 {
     return(PortalCrmConfigurationManager.CreateCrmEntitySecurityProvider(PortalName)
            .TryAssert(serviceContext, result.Entity, CrmEntityRight.Read));
 }
        public virtual ICrmEntitySearchResult GetResult(Document document, float score, int number)
        {
            if (document == null)
            {
                throw new ArgumentNullException("document");
            }

            var logicalNameField = document.GetField(Index.LogicalNameFieldName);

            if (logicalNameField == null || !logicalNameField.IsStored)
            {
                return(null);
            }

            var logicalName = logicalNameField.StringValue;

            var primaryKeyLogicalNameField = document.GetField(Index.PrimaryKeyLogicalNameFieldName);

            if (primaryKeyLogicalNameField == null || !primaryKeyLogicalNameField.IsStored)
            {
                return(null);
            }

            var primaryKeyPropertyName = primaryKeyLogicalNameField.StringValue;

            var context = Index.DataContext;

            var primaryKeyField = document.GetField(Index.PrimaryKeyFieldName);

            if (primaryKeyField == null || !primaryKeyField.IsStored)
            {
                return(null);
            }

            var primaryKey = new Guid(primaryKeyField.StringValue);

            var titleField = document.GetField(Index.TitleFieldName);

            var title = string.Empty;

            if (logicalName != "annotation")
            {
                if (titleField == null || !titleField.IsStored)
                {
                    return(null);
                }
                title = titleField.StringValue;
            }

            var entity = context.CreateQuery(logicalName).FirstOrDefault(e => e.GetAttributeValue <Guid>(primaryKeyPropertyName) == primaryKey);

            if (entity == null)
            {
                return(null);
            }

            var url = GetUrl(context, document, score, number, entity);

            var result = new CrmEntitySearchResult(entity, score, number, title, url);

            if (!Validate(context, result))
            {
                return(null);
            }

            result.Fragment = FragmentProvider.GetFragment(document);

            return(result);
        }
 protected virtual bool Validate(OrganizationServiceContext context, CrmEntitySearchResult result)
 {
     return(true);
 }