A partire da questa lezione, cominciamo ad esplorare i concetti fondamentali per l'amministrazione del database Neo4j, ed in particolare ci occupiamo della sicurezza.
Per quanto riguarda l'autenticazione, Neo4j Enterprise permette:
- di autenticarsi sul database con username e password. Questa è la configurazione standard, vedremo più avanti come gestire le password;
- di autenticarsi tramite un'integrazione LDAP, quindi realizzando un vero e proprio Single Sign On nella rete locale, che è molto utile appunto nei contesti aziendali.
In ogni caso, ad ogni utente vanno associati uno o più ruoli, che definiscono l'insieme di autorizzazioni di cui l'utente dispone per effettuare operazioni sul database.
Ruoli predefiniti
Neo4j prevede un insieme di ruoli predefiniti associati alle tipiche operazioni che possono essere eseguite:
- Reader: può esclusivamente leggere i dati, cioè fare delle query di sola lettura e modificare la propria password. Tipicamente questo ruolo può essere assegnato ad un utente che faccia solo reportistica. Ad esempio, se utilizzamo un motore come JasperReports per effettuare delle reportistiche, è opportuno creare un utente ad-hoc con cui il tool di reportistica si autentica sul database. Questo perché, se venisse attaccato il frontend di reportistica da un malintenzionato che riuscisse in qualche modo ad avere accesso al database, esso non potrebbe scrivere o rimuovere i dati.
- Editor: rispetto al reader, gli utenti con questo ruolo possono effettuare le query di modifica che abbiamo visto nelle precedenti lezioni. Possono quindi creare nodi, relazioni, impostare proprietà ed anche eliminare dati. Possono modificare la propria password ma non possono creare o modificare gli utenti. Gli utenti con questo ruolo non possono creare nuove label, né nuovi tipi di relazioni, né nuovi tipi di proprietà. Questo ruolo dovrebbe essere assegnato agli utenti con cui le applicazioni che sviluppiamo si autenticano sul database. Come per i database SQL, non è opportuno che un'applicazione web esposta su Internet si autentichi sul database con un utente amministratore.
- Publisher: ha gli stessi privilegi dell'editor; in più, può creare label, tipi di relazioni e di proprietà. Non può creare indici né amministrare gli utenti.
- architect: è un publisher che può maneggiare indici e vincoli, quindi ha il pieno controllo dello "schema" del database. Tipicamente questo ruolo può essere dato agli sviluppatori.
- Admin: il ruolo degli amministratori ovviamente. Può fare qualsiasi operazione disponibile nel sistema, quindi anche creare utenti, monitorarli ed eliminarli.
Bisogna notare che un utente senza ruoli può esclusivamente autenticarsi, ma poi non può svolgere alcuna operazione finché non gli viene associato almeno un ruolo.
Gli utenti admin possono anche creare nuovi ruoli e associarli agli utenti. Lo scopo di questi ruoli personalizzati è di mapparli su eventuali procedure ed estensioni di Neo4j.
Se un utente ha più ruoli, ha automaticamente i permessi ereditati da entrambi i ruoli.
Gestione di utenti e ruoli
La gestione degli utenti può essere effettuata non tramite comandi specifici del linguaggio, ma tramite procedure che devono essere invocate con la parola chiave CALL
. Le procedure per la sicurezza si trovano nel namespace dbms.security
. Vediamo subito come un amministratore può creare un nuovo utente e associargli un nuovo ruolo. Apriamo una console e creiamo un utente:
CALL dbms.security.createUser('j_random', 'change_me', true)
In questo modo abbiamo creato un utente con una password provvisoria (change_me). Con il terzo parametro booleano stiamo forzando Neo4j a far cambiare la password all'utente al primo accesso. Si noti che, se proviamo ad eseguire la procedura entrando come utenti non amministratori, otterremo un errore che ci avvisa che non abbiamo i permessi per effettuare l'operazione. Ora associamo il ruolo di architect al nostro nuovo sviluppatore John Random:
CALL dbms.security.addRoleToUser('architect', 'j_random')
Quindi l'utente al prossimo ingresso, dovrà cambiare password, quindi potrà lavorare sul database liberamente senza poter quindi creare altri utenti o monitorarli. Supponiamo di aver dato troppi permessi al nostro nuovo sviluppatore; per cambiare ruolo all'utente non basta aggiungere il nuovo ruolo, ma togliere anche l'altro altrimenti li avrebbe entrambi:
CALL dbms.security.addRoleToUser('publisher', 'j_random')
CALL dbms.security.removeRoleFromUser('architect', 'j_random')
Con la seguente procedura si può vedere quali ruoli sono stati associati all'utente:
CALL dbms.security.listRolesForUser('j_random')
Il risultato sarà un elenco con un solo elemento (publisher).
Altre procedure molto utili sono:
dbms.security.listUsers()
, che mostra l'elenco di tutti gli utenti, ognuno con il suo ruolodbms.security.suspendUser(utente)
, per sospendere temporaneamente un utente. La sospensione ha un effetto immediato: se l'utente è connesso viene disconesso, e qualsiasi sua operazione in corso viene interrotta (le transazioni andranno in rollback)dbms.security.activateUser(utente, richiediCambioPassword)
, che riattiva un utente sospeso e opzionalmente forza l'utente a cambiare password al prossimo avviodbms.security.deleteUser(utente)
, che elimina definitavamente un utente dal sistema.dbms.procedures()
, che mostra l'elenco di tutte le procedure presenti (non solo quelle built-in, ma anche eventuali procedure personalizzate o estensioni a Neo4j che abbiamo installato o sviluppato), e per ognuna riporta quali ruoli possono eseguirle.
Come vedremo nella prossima lezione, un amministratore può anche visualizzare quali sono le query in esecuzione istante per istante, e ciò è particolarmente utile, ad esempio, per capire perché il server è sovraccarico. L'amministratore potrà quindi decidere di terminare le query troppo pesanti per liberare risorse, oppure addirittura sospendere temporaneamente l'utente (che potrebbe corrispondere ad un servizio ad esempio di reportistica o di business intelligence) che sta effettuando operazioni troppo onerose.
Cambio password
La facoltà di cambiare la propria password è l'unica operazione consentita ai ruoli diversi da admin. È sufficiente invocare:
CALL dbms.security.changePassword('nu0v4 P4$sw=rd')