La gestione della sicurezza nell’architettura EJB

Analisi ed implementazione di uno studio di caso

Claudio Di Vita Alessio De Nichilo

Il modello della sicurezza in J2EE
La piattaforma J2EE prevede un modello della sicurezza dichiarativo, nel quale i fruitori di un’applicazione, con le rispettive autorizzazioni, vengono definiti mediante un descrittore di deployment standard. Questo separa la logica applicativa dei componenti dalla gestione della sicurezza, che viene affidata al container.

La terminologia
Un application server J2EE interagisce con i seguenti componenti: • Reami • Utenti • Gruppi • Ruoli

Gli utenti, i gruppi ed i reami
Un utente è un individuo che ha accesso ad una o più applicazioni, e può essere associato ad un gruppo. Un gruppo è un insieme di utenti, i quali possono essere classificati in base ad una serie di caratteristiche comuni. Un reame è una collezione di utenti e gruppi che sono sottoposti alle stesse policy di sicurezza.

I ruoli
Un ruolo è l’astrazione del permesso di accedere ad un determinato insieme di risorse in una applicazione. All’interno della piattaforma J2EE un ruolo viene spesso paragonato ad una chiave in grado di aprire un lucchetto: l’identità dell’individuo che desidera aprirlo non ha rilevanza, è sufficiente essere in possesso di una copia della chiave.

La specifica dei ruoli
I ruoli di una applicazione, detti anche security roles, devono essere definiti dall’Application Assembler, a seconda della tipologia dei componenti, mediante gli appropriati descrittori di deployment: • ejb-jar.xml, nel caso degli EJB • web.xml, nel caso di Servlet e JSP

L’assegnazione dei ruoli agli utenti ed ai gruppi
Il mapping tra i ruoli e gli utenti ed i gruppi, avviene durante il processo di deployment dell’applicazione.

Utilizzare la sicurezza dichiarativa con gli EJB
Per quanto riguarda gli EJB, le policy di sicurezza dichiarative devono essere opportunamente definite all’interno del descrittore ejb-jar.xml. Gli elementi da specificare sono: • Security roles • Method permissions

La definizione dei security-roles
Ogni security role deve essere definito mediante il tag <security-role>, il quale prevede gli elementi: • <role-name>, per indicare il nome del ruolo • <description>, per fornirne una descrizione I security roles sono validi per tutti gli EJB dichiarati all’interno del descrittore ejb-jar.xml.

I permessi sui metodi
Una method permission deve essere definita mediante il tag <method-permission>, il quale contiene: • Una lista di uno o più security roles • Un insieme di uno o più metodi Tutti i security roles indicati all’interno di un elemento <method-permission> hanno la possibilità di invocare i metodi elencati.

L’elemento <method> di <method-permission>
Per indicare i metodi per i quali devono essere applicati i permessi che sono stati definiti, è necessario utilizzare il tag <method> ed i suoi elementi. Per indicare l’EJB al quale appartiene il metodo si utilizza l’elemento <ejb-name>. Il nome del metodo si indica con il tag <method-name>: specificando * come valore, si fa riferimento a tutti i metodi dell’EJB indicato da <ejb-name>.

Altre caratteristiche del tag <method>
Con l’elemento <method-params> vengono specificati i parametri del metodo, nei casi di overloading del nome. A sua volta il tag <method-params> contiene uno o più elementi <method-param>, i quali rappresentano gli argomenti del metodo ed il cui valore deve essere il tipo dell’argomento. Il tag <method-intf> viene utilizzato per differenziare tra metodi che hanno la stessa segnatura e sono definiti in più contesti, quali le interfacce Home e Remote.

I limiti del modello dichiarativo
Purtroppo in alcune situazioni il modello della sicurezza di J2EE risulta inadeguato. Con un sistema di autorizzazione basato esclusivamente sui ruoli, non è infatti possibile specificare delle policy che siano in qualche modo legate alle informazioni trattate dall’applicazione.

La sicurezza programmatica
Per implementare delle policy complesse è quindi necessario immergere del codice, estraneo alla logica applicativa, all’interno dei componenti. L’interfaccia javax.ejb.EJBContext fornisce 2 metodi per consentire al Bean Provider l’accesso ai dati relativi all’identità dell’utente che ha invocato l’EJB. In questo modo è possibile implementare delle policy legate allo “stato” dell’applicazione in un certo momento.

Il metodo getCallerPrincipal()
Restituisce una istanza di java.security.Principal che rappresenta l’utente che ha invocato l’EJB. Ovviamente il risultato di questo metodo è fortemente influenzato dalle modalità con le quali viene effettuato il mapping dei principal.

