Exemplo n.º 1
0
        public override void Render(Context context, TextWriter result)
        {
            IPortalLiquidContext portalLiquidContext;

            if (!context.TryGetPortalLiquidContext(out portalLiquidContext))
            {
                return;
            }

            using (TextWriter xml = new StringWriter())
            {
                base.Render(context, xml);

                var fetch = Fetch.Parse(xml.ToString());

                var right = GetRight(context);

                CrmEntityPermissionProvider.EntityPermissionRightResult permissionResult = new CrmEntityPermissionProvider()
                                                                                           .TryApplyRecordLevelFiltersToFetch(portalLiquidContext.PortalViewContext.CreateServiceContext(), right, fetch);

                // Apply Content Access Level filtering
                var contentAccessLevelProvider = new ContentAccessLevelProvider();
                contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);

                // Apply Product filtering
                var productAccessProvider = new ProductAccessProvider();
                productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetch);

                context.Scopes.Last()[_variableName] = new FetchXmlQueryDrop(portalLiquidContext, fetch, permissionResult);
            }
        }
        private IQueryable <Entity> GetLookupRecords(string fetchXml, OrganizationServiceContext context)
        {
            var fetch = Fetch.Parse(fetchXml);

            var crmEntityPermissionProvider = new CrmEntityPermissionProvider();

            crmEntityPermissionProvider.TryApplyRecordLevelFiltersToFetch(context, CrmEntityPermissionRight.Read, fetch);

            crmEntityPermissionProvider.TryApplyRecordLevelFiltersToFetch(context, CrmEntityPermissionRight.Append, fetch);

            // Apply Content Access Level filtering
            var contentAccessLevelProvider = new ContentAccessLevelProvider();

            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetch);

            // Apply Product filtering
            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetch);

            var response = (RetrieveMultipleResponse)context.Execute(fetch.ToRetrieveMultipleRequest());

            var data = response.EntityCollection;

            if (data == null || data.Entities == null)
            {
                return(null);
            }

            return(data.Entities.AsQueryable());
        }
