It is important to realize before we get started that this error was also present within SharePoint 2007. When creating timer jobs, it is important to understand the relationships between the SPSecurity.RunWithElevatedPrivileges method and the associated SPWebApplication object. When using SPSecurity.RunWithElevatedPrivileges, it will not allow modification of the SPWebApplication since it is persisted to the configuration database. However, other proxy objects are exempt from this such as SPSite ‘s and SPWeb ‘s. SPSecurity.RunWithElevatedPrivileges allows the elevation to just the content database, NOT the configuration database (which has the SPWebApplication property bag) which is generally more locked down.
The easiest way to fix this is to impersonate the user account for proxy objects (assuming you are using a current context to reference the application property) with an account that has the wss_content_application_pools database role for the config database since this will have elevated rights for stored procedures and what not. This will allow you to modify your timer jobs easily. If you want to be really lazy, just use the same account as the central admin app pool which inherently provides the required access to the configuration database.
When working with timer jobs, feature receivers, and other SharePoint assets that use the service application architecture components you may encounter the error:
UnauthorizedAccessException: “The current user has insufficient permissions to perform this operation”
even when leveraging a highly privileged accounts such as domain administrators. While the focus of this post is just going to use the Term Store as an example, this can happen with anything that subscribes to the 2010 services architecture.
Consider the below sample code which will attempt instantiating a few objects from the Term Store:
TaxonomySession session = new TaxonomySession(site);
// can also be a Metadata Term Store Name
TermStore store = session.TermStores;
// Bad news bear happens here
GroupCollection groups = store.Groups;
// Or other actions can cause this error
Group group = store.CreateGroup(“Group”);
TermSet set = group.CreateTermSet(“Term Set 1”);
set.CreateTerm(“Term 1”, 1033);
The second sample is just there for posterity, assume the first example piece of code because it is a pretty simple collection hydration. TaxonomySession is the entry point to accessing all data associated with TermStore objects as can be seen with the use of the TaxonomySession.TermStores property following. You can pretty much do whatever after those proxy objects are set in place.
Due to service application interaction in SharePoint 2010, services architecture process accounts running things like timer jobs and feature event sinks still lean on a proxy for connectivity. In 2007 this was a lot different because it was more blanket, timer process accounts were more liberally leveraged across processes. In 2010, it becomes increasingly important to ensure that accounts are specifically designated for particular services.
Under these pretenses, it is necessary to determine what is being used for the SharePoint\System account (your app pool and farm account, I know you can mask in a similar format ala policies) and add it to the Term Store Administrators or whatever service group you need. Should run just fine afterwards.