Il metodo isCallerInRole(String roleName)
Restituisce un valore booleano che indica se l’utente che ha invocato l’EJB è stato assegnato il ruolo indicato da roleName. Questo metodo aiuta il Bean Provider ad implementare dei controlli che non possono essere definiti facilmente nel descrittore di deployment ejb-jar.xml, come porre un limite a determinate operazioni sulla base del ruolo del richiedente.

I riferimenti ai security roles
Affinché il metodo isCallerInRole(String roleName) possa essere invocato correttamente, è necessario che all’interno del descrittore ejb-jar.xml vengano specificati i riferimenti ai security roles. Infatti il ruolo rappresentato dal parametro roleName non è direttamente un security role, ma un ruolo fittizio il quale fa riferimento ad un security role definito all’interno dell’applicazione.

Specificare i riferimenti ai security roles
La definizione di ciascun riferimento ad un security role avviene mediante il tag <security-role-ref>. L’elemento <role-name> indica il nome del riferimento, mentre il tag <role-link> serve ad associare un security role al riferimento. È importante sottolineare che i riferimenti ai security roles vanno definiti per ogni EJB che utilizza il metodo isCallerInRole(String roleName).

Gli svantaggi della sicurezza programmatica
L’introduzione di codice “estraneo” alla logica applicativa di un componente per gestire la sicurezza: • Non favorisce la separazione degli interessi • Rende il codice difficile da mantenere Sfortunatamente questa è l’unica soluzione applicabile, a meno che non si decida di utilizzare le funzionalità offerte da un particolare Application Server.

I security proxies di JBoss
Uno dei più diffusi Application Server sul mercato, JBoss, offre una valida alternativa alla sicurezza programmatica, introducendo il concetto di security proxy. In aggiunta ai controlli di sicurezza standard, per ogni EJB è possibile definire un oggetto che ha la possibilità di intercettare le richieste di esecuzione dei metodi in modo tale da poterne verificare la legittimità.

Le caratteristiche di un security proxy
Utilizzando un security proxy è quindi possibile applicare policy di sicurezza complesse la cui implementazione è indipendente dalla logica applicativa dell’EJB. Per poter utilizzare un security proxy, all’interno del descrittore dell’Application Server, il file jboss.xml, si deve indicare, mediante l’elemento <security-proxy>, il nome della classe che ricoprirà tale funzione.

Realizzare un security proxy
L’architettura di JBoss offre due differenti possibilità per realizzare dei security proxy. Una soluzione più scalabile prevede l’implementazione, da parte dell’oggetto che farà da proxy, dell’interfaccia org.jboss.security.SecurityProxy. L’alternativa è sviluppare un oggetto che implementa uno o più metodi delle interfacce Home oppure Remote dell’EJB.

L’interfaccia org.jboss.security.SecurityProxy
Questa interfaccia prevede l’implementazione di due metodi: • invoke(), per i controlli sull’interfaccia Remote • invokeHome(), per i controlli sull’interfaccia Home i quali sono invocati prima dei metodi dell’EJB.

L’impiego della reflection
La tipologia dei parametri passati ai metodi invoke() ed invokeHome() impone l’utilizzo delle reflection API, per poter utilizzare adeguatamente le informazioni che sono state fornite. Infatti gli argomenti dei metodi appartengono alle classi:
• java.lang.reflect.Method • java.lang.Object

I security proxy che implementano i metodi dell’EJB
La realizzazione di security proxy che utilizzano questa tecnica risulta estremamente semplice. Prima di eseguire il metodo dell’EJB, il container invoca il corrispondente metodo del proxy, in modo tale da poter eseguire i controlli necessari alla verifica delle policy. Nel caso in cui un metodo invocato sull’EJB non abbia una corrispondenza nel proxy, l’esecuzione prosegue normalmente.

La sicurezza nell’architettura EJB: uno studio di caso
L’applicazione ejbVSF è un filesystem remoto al quale hanno accesso diverse categorie di utenti. Si vogliono implementare due versioni dell’applicazione: • Basic • Standard le quali offrono livelli di sicurezza differenti.

Caratteristiche di ejbVSF-basic
La versione basic di ejbVSF distingue tra due tipologie di utenti: • Administrators • Users Di conseguenza per determinare la tipologia di accesso da attribuire, bisogna ricorrere all’autenticazione degli utenti.

Le tipologie degli utenti
Gli utenti di tipo Administrators hanno la possibilità di effettuare qualunque operazione sul filesystem remoto: di conseguenza possono creare, modificare e cancellare file e directory. Diversamente gli Users hanno dei privilegi limitati: a loro è consentito l’accesso alle risorse, senza però poterle modificare in alcun modo.

I limiti di ejbVSF-basic
Il modello della sicurezza di ejbVSF-basic è di tipo dichiarativo, e consente solo ad alcuni utenti la modifica del filesystem. Ma questo non è sufficiente nel caso in cui si vogliano applicare delle policy che regolano l’accesso alle risorse sulla base di caratteristiche quali l’appartenenza allo stesso gruppo di utenti (come gli impiegati del reparto contabilità, oppure i responsabili dei sistemi informativi).