Exemplo n.º 3
0
        private Fetch GetBaseArticleFetch(int pageSize = 5, string languageLocaleCode = null)
        {
            const int published = 3;

            // if language locale code is not provided, fallback to the site setting
            if (string.IsNullOrWhiteSpace(languageLocaleCode))
            {
                var portalContext = PortalCrmConfigurationManager.CreatePortalContext();
                languageLocaleCode = portalContext.ServiceContext.GetSiteSettingValueByName(portalContext.Website, "KnowledgeManagement/Article/Language");
            }
            var optionalLanguageCondition = string.IsNullOrWhiteSpace(languageLocaleCode) ? string.Empty : string.Format("<condition entityname='language_locale' attribute='code' operator='eq' value = '{0}' />", languageLocaleCode);

            var articlesFetchXmlFormat = @"
			<fetch mapping='logical' count='{0}' returntotalrecordcount='true'>
				<entity name='knowledgearticle'>
					<all-attributes /> 
					<link-entity name='languagelocale' from='languagelocaleid' to='languagelocaleid' visible='false' link-type='outer'  alias='language_locale'>
						<attribute name='localeid' />
						<attribute name='code' />
						<attribute name='region' />
						<attribute name='name' />
						<attribute name='language' />
					</link-entity>
					<filter type='and'>
						<condition attribute='isrootarticle' operator='eq' value='0' />
						<condition attribute='statecode' operator='eq' value='{1}' />
						<condition attribute='isinternal' operator='eq' value='0' />
						{2}
					</filter>
				</entity>
			</fetch>"            ;

            var articlesFetchXml = string.Format(articlesFetchXmlFormat, pageSize, published, optionalLanguageCondition);

            var articleFetch = Fetch.Parse(articlesFetchXml);

            // Apply Content Access Level filtering
            var contentAccessProvider = new ContentAccessLevelProvider();

            contentAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, articleFetch);

            // Apply Product filtering
            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, articleFetch);

            return(articleFetch);
        }
        private static Entity GetArticle(OrganizationServiceContext serviceContext, string number, CrmWebsite website, string lang, out string languageLocaleCode)
        {
            const int published     = 3;
            var       portalContext = PortalCrmConfigurationManager.CreatePortalContext();

            languageLocaleCode = lang;

            // If language locale code is NOT provided and multi-language is enabled, then use the context website language.
            var contextLanguageInfo = System.Web.HttpContext.Current.GetContextLanguageInfo();

            if (contextLanguageInfo.IsCrmMultiLanguageEnabled && string.IsNullOrWhiteSpace(languageLocaleCode))
            {
                languageLocaleCode = contextLanguageInfo.ContextLanguage.Code;
            }
            // If language locale code is NOT provided and we're not using multi-language, fall back to site setting.
            else if (string.IsNullOrWhiteSpace(languageLocaleCode))
            {
                languageLocaleCode = portalContext.ServiceContext.GetSiteSettingValueByName(portalContext.Website,
                                                                                            "KnowledgeManagement/Article/Language");
            }

            var optionalLanguageCondition = string.IsNullOrWhiteSpace(languageLocaleCode) ? string.Empty : string.Format("<condition entityname='language_locale' attribute='code' operator='eq' value = '{0}' />", languageLocaleCode);
            var articlesFetchXml          = string.Format(ArticlesFetchXmlFormat, published, number, optionalLanguageCondition);
            var fetchArticles             = Fetch.Parse(articlesFetchXml);

            var settings           = website.Settings;
            var productFilteringOn = settings.Get <bool>(ProductFilteringSiteSettingName);
            var calFilteringOn     = settings.Get <bool>(CalEnabledSiteSettingName);

            if (calFilteringOn)
            {
                // Apply CAL filtering
                var contentAccessLevelProvider = new ContentAccessLevelProvider();
                contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetchArticles);
            }

            if (productFilteringOn)
            {
                // Apply Product filtering
                var productAccessProvider = new ProductAccessProvider();
                productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetchArticles);
            }

            var article = serviceContext.RetrieveSingle(fetchArticles, false, false, RequestFlag.AllowStaleData);

            return(article);
        }
Exemplo n.º 5
0
        private static bool AddPermissionFilterToFetch(Fetch fetch, OrganizationServiceContext serviceContext, CrmEntityPermissionRight right)
        {
            var crmEntityPermissionProvider = new CrmEntityPermissionProvider();

            var result = crmEntityPermissionProvider.TryApplyRecordLevelFiltersToFetch(serviceContext, right, fetch);

            // Apply Content Access Level filtering
            var contentAccessLevelProvider = new ContentAccessLevelProvider();

            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);

            // Apply Product filtering
            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);

            return(result.GlobalPermissionGranted && result.PermissionGranted);
        }
Exemplo n.º 6
0
        private Fetch CreateFetch(OrganizationServiceContext context,
                                  string entityName,
                                  string latitudeFieldName,
                                  string longitudeFieldName)
        {
            var fetchIn = new Fetch
            {
                Entity = new FetchEntity
                {
                    Name    = entityName,
                    Filters = new List <AdxFilter>
                    {
                        new AdxFilter
                        {
                            Type       = LogicalOperator.And,
                            Conditions = new[]
                            {
                                new Condition(latitudeFieldName, ConditionOperator.NotNull),
                                new Condition(longitudeFieldName, ConditionOperator.NotNull)
                            }
                        }
                    }
                }
            };

            var permissionChecker     = new CrmEntityPermissionProvider();
            var permissionCheckResult = permissionChecker.TryApplyRecordLevelFiltersToFetch(context, CrmEntityPermissionRight.Read, fetchIn);

            if (!permissionCheckResult.GlobalPermissionGranted && !permissionCheckResult.PermissionGranted)
            {
                return(null);
            }

            var contentAccessLevelProvider = new ContentAccessLevelProvider();

            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetchIn);

            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetchIn);

            return(fetchIn);
        }
        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);
        }
        protected void AddPermissionFilterToFetch(Fetch fetch, EntityListSettings settings, OrganizationServiceContext serviceContext, CrmEntityPermissionRight right)
        {
            if (!settings.EntityPermissionsEnabled)
            {
                return;
            }

            var crmEntityPermissionProvider = new CrmEntityPermissionProvider();

            var result = crmEntityPermissionProvider.TryApplyRecordLevelFiltersToFetch(serviceContext, right, fetch);

            // Apply Content Access Level filtering
            var contentAccessLevelProvider = new ContentAccessLevelProvider();

            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);

            // Apply Product filtering
            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);

            EntityPermissionDenied = !result.GlobalPermissionGranted && !result.PermissionGranted;
        }
