2009-07-27 9 views
1

Ich versuche, eine gute Möglichkeit zu finden, Authentifizierung und Autorisierung zu tun. Hier ist was ich habe. Kommentare sind willkommen und was ich mir erhoffe.Autorisierung System Design Frage

Ich habe PHP auf einem Mac-Server. Ich habe Microsoft AD für Benutzerkonten.

Ich verwende LDAP, um das AD abzufragen, wenn sich der Benutzer im Intranet anmeldet.

Meine Entwurfsfrage betrifft, was mit dieser AD-Information zu tun ist. Es wurde von einem Mitarbeiter vorgeschlagen, im AD eine Namenskonvention zu verwenden, um eine zwischengeschaltete Datenbank zu vermeiden. Zum Beispiel habe ich eine Webseite, personal_payroll.php. Ich bekomme die URL und mit der URL und dem AD-Benutzer Abfrage der AD für die Gruppe personal_payroll. Wenn sich der angemeldete Benutzer in dieser Gruppe befindet, ist er berechtigt, die Seite anzuzeigen. Ich müsste eine Gruppe für jede Seite oder zumindest Benutzer der Benutzerdomäne für die generische Authentifizierung haben.

Es wird schwieriger mit Kontrollen auf einer Seite. Angenommen, es gibt eine Schaltfläche auf einer Seite oder einem Raster, nur Manager können dies sehen. Ich würde personal_payroll_myButton als Gruppe in meinem AD benötigen. Wenn der Benutzer in dieser Gruppe ist, erhalten sie die Schaltfläche. Ich könnte viele Gruppen haben, wenn eine Seite mehrere verschiedene Berechtigungsstufen hat.

Ja, das wäre mein AD sehr groß sein, aber wenn ich diese etwas anderes wird nicht tun, ob es sich um MySQL (oder ein anderer db), eine Textdatei, die httpd.conf usw.

Ich würde eine generische php funciton IsAuthorized für die verschiedenen Elemente haben, die den URL- oder Kontrollnamen und den authentifizierten Benutzer übergibt.

Gibt es etwas in sich Falsches mit der Verwendung einer Namenskonvention für Sicherheit wie diese und die Verwendung der AD als dieses Repository? Ich muss irgendwo bleiben. Warum nicht AD?

Vielen Dank für Ihre Kommentare.

EDIT: Denken Sie, dass dieses Schema wegen der LDAP-Aufrufe in superlangsame Seiten resultieren würde?

EDIT: Ich kann nicht die erste Person sein, die jemals darüber nachdenkt. Irgendwelche Gedanken dazu sind geschätzt.

EDIT: Vielen Dank an alle. Es tut mir leid, dass ich Ihnen nicht mehr Punkte für die Beantwortung geben konnte. Ich musste einen auswählen.

Antwort

3

Ich frage mich, ob es eine andere Möglichkeit geben könnte, die Berechtigungen auszudrücken und zu speichern, die sauberer und effizienter arbeiten würden.

Die meisten Anwendungen sind in Funktionsbereiche oder Rollen unterteilt, und Berechtigungen werden basierend auf diesen [breiten] Bereichen zugewiesen, im Gegensatz zu Berechtigungen pro Seite. So zum Beispiel, könnten Sie Berechtigungen wie:

  • UseApplication
  • AngelegtVon
  • ResetOtherUserPassword
  • ViewPayrollData
  • ModifyPayrollData

Oder mit Rollen, könnten Sie haben:

  • ApplicationUser
  • ApplicationAdmin
  • PayrollAdmin

Es ist wahrscheinlich, dass die Rollen (und möglicherweise die pro-Funktionalität Berechtigungen) können bereits in Active Directory, wie bestehende AD-Gruppen/Rollen zu speichernden Daten abzubilden. Und wenn dies nicht der Fall ist, ist es immer noch viel einfacher zu verwalten als pro-Seite-Berechtigungen. Die Berechtigungen können als Benutzergruppen gepflegt werden (ein Benutzer entweder in einer Gruppe, so die Berechtigung hat oder nicht), oder alternativ als ein benutzerdefiniertes Attribut:

dn: cn=John Doe,dc=example,dc=com 
objectClass: top 
objectClass: person 
objectClass: webAppUser 
cn: John Doe 
givenName: John 
... 
myApplicationPermission: UseApplication 
myApplicationPermission: ViewPayrollData 

Dies hat den Vorteil, dass die Schemaänderungen sind minimal. Wenn Sie Gruppen verwenden, verfügt AD (und jeder andere LDAP-Server auf dem Planeten) bereits über diese Funktionalität. Wenn Sie ein benutzerdefiniertes Attribut wie dieses verwenden, müsste nur ein einziges Attribut (und vermutlich objectClass, webAppUser im obigen Beispiel) erforderlich sein hinzugefügt werden.