La sicurezza nella versione standard di ejbVSF
Nella versione standard, ejbVSF amplia il modello della sicurezza di ejbVSF-basic, limitando l’accesso ai file ed alle directory sulla base di alcune proprietà. Ad ogni risorsa è associata una lista che indica i privilegi di accesso assegnati ad un determinato utente, rispetto alla risorsa stessa. Quando un utente tenta di accedere ad un file, viene consultata la lista di controllo di accesso per verificare la legittimità di tale richiesta.

La lista di controllo di accesso
Quando viene creato un file sul filesystem remoto, ad esso viene associata una lista di controllo di accesso che comprende l’utente che ha effettuato l’operazione ed il suo gruppo di appartenenza, ai quali vengono assegnati i permessi di lettura e scrittura. La radice del filesystem possiede una particolare lista di controllo di accesso: comprende un utente speciale che rappresenta tutti gli utenti, ed è immutabile.

I dettagli implementativi di ejbVSF
Ovviamente entrambe le versioni di ejbVSF condividono la stessa architettura di base. FileSystemExplorer è il session bean di tipo stateful che permette l’utilizzo del filesystem, e offre all’utente servizi quali: • Esplorazione del filesystem • Creazione, modifica ed eliminazione dei file

La modifica del filesystem
Le operazioni sui file e sulle directory non vengono realizzate direttamente da FileSystemExplorer, ma sono delegate ad un altro EJB, che implementa l’interfaccia FileSystem del package it.dide.ejbvsf. La differenza tra le versioni basic e standard di ejbVSF risiede nell’EJB che viene utilizzato per realizzare le operazioni sul filesystem. In entrambi i casi però, si tratta comunque di un session bean di tipo stateless con visibilità locale.

I metodi principali dell’interfaccia FileSystem

createDirectory(VSFile parent, String name); createFile(VSFile parent, String name, byte[] content); delete(VSFile file); getDirectory(VSFile parent, String name); getFile(VSFile parent, String name); list(VSFile directory)

Il filesystem utilizzato da ejbVSF-basic
A causa del modello della sicurezza esclusivamente dichiarativo di ejbVSF-basic, il bean che implementa le operazioni sul filesystem non deve gestire alcun tipo di informazione extra. Quindi BasicFileSystem, l’EJB utilizzato da ejbVSF-basic per modificare il filesystem, si limita all’esecuzione delle operazioni richieste.

Il filesystem della versione standard di ejbVSF
La gestione delle operazioni sul filesystem non è l’unico compito svolto da DideFileSystem, l’EJB utilizzato dalla versione standard di ejbVSF. Infatti per fornire al security proxy le informazioni necessarie a determinare la legittimità delle richieste che vengono inoltrate, DideFileSystem deve mantenere una lista di controllo di accesso per ogni risorsa presente sul filesystem.

Tratti comuni tra le versioni di ejbVSF
In entrambe le versioni dell’applicazione, la radice del filesystem è rappresentata da una particolare istanza di un oggetto della classe VSFile, il cui nome è ROOT. In pratica ROOT è una directory che contiene al suo interno tutti i file presenti sul filesystem.

Un semplice accesso a ejbVSF: JBossConsoleClient
Grazie al bean FileSystemExplorer, l’accesso ad ejbVSF può avvenire in diverse modalità: ad esempio mediante un’interfaccia web. Per fornire un rapido accesso ad un filesystem gestito da una qualunque versione di ejbVSF, è stato realizzato un client a linea di comando che accetta gli stessi comandi base della shell bash dei sistemi Linux.

Conclusioni
La piattaforma J2EE offre la possibilità di specificare delle policy di sicurezza sulla base di autorizzazioni definite esternamente all’applicazione, delegando la gestione di quest’ultime all’Application Server. Tale modello consente di separare la logica applicativa dei componenti dalla gestione della sicurezza, limitando però la complessità delle policy che possono essere applicate. In particolare non è possibile specificare dei vincoli legati alle informazioni trattate dall’applicazione.

Conclusioni
Per gestire delle policy di sicurezza complesse, è quindi necessario introdurre del codice “estraneo” alla logica applicativa all’interno dei componenti, in modo tale da poter effettuare dei controlli di sicurezza personalizzati, diminuendo però la mantenibilità del codice. È possibile adottare delle soluzioni che consentono di mantenere la logica applicativa separata dalla gestione della sicurezza sfruttando le funzionalità offerte da alcuni Application Server, ma questo influisce pesantemente sulla portabilità dei componenti.

Riferimenti

• J2EE Specification 1.4 • The J2EE 1.4 Tutorial • EJB Specification 2.1 • The JBoss 4 Application Server Guide