CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

Sicurezza in Enterprise JavaBeans (EJB)

Enterprise JavaBeans ha un modello di sicurezza elegante, flessibile e portabile su sistemi eterogenei.
La sicurezza delle applicazioni coinvolge essenzialmente due funzioni: l’autenticazione e l’autorizzazione.
L’autenticazione è il processo attraverso il quale si verifica l’identità dell’utente e si traduce tipicamente nel controllo di un username e una password.
L’autorizzazione invece è il processo mediante il quale si determina quale utente ha accesso a una data risorsa una volta che è stato autenticato: in un sistema aperto un utente autenticato può accedere a qualsiasi risorsa, in molti sistemi però occorre restringere l’accesso alle risorse agli utenti autorizzati.
Per rendere più efficiente il mantenimento delle autorizzazioni può essere utile organizzare gli utenti in gruppi e quindi garantire l’accesso alle risorse agli utenti che appartengono ad un dato gruppo.
Il concetto di ruolo è strettamente connesso al concetto di gruppo ed ha a che vedere con le “responsabilità” ricoperte da un dato utente dell’applicazione all’interno del gruppo di appartenenza.

Java Authentication and Authorization Service (JAAS)

La sicurezza in Java EE si basa su Java Authentication and Authorization Service API (JAAS).
JAAS è progettato in maniera tale che l’autenticazione e l’autorizzazione possano essere effettuate a qualsiasi livello Java EE (web, EJB, …) di fatto però molte applicazioni Java EE sono accessibili dal web e condividono le informazioni di autenticazione fra i livelli.
JAAS facilita questo approccio perché una volta che un utente si autentica ad un dato livello, l’autenticazione si propaga agli altri livelli evitando in tal modo di dover ripetere le procedure di autenticazione: l’oggetto Principal rappresenta l’authentication context condivisibile tra i livelli.
Una volta che un utente si autentica ad un dato livello fornendo le sue credenziali, JAAS fornisce un Principal che è associato ad uno o più ruoli, l’application server quindi controlla se l’utente è autorizzato ad accedere alle risorse richieste.
Se necessario il Principal viene propagato fra i livelli in maniera del tutto trasparente allo sviluppatore.

Autenticazione e autorizzazione a livello web

Le specifiche servlet nascondono un grande numero di dettagli ad alto livello per l’authenticazione e l’autorizzazione.
Lo sviluppatore deve semplicemente indicare al container quali risorse vuole proteggere, come proteggerle , come gestire le credenziali e quali ruoi hanno accesso alle risorse: il container fa il resto.
La sicurezza a livello web è configurata usando gli elementi login-config e security-constraint del file web.xml.
<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>MiaApplication</realm-name>
</login-config>

...

<security-constraint>
  <web-resource-collection>
    <web-resource-name>
      Amministrazione
    </web-resource-name>
    <url-pattern>/admin/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>RUOLO</role-name>
  </auth-constraint>
</security-constraint>
Nell’esempio precedente è stato scelto il meccanismo di autenticazione più semplice cioè BASIC, il quale usa uno schema di autenticazione basato sull’header http che fa si che il browser chieda le informazioni utente e password.
Altre forme di autenticazione popolari sono FORM che è essenzialmente simile a BASIC se non per il fatto che le informazioni di autenticazione sono fornite mediante un form HTML e CLIENT_CERT in cui il client invia un certificato di client pubblica memorizzato nel browser al web server usando SSL (Secure Socket Layer) e il server autentica i contenuti del certificato piuttosto che username/password.
Le credenziali sono quindi validate da un provider JAAS.
Nell’esempio viene inoltre indicato il reame del container che dovrebbe essere protetto, gli url da proteggere e i ruoli che possono accedere alle pagine
Così come avviene per la gestione delle transazioni, l’autorizzazione può essere dichiarativa o programmatica: ciascuna di queste fornisce un differente controllo sul processo di autenticazione.

Sicurezza dichiarativa

