Now checks for the sensitiveData group to view sensitive data

This commit is contained in:
Shannon
2018-01-25 15:06:23 -07:00
parent 54cc80f4e8
commit 469d6f9ca3
9 changed files with 102 additions and 97 deletions

View File

@@ -9,6 +9,7 @@ namespace Umbraco.Core
{
public const string AdminGroupAlias = "admin";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
@@ -36,4 +37,4 @@ namespace Umbraco.Core
}
}
}
}

View File

@@ -261,6 +261,16 @@ namespace Umbraco.Core.Models
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias);
}
/// <summary>
/// Determines whether this user has access to view sensitive data
/// </summary>
/// <param name="user"></param>
public static bool HasAccessToSensitiveData(this IUser user)
{
if (user == null) throw new ArgumentNullException("user");
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.SensitiveDataGroupAlias);
}
// calc. start nodes, combining groups' and user's, and excluding what's in the bin
public static int[] CalculateContentStartNodeIds(this IUser user, IEntityService entityService)
{
@@ -413,4 +423,4 @@ namespace Umbraco.Core.Models
return lsn.ToArray();
}
}
}
}

View File

@@ -219,7 +219,7 @@ namespace Umbraco.Web.Editors
Path = "-1," + Constants.System.RecycleBinContent
};
TabsAndPropertiesResolver.AddListView(display, "content", Services.DataTypeService, Services.TextService);
TabsAndPropertiesResolver<IContent>.AddListView(display, "content", Services.DataTypeService, Services.TextService);
return display;
}

View File

@@ -115,7 +115,7 @@ namespace Umbraco.Web.Editors
Path = "-1," + Constants.System.RecycleBinMedia
};
TabsAndPropertiesResolver.AddListView(display, "media", Services.DataTypeService, Services.TextService);
TabsAndPropertiesResolver<IMedia>.AddListView(display, "media", Services.DataTypeService, Services.TextService);
return display;
}

View File

@@ -154,7 +154,7 @@ namespace Umbraco.Web.Editors
ParentId = -1
};
TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService, Services.TextService);
TabsAndPropertiesResolver<IMember>.AddListView(display, "member", Services.DataTypeService, Services.TextService);
return display;
}

View File

@@ -56,7 +56,7 @@ namespace Umbraco.Web.Models.Mapping
expression.MapFrom(content => content.ContentType.AllowedTemplates
.Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)
.ToDictionary(t => t.Alias, t => t.Name)))
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver<IContent>(applicationContext.Services.TextService)))
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService), new Lazy<IContentService>(() => applicationContext.Services.ContentService))))
.AfterMap((content, display) => AfterMap(content, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
@@ -100,6 +100,8 @@ namespace Umbraco.Web.Models.Mapping
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
ILocalizedTextService localizedText, IContentTypeService contentTypeService)
{
//TODO: All of this logic should be moved to the TabsAndPropertiesResolver and not in AfterMap
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
//TODO: STOP using these extension methods, they are not testable and require singletons to be setup
var parent = content.Parent();
@@ -113,7 +115,7 @@ namespace Umbraco.Web.Models.Mapping
if (content.ContentType.IsContainer)
{
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText);
TabsAndPropertiesResolver<IContent>.AddListView(display, "content", dataTypeService, localizedText);
}
}

View File

@@ -41,7 +41,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Alias, expression => expression.Ignore())
.ForMember(display => display.IsContainer, expression => expression.Ignore())
.ForMember(display => display.HasPublishedVersion, expression => expression.Ignore())
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver<IMedia>(applicationContext.Services.TextService)))
.ForMember(display => display.ContentType, expression => expression.ResolveUsing<MediaTypeBasicResolver>())
.ForMember(display => display.MediaLink, expression => expression.ResolveUsing(
content => string.Join(",", content.GetUrls(UmbracoConfig.For.UmbracoSettings().Content, applicationContext.ProfilingLogger.Logger))))
@@ -70,6 +70,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
}
//TODO: All of this logic should be moved to the TabsAndPropertiesResolver and not in AfterMap
private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, IContentTypeService contentTypeService, ILogger logger)
{
// Adapted from ContentModelMapper
@@ -80,7 +81,7 @@ namespace Umbraco.Web.Models.Mapping
if (media.ContentType.IsContainer)
{
TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText);
TabsAndPropertiesResolver<IMedia>.AddListView(display, "media", dataTypeService, localizedText);
}
}