Exemplo n.º 9
0
        /// <summary>
        /// Gets Related Articles of a Category
        /// </summary>
        /// <returns>IEnumerable of Related Article</returns>
        public IEnumerable <RelatedArticle> SelectRelatedArticles()
        {
            var category = this.Select();

            var relatedArticlesFetch = new Fetch
            {
                Distinct = true,
                Entity   = new FetchEntity
                {
                    Name       = "knowledgearticle",
                    Attributes = new List <FetchAttribute>()
                    {
                        new FetchAttribute("articlepublicnumber"),
                        new FetchAttribute("knowledgearticleid"),
                        new FetchAttribute("title"),
                        new FetchAttribute("keywords"),
                        new FetchAttribute("createdon"),
                        new FetchAttribute("statecode"),
                        new FetchAttribute("statuscode"),
                        new FetchAttribute("isrootarticle"),
                        new FetchAttribute("islatestversion"),
                        new FetchAttribute("isprimary"),
                        new FetchAttribute("knowledgearticleviews")
                    },
                    Filters = new List <Filter>()
                    {
                        new Filter
                        {
                            Type       = LogicalOperator.And,
                            Conditions = new List <Condition>()
                            {
                                new Condition("isrootarticle", ConditionOperator.Equal, 0),
                                new Condition("statecode", ConditionOperator.Equal, 3),
                                new Condition("isinternal", ConditionOperator.Equal, 0)
                            }
                        },
                    },
                    Links = new List <Link>()
                    {
                        new Link
                        {
                            Name          = "knowledgearticlescategories",
                            FromAttribute = "knowledgearticleid",
                            ToAttribute   = "knowledgearticleid",
                            Intersect     = true,
                            Visible       = false,
                            Filters       = new List <Filter>()
                            {
                                new Filter
                                {
                                    Type       = LogicalOperator.And,
                                    Conditions = new List <Condition>()
                                    {
                                        new Condition("categoryid", ConditionOperator.Equal, category.Id)
                                    }
                                }
                            }
                        }
                    }
                }
            };

            var relatedArticles = Enumerable.Empty <RelatedArticle>();

            var serviceContext   = this.Dependencies.GetServiceContext();
            var securityProvider = this.Dependencies.GetSecurityProvider();
            var urlProvider      = this.Dependencies.GetUrlProvider();

            // Apply Content Access Level filtering
            var contentAccessProvider = new ContentAccessLevelProvider();

            contentAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, relatedArticlesFetch);

            // Apply Product filtering
            var productAccessProvider = new ProductAccessProvider();

            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, relatedArticlesFetch);

            var relatedArticlesEntityCollection = relatedArticlesFetch.Execute(serviceContext as IOrganizationService);

            if (relatedArticlesEntityCollection != null && relatedArticlesEntityCollection.Entities != null && relatedArticlesEntityCollection.Entities.Any())
            {
                relatedArticles =
                    relatedArticlesEntityCollection.Entities.Where(e => securityProvider.TryAssert(serviceContext, e, CrmEntityRight.Read))
                    .Select(e => new { Title = e.GetAttributeValue <string>("title"), Url = urlProvider.GetUrl(serviceContext, e) })
                    .Where(e => !(string.IsNullOrEmpty(e.Title) || string.IsNullOrEmpty(e.Url)))
                    .Select(e => new RelatedArticle(e.Title, e.Url))
                    .OrderBy(e => e.Title);
            }

            return(relatedArticles);
        }
        /// <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());
        }