Als nächstes müssen Sie entscheiden, wie die Daten verwenden. Eine Möglichkeit wäre, die Berechtigungen des Benutzers zu überprüfen (herauszufinden, in welchen Gruppen sie sich befinden oder welche Berechtigungen ihnen gewährt wurden), wenn sie sich anmelden und auf der Webserverseite in ihrer Sitzung speichern.Dies hat das Problem, dass Änderungen der Berechtigungen nur bei der Benutzeranmeldung und nicht sofort wirksam werden. Wenn Sie nicht erwarten, dass Berechtigungen sehr oft geändert werden (oder wenn ein Benutzer gleichzeitig das System verwendet), ist dies wahrscheinlich ein sinnvoller Weg. Es gibt Varianten davon, z. B. das erneute Laden der Berechtigungen des Benutzers nach Ablauf einer bestimmten Zeit.

Eine andere Möglichkeit, aber mit ernsthafteren (negativen) Auswirkungen auf die Leistung besteht darin, die Berechtigungen nach Bedarf zu überprüfen. In diesem Fall treffen Sie häufiger den AD-Server und verursachen eine erhöhte Auslastung (sowohl auf dem Webserver als auch dem AD-Server), erhöhten Netzwerkverkehr und höhere Latenz-/Anforderungszeiten. Aber Sie können sicher sein, dass die Berechtigungen immer aktuell sind.

Wenn Sie immer noch denken, dass es nützlich wäre, einzelne Seiten- und Schaltflächennamen als Teil der Berechtigungsprüfung zu verwenden, könnten Sie eine globale "Karte" der Seite/button => Berechtigung haben und alle Ihre Berechtigungsnachfragen durchführen dadurch. Etwas (völlig un-geprüft und meist Pseudo-Code):

$permMap = array(
    "personnel_payroll" => "ViewPayroll", 
    "personnel_payroll_myButton" => "EditPayroll", 
    ... 
); 

function check_permission($elementName) { 
    $permissionName = $permMap[$elementName]; 
    return isUserInLdapGroup($user,$permissionName); 
} 
1

Sie werden sehr langsame Seiten auf diese Weise haben (es klingt für mich wie Sie AD LDAP jedes Mal erneut abfragen werden, wenn ein Benutzer navigiert, um herauszufinden, was er tun kann), es sei denn, Sie implementieren Caching einer Art dann können Sie auf Probleme mit der volatilen Berechtigung stoßen (widerrufene/hinzugefügte Berechtigungen für AD, obwohl Sie nichts darüber wussten).

Ich würde Berechtigungen behalten und solche separate und nicht AD als Repository verwenden, um Ihre anwendungsspezifische Berechtigung zu verwalten. Verwenden Sie stattdessen einen separaten Speicheranbieter, der wesentlich einfacher zu warten und bei Bedarf zu erweitern ist.

2

Die Idee, AD für Berechtigungen zu verwenden, ist nicht fehlerhaft, wenn Ihr AD nicht skalieren kann. Wenn die Verwendung einer lokalen Datenbank schneller/zuverlässiger/flexibler wäre, dann verwenden Sie diese.

Die Verwendung der Namenskonvention zum Ermitteln der richtigen Sicherheitsrollen ist jedoch ziemlich fragil. Sie werden unweigerlich in Situationen geraten, in denen Ihr natürliches Mapping nicht dem realen Mapping entspricht. Dumme Sachen wie du willst, dass die URL "finbiz" ist, aber bereits in AD als "Business-Finance" - duplizierst du die Gruppe und hältst sie synchronisiert, oder machst du die Remapping innerhalb deiner Anwendung ...?Manchmal ist es so einfach wie "FinBiz" vs "Finbiz".

IMO, ist es am besten, diese Art von Problem zu vermeiden, z. B. verwenden Sie die Gruppe "185" anstelle von "Finbiz" oder "Business-Finance", oder einen anderen Schlüssel, den Sie mehr Kontrolle haben.

Unabhängig von wie Ihre Erlangung Ihrer Berechtigungen, wenn am Ende, es zu cachen, müssen Sie mit veralteten Cache-Daten beschäftigen.

Wenn Sie ldap verwenden müssen, wäre es sinnvoller, eine Berechtigung ou (oder was auch immer das AD-Äquivalent von "schema" ist) zu erstellen, so dass Sie beliebigen Entitäten diese Berechtigungen zuordnen können. Cache diese Daten, und Sie sollten in Ordnung sein.

Edit:

Ein Teil der Frage scheint eine intermediäre Datenbank zu vermeiden zu sein - warum nicht die primären den Vermittler machen? Synchronisieren Sie die lokale Berechtigungsdatenbank regelmäßig mit AD (über einen Hook oder Polling), und vermeiden Sie zwei wichtige Probleme 1) zerbrechliche Benennungskonvention, 2) externe Datenquelle geht unter.

1

Gibt es etwas grundsätzlich falsch mit einer Namenskonvention für die Sicherheit wie mit diesem und mit dem AD als das Repository? Ich muss irgendwo bleiben. Warum nicht AD?