View File

@@ -217,7 +217,7 @@ namespace Umbraco.Web.Models.Mapping
///
/// This also ensures that the IsSensitive property display value is set based on the configured IMemberType property type
/// </remarks>
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver, IValueResolver
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver<IMember>
{
private readonly ILocalizedTextService _localizedTextService;
private readonly IMemberService _memberService;
@@ -238,45 +238,23 @@ namespace Umbraco.Web.Models.Mapping
_memberService = memberService;
_userService = userService;
}
/// <summary>
/// Explicitly implement to override behavior
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
/// <remarks>
/// This is required to get access to the <see cref="ResolutionResult"/> object which allows us access to the mapping options
/// </remarks>
ResolutionResult IValueResolver.Resolve(ResolutionResult source)
{
//call the base class logic
var result = base.Resolve(source);
var member = (IMember)source.Value;
//now we can customize the result and use the ResolutionResult options to get the UmbracoContext
var tabs = (List<Tab<ContentPropertyDisplay>>) result.Value;
//now we can customize the result with the current context, we can get the UmbracoContext from the options
CustomizeProperties(source.Context.GetUmbracoContext(), member, tabs);
return result;
}
/// <summary>
/// Overridden to deal with custom member properties
/// Overridden to deal with custom member properties and permissions
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="content"></param>
/// <returns></returns>
protected override List<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content)
protected override List<Tab<ContentPropertyDisplay>> ResolveCore(UmbracoContext umbracoContext, IMember content)
{
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
IgnoreProperties = content.PropertyTypes
.Where(x => x.HasIdentity == false)
.Select(x => x.Alias)
.ToArray();
var result = base.ResolveCore(content);
var result = base.ResolveCore(umbracoContext, content);
if (provider.IsUmbracoMembershipProvider() == false)
{
@@ -303,6 +281,39 @@ namespace Umbraco.Web.Models.Mapping
}
}
if (umbracoContext != null && umbracoContext.Security.CurrentUser != null
&& umbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", content.ContentTypeId);
//Replace the doctype property
var docTypeProperty = result.SelectMany(x => x.Properties)
.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
docTypeProperty.Value = new List<object>
{
new
{
linkText = content.ContentType.Name,
url = memberTypeLink,
target = "_self",
icon = "icon-item-arrangement"
}
};
docTypeProperty.View = "urllist";
}
//check if there's an approval field
var legacyProvider = provider as global::umbraco.providers.members.UmbracoMembershipProvider;
if (content.HasIdentity == false && legacyProvider != null)
{
var approvedField = legacyProvider.ApprovedPropertyTypeAlias;
var prop = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == approvedField);
if (prop != null)
{
prop.Value = 1;
}
}
return result;
}
@@ -362,63 +373,17 @@ namespace Umbraco.Web.Models.Mapping
return genericProperties;
}
/// <summary>
/// Performs some customizations for the properties based on the current context
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="member"></param>
/// <param name="tabs">The current tab collection</param>
/// <remarks>
/// If this is a new entity and there is an approved field then we'll set it to true by default.
/// </remarks>
private void CustomizeProperties(UmbracoContext umbracoContext, IMember member, List<Tab<ContentPropertyDisplay>> tabs)
{
var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
if (umbracoContext != null && umbracoContext.Security.CurrentUser != null
&& umbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", member.ContentTypeId);
//Replace the doctype property
var docTypeProperty = tabs.SelectMany(x => x.Properties)
.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
docTypeProperty.Value = new List<object>
{
new
{
linkText = member.ContentType.Name,
url = memberTypeLink,
target = "_self",
icon = "icon-item-arrangement"
}
};
docTypeProperty.View = "urllist";
}
//check if there's an approval field
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
if (member.HasIdentity == false && provider != null)
{
var approvedField = provider.ApprovedPropertyTypeAlias;
var prop = tabs.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == approvedField);
if (prop != null)
{
prop.Value = 1;
}
}
}
/// <summary>
/// Overridden to assign the IsSensitive property values
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="content"></param>
/// <param name="properties"></param>
/// <returns></returns>
protected override List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties)
protected override List<ContentPropertyDisplay> MapProperties(UmbracoContext umbracoContext, IContentBase content, List<Property> properties)
{
var result = base.MapProperties(content, properties);
var result = base.MapProperties(umbracoContext, content, properties);
var member = (IMember)content;
var memberType = member.ContentType;
var labelPropEditor = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View;
@@ -427,8 +392,7 @@ namespace Umbraco.Web.Models.Mapping
{
prop.IsSensitive = memberType.IsSensitiveProperty(prop.Alias);
//check permissions for viewing sensitive data
if (prop.IsSensitive)
if (prop.IsSensitive && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
{
//replace this editor with a label
prop.View = labelPropEditor;

View File

@@ -16,7 +16,8 @@ namespace Umbraco.Web.Models.Mapping
/// <summary>
/// Creates the tabs collection with properties assigned for display models
/// </summary>
internal class TabsAndPropertiesResolver : ValueResolver<IContentBase, List<Tab<ContentPropertyDisplay>>>
internal class TabsAndPropertiesResolver<TSource> : IValueResolver
where TSource : IContentBase
{
private readonly ILocalizedTextService _localizedTextService;
protected IEnumerable<string> IgnoreProperties { get; set; }
@@ -35,6 +36,24 @@ namespace Umbraco.Web.Models.Mapping
IgnoreProperties = ignoreProperties;
}
/// <summary>
/// Implements the <see cref="IValueResolver"/>
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public ResolutionResult Resolve(ResolutionResult source)
{
if (source.Value != null && (source.Value is TSource) == false)
throw new AutoMapperMappingException(string.Format("Value supplied is of type {0} but expected {1}.\nChange the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.", new object[]
{
source.Value.GetType(),
typeof (TSource)
}));
return source.New(
//perform the mapping with the current umbraco context
ResolveCore(source.Context.GetUmbracoContext(), (TSource)source.Value), typeof(List<Tab<ContentPropertyDisplay>>));
}
/// <summary>
/// Adds the container (listview) tab to the document
/// </summary>
@@ -145,7 +164,13 @@ namespace Umbraco.Web.Models.Mapping
display.Tabs = tabs;
}
protected override List<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content)
/// <summary>
/// Create the list of tabs for the <see cref="IContentBase"/>
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="content">Source value</param>
/// <returns>Destination</returns>
protected virtual List<Tab<ContentPropertyDisplay>> ResolveCore(UmbracoContext umbracoContext, TSource content)
{
var tabs = new List<Tab<ContentPropertyDisplay>>();
@@ -171,7 +196,7 @@ namespace Umbraco.Web.Models.Mapping
continue;
//map the properties
var mappedProperties = MapProperties(content, properties);
var mappedProperties = MapProperties(umbracoContext, content, properties);
// add the tab
// we need to pick an identifier... there is no "right" way...
@@ -189,7 +214,7 @@ namespace Umbraco.Web.Models.Mapping
});
}
MapGenericProperties(content, tabs);
MapGenericProperties(umbracoContext, content, tabs);
// activate the first tab
tabs[0].IsActive = true;
@@ -209,20 +234,21 @@ namespace Umbraco.Web.Models.Mapping
/// <summary>
/// Maps properties on to the generic properties tab
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="content"></param>
/// <param name="tabs"></param>
/// <remarks>
/// The generic properties tab is responsible for
/// setting up the properties such as Created date, updated date, template selected, etc...
/// </remarks>
protected virtual void MapGenericProperties(IContentBase content, List<Tab<ContentPropertyDisplay>> tabs)
protected virtual void MapGenericProperties(UmbracoContext umbracoContext, IContentBase content, List<Tab<ContentPropertyDisplay>> tabs)
{
// add the generic properties tab, for properties that don't belong to a tab
// get the properties, map and translate them, then add the tab
var noGroupProperties = content.GetNonGroupedProperties()
.Where(x => IgnoreProperties.Contains(x.Alias) == false) // skip ignored
.ToList();
var genericproperties = MapProperties(content, noGroupProperties);
var genericproperties = MapProperties(umbracoContext, content, noGroupProperties);
tabs.Add(new Tab<ContentPropertyDisplay>
{
@@ -268,10 +294,11 @@ namespace Umbraco.Web.Models.Mapping
/// <summary>
/// Maps a list of <see cref="Property"/> to a list of <see cref="ContentPropertyDisplay"/>
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="content"></param>
/// <param name="properties"></param>
/// <returns></returns>
protected virtual List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties)
protected virtual List<ContentPropertyDisplay> MapProperties(UmbracoContext umbracoContext, IContentBase content, List<Property> properties)
{
var result = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.