10 tips on how to prevent business value risk
One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.
The content has been bookmarked!
There was an error bookmarking this content! Please retry.

Posted by Grzegorz Gogolowicz on Nov 24, 2008
Windows SharePoint Services 3.0 and Microsoft Office SharePoint Server 2007 support a rich security model that allows administrators to control access to sites and content by assigning permissions to users and groups for a specific securable object (such as site, list, library, folder and even an individual document or item).
However, in certain scenarios there is a need to secure access to individual columns in lists or document libraries. Currently, SharePoint does not provide out of the box support for securing columns or views. A typical scenario that would require this might be a list that contains a broad spectrum of information about an employee or a client, where certain columns (salary, revenue to date, potential to promote, etc.) might ideally only be viewable by certain groups within the portal.
To address those scenarios, this paper describes a method to leverage SharePoint extensibility and built-in item to level security to allow applying column-level permissions to a custom field type. This is accomplished through the use of a lookup field as the column, with behind the scenes ties to another list that contains the secure values and a method to provision those values back to the lookup only for users with valid permissions.
The result is that in the view mode authorized users will see the content of a secure column as if it was a normal column, while unauthorized users will not see the content of the column at all. This different behavior is shown in Figure 1. Similarly, only authorized users will be able to access the content of a secure column in new and edit modes.
Figure 1 Secure Column as viewed by an authorized and unauthorized users
To design a custom column-level security solution, the following aspects need to be addressed:
In order to resolve these issues, we decided to use a Custom Field Type for data rendering and processing and to use Item Level Security for data storage.
Custom Field Types together with Content Types and List Forms are primary extensibility mechanisms in Windows SharePoint Services that allow customizing data access, rendering and processing. You can read more about Custom Field Types in Windows SharePoint Services 3.0 SDK here.
The primary role of our custom field type is to ensure that only users with proper authorization can view or modify the data. We implemented a custom field type called Secure Column that can be used in any SharePoint list.
For storing data, one of the options that we considered was to use a separate table in a separate database. This could be a good option for SharePoint implementations that already use a separate database for other purposes. However, considering that many SharePoint solutions do not use any non-SharePoint databases, for the purpose of this article and sample, we decided to use a SharePoint List as the storage mechanism and to not introduce any dependencies on separate databases.
Using a SharePoint List for backend storage of secured data provides the ability to create a List Item for each piece of data to secure. To provide the appropriate level of security guarantee, the Item-Level Security feature will be used. The promise here is that our column-level security should be as secure as the built-in SharePoint Item Level Security.
It is important to note the implementation decisions to use a SharePoint List and Lookup column functionality also has some inherent limitations. These limitations are: lookups on very large lists can hinder performance and Lookup columns are not able to be directed at lists which are part of a different Site Collection.
To implement column-level security several custom components are required:
These components work together as depicted in Figure 2 to allow the user to create, view, and edit data stored in the secured column.
Figure 2 Implementation Overview
For the sample implementation a single Data Storage List is used for all data in a Site Collection. This allows for easy maintenance and is a simpler solution. One drawback to this solution is that there is a single point where all secure fields will depend. This could cause performance issues in a very large solution. If this occurs the example solution could be extended to create a new Data Storage List per secure field.
While using a SharePoint list for storage of secure data provides many advantages like Item-Level security and full API support. It also poses several challenges:
Each of these challenges can be addressed using standard SharePoint list functionality or custom code added to our Custom Field Type.
To address the issue of visibility we create the list as a "catalog" list. This is similar to the way other system lists are created in the standard SharePoint implementation. Examples include: web part gallery, site template gallery, and master page library. In addition, the following properties of the SPList object are set to further hide the list:
To address the scalability and permission maintenance issues we decided not to use a flat list, but instead to create a two-level folder structure to house groups of items. The first level of the folder structure corresponds to the list to which a given Secure Column belongs to. The second level of the folder structure corresponds to the given Secure Column itself. As the result, the number of items in a single folder never exceeds the number of items in a list to which given secure column belongs to, even if the lists contains multiple secure columns. This approach addresses the scalability issues and having this folder structure, we use the permissions of a second-level folder to represent the permissions associated with a given Secure Column. This eliminates the need to maintain permissions for each individual item.
Figure 3 Folder Structure
The final issue of creating this list is something that can be easily handled as part of the Custom Field Type. To do this we programmatically create the list if it does not exist when a new field is created.
As mentioned in the Solution Architecture section above, data that is logically represented by a Secure Column added to a SharePoint list, is not stored in that list. Instead it is securely stored in a separate, dedicated SharePoint list that we refer to as the Data Storage List (this list will have an internal name of _SecureFieldStorage and a site relative URL of _catalogs/_SecureFieldStorage). Retrieving data stored in this separate Data Storage List and displaying it in the context of a host list (i.e., the list that contains a Secure Column) is the primary purpose of our custom field type.
When looking to implement this functionality, we wanted to avoid starting from ground up by deriving our custom field type from the base SPField class. Instead, we wanted to leverage existing SharePoint functionality as much as possible. When considering the available out of the box SharePoint field types to use as a base for our custom field type, the lookup field type (SPFieldLookup) stands out.
The primary feature of a lookup field we want to use is its ability to be pointed at a field in another SharePoint list and retrieve this field's value based on a specific list item id, which is well aligned with what we needed. What more, using the lookup field functionality allows taking advantage of its internal implementation which leverages SQL joins and is very scalable while still being secure.
While the core functionality of the lookup field type is a great starting point for the functionality we needed, there are a number of mismatches between the standard lookup field features and our needs. These are where our custom code is used to extend the SPLookupField:
An important component of any custom field type implementation is the custom fldtypes.xml file. In our case this file has been customized to point to our custom field type class:
<FieldName="FieldTypeClass"> SecureField.SecureField, SecureField, Version=1.0.0.0, Culture=neutral, PublicKeyToken=48a15d1316dd0f7d Field>
We also include a custom display pattern. The display pattern is identified below and will ensure this is not rendered as a hyperlink, which is the default for a Lookup column.
<LookupColumn HTMLEncode ="TRUE" "AutoHyperLink="FALSE""/>
The only other customization we have made was to specify a custom field editor control.
<FieldName="FieldEditorUserControl">/_controltemplates/SecureFieldEditor.ascx Field>
The custom field type class is the piece where most of the work for customizing the core lookup field functionality is located. This functionality includes:
The class is inheriting from SPFieldLookup and it overrides the Update method so that whenever a secure column is created or edited, the backing Data Storage List is created and set with appropriate permissions.
public override void Update()
{
SPSecurity.RunWithElevatedPrivileges(EnsureSecureFieldStorageListExists);
SPWeb web = SPContext.Current.Site.RootWeb;
this.LookupWebId = web.ID;
this.LookupField = secureFieldStorageFieldName;
this.LookupList = web.Lists[secureFieldStorageListName].ID.ToString();
RetrieveCustomProperties();
SPSecurity.RunWithElevatedPrivileges(ApplyPermissions);
base.Update();
}
All of these actions are performed in an elevated permission level. This is to ensure even standard users can create new secure columns without error.
In addition, to this customization, we also need to override the FieldRenderingControl property to enable our custom field control to be used.
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl control = new SecuredFieldControl();
control.FieldName = this.InternalName;
return control;
}
}
The final customization is to override the OnDeleting method to ensure we clean up any related data when a column is deleted.
public override void OnDeleting()
{
base.OnDeleting();
SPSecurity.RunWithElevatedPrivileges(removeFieldFolder);
}
In addition to the core field type class, a custom field editor control is required to allow users to set the permission on a secure column. Permission can be set not only when the column is added to a list, but also can be updated anytime later. This functionality is implemented using a new user control which will include a SharePoint PeopleEditor control. This control enables the user to search and select principals.
<sharepoint:PeopleEditor ID="AllowedPrincipalsPeoplePicker" runat="server" AutoPostBack="false" PlaceButtonsUnderEntityEditor="true" SelectionSet="SPGroup" MultiSelect="true" />
To set and retrieve the security settings from the secure field type the code-behind class for the user control implements the IFieldEditor interface. Specifically, the InitializeWithField method is used to retrieve any existing security settings from the field.
if (Page.IsPostBack)
return;
// Initialize the people picker control using comma separated account list from the secure field
SecureField secureField = (SecureField)field;
if (secureField != null && secureField.AllowedPrincipals != null)
{
StringBuilder accounts = new StringBuilder();
foreach (object entity in secureField.AllowedPrincipals)
{
accounts.Append((entity as PickerEntity).Key);
accounts.Append(',');
}
this.AllowedPrincipalsPeoplePicker.CommaSeparatedAccounts = accounts.ToString();
this.AllowedPrincipalsPeoplePicker.Validate();
}
In addition, the OnSaveChange method is used to update the field security settings.
AllowedPrincipalsPeoplePicker.Validate();
SecureField secureField = (SecureField)field;
secureField.AllowedPrincipals = AllowedPrincipalsPeoplePicker.ResolvedEntities;
secureField.SaveCustomProperties();
The final piece of the custom field type is the custom field control which implements the logic to create and maintain the data stored in the Data Storage List. To do this and still keep the existing lookup field functionality we inherit our custom class from the LookupField class. This base class handles all of the functionality when the field is in display mode. However, in new and edit modes we modified how the control works to meet our needs. The way to determine what mode the field control is currently in, we use the ControlMode property of the base class.
When the field control is in new or edit mode there are several changes to the default functionality to implement the following behavior:
To control the visibility of the control the best method is to override the Visible property. In the implementation of the properties getter we check if the user has access to the data and return false if they do not.
In order to display a text box for the user to allow entering or editing data we can use an existing SharePoint template with the id TextField. This is the same template used by the standard text field. To implement this we simply need to override the DefaultTemplateName property's get method to implement the following.
// If the mode is Display default to Lookup Field functionality
if (ControlMode == SPControlMode.Display || ControlMode == SPControlMode.Invalid)
{
return base.DefaultTemplateName;
}
return @"TextField";
To implement the remaining functionality to create or update the Data Storage List, we need to override the Value property's get and set methods. The get method will be used by the SharePoint framework to update the field value. Our Customizations to this logic are to create or edit the backing item located in the Data Storage List based on the values entered by the user. To ensure users without permission to modify lists, this functionality runs in at an elevated level where necessary. We also implement logic to ensure a user who should not be able to edit this field cannot. In this code we reference several helper methods. The code for these methods can be found at the end of this section.
// If the mode is Display default to Lookup Field functionality if (ControlMode == SPControlMode.Display || ControlMode == SPControlMode.Invalid)
{
return base.Value;
}
this.EnsureChildControls();
// Validate the current users permissions.
if (!DoesUserHavePermissions())
{
return lookupListItemId;
}
// Check for an existing value to determine if we create new or edit.
if (lookupListItemId == null)
{
SPSecurity.RunWithElevatedPrivileges(createLookupListItem);
}
else
{
SPSecurity.RunWithElevatedPrivileges(updateLookupListItem);
}
return lookupListItemId;
The set method of the Value property is used to set the current value of the field for the current List Item. Our customizations to this functionality need to retrieve the current value from the Data Storage List and populate our text box. This also implements functionality to ensure the security of the data.
// If the mode is Display default to Lookup Field functionality
if (ControlMode == SPControlMode.Display || ControlMode == SPControlMode.Invalid)
{
base.Value = value;
return;
}
this.EnsureChildControls();
// Validate the current users permissions.
if (!DoesUserHavePermissions())
{
return;
}
if( value != null)
{
if (value is SPFieldLookupValue)
{
SPFieldLookupValue fullValue = value as SPFieldLookupValue;
lookupListItemId = fullValue.LookupId;
this.TextBoxValue.Text = fullValue.LookupValue;
}
else
{
if (!(value is string))
{
throw new ArgumentException();
}
try
{
SPFieldLookupValue fullValue = new SPFieldLookupValue(value as string);
lookupListItemId = fullValue.LookupId;
this.TextBoxValue.Text = fullValue.LookupValue;
}
catch (ArgumentException ex)
{
this.TextBoxValue.Text = string.Empty;
}
}
The following methods are the helper methods which were used earlier.
private bool DoesUserHavePermissions()
{
bool doesUserHavePermissions = false;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPFieldLookup lookupField = this.Field as SPFieldLookup;
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = site.OpenWeb(lookupField.LookupWebId))
{
SPList list = web.Lists[new Guid(lookupField.LookupList)];
SPListItem subFolderItem = SecureField.GetOrCreateSubFolderItem(web, list, ListId, Field, false);
if (subFolderItem == null)
{
throw new Exception("Cannot find the List folder or Field folder.");
}
doesUserHavePermissions = subFolderItem.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser, SPBasePermissions.ViewListItems);
}
}
});
return doesUserHavePermissions;
}
private void createLookupListItem()
{
SPFieldLookup lookupField = this.Field as SPFieldLookup;
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = site.OpenWeb(lookupField.LookupWebId))
{
SPList list = web.Lists[new Guid(lookupField.LookupList)];
SPListItem subFolderItem = SecureField.GetOrCreateSubFolderItem(web, list, ListId, Field, false);
if (subFolderItem == null)
{
throw new Exception("Cannot find the List folder or Field folder.");
}
// Create the list item.
SPListItem listItem = list.Items.Add(subFolderItem.Folder.ServerRelativeUrl, SPFileSystemObjectType.File, this.TextBoxValue.Text);
listItem[SecureField.secureFieldStorageFieldName] = this.TextBoxValue.Text;
web.AllowUnsafeUpdates = true;
listItem.Update();
lookupListItemId = listItem.ID;
}
}
}
private void updateLookupListItem()
{
if (lookupListItemId == null)
{
return;
}
SPFieldLookup lookupField = this.Field as SPFieldLookup;
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = site.OpenWeb(lookupField.LookupWebId))
{
SPList list = web.Lists[new Guid(lookupField.LookupList)];
SPListItem listItem = list.GetItemById((int)lookupListItemId);
listItem[SecureField.secureFieldStorageFieldName] = this.TextBoxValue.Text;
web.AllowUnsafeUpdates = true;
listItem.Update();
}
}
}
As with most custom development which extends SharePoint's core functionality, SharePoint Solution packages are the ideal deployment tool. This framework allows us to create a package which will be deployed to all servers in the farm in a central, consistent, and monitored way. Our implementation of custom-level security consists of one assembly, one Xml configuration file, and one control template file and is a perfect fit for a Solution package.
By using these components in conjunction with one another the user can add a secure column using the standard SharePoint interface as shown in Figure 4.
Figure 4 Creating a Secure Column
As part of adding the column the user can select the users and groups who should have access to the column. This functionality use the standard SharePoint "People Picker" control as is shown in Figure 5.
Figure 5 Configuring Permissions for a Secure Column
Once the column is added and configured a user with rights to the column can add data using the standard SharePoint new and edit forms as shown in Figure 6.
Figure 6 Editing a value of a Secure Column
A user who does not have permission to this column would not be allowed to edit or see the data within this column. This can be seen in Figure 7.
Figure 7 Edit mode when user doesn't have permission to edit a Secure Column
When this column is added to a view within SharePoint, only users with permission to this column would have access. This can be seen in Figures 8 and 9.
Figure 8 Viewing a list by a user with permission to a Secure Column
Figure 9 Viewing a list by a user without permissions to a Secure Column
This article has shown how to extend SharePoint to include column-level security and still keep all of the data within SharePoint. The strategies identified in this article enable the seamless addition of this functionality into any SharePoint environment. In addition, we have published full source code and deployment files of a working example at MSDN Code Gallery here.
Although we believe the approach presented in the article can sufficiently scale and is secure, we did not run any extensive tests and we fully expect that if Microsoft delivers a built-in column-level security in SharePoint in the future, it would offer better UI and better performance and scalability than our sample and it would be supported, while obviously our sample is not.
Some other things which were not addressed as part of the example are identified below:
Look into improving column functionality when in datasheet view.
Matthew Dressel has over 8 years experience designing and implementing solutions for organizations intent on using the latest Microsoft technologies. His current work is focused on solution architecture and project leadership, for clients in the Education space looking to implement Microsoft's SharePoint technologies. Matthew has been working with the Microsoft SharePoint platform for over 3 years. His work experience includes implementations of the earliest releases of the product and the subsequent migrations to the current version. In addition to numerous successful implementations of 'standard' SharePoint, Matthew has been recently involved in several projects where the SharePoint platform is used as the basis for the creation of a new product or service. These projects utilize highly custom code and processes requiring careful architecture and a deep knowledge of the intricacies and the power of the platform.
Grzegorz Gogolowicz is a Senior Solutions Architect on the Global Partner Architecture Team at Microsoft with 15+ years of software development experience. Previously he was Technical Lead on Visual Studio Team System product group at Microsoft focusing on Team Foundation Server. In his current role, Grzegorz specializes in application platform architecture, including .NET, SharePoint and Azure Services Platform.
For more information, see the following resources:
Great job on using standard SharePoint features to implement secure columns. Since this is a general-purpose solution, is it available for download for those of us who are a bit too busy to implement it ourselves?
Thanks in advance.
If you look in the conclusion section you will see a link to download the source and binaries.
This solution works fine, but it seems that only SharePoint administrator user can create secure fields. In my case any other user receives "no access" error when trying to add a field. Though full access is granted for these users.
The feature is great but I can still export to a spreadsheet or open with access and see the data if I'm a person without rights to see the data on screen.
Any ideas how to prevent seeing the data in access or excel?
The feature is great but I need secure field to be choice (menu to choose from).
Any ideas ?
Thanks Marijan
Greetings:
From within Site Actions --> Create, I don't see where/how to create a Catalog list as mentioned in the article (for the purpose of holding the secure data).
Please, if someone can provide me guidance/advice on that issue, it would be greatly appreciated.
Thanks...
Ed in Tampa
Did you make it work? IF so could you/any one pl guide me, even I am trying to secure a choice field.
You can tryout "Infowise Smart List Pro" which extend the SharePoint lists and give them extra capabilities like - fields permissions, fields Value Validation, tabbed Interface, view permissions, default values and more.
infowisesolutions.com/product.aspx?id=SmartListPro
Regards,
Eitan Bach
One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.
InfoQ spoke to the authors of Software Systems Architecture on a couple of new topics, the System Context viewpoint and Agile, which have been added to the second edition.
Alex Papadimoulis discusses ugly code, where it comes from, how to avoid it, and how to get rid of it.
John Davies examines Visa’s architecture and shows how enterprises have architected complex integrations incorporating Hadoop, memcached, Ruby on Rails, and others to deliver innovative solutions.
Sean Comerford unveils ESPN.com’s architecture, what components are used and why, and the current changes the website goes through.
Are there repeated patterns of failure on Enterprise Agile Enablement efforts? Sanjiv and Arlen discuss Seven Deadly Sins to avoid when adopting Agile in an enterprise.
Erik Dörnenburg answers: What is Enterprise and Evolutionary Architecture?, discussing 4 issues: Turning strategy into execution, Ensuring conformance, Where do the architects sit? Buying or building?
Sean Cribbs explains what Map-Reduce and Riak are, why and how to use Map-Reduce with Riak, and how to convert SQL queries into their Map-Reduce equivalents.
8 comments
Watch Thread Reply