Logischerweise ist die Verwendung von Gruppen für die Autorisierung in LDAP/AD genau das, wofür es entwickelt wurde. Eine LDAP-Abfrage eines bestimmten Benutzers sollte relativ schnell sein.

In der Praxis kann AD sehr unvorhersehbar sein, wie lange Datenänderungen zur Replikation zwischen Servern dauern. Wenn Ihre App eines Tages in einem großen Wald mit über den ganzen Kontinent verteilten Domänencontrollern endet, werden Sie es wirklich bereuen, feinkörnige Daten dorthin zu übertragen. Im Ernst, es kann eine Stunde dauern, bis das Zeug für einige Kunden repliziert wird, mit denen ich gearbeitet habe. Es entstehen mysteriöse Situationen, in denen die Dinge nach dem Neustart der Server und ähnlichem auf magische Weise funktionieren.

Es ist in Ordnung, ein Verzeichnis für die Gruppen 'myapp-users', 'managers' und 'payroll' zu verwenden. Versuchen Sie, wiederholte und verschwenderische LDAP-Suchen zu vermeiden.

Wenn Sie unter Windows arbeiten, besteht eine Möglichkeit darin, für jedes autorisierte Objekt eine kleine Datei auf der lokalen Festplatte zu erstellen. Dies gibt Ihnen 'sicherbare Objekte'. Ihre App kann dann die Identität des Benutzers annehmen und versuchen, die Datei zu öffnen. Dies nutzt die großen Investitionen von MS im Laufe der Jahre bei der Optimierung dieser Dinge. Vielleicht kannst du das irgendwie auf dem Mac machen.

Überprüfen Sie auch Apache mod_auth_ldap. Es wird gesagt, dass "komplexe Autorisierungsrichtlinien implementiert werden können, indem die Richtlinie mit LDAP-Filtern dargestellt wird".

Ich weiß nicht, was Ihre App tut, dass es keine Art von Datenbank für Sachen verwendet. Gut für dich, weil du den einfachen Ausweg nicht genommen hast! Hier kann eine flache Textdatei mit JSON einen langen Weg zurücklegen.

0

Es scheint, dass Sie eine Zugriffskontrollliste (ACL) zur Authentifizierung beschreiben, da Sie über "Gruppen" hinaus zu bestimmten Aktionen innerhalb dieser Gruppe gehen. Um eine ACL ohne eine von Ihren Authentifizierungsmitteln getrennte Datenbank zu erstellen, würde ich vorschlagen, das Zend Framework für PHP zu betrachten, speziell die ACL module.

In Ihren AD-Einstellungen ordnen Sie Benutzer Gruppen zu (Sie nennen "Manager", wahrscheinlich "Benutzer", "Administratoren", möglicherweise einige abteilungsspezifische Gruppen und eine generische "Öffentlichkeit", wenn ein Benutzer ist nicht Teil einer Gruppe). Das Zend ACL-Modul ermöglicht Ihnen die Definition von "Ressourcen" (in Ihrem Beispiel den Seitennamen) und "Aktionen" innerhalb dieser Ressourcen.Diese werden dann in der Sitzung als Objekt gespeichert, auf das verwiesen werden kann, um festzustellen, ob ein Benutzer Zugriff hat. Zum Beispiel:

<?php 
$acl = new Zend_Acl(); 
$acl->addRole(new Zend_Acl_Role('public')); 
$acl->addRole(new Zend_Acl_Role('users')); 
$acl->addRole(new Zend_Acl_Role('manager'), 'users'); 

$acl->add(new Zend_Acl_Resource('about')); // Public 'about us' page 
$acl->add(new Zend_Acl_Resource('personnel_payroll')); // Payroll page from original post 

$acl->allow('users', null, 'view'); // 'users' can view all pages 
$acl->allow('public', 'about', 'view'); // 'public' can only view about page 
$acl->allow('managers', 'personnel_payroll', 'edit'); // 'managers' can edit the personnel_payroll page, and can view it since they inherit permissions of the 'users' group 

// Query the ACL: 
echo $acl->isAllowed('public', 'personnel_payroll', 'view') ? "allowed" : "denied"; // denied 
echo $acl->isAllowed('users', 'personnel_payroll', 'view') ? "allowed" : "denied"; // allowed 
echo $acl->isAllowed('users', 'personnel_payroll', 'edit') ? "allowed" : "denied"; // denied 
echo $acl->isAllowed('managers', 'personnel_payroll', 'edit') ? "allowed" : "denied"; // allowed 
?> 

Der Vorteil der ACL von der AD zu trenn wäre, dass wie die Code-Änderungen (und was „Aktionen“ sind innerhalb der verschiedenen Bereiche), die Gewährung des Zugangs zu ihnen in der gleichen Lage, anstatt den AD-Server zu verwalten, um die Änderung vorzunehmen. Und Sie verwenden ein bestehendes (stabiles) Framework, damit Sie das Rad nicht mit Ihrer eigenen isAuthorized-Funktion neu erfinden müssen.