Depurando un error de Permisos Insuficientes en CRM 4.0

Hace unas semanas un compañero del departamento de consultoría nos comentaba que en uno de sus proyectos obtenían un error de permisos insuficientes cuando un usuario se conectaba a CRM por primera vez. La única peculiaridad era que el único rol de seguridad asignado al usuario había sido creado desde cero.

El error obtenido por el usuario era el siguiente:

screen14

 
Proceso de resolución del problema

Para depurar este error bastó con activar la opción DevErros y volver a reproducir el error. En este caso el error obtenido fue el siguiente:

screen15

El contenido completo del informe de error era:

Error Description:

SecLib::CrmCheckPrivilege failed. Returned hr = -2147220960 on UserId: b1d4add8-54ac-dd11-b383-0003ff1206c7 and PrivilegeId: 588725dd-c878-41c5-a4c3-5efc93cd3ffd

Error Details:

SecLib::CrmCheckPrivilege failed. Returned hr = -2147220960 on UserId: b1d4add8-54ac-dd11-b383-0003ff1206c7 and PrivilegeId: 588725dd-c878-41c5-a4c3-5efc93cd3ffd

Full Stack: [CrmSecurityException: SecLib::CrmCheckPrivilege failed. Returned hr = -2147220960 on UserId: b1d4add8-54ac-dd11-b383-0003ff1206c7 and PrivilegeId: 588725dd-c878-41c5-a4c3-5efc93cd3ffd] at Microsoft.Crm.BusinessEntities.SecurityLibrary.CheckPrivilege(Guid user, Guid privilege, ExecutionContext context) at Microsoft.Crm.BusinessEntities.SecurityExtension.PreUpdateHandlerEntityPrivilegeCheck(Object sender, SecurityTraits traits, SecurityAttributes attributes, ExtensionEventArgs e) at Microsoft.Crm.ObjectModel.BypassAppendAppendToSecurityExtension.PreUpdateHandler(ExtensionEventArgs e, Object sender) at Microsoft.Crm.BusinessEntities.SecurityExtension.PreUpdateHandler(Object sender, ExtensionEventArgs e) at Microsoft.Crm.BusinessEntities.BusinessProcessObject.PreUpdateEventHandler.Invoke(Object sender, ExtensionEventArgs e) at Microsoft.Crm.BusinessEntities.BusinessProcessObject.Update(IBusinessEntity entity, ExecutionContext context) at Microsoft.Crm.ObjectModel.UserSettingsServiceInternal`1.Update(IBusinessEntity usersettings, ExecutionContext context) at Microsoft.Crm.ObjectModel.SystemUserServiceInternal`1.UpdateUserSettings(Guid userId, UserSettings settings, ExecutionContext context)

[TargetInvocationException: Exception has been thrown by the target of an invocation.] at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Web.Services.Protocols.LogicalMethodInfo.Invoke(Object target, Object[] values) at Microsoft.Crm.Extensibility.InternalOperationPlugin.Execute(IPluginExecutionContext context) at Microsoft.Crm.Extensibility.PluginStep.Execute(PipelineExecutionContext context) at Microsoft.Crm.Extensibility.Pipeline.Execute(PipelineExecutionContext context) at Microsoft.Crm.Extensibility.MessageProcessor.Execute(PipelineExecutionContext context) at Microsoft.Crm.Extensibility.InternalMessageDispatcher.Execute(PipelineExecutionContext context) at Microsoft.Crm.Extensibility.ExternalMessageDispatcher.Execute(String messageName, Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, PropertyBag fields, CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId) at Microsoft.Crm.Sdk.RequestBase.Process(Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId) at Microsoft.Crm.Sdk.RequestBase.Process(CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId) at Microsoft.Crm.Sdk.CrmServiceInternal.Execute(RequestBase request, CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId) at Microsoft.Crm.Sdk.InProcessCrmService.Execute(Object request) at Microsoft.Crm.Application.Platform.ServiceCommands.PlatformCommand.ExecuteInternal() at Microsoft.Crm.Application.Platform.ServiceCommands.UpdateCommand.Execute() at Microsoft.Crm.Application.Platform.DataSource.Update(Entity entity) at Microsoft.Crm.Application.Controls.AppPage.UpdateUserLanguageIfNecessary() at Microsoft.Crm.Application.Controls.AppPage.OnInit(EventArgs e) at System.Web.UI.Control.InitRecursive(Control namingContainer) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

[HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown.] at System.Web.UI.Page.HandleError(Exception e) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessRequest() at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) at System.Web.UI.Page.ProcessRequest(HttpContext context) at ASP.default_aspx.ProcessRequest(HttpContext context) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Other Message:

Error Number: 0x80040220

Source File: Not available

Line Number: Not available

Request URL: https://vjpeiro-dc-sql:5555/default.aspx

La traducción del error número 0x80040220 es: "The user does not hold the necessary privileges." lo cual concordaba con el mensaje obtenido inicialmente.

Para identificar los privilegios que el usuario no poseía y que causaban el error sólo tuvimos que fijarnos en la descripción del error. En esta sección podemos encontrar tanto en el UserId del usuario que se intenta conectar (b1d4add8-54ac-dd11-b383-0003ff1206c7), como en el PrivilegeId que el usuario no posee (588725dd-c878-41c5-a4c3-5efc93cd3ffd). Una vez que conocimos el identificador del privilegio sólo tuvimos que ejecutar la siguiente consulta de SQL contra la base de datos de la organización:

screen16

La etiqueta prvWriteUserSettings se refiere al privilegio de Escritura sobre la entidad Configuración de Usuario. Finalmente el problema se subsanó otorgando este permiso con un nivel de acceso de usuario.

 
Causa del problema

La configuración de usuario se crea al mismo tiempo que un usuario es dado de alta en CRM; sin embargo esta configuración es modificada la primera vez que dicho usuario se conecta a CRM para establecer el Modo de Búsqueda Avanzada, el Idioma de Interfaz de Usuario y el Idioma de la Ayuda. Es por esto que el usuario debe tener privilegios de escritura sobre la entidad Configuración de Usuario con un nivel de acceso de usuario o mayor en el momento de conectarse a CRM por primera vez.

Este privilegio permitirá también que el usuario pueda modificar su configuración a través de la opción Opciones del menú de Herramientas.

 
Algunas consideraciones adicionales

En este caso, el error de denegación de permisos fue causado por una acción ejecutada desde el interfaz de usuario y esto permitió usar la opción DevErrors para ampliar la información relativa al error. Sin embargo, en otras ocasiones el error de denegación puede estar causado por un componente de CRM o un desarrollo que no presente un interfaz. En este caso será necesario la captura de trazas de plataforma en el servidor de CRM donde se registrará un error con la misma información que en este caso nos mostraba la opción DevErrors.

 

Por Nacho Peiro Alba