Filtrare l’accesso ai dati è una caratteristica indispensabile per impedire l’accesso di malintenzionati all’applicazione.
Finora era possibile esporre o non esporre come risorsa REST una classe di dati e alcuni dei suoi attributi. Si trattava già di un mezzo conveniente per limitare l’accesso ai dati. Tuttavia, siamo entusiasti di offrire nella v19R8 un sistema potente e completamente personalizzabile per proteggere i dati da utenti non autorizzati. Un sistema di protezione dei dati dipende da chi vi accede e da quali dati vi accedono.
Come richiesto durante gli scambi con i clienti, ora sarete in grado di gestire molti utenti che lavorano su attività diverse e di regolare l’accesso ai vostri dati con diversi livelli di granularità, dal più generale al più preciso.
Dopo le sessioni web scalabili, questa funzione vi permette di costruire un’applicazione affidabile e protetta.
contesto generale
Questa nuova funzionalità si basa sui concetti di ORDA e sulle sessioni web (più precisamente sulle sessioni web scalabili).
Copre tutti i processi web, come le richieste REST e le richieste ricevute su un datastore remoto, ma anche processi web come 4DACTION o tag 4D.
concetti principali
Nella vostra applicazione, potete ora definire i permessi consentiti.
Un permesso indica una risorsa e i privilegi associati alle azioni su questa risorsa.
Lerisorse sono un attributo della classe di dati, una funzione del modello di dati ORDA, una classe di dati e l’intero archivio di dati.
Leazioni sono: creare, leggere, aggiornare, cancellare, descrivere, eseguire (una funzione) e promuovere (una funzione).
un’autorizzazione per un attributo di una classe di dati
L’attributo personalNotes della classe di dati Records può essere letto dal privilegio medicalAction.
Risorsa Records.personalNotes | Privilegi |
---|---|
Leggere | azione medica |
un permesso per una funzione della classe di dati
La funzione deleteOldRecords() definita nella classe di dati Records può essere eseguita con il privilegio administrate.
Risorsa Records.deleteOldRecords() | Privilegi |
---|---|
Eseguire | amministrare |
un permesso per una classe di dati
La classe di dati Records può essere letta da entrambi i privilegi medicalAction e administrate, mentre le entità possono essere create dal privilegio medicalAction.
Risorsa Record | Privilegi |
---|---|
Leggere | medicalAction, administrate |
Creare | azione medica |
un permesso per l’intero datastore
Il privilegio administrate può rilasciare entità in qualsiasi classe di dati del datastore
Risorsa ds | Privilegi |
---|---|
Rilasciare | amministrare |
Per impostare le regole personalizzate per i permessi, è sufficiente creare un file roles.json nella cartella Project/Sources dell’applicazione.
Alcuni ruoli( cioè un insieme di privilegi) possono anche essere definiti e associati da voi stessi a ogni utente della vostra applicazione.
Si ricordi che è possibile associare alcuni privilegi a una sessione Web scalabile. Quindi, quando il sistema riceve una richiesta, viene effettuato un controllo sui privilegi dell’utente memorizzati nella sessione web e sulle azioni consentite per tali privilegi nel file roles.json.
Se l’azione sulla risorsa non è consentita, viene segnalato un errore di autorizzazione.
il meccanismo in dettaglio
Quando non sono stati impostati privilegi nella sessione web, questa è una sessione ospite. Per impostazione predefinita, tutti i dati sono accessibili per questo privilegio ospite. Inoltre, se non si imposta alcun permesso nel file roles.json, tutti i dati sono accessibili a chiunque.
Successivamente, i permessi impostati nel file roles.json entrano in gioco e limitano l’accesso ai dati.
I permessi possono essere impostati per le risorse a diversi livelli di granularità. Le risorse sono elencate di seguito per livelli di granularità (dal più generale al più preciso):
– il datastore
– una classe di dati
– un attributo di classe di dati / una funzione di classe di dati
I privilegi impostati a un determinato livello sono sovrascritti o completati da privilegi specificati a un livello più preciso.
Il diagramma seguente fornisce una rappresentazione più grafica dei privilegi associati alle azioni su alcune risorse.
Il privilegio guest può eseguire azioni su risorse associate a nessun privilegio. Si limita l’accesso ai dati non appena si associa un privilegio a una coppia risorsa/azione.
SUGGERIMENTO: se volete che i vostri dati siano irraggiungibili per impostazione predefinita, associate al datastore un privilegio nessuno per tutte le azioni e assicuratevi che questo privilegio non venga mai inserito nella sessione.
Approfondimento con esempi
Lavoriamo con questo semplice modello di dati.
In questa applicazione, vogliamo implementare queste regole:
- solo il privilegio administrate può abbandonare e creare entità sull’intero datastore
- la classe di dati Pazienti può essere letta solo dal privilegio medicalAction
- l’attributo Records.personalNotes può essere letto solo dal privilegio medicalAction (anche se la classe di dati è leggibile da diversi altri privilegi)
- la funzione deleteOldRecords() definita nella classe di dati Records è eseguibile solo dal privilegio administrate
- gestire una funzione authenticate() eseguibile da chiunque (privilegio guest)
il privilegio administrate può rilasciare e creare entità sull’intero datastore.
Nel file roles.json qui sotto, abbiamo definito il privilegio administrate. Questo privilegio è autorizzato a:
- abbandonare
- creare
entità dell’intero datastore (tutte le classi di dati).
Solo il privilegio administrate è autorizzato a eseguire queste azioni. Poiché per impostazione predefinita, tutte le azioni sono consentite su tutti i dati e non abbiamo associato alcun privilegio all’azione di lettura per il datastore, chiunque può leggere tutte le classi di dati del datastore.
{"privilegi": [{"privilegio":"amministrare"}], "ruoli": [{}], "permessi": { "allowed": [{"applyTo":"ds", "type": "datastore", "drop": ["amministra"], "crea": ["administrate"]}] } }
La classe di dati pazienti può essere letta solo con il privilegio di azione medica.
Nel file roles.json qui sotto, abbiamo aggiunto un privilegio medicalAction.
Solo questo privilegio medicalAction è autorizzato a leggere la classe di dati Patients. Poiché questa autorizzazione è impostata a livello di classe di dati, essa sovrascrive le autorizzazioni impostate a livello di datastore e le autorizzazioni per gli ospiti. Pertanto, solo il privilegio medicalAction può leggere la classe di dati Patients. Le altre classi di dati sono leggibili da chiunque.
{"privilegi": [{"privilegio": "amministrare"},{"privilegio":"medicalAction"}], "ruoli": [ {} ], "permessi": {"allowed": [ {"applyTo": "ds", "type": "datastore", "drop": ["amministra"], "crea": ["amministrare"] }, {"applyTo":"Pazienti", "type": "dataclass", "read": ["medicalAction"] } ] } }
l’attributo records.personalnotes è leggibile solo dal privilegio medicalAction
In questo esempio, è stato aggiunto il privilegio readRecords. Poiché il privilegio readRecords è incluso nel privilegio medicalAction, il privilegio medicalAction può eseguire tutte le azioni consentite dal privilegio readRecords.
Sia i privilegi readRecords che possono leggere la classe di dati Records, ma l’attributo personalNotes può essere letto solo dal privilegio medicalAction.
{"privilegio": [{"privilegio": "amministrare"}, {"privilegio":"readRecords"}, {"privilegio":"medicalAction", "include": ["readRecords"] } ], "ruoli": [ {} ], "permessi": { "allowed": [ {"applyTo": "ds", "type": "datastore", "drop": ["amministra"], "crea": ["amministra"] }, {"applyTo": "Patients", "type": "dataclass", "read": ["medicalAction"] }, {"applyTo":"Record", "type": "dataclass", "read": ["readRecords"] }, {"applyTo":"Records.personalNotes", "type": "attribute", "read": ["medicalAction"] } ] } }
La funzione deleteoldrecords della classe di dati records è eseguibile solo dal privilegio administrate.
Nell’esempio seguente, poiché solo l’amministratore del sistema deve essere autorizzato a cancellare i vecchi record, abbiamo aggiunto al privilegio administrate il permesso di eseguire la funzione deleteOldRecords() definita nella classe di dati Records.
Solo questo privilegio può eseguirla.
Abbiamo anche aggiunto il permesso per il privilegio administrate di leggere la classe di dati Records, perché la lettura delle entità è necessaria per eliminarle.
{"privilegi": [ {"privilegio":"amministrare"}, {"privilegio": "leggiRegistri"}, {"privilegio": "medicalAction", "include": ["readRecords"] } ], "ruoli": [ {} ], "permessi": { "allowed": [ {"applyTo": "ds", "type": "datastore", "drop": ["amministra"], "crea": [ "amministra"] }, {"applyTo": "Patients", "type": "dataclass", "read": ["medicalAction"] }, {"applyTo": "Record", "type": "dataclass", "read": ["readRecords","administrate"] }, {"applyTo": "Records.personalNotes", "type": "attribute", "read": ["medicalAction"] }, {"applyTo":"Records.deleteOldRecords", "type": "method", "execute": ["amministra" ] } ] } }
gestire una funzione authenticate eseguibile dall’ospite
Per evitare che un utente estraneo esegua qualsiasi funzione nella nostra applicazione, abbiamo limitato l’esecuzione di funzioni a livello di datastore al privilegio none (non viene mai inserito nella sessione web).
Nel nostro sistema, abbiamo una funzione authenticate() (definita nella classe DataStore ) che deve essere eseguita dagli utenti per entrare nell’applicazione. Abbiamo aggiunto il permesso di eseguire questa funzione authenticate().
Poiché deve essere eseguibile da chiunque, l’azione execute è stata impostata per il privilegio guest. Abbiamo anche aggiunto i privilegi hr per evitare che la classe di dati Users venga letta da persone estranee all’applicazione.
La funzione authenticate() deve leggere il dataclass Users per verificare l’esistenza e la password dell’utente. Pertanto viene promossa con il privilegio hr. L’azione promote aggiunge un privilegio nella sessione web (solo durante l’esecuzione della funzione).
{"privilegi": [ {"privilegio": "amministrare"}, {"privilegio": "leggiRegistri"}, {"privilegio": "medicalAction", "include": ["readRecords"] }, {"privilegio":"hr"}, {"privilegio":"nessuno"} ], "ruoli": [ {} ], "permessi": { "allowed": [ {"applyTo": "ds", "type": "datastore", "drop": ["amministra"], "crea": ["amministra"], "esegui": ["nessuno"] }, {"applyTo": "Patients", "type": "dataclass", "read": ["medicalAction"] }, {"applyTo": "Utenti", "type": "dataclass", "read": ["hr"] }, {"applyTo": "Records", "type": "dataclass", "read": ["readRecords", "administrate"] }, {"applyTo": "Records.personalNotes", "type": "attribute", "read": ["medicalAction"] }, {"applyTo": "Records.deleteOldRecords", "type": "method", "execute": ["amministra"] }, {"applyTo": "ds.authenticate", "type": "method", "promote": ["hr"], "execute": ["ospite"] } ] } }
la fase di autenticazione
Nel file roles.json si possono definire i ruoli, cioè un insieme di privilegi. Nell’esempio che segue, abbiamo aggiunto il ruolo del Segretario , che contiene i privilegi createPatient e readRecords.
Gli utenti associati a questo ruolo possono eseguire tutte le azioni consentite dai privilegi createPatient e readRecords (creare un nuovo paziente e leggere i record).
{ "privilegi": [ {"privilegio": "amministrare" }, {"privilegio":"readRecords" }, {"privilegio": "medicalAction", "include": ["readRecords"] }, {"privilegio": "hr" }, {"privilegio": "nessuno"}, {"privilegio":"createPatient" } ], "ruoli": [ {"role":"Il Segretario", "privilegi": ["creaPaziente","leggiRegistrazioni" ] } } ], "permessi": { "permesso": [ {"applyTo": "ds", "type": "datastore", "drop": ["amministra"], "crea": ["amministra"], "esegui": ["nessuno"] }, {"applyTo": "Pazienti", "tipo": "dataclass", "read": ["medicalAction"], "create": ["createPatient"] }, {"applyTo": "Utenti", "type": "dataclass", "read": ["hr"] }, {"applyTo": "Record", "type": "dataclass", "read": ["readRecords", "administrate"] }, {"applyTo": "Records.personalNotes", "type": "attributo", "leggi": ["medicalAction"] }, {"applyTo": "Records.deleteOldRecords", "type": "method", "execute": ["amministra"] }, {"applyTo": "ds.authenticate", "type": "method", "promote": ["hr"], "execute": ["ospite"] } ] } }
Nella vostra applicazione, dovete associare ogni utente a un ruolo in una classe di dati (la classe di dati Users in questo esempio).
Ecco la classe di dati
e i dati
Durante la fase di autenticazione, è possibile inserire i privilegi associati a questo ruolo nella sessione web.
Ecco un esempio di funzione authenticate().
exposed Function authenticate($identifier : Text; $password : Text) : Text
var $user : cs.UsersEntity
Session.clearPrivileges()
$user:=ds.Users.query("identifier = :1"; $identifier).first()
If ($user#Null)
If (Verify password hash($password; $user.password))
Session.setPrivileges(New object("roles"; $user.role))
return "Your are authenticated as "+$user.role
Else
return "Your are authenticated as Guest"
End if
Else
return "Your are authenticated as Guest"
End if
Leggere attentamente la documentazione per saperne di più sui permessi e scaricare l’HDI di cui sopra per eseguire un esempio dimostrativo.
Sentitevi liberi di aprire discussioni sul forum.