MokaByte 76 - Luglio Agosto 2003 
Setup di architetture J2EE
JBossSX e la gestione della sicurezza per le applicazioni enterprise
di
Davide Brusamolino

La sicurezza è un aspetto fondamentale per la gestione e per l'utilizzo, da parte di un particolare profilo utente, delle applicazioni enterprise. La piattaforma J2EE utilizza un modello di sicurezza basato sulla dichiarazione di roles logiche all'interno di appositi file ( es. per EJB ejb-jar.xml ), senza entrare nel dettaglio implementativo. Sarà compito dell'amministratore mappare l'ambiente logico sullo specifico ambiente utilizzato. L'alternativa a questo modello generalmente è quella di integrare il codice del mio EJB con codice atto a garantirmi la sicurezza creando un indesiderabile miscela di business logic e security logic.
JBoss offre una soluzione alternativa a questo problema offrendo un architettura proprietaria basata sul concetto di 'proxy' che mi permette di separare la business logic dalla security logic.


JAAS e JBoss
In JBoss la sicurezza viene gestita dal modulo JBossSX basato sullo standard JAAS.
Il cuore della sicurezza del modulo JBossSX è la classe JaasSecurityManager che implementa due interfacce proprietarie:

1) AuthenticationManager: gli viene accreditato il compito di controllare la validazione delle credentials associate al principals.
2) RealmMapping: è responsabile nella mappatura delle role e dei principals.

Come tutti i servizi di JBoss anche al JaasSecurityManager sono associati degli MBean definiti nel file jboss.jcml:

<!-- ======================================================== -->
<!-- Security -->
<!-- ======================================================== -->

<!-- JAAS security manager and realm mapping -->
<mbean code="org.jboss.security.plugins.JaasSecurityManagerService"
name="Security:name=JaasSecurityManager">
<attribute
name="SecurityManagerClassName">
org.jboss.security.plugins.JaasSecurityManager
</attribute>
<attribute name="LoginConfig">
Security:name=DefaultLoginConfig
</attribute>
</mbean>
<mbean code="org.jboss.security.plugins.DefaultLoginConfig"
name="Security:name=DefaultLoginConfig">
<attribute name="AuthConfig">auth.conf</attribute>
</mbean>

L'associazione del JaasSecurityManager al modulo di login, atto a creare il mio Subject con le proprie credenziali, avviene nel file auth.conf.
La struttura è la seguente:

nome_dominio1 {
classe modulo di login
eventuali parametri
};
nome_dominio2 {
classe modulo di login
eventuali parametri
};
etc…….

Per quanto riguarda i moduli di login JBoss mi mette a disposizioni classi predefinite; questo non toglie che l'utente possa implementarsi un proprio modulo di login.
La traccia da seguire è la seguente: devo implementare la classe AbstractLoginModule e fare l'override di tutti i metodi abstract in essa contenuti.
Qui viene utilizzata la classe org.jboss.security.auth.spi.DatabaseServerLoginModule

 

DatabaseServerLoginModule
La classe DatabaseServerLoginModule è un modulo di login che si appoggia ad un database per memorizzare all'interno di tabelle le mie roles e i miei principals.
Le due tabelle sono:

CREATE TABLE Principals (
PrincipalID VARCHAR(64) PRIMARY KEY,
Password VARCHAR(64) )
);

CREATE TABLE Roles (
PrincipalID VARCHAR(64),
Role VARCHAR(64),
RoleGroup VARCHAR(64) )
);

Nella prima tabella ho l'associazione tra principals e password; nella seconda ho l'associazione fra principals e roles.
I parametri della classe sono fra gli altri:

a) il modulo di login rappresentato dalla classe specificata.
b) dsJndiName: rappresenta il JNDI name associato al mio database attraverso la configurazione precedentemente fatta nel file jboss.xml.
c),d) sono le query utilizzate per interrogare le tabelle nel database.

Vediamo un esempio:

dominio1 {
a) org.jboss.security.auth.spi.DatabaseServerLoginModule required
b) dsJndiName="java:/DefaultDS"
c) principalsQuery="select Password from Principals where PrincipalID=?"
d) rolesQuery="select Role, RoleGroup from Roles where PrincipalID=?";
};


File jboss.xml
La mappatura interna a JBoss avviene attraverso il solito file jboss.xml:



Figura 1

Il tag 'security-domain' mi identifica il nome logico (JNDI) del security manager utilizzato da JBoss per la gestione della sicurezza a livello di EJB appartenenti alla mia applicazione.
Un esempio di codice per associare il mio dominio di sicurezza con il mio EJB è il seguente:

<?xml version="1.0" encoding="UTF-8"?>
<jboss>
<security-domain>java:/jaas/dominio1</security-domain>
<enterprise-beans>
<session>
<ejb-name>Bean1</ejb-name>
<jndi-name>ejb/Bean1</jndi-name>
</session>
</enterprise-beans>
</jboss>

premesso l'esistenza del file ejb-jar.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
"http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>StatelessSession</ejb-name>
<home>Bean1Home</home>
<remote>Bean1Remote</remote>
<ejb-class>Bean1</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name> role1</role-name>
</security-role>
<method-permission>
<role-name>role1</role-name>
<method>
<ejb-name>Bean1</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<method-permission>
<role-name>role2</role-name>
<method>
<ejb-name>Bean1</ejb-name>
<method-name>create</method-name>
</method>
<method>
<ejb-name> Bean1</ejb-name>
<method-name>remove</method-name>
</method>
<method>
<ejb-name> Bean1</ejb-name>
<method-name>make</method-name>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>

A questo punto qualsiasi utente precedentemente configurato al quale è associata una roles di tipo role1 avrà l'accesso a qualsiasi metodo del mio EJB mentre a chi associata la role2 potrà utilizzare solo i metodi create, remove e make. A qualsiasi altro utente che non soddisfa queste condizioni viene vietato l'utilizzo dell'EJB.

 

Proxy security
JBoss mi mette a disposizione un' ulteriore metodologia per ampliare la sicurezza associata alla mia applicazione, separando la parte di controllo (proxy) dalla logica di business.
Lo sviluppatore si dovrà concentrare su due fronti differenti e ben separati: la/le classi EJB, i/il sucurity proxy da associare ai vari EJB. Sarà poi compito del container invocare un particolare metodo del mio security-proxy e permettere o meno l'invocazione del codice del mio EJB, se le politiche di sicurezza implementata dallo sviluppatore risultano soddisfatte . In particolare il container creerà un istanza del MioSecurityProxy che verrà utilizzata per tutte le istanze del EJB (Bean1).

Per ottenere questo risultato devo creare una classe che implementare l'interfaccia org.jboss.security.Proxy che ha due metodi invokeHome e invoke che vengono chiamati dal container prima di accedere all' EJB stesso.
In particolare il metodo invokeHome mi viene invocato dal container per controllare le credenziali dell'utente e permette quindi l'invocazione dei metodi contenuti nella home interface del mio EJB; mentre invoke viene invocato per controllare le credenziali per permettere l'accesso o meno dei metodi contenuti nella remote interface.
Per poter utilizzare la nuova classe creata ad-hoc la devo specificare nel file jboss.xml attraverso il tag security-proxy:

<?xml version="1.0" encoding="UTF-8"?>
<jboss>
<security-domain>java:/jaas/dominio1</security-domain>
<enterprise-beans>
<session>
<ejb-name>Bean1</ejb-name>
<jndi-name>ejb/Bean1</jndi-name>
<security-proxy>MioSecurityProxy</security-proxy>
</session>
</enterprise-beans>
</jboss>


Per esempio una bozza di Proxy:

public class MioSecurityProxy implements SecurityProxy {
  private Category _log = Category.getInstance(
                          getClass().getName());
  private ThreadLocal _ctx = new ThreadLocal();

  public void setEJBContext(EJBContext ctx) {
    _ctx.set(ctx);
  }

  public void invokeHome(Method m, Object[] args){
    //Codice per la validazione per accedere ai metodi della
    //Home interface
  }

  private Connection getConnection(){
    try{
      Context in = new InitialContext();
      DataSource ds = (DataSource)in.lookup("java:comp/
                                             env/jdbc/MySqlDS");
      return ds.getConnection();
    }catch(Exception e){
      e.printStackTrace();
    }
    return null;
  }

  public void invoke(Method m, Object[] args, Object bean)
                     throws SecurityException {
    //Codice per la validazione per accedere ai metodi della
    //Remote interface
    ...
    ...

  }
}


Conclusioni
Sicuramente la parte di sicurezza basata sul 'proxy' è molto interessante in quanto il mio EJB svolge solo il compito di esecutore della business logic; purtroppo il lavoro che faccio per gestire la sicurezza in classi separate (proxy) è limitato al solo ambiente di JBoss e quindi non portabile.

 

Bibliografia
[1] * "Manual - online HTML version"- www.jboss.org
[2] * SCOTT STARK, MARC FLEURY "JBoss Administration and Development "- JBoss Group
[3] * Davide Brusamolino "Configurare una connessione a db con JBoss 2.4.x" - Mokabyte Aprile 2003

 

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it