2011-09-13 9 views
16

Questa domanda si presentava mentre si progettava un sistema ACL dedicato per un'applicazione personalizzata, ma penso che si applichi ai sistemi ACL in generale, poiché non ho scoperto come affrontare questo problema osservando alcuni dei sistemi mainstream, come Zend_ACL.creazione di un sistema ACL dinamico "bidirezionale"

Nella mia applicazione, le autorizzazioni sono concesse in modo dinamico, ad esempio: un utente ottiene le autorizzazioni di visualizzazione su un'attività perché è un membro del team a cui è collegata l'attività. Questo presuppone che tu abbia sempre un Employee (utente) che vuole eseguire un'azione (visualizza/modifica/ecc.) Su uno Item (uno degli oggetti nella mia applicazione, ad esempio Attività, Squadra, ecc.). Questo è sufficiente per il mio uso mirato;

$Activity = new Activity($_POST['activity_id']); 

$Acl = new Acl($Activity); 
if (!$Acl->check('edit') { 
    throw new AclException('no permission to edit'); 
} 

La mia classe Acl contiene tutte le regole di business per concedere le autorizzazioni, e vengono creati 'on the fly' (anche se a volte nella cache per motivi di prestazioni);

/** 
* Check the permissions on a given activity. 
* @param Activity $Activity 
* @param int $permission (optional) check for a specific permission 
* @return mixed integer containing all the permissions, or a bool when $permission is set 
*/ 
public function checkActivity(Activity $Activity, $permission = null) { 
    $permissions = 0; 

    if ($Activity->owner_actor_id == $this->Employee->employee_id) { 
     $permissions |= $this->activity['view']; 
     $permissions |= $this->activity['remove']; 
     $permissions |= $this->activity['edit']; 
    } elseif (in_array($this->Employee->employee_id, $Activity->contributor_ids_arr)) { 
     $permissions |= $this->activity['view']; 
    } else { 
     /** 
     * Logged in user is not the owner of the activity, he can contribute 
     * if he's in the team the activity is linked to 
     */ 
     if ($Activity->getTeam()->isMember($this->Employee)) { 
      $permissions |= $this->activity['view']; 
     } 
    } 

    return ($permission ? (($permission & $permissions) === $permission) : $permissions); 
} 

Questo sistema funziona così com'è.

Il problema con questo approccio si verifica quando si desidera "invertire" le regole ACL. Ad esempio, "recupera tutte le attività che sono autorizzato a modificare". Non voglio inserire alcuna logica come WHERE owner_actor_id = $Employee->employee_id nel codice che richiede le attività, poiché questa è la responsabilità della classe Acl e dovrebbe essere mantenuta centralizzata. Con l'implementazione corrente, non ho altra scelta che recuperare tutte le attività nel codice e quindi dichiararle una per una. Questo è ovviamente un approccio molto inefficiente.

Quindi quello che sto cercando è alcune idee su una buona architettura (o un puntatore a un'implementazione ACL esistente o alcuni modelli di progettazione rilevanti) per creare un sistema di ACL che in qualche modo possono fare entrambe le cose e hasPermission($Item, $permission)fetchAllItems($permission), idealmente con il stesso insieme di regole aziendali.

Grazie a tutti in anticipo!


Ho guardato il Zend_ACL realizzazione, ma che si concentra più sulle autorizzazioni generali. Ho trovato anche le seguenti domande qui su SO:

Ma purtroppo non sembrano rispondere alla domanda sia.

+0

Qual è l'argomento contro mettendo i 'fetchAllItems()' metodo nella 'Classe acl'? Non sono sicuro di capire davvero la domanda. – erisco

risposta

1

Un collega mi ha offerto un altro punto di vista sulla questione, che potrebbe anche essere la soluzione a questo problema.

Quello che ho pensato volevo è messo tutto il codice di accesso legate nella classe ACL (mirroring mia affermazione che "Non voglio mettere qualsiasi logica come WHERE owner_actor_id = $Employee->employee_id nel codice che ha bisogno di attività, perché questa è la responsabilità della classe Acl e dovrebbe essere mantenuta centralizzata. ").

Quello che ho veramente voglio è assicurarsi che l'utente non può mai accedere qualcosa che non è conforme alle regole elencate nella classe ACL.Non davvero è un problema se il 'codice di lavoratore' recupera già un sottoinsieme dei dati - fintanto che è in ultima analisi, confrontata con la 'vera' ACL. Il peggio che può accadere è che l'utente vede meno di quanto dovrebbe, il che è molto meglio di più.

Con questa "soluzione" (approccio alternativo se lo si desidera), si evita di recuperare i dati tutti, mantenendo il vantaggio di avere tutte le regole in un'unica posizione. Qualsiasi altra soluzione che potrei pensare implicherebbe una duplicazione delle regole, dal momento che hai bisogno di regole in PHP per controllare una determinata risorsa e regole scritte in MySQL per il recupero di tutte.

È comunque possibile inserire il codice di subset fetch nella classe Acl, tuttavia penso che sarebbe meglio mantenere la classe piccola e focalizzata (perché penso che la leggibilità del codice in quella classe è anche molto importante).

+0

Ti dispiacerebbe spiegarlo un po 'di più? – Xeoncross

+0

@Xeoncross: certo, che cosa non capisci? – Rijk

0

Per quanto ne so ACL deve essere utilizzato per controllare le autorizzazioni generali. Le autorizzazioni basate sull'entità non dovrebbero essere soggette all'ACL. Per tale compito vedrò come Linux/Unix gestiscono i permessi dei file.

  owner group all 
read  1  1  1 
write  1  0  0 
execute  1  0  0 
-------------------------------------- 
      7  4  4 

con simili implementazione sia il recupero e le autorizzazioni di controllo sono facili, ma è necessario aggiungere un altro strato alla propria applicazione.

edit: Anche questa architettura rispetterà Principio Responsabilità singolo quanto il controllo "se l'utente è autorizzato ad aprire una pagina" è diverso da "ciò che l'utente vedrà la pagina"

+0

Ma questo è un sistema di autorizzazione, hai solo da vedere proprietario, il gruppo, e tutte le entità, e una parte importante di che le autorizzazioni è avere un proprietario. Questo è ACL, si assegnano determinati utenti e gruppi ad alcune azioni e sono presenti regole di ereditarietà e regole di gruppo. –

+0

Non riesco a vedere la differenza tra un 'file' e un' Activity object' - sono entrambi 'entità' giuste?E un utente può avere una serie di permessi sull'entità, come "visualizza", "modifica", "rimuovi" o "leggi", "scrivi", "esegui" in caso di Linux. La differenza tra il mio sistema e quello di Linux è che le mie autorizzazioni derivano dal contesto invece che dall'entità codificata per entità. – Rijk

0

che sembra essere più come un controllo dell'accesso basato sui ruoli o RBAC, rispetto a un elenco di controllo di accesso ACL, poiché concedi autorizzazioni all'utente sull'oggetto dipende dal ruolo che hanno, se sono nel gruppo, dall'elenco collaborativo o dal proprietario, ma non lo sei memorizzando come un ruolo, quindi non può essere un RBAC, ma non si memorizzano le autorizzazioni perché si presuppone che non possa essere un ACL.

Quindi, se si desidera eseguire una query per un gruppo di oggetti in base al permesso che si assume, è ovvio che è necessario calcolare prima le autorizzazioni assegnate per ottenerle.

Quindi è possibile calcolarlo in una stored procedure/funzione udf se si desidera che nel db non venga recuperato tutto, o che sia stata creata una tabella/elenco ACL o un'autorizzazione di ruolo collegata agli oggetti a cui si desidera concedere le autorizzazioni.

Spero che questo sia utile, buona domanda è fritto un po 'il mio cervello, ma ora ho bisogno di fare qualcosa di simile .. hanno un giorno piacevole

+0

Grazie per il tuo commento! Ho esaminato l'RBAC, ma non sembra adattarsi al mio caso. Wikipedia afferma che "RBAC è ** non ** un modello per assegnare le autorizzazioni dinamicamente" - Credo che l'assegnazione dinamica sia ciò che sto cercando di fare qui. – Rijk

+0

Il punto che cerco di dire è che l'RBAC è un'entità centralizzata di controllo dell'accesso e per ottenere una sovvenzione per un oggetto è necessario chiedere a questa entità la permissione. D'altra parte, ACL ha una lista collegata o nell'oggetto, e l'API chiede se l'ACL dell'oggetto concede accesso all'utente. Se vuoi assegnare dinamicamente senza ottenere tutto da db, la tua unica soluzione è una procedura UDF/stored procedure, se hai qualche dubbio su come scriverlo, chiedi. –