Exemplo n.º 11
0
        /// <summary>
        /// Overrides Search behavior to do faceted search with BoboBrowse.Net
        /// </summary>
        /// <param name="query">
        /// The search query.
        /// </param>
        /// <returns>
        /// The <see cref="Query"/>.
        /// </returns>
        protected override Query CreateQuery(ICrmEntityQuery query)
        {
            if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.CmsEnabledSearching))
            {
                var baseQuery      = base.CreateQuery(query);
                var compositeQuery = new BooleanQuery()
                {
                    { baseQuery, Occur.MUST }
                };
                var contentAccessLevelProvider = new ContentAccessLevelProvider();

                compositeQuery.Add(new TermQuery(new Term("_logicalname", "annotation")), Occur.MUST_NOT);

                if (contentAccessLevelProvider.IsEnabled())
                {
                    var calQuery = new BooleanQuery();
                    var userCals = contentAccessLevelProvider.GetContentAccessLevels();

                    ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, "Adding User CALs to Lucene query");

                    foreach (var cal in userCals)
                    {
                        ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, string.Format("User CAL {0}", cal.Id));
                        calQuery.Add(new TermQuery(new Term(FixedFacetsConfiguration.ContentAccessLevel, cal.Id.ToString())), Occur.SHOULD);
                    }
                    calQuery.Add(new TermQuery(new Term(FixedFacetsConfiguration.ContentAccessLevel, "public")), Occur.SHOULD);

                    compositeQuery.Add(calQuery, Occur.MUST);
                }

                var productAccessProvider = new ProductAccessProvider();

                if (productAccessProvider.IsEnabled())
                {
                    var productFilteringQuery = new BooleanQuery
                    {
                        {
                            new TermQuery(
                                new Term(FixedFacetsConfiguration.ProductFieldFacetName, this.Index.ProductAccessNonKnowledgeArticleDefaultValue)),
                            Occur.SHOULD
                        }
                    };
                    var userProducts = productAccessProvider.GetProducts();
                    ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, "Adding User products to Lucene query");

                    foreach (var product in userProducts)
                    {
                        ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, string.Format("User product {0}", product));
                        productFilteringQuery.Add(
                            new TermQuery(new Term(FixedFacetsConfiguration.ProductFieldFacetName, product.ToString())),
                            Occur.SHOULD);
                    }

                    if (PortalContext.Current.User != null)
                    {
                        if (productAccessProvider.DisplayArticlesWithoutAssociatedProductsEnabled())
                        {
                            productFilteringQuery.Add(
                                new TermQuery(new Term(FixedFacetsConfiguration.ProductFieldFacetName, this.Index.ProductAccessDefaultValue)),
                                Occur.SHOULD);
                        }
                    }
                    else
                    {
                        productFilteringQuery.Add(
                            new TermQuery(new Term(FixedFacetsConfiguration.ProductFieldFacetName, "unauthenticatedUser")),
                            Occur.SHOULD);
                    }

                    compositeQuery.Add(productFilteringQuery, Occur.MUST);
                }

                ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, string.Format("Adding User WebRoleDefaultValue to Lucene query: {0}", this.Index.WebRoleDefaultValue));

                var cmsQuery = new BooleanQuery
                {
                    {
                        new TermQuery(
                            new Term(this.Index.WebRoleFieldName, this.Index.WebRoleDefaultValue)),
                        Occur.SHOULD
                    }
                };

                // Windows Live ID Server decided to return null for an unauthenticated user's name
                // A null username, however, breaks the Roles.GetRolesForUser() because it expects an empty string.
                var currentUsername = (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity != null)
                                        ? HttpContext.Current.User.Identity.Name ?? string.Empty
                                        : string.Empty;

                var userRoles = Roles.GetRolesForUser(currentUsername);

                ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, "Adding user role to Lucene query");
                foreach (var role in userRoles)
                {
                    ADXTrace.Instance.TraceInfo(TraceCategory.Monitoring, string.Format("User role: {0}", role));
                    cmsQuery.Add(new TermQuery(new Term(this.Index.WebRoleFieldName, role)), Occur.SHOULD);
                }

                compositeQuery.Add(cmsQuery, Occur.MUST);

                // Add the Url Defined Part to the Query.
                var urlDefinedQuery = new BooleanQuery
                {
                    {
                        new TermQuery(
                            new Term(this.Index.IsUrlDefinedFieldName, bool.TrueString)),
                        Occur.SHOULD
                    }
                };
                compositeQuery.Add(urlDefinedQuery, Occur.MUST);

                // Add knowledgearticle to the query
                compositeQuery.Add(
                    new TermQuery(new Term(FixedFacetsConfiguration.RecordTypeFacetFieldName, FixedFacetsConfiguration.KnowledgeArticleConstraintName)),
                    Occur.SHOULD);

                return(compositeQuery);
            }
            else
            {
                return(base.CreateQuery(query));
            }
        }
Exemplo n.º 12
0
        protected override bool TryCreateHandler(OrganizationServiceContext context, string logicalName, Guid id, out IHttpHandler handler)
        {
            if (string.Equals(logicalName, "annotation", StringComparison.InvariantCulture))
            {
                var annotation = context.CreateQuery(logicalName).FirstOrDefault(e => e.GetAttributeValue <Guid>("annotationid") == id);

                if (annotation != null)
                {
                    var regarding = annotation.GetAttributeValue <EntityReference>("objectid");

                    if (regarding != null && string.Equals(regarding.LogicalName, "knowledgearticle", StringComparison.InvariantCulture))
                    {
                        // Access to a note associated to a knowledge article requires the CMS Security to grant read of the annotation and the related knowledge article.
                        // Additionally, if CAL or Product filtering is enabled and the CAL and/or Product providers reject access to the knowledge article
                        // then access to the note is denied. If CAL and Product filtering are NOT enabled or CAL and/or Product Provider assertion passed,
                        // we must continue to check the Entity Permissions. If the Entity Permission Provider grants read to the knowledge article then the
                        // note can be accessed, otherwise access will be denied.

                        // Assert CMS Security on the annotation and knowledge article.
                        if (TryAssertByCrmEntitySecurityProvider(context, annotation.ToEntityReference()) && TryAssertByCrmEntitySecurityProvider(context, regarding))
                        {
                            // Assert CAL and/or Product Filtering if enabled.
                            var contentAccessLevelProvider = new ContentAccessLevelProvider();
                            var productAccessProvider      = new ProductAccessProvider();

                            if (contentAccessLevelProvider.IsEnabled() || productAccessProvider.IsEnabled())
                            {
                                if (!AssertKnowledgeArticleCalAndProductFiltering(annotation, context, contentAccessLevelProvider, productAccessProvider))
                                {
                                    ADXTrace.Instance.TraceInfo(TraceCategory.Application, $"Access to {EntityNamePrivacy.GetEntityName(annotation.LogicalName)} was denied. Id:{id} RegardingId={regarding.Id} RegardingLogicalName={EntityNamePrivacy.GetEntityName(regarding.LogicalName)}");
                                    handler = null;
                                    return(false);
                                }
                            }

                            // Assert Entity Permissions on the knowledge article.
                            if (TryAssertByCrmEntityPermissionProvider(context, regarding))
                            {
                                ADXTrace.Instance.TraceInfo(TraceCategory.Application, $"Access to {EntityNamePrivacy.GetEntityName(annotation.LogicalName)} was granted. Id:{id} RegardingId={regarding.Id} RegardingLogicalName={EntityNamePrivacy.GetEntityName(regarding.LogicalName)}");
                                handler = CreateAnnotationHandler(annotation);
                                return(true);
                            }
                        }

                        ADXTrace.Instance.TraceInfo(TraceCategory.Application, $"Access to {EntityNamePrivacy.GetEntityName(annotation.LogicalName)} was denied. Id:{id} RegardingId={regarding.Id} RegardingLogicalName={EntityNamePrivacy.GetEntityName(regarding.LogicalName)}");
                        handler = null;
                        return(false);
                    }

                    // Assert CMS security on the regarding entity or assert entity permission on the annotation and the regarding entity.
                    if (TryAssertByCrmEntitySecurityProvider(context, regarding) || TryAssertByCrmEntityPermissionProvider(context, annotation, regarding))
                    {
                        ADXTrace.Instance.TraceInfo(TraceCategory.Application, $"Access to {EntityNamePrivacy.GetEntityName(annotation.LogicalName)} was granted. Id={id} RegardingId={regarding?.Id} RegardingLogicalName={EntityNamePrivacy.GetEntityName(regarding?.LogicalName)}");
                        handler = CreateAnnotationHandler(annotation);
                        return(true);
                    }
                }
            }

            if (string.Equals(logicalName, "salesliteratureitem", StringComparison.InvariantCulture))
            {
                var salesliteratureitem = context.CreateQuery(logicalName).FirstOrDefault(e => e.GetAttributeValue <Guid>("salesliteratureitemid") == id);

                if (salesliteratureitem != null)
                {
                    //Currently salesliteratureitem.iscustomerviewable is not exposed to CRM UI, therefore get the parent and check visibility.
                    //var isCustomerViewable = salesliteratureitem.GetAttributeValue<bool?>("iscustomerviewable").GetValueOrDefault();
                    var salesliterature =
                        context.CreateQuery("salesliterature")
                        .FirstOrDefault(
                            e =>
                            e.GetAttributeValue <Guid>("salesliteratureid") ==
                            salesliteratureitem.GetAttributeValue <EntityReference>("salesliteratureid").Id);

                    if (salesliterature != null)
                    {
                        var isCustomerViewable = salesliterature.GetAttributeValue <bool?>("iscustomerviewable").GetValueOrDefault();

                        if (isCustomerViewable)
                        {
                            handler = CreateSalesAttachmentHandler(salesliteratureitem);
                            return(true);
                        }
                    }
                }
            }

            if (string.Equals(logicalName, "sharepointdocumentlocation", StringComparison.InvariantCulture))
            {
                var location = context.CreateQuery(logicalName).FirstOrDefault(e => e.GetAttributeValue <Guid>("sharepointdocumentlocationid") == id);

                if (location != null)
                {
                    var httpContext = HttpContext.Current;
                    var regardingId = location.GetAttributeValue <EntityReference>("regardingobjectid");

                    // assert CMS access to the regarding entity or assert entity permission on the entity
                    if (TryAssertByCrmEntitySecurityProvider(context, regardingId) || TryAssertByCrmEntityPermissionProvider(context, location, location.GetAttributeValue <EntityReference>("regardingobjectid")))
                    {
                        var locationUrl = context.GetDocumentLocationUrl(location);
                        var fileName    = httpContext.Request["file"];

                        // Ensure safe file URL - it cannot begin or end with dot, contain consecutive dots, or any of ~ " # % & * : < > ? \ { | }
                        fileName = Regex.Replace(fileName, @"(\.{2,})|([\~\""\#\%\&\*\:\<\>\?\/\\\{\|\}])|(^\.)|(\.$)", string.Empty);                         // also removes solidus

                        var folderPath = httpContext.Request["folderPath"];

                        Uri sharePointFileUrl;

                        if (!string.IsNullOrWhiteSpace(folderPath))
                        {
                            // Ensure safe folder URL - it cannot begin or end with dot, contain consecutive dots, or any of ~ " # % & * : < > ? \ { | }
                            folderPath = Regex.Replace(folderPath, @"(\.{2,})|([\~\""\#\%\&\*\:\<\>\?\\\{\|\}])|(^\.)|(\.$)", string.Empty).Trim('/');

                            sharePointFileUrl = new Uri("{0}/{1}/{2}".FormatWith(locationUrl.OriginalString, folderPath, fileName));
                        }
                        else
                        {
                            sharePointFileUrl = new Uri("{0}/{1}".FormatWith(locationUrl.OriginalString, fileName));
                        }



                        handler = CreateSharePointFileHandler(sharePointFileUrl, fileName);
                        return(true);
                    }

                    if (!httpContext.Request.IsAuthenticated)
                    {
                        httpContext.Response.ForbiddenAndEndResponse();
                    }
                    else
                    {
                        // Sending Forbidden gets caught by the Application_EndRequest and throws an error trying to redirect to the Access Denied page.
                        // Send a 404 instead with plain text indicating Access Denied.
                        httpContext.Response.StatusCode  = (int)HttpStatusCode.NotFound;
                        httpContext.Response.ContentType = "text/plain";
                        httpContext.Response.Write("Access Denied");
                        httpContext.Response.End();
                    }
                }
            }

            if (string.Equals(logicalName, "activitymimeattachment", StringComparison.InvariantCulture))
            {
                var attachment = context.CreateQuery(logicalName).FirstOrDefault(e => e.GetAttributeValue <Guid>("attachmentid") == id);

                if (attachment != null)
                {
                    // retrieve the parent object for the annoation

                    var objectId = attachment.GetAttributeValue <EntityReference>("objectid");

                    // assert CMS access to the regarding entity or assert entity permission on the entity

                    if (TryAssertByCrmEntitySecurityProvider(context, objectId) || TryAssertByCrmEntityPermissionProvider(context, attachment, attachment.GetAttributeValue <EntityReference>("objectid")))
                    {
                        handler = CreateActivityMimeAttachmentHandler(attachment);
                        return(true);
                    }
                }
            }

            handler = null;
            return(false);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Adds Content Access Level and Product Filtering to fetch
        /// </summary>
        /// <param name="annotation">Annotation</param>
        /// <param name="context">Context</param>
        /// <param name="contentAccessLevelProvider">content Access Level Provider</param>
        /// <param name="productAccessProvider">product Access Provider</param>
        private bool AssertKnowledgeArticleCalAndProductFiltering(Entity annotation, OrganizationServiceContext context, ContentAccessLevelProvider contentAccessLevelProvider, ProductAccessProvider productAccessProvider)
        {
            if (!contentAccessLevelProvider.IsEnabled() & !productAccessProvider.IsEnabled())
            {
                // If CAL and Product Filtering is not enabled then we must not restrict access to the article. This will also eliminate an unnecessary knowledge article query.

                return(true);
            }

            var entityReference = annotation.GetAttributeValue <EntityReference>("objectid");

            var fetch = new Fetch();
            var knowledgeArticleFetch = new FetchEntity("knowledgearticle")
            {
                Filters = new List <Filter>
                {
                    new Filter
                    {
                        Type       = LogicalOperator.And,
                        Conditions = new List <Condition>
                        {
                            new Condition("knowledgearticleid", ConditionOperator.Equal, entityReference.Id)
                        }
                    }
                },
                Links = new List <Link>()
            };

            fetch.Entity = knowledgeArticleFetch;

            // Apply Content Access Level filtering. If it is not enabled the fetch will not be modified
            contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetch);

            // Apply Product filtering. If it is not enabled the fetch will not be modified.
            productAccessProvider.TryApplyRecordLevelFiltersToFetch(CrmEntityPermissionRight.Read, fetch);

            var kaResponse = (RetrieveMultipleResponse)context.Execute(fetch.ToRetrieveMultipleRequest());

            var isValid = kaResponse.EntityCollection.Entities.Any();

            if (isValid)
            {
                if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
                {
                    PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "TryCreateHandler CAL/PF passed", 1, annotation.ToEntityReference(), "read");
                }
                return(true);
            }
            if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
            {
                PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "TryCreateHandler CAL/PF failed", 1, annotation.ToEntityReference(), "read");
            }
            return(false);
        }