Entre las muchas cosas buenas que tiene SharePoint, una es el nivel de seguridad que se le puede aplicar a todos los artefactos propios de la plataforma. Esta característica nos facilita la vida en muchas ocasiones, y nos brinda soluciones técnicamente brillantes en circunstancias en las que en otros sistemas nos costaría muchísimo tiempo de implementar (por este motivo estarían prácticamente descartadas). Aunque a la hora de jugar con los permisos hay que revisar con mucha atención los limites que trae SharePoint, algo que debe de mejorar, porque Microsoft no garantiza el rendimiento de tu sistema si asignas permisos exclusivos a más de 50.000 items a nivel de lista. Podeís consultar estos limites en el siguiente link
Caso Real
Estamos en el desarrollo de una Intranet para una compañía y uno de los primeros requisitos que solicita la Dirección es que exista un «clásico» Buzón de sugerencias, donde toda la organización pueda añadir su sugerencia y una vez la reciba la Dirección, se implementan diversos estados de un flujo de trabajo (que varía dependiendo de la organización).
¿Como lo hacemos?
Vamos a centrarnos en la parte donde vamos a guardar las sugerencias (la capa vista, flujos posteriores, etc. no son objeto de este post). Naturalmente, se almacena la información en una lista de SharePoint (salvo contadas excepciones no creo que superemos los 50.000 elementos de permisos únicos). La cuestión es que la Dirección solamente quiere que las sugerencias las puedan ver el propio departamento de Dirección/Recursos Humanos y el interesado que ha realizado la sugerencia.
La primera opción es ver qué traen las listas «out-of-the-box» para ver si podemos implementar este requerimiento y entonces, nos encontramos con esta pantalla:
Como vemos, las posibilidades que ofrece para que cumplir con los requisitos, solamente se satisfacen si hacemos Administradores a los miembros de Dirección para que, de esta forma, ellos puedan ver todos los elementos de una lista. Algo que es como matar moscas a cañonazos o similar.
¿ Es necesario que hacer a un usuario Administrador cuando su rol no es ese? La respuesta se contesta por si sola, NO. Esto solamente nos puede ocasionar problemas y más problemas.
Solución
La solución pasa inevitablemente por dar permisos exclusivos a cada item. En esta lista todo el mundo tiene permiso para escribir en ella (porque de esta forma todo el mundo podría añadir sugerencias) pero en el momento que se cree un elemento, estos permisos se modifican.
Para conseguir este elemento lo podemos hacer de dos formas:
- Mediante un Workflow
- Mediante un desarrollo personalizado en el EventReceiver
Para la primera opción, mediante SharePoint Designer podemos realizar un flujo de trabajo sencillo para obtener este objetivo.
Para la segunda opción, mediante el siguiente código lo podemos conseguir:
SPSecurity.RunWithElevatedPrivileges(delegate { using (SPSite spSite = new SPSite(idSite)) { using (SPWeb spWeb = spSite.OpenWeb()) { spWeb.AllowUnsafeUpdates = true; var oGroup = spWeb.Groups.GetByID(Convert.ToInt32(user)); SPRoleAssignment roleAssignment = new SPRoleAssignment(oGroup); SPRoleDefinition roleDefinition = spWeb.RoleDefinitions[role]; roleAssignment.RoleDefinitionBindings.Add(roleDefinition); var item = spWeb.Lists.TryGetList(Lista).GetItemById(id); if (!item.HasUniqueRoleAssignments) { item.BreakRoleInheritance(false); // Ensure we don't inherit permissions from parent } item.RoleAssignments.Add(roleAssignment); item.SystemUpdate(false); } } });
Del código introducido, una serie de apuntes:
- Para poder dar permisos a un elemento de una lista tenemos que asegurarnos que no esta heredando los permisos del padre, porque si no, no es posible asignarle ningún tipo de permisos.
- ¿Porqué he utilizado un RunWithElevatedPrivileges? Tengo que reconocer que no soy amigo de elevar los permisos a usuario Administrador salvo fuerza mayor. En muchos desarrollos me he encontrado con el hecho de que para salvar diversas trabas (como por ejemplo, el número de elementos a visualizar, permisos, etc.) la salida fácil es elevar los permisos y así, el desarrollo funciona. Pero, ¿realmente funciona? Si elevamos los permisos quizás un usuario este viendo información que no le corresponda ver. Imagínate el agujero de seguridad que puede ser esto. En este caso concreto los elevo porque primero es una operación que tiene que hacer el sistema como es dar/quitar permisos a un elemento, y segundo porque en algunas ocasiones un usuario normal no tiene permisos para poder consultar grupos del Active Directory, y en este caso necesitamos dar permisos a un grupo sí o sí.
- Como última mención, ¿porqué he utilizado el SystemUpdate(), en lugar del Update()? El motivo es que estamos modificando algo del sistema no del elemento, en caso de poner Update() no actualiza los permisos del elemento.
¿Cuando utilizar cada opción?
El principal inconveniente que tiene la opción 1, es que al utilizar un flujo de trabajo no se va a ejecutar inmediatamente. Es decir, un flujo de trabajo es un proceso que se ejecuta en el Timer de la Administración Central cada 5 minutos por lo tanto, es posible y en algunas circunstancias que estemos 5 minutos sin que la modificación de los permisos se haya hecho efectiva. Por lo tanto, si queremos optar por esta solución, tendremos que poner alguna solución «extra» para evitar que hasta que el flujo de trabajo realice esta modificación, los usuarios/empleados no puedan consultar algo que no deben.
La opción de realizarlo mediante programación tiene otra ventaja más es que es escalable, lo podemos reutilizar en otros desarrollos y en el caso de que necesitemos algún requisito extra es más sencillo implementarlo que realizarlo utilizando SharePoint Designer.
Conclusión
El tema de la seguridad de la información es algo muy importante a la hora de llevar con éxito la implantación de cualquier solución de SharePoint. Muchísimas veces nos centramos en buscar soluciones «faraónicas» que tienen un agujero de seguridad muy fácil de descubrir sin necesidad de ser Chema Alonso, tan solo con saberte la url donde SharePoint ubica la lista ya podemos observar los datos. Para evitar que cualquier usuario pueda acceder a elementos que no corresponde en ENCAMINA utilizamos un framework propio llamado «Enmarcha» del cual ya os hablaré próximamente 🙂