Nell’autorizzazione dichiarativa si dichiarano i ruoli che hanno accesso a moduli EJB, EJB o metodi di business.
@DeclareRoles("UTENTE", "AMMINISTRATORE")
@Stateless
public class MioBean implements InterfacciaMioBean 
{
  @RolesAllowed("UTENTE",”AMMINISTRATORE”)
  public void metodo1() 
  {
    ...
  }

  @PermitAll
  public void metodo2()
  {
    ...
  }
}
Nell’autorizzazione dichiarativa si dichiarano i ruoli che hanno accesso a moduli EJB, EJB o metodi di business.
Esistono diversi modi per dichiarare ruoli: uno di questi è rappresentato dall’annotazione @DeclareRoles che può essere applicata a un metodo o all’intera classe e che consente di specificare un elenco di ruoli che possono accedere alle risorse.
Alternativamente è possibile specificare i ruoli mediante deployment descriptors.
Se non si dichiarano i ruoli, il container creerà automaticamente una lista di ruoli analizzando l’annotazione @RolesAllowed.
L’annotazione @RolesAllowed assume un ruolo cruciale nella gestione della sicurezza dichiarativa in quanto permette di specificare i ruoli ai quali è consentito l’accesso ad una risorsa.
Questa annotazione può essere applicata o ad un metodo o a una classe intera in quest’ultimo caso i ruoli vengono propagati a tutti i metodi della classe.
E’ possibile sovrascrivere le annotazioni a livello classe riapplicando l’annotazione a livello di metodo
E’ possibile usare l’annotazione @PermitAll per rendere accessibile la classe EJB o il metodo a qualsiasi ruolo.
Viceversa @DenyAll nega l’accesso alla classe o al metodo a qualsiasi ruolo
L’annotazione @RunAs viene utilizzata quando si vuole assegnare dinamicamente un nuovo ruolo al Principal esistente nello scope dell’invocazione di un metodo EJB.
Se ad esempio si sta invocando un altro EJB all’interno di un metodo che richiede un determinato ruolo da quello del Principal corrente si può usare questa annotazione
@RunAS("AMMINISTRATORE")
@RolesAllowed("UTENTE")
public void metodo3()
{
  ...
}

Sicurezza programmatica

La sicurezza programmatica fornisce un accesso diretto al Principal così da poterne controllare direttamente il ruolo da codice.
@Stateless
public class MioBean implements InterfacciaMioBean
{
  @Resource SessionContext context;
  ...
  
  public void metodo1() 
  {
    if (!context.isCallerInRole("AMMINISTRATORE")) 
    {
      throw new SecurityException("Permesso negato.");
    }
  
    ...

  }
 
  ...

}
La sicurezza programmatica fa usco esclusivamente di due metodi getCallerPrincipal e isCallerInRole.
public interface EJBContext 
{
  ...
  public java.security.Principal getCallerPrincipal();
  public boolean isCallerInRole(java.lang.String roleName);
  ...  
}
Il metodo isCallerInRole consente di vedere se il principal autenticato ha un determinato ruolo: se non è così viene invocata una java.lang.SecurityEception per notificare la violazione.
Il metodo getCallerPrincipal da diretto accesso a java.security.Principal rappresentante l’authentication context corrente.
L’unico metodo interessante di Principal è getName che restituisce il nome del Principal ovvero il login name dell’utente validato.

Sicurezza programmatica con gli interceptor

Per effettuare il controllo delle credenziali prima dell'invocazione di un metodo è possibile ricorrere all'uso degli interceptor:
public class MioInterceptor 
{
  @AroundInvoke
  public Object controllo(InvocationContext context) throws Exception 
  {
    if (!context.getEJBContext().isCallerInRole("ADMIN")) 
    {
      throw new SecurityException("Permesso negato.");
    }
    return context.proceed();
  }
}

@Stateless
public class MioBean implements InterfacciaMioBeean 
{
  @Interceptors(miopackage.MioInterceptor.class)
  public void metodo1 
  { 
    ... 
  }
}