Security auf ListItem-Ebene

Es gibt Fälle, in denen muss man Berechtigungen für einzelne Listenelemente setzen, beispielsweise wenn es um eine Liste mit Personendaten geht.

Ich musste selbiges beispielsweise für eine Liste mit Urlaubsansprüchen machen, in der für jeden Mitarbeiter ein Datensatz mit Angabe des Vorgesetzten und seines derzeitigen Anspruches an Urlaubstagen verwaltet wurde. Diese Daten dürfen natürlich nur der Mitarbeiter und sein Vorgesetzter sehen und nur Letzterer darf diese auch bearbeiten.

Der erste Ansatz mittels Views scheiterte, da diese vom Benutzer auch selbst erstellt und geändert werden können. Doch in der API gibt es für die Objekte des Typs ListItem ein Property namens RoleAssignments. Über dieses kann man Benutzern Rollen geben und damit Zugriffsrechte zuweisen. Diese Rechte werden bereits bei der Darstellung der Liste berücksichtigt, sodass nur berechtigte Benutzer mit Lesezugriff überhaupt Elemente sehen und nur Benutzer mit Schreibrechten ein Element bearbeiten können.

Umsetzung

So viel zur Theorie, jetzt geht es in die Praxis:

Um an das ListItem überhaupt heranzukommen, benötigen wir einen EventHandler, und zwar vom Typ ItemAdded. In diesem Event Handler können wir dann mittels des folgenden Codes Rollen zuweisen:

  1. SPListItem item = properties.ListItem;
  2. SPWeb web = properties.OpenWeb();
  3. //Liest das Feld Mitarbeiter aus dem listItem und erstellt damit ein User-Objekt
  4. SPUser user = web.EnsureUser((new SPFieldLookupValue(item["Mitarbeiter"].ToString())).LookupValue);
  5. SPUser vorgesetzter = web.EnsureUser((new SPFieldLookupValue(item["Vorgesetzter"].ToString())).LookupValue);
  6. SPUser personalAbteilung = web.EnsureUser((new SPFieldLookupValue(item["Personalabteilung"].ToString())).LookupValue);
  7. //Erzeugen von Rollendefinition, einmal Leser und einmal Schreibender
  8. SPRoleDefinition RoleDefReader = web.RoleDefinitions.GetByType(SPRoleType.Reader);
  9. SPRoleDefinition RoleDefWriter = web.RoleDefinitions.GetByType(SPRoleType.Contributor);
  10. //Rollenzuweisung: Mitarbeiter bekommt Leserechte, Vorgesetzter und Personalabteilung Schreibrechte
  11. SPRoleAssignment RoleAssReader = new SPRoleAssignment((SPPrincipal)user);
  12. SPRoleAssignment RoleAssWriter = new SPRoleAssignment((SPPrincipal)vorgesetzter);
  13. SPRoleAssignment RoleAssWriter2 = new SPRoleAssignment((SPPrincipal)personalAbteilung);
  14. //Rollenzuweisung dem ListItem hinzufügen
  15. RoleAssReader.RoleDefinitionBindings.Add(RoleDefReader);
  16. RoleAssWriter.RoleDefinitionBindings.Add(RoleDefWriter);
  17. RoleAssWriter2.RoleDefinitionBindings.Add(RoleDefWriter);
  18. //Wenn keine speziellen Berechtigungen auf dieses Item gesetzt sind (Vererbung) ...
  19. if (!item.HasUniqueRoleAssignments)
  20. //... durchbrechen wir die Vererbungshierarchie, ohne Berechtigungen zu kopieren
  21. item.BreakRoleInheritance(false);
  22. item.RoleAssignments.Add(RoleAssReader);
  23. item.RoleAssignments.Add(RoleAssWriter);
  24. item.RoleAssignments.Add(RoleAssWriter2);
  25. item.Update();

Diese obigen Zeilen sollten eigentlich ausreichend kommentiert sein. Um auch bei Änderungen an dem Item die Rollen updaten zu können, muss man natürlich entsprechenden Code auch für das Event ItemUpdated anpassen.

Der Grund dafür, dass ich statt ItemUpdating das asynchrone Event ItemUpdated verwendet habe, liegt darin, dass im ersteren Fall das Item noch nicht erzeugt wurde und damit habe ich noch keine Möglichkeit Rollen zuzuweisen. Weder RoleAssigments noch die bei Tasks verfügbaren SpecialPermissions sind in diesem Zustand bereits verwendbar.