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()); }
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); }
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); }
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; }
/// <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()); }
/// <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)); } }
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); }
/// <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); }