crítica

A ver, primero que nada, la documentación de todo ésto es pésima.

Seam Security 3 usa PicketLink por debajo >> y, por lo tanto no se molesta en explicar cómo se configura sino su JPAIdentityStore, que es un extra que le añaden a las HibernateIdentityStore y LDAPIdentityStore que trae PicketLink >>

Para lo demás, supuestamente hay que remitirse a la documentación de PicketLink >>

Allí se habla de un idm-config.xml >> pero no queda claro dónde entraría ésto en Seam >>
En todo caso, este archivo es el que se usaría para crear un objeto IdentityConfigurationMetaData, según dice más abajo.
La otra opción es definir ésto en una clase java que implemente ‘varias’ interfaces (no se sabe exactamente cuáles)…

Después el texto se alarga sobre todos los posibles tags que puede tener el idm-config.xml, y llegado a las implementaciones prácticamente hace lo mismo pero dando un ejemplo para cada una.

Respecto a como instruir al framework si usar lo uno o lo otro, nada, ni dónde dejar este archivo siquiera…

Hasta la parte deployment, donde en el fondo de dicen que o te traes el archivo programáticamente

IdentitySessionFactory identitySessionFactory = new IdentityConfigurationImpl().configure(new File("src/test/resources/example-db-config.xml")).buildIdentitySessionFactory();

O, lo que sería más interesante, lo deployas en el servidor para referenciarlo por JNDI (así se compartiría entre instancias, aplicaciones, etc.). Desafortunadamente, las instrucciones que hay son para JBoss 5 y JBoss 6 no reconoce el sufijo -jboss-idm.xml, ni lo toma en cuenta si se deja como un data source normal (-ds.xml). Mucho menos JBoss 7, que ya no usa deployment descriptors sino que centraliza la información en la configuración del servidor (ej. standalone.xml)

Y sería la documentación…

destructiva

Si miramos la bosta de ejemplo que proveen >> podemos apreciar que no se la cranean y le meten un java.io.File no más como arriba.

Pero ésto ¿dónde se supone que se deja? ¿En el sistema de ficheros del computador? ¿O sea que la aplicación sólo corre en mi máquina?

¿En el servidor, usando una variable de entorno tipo $JBOSS_HOME? Éso podría ser un poco más portable, pero implica estar haciendo modificaciones a cada servidor donde queramos hacer correr la aplicación. Por lo demás, java.io.File busca desde su raíz de ejecución, i.e. del directorio bin/ ¿o sea que debemos dejar la configuración para una aplicación en específico con los ejecutables de JBoss? ¿O si no dónde? ¿Donde nos dé la gana?

Lo lógico es que la configuración de autentificación quede dentro de la aplicación a la que pertence. Lo cual se puede lograr con algo como

String idmconfig = Thread.currentThread().getContextClassLoader().getResource("idm-config.xml").getPath();//ruta relativa
IdentitySessionFactory identitySessionFactory = new IdentityConfigurationImpl().configure(new File(idmconfig)).buildIdentitySessionFactory();

Lo cual funciona… siempre y cuando el WAR sea deployado como exploded, pero si lo deployamos comprimido – que es como debe distribuirse a la final – java.io no es capaz de leer dentro de un archivo zipeado (el WAR).

constructiva

Por lo tanto, de Seam no sabemos como instruirle que use el IdentitySessionFactory para LDAP al que supuestamente tiene acceso, ni de PicketLink cómo exactamente darle la configuración de nuestro dominio LDAP a éste. ¿Qué hacemos? Ensayo y error.

Lo primero, que pese a lo que – mal – dice la documentación, IdentityConfigurationImpl tiene un tercer constructor que admite un String. A éste se le puede pasar el nombre del archivo de configuración para que lo busque dentro del WAR – comprimido o no

new IdentityConfigurationImpl().configure("idm-config.xml").buildIdentitySessionFactory();

En seguida, no debe ser muy escalable estar leyendo un archivo cada vez que queramos autentificar un usuario, máxime cuando lo hacemos para construir una Factory que por definición debiera poder configurarse una sola vez y ella generar distintas instancias.
Una solución parche – ya que no contamos con la oficial – es meterla dentro de un bean @ApplicationScoped

@Stateful
@Named
@ApplicationScoped
public class ProductorIdentitySessionFactory {
private IdentitySessionFactory laFactoría;
@PostConstruct
public void init(){
laFactoría = new IdentityConfigurationImpl().configure("idm-config.xml").buildIdentitySessionFactory();
}
}

¿Por qué @ApplicationScoped? Para que lo lea una sola vez al iniciar la aplicación (o reiniciar) y quienes lo necesiten inyecten esta única configuración. No uso @Singleton porque éste scope es de EJB y no de CDI, por lo que no se hace un proxy a él sino una referencia directa. Ésto puede traer problemas, por ej. si lo inyectamos dentro de beans serializables, los cuales lo podrían duplicar al pasivarse, y toda esa manga de cosas raras. Tampoco es necesario que sea @Startup ya que igual se instanciará para el primer login.

Ahora, la duda que me queda es cuál debiera ser el scope de una IndentitySessionImpl. Si es solamante una interfaz para autentificar, podría también bastar uno por aplicación, en ese caso podría instanciarlo desde el mismo @PostConstruct de arriba y anotar el campo con @Produces.

Sin embargo, si nos fijamos en el productor de Seam >> que, de alguna manera, estamos sobrescribiendo – vemos que se instancia a cada vez desde el getter y que se le da @RequestScoped para que sea inmediatamente destruído, así es que imitaremos este comportamiento.
En el mismo bean :

@Produces
@RequestScoped
@MiIdentitySession
public IdentitySession getIdentitySession(){
try {
return laFactoría.createIdentitySession("realm://EjemploRealm");
}
catch (IdentityException e) {
e.printStackTrace();
return null;
}
}

Como se puede observar, se hace necesario usar un Qualifier para distinguirlo del IdentitySession de Seam – que es el que debiéramos haber podido configurar – el cual se define así

@Target({TYPE,FIELD,METHOD,PARAMETER})
@Retention(RUNTIME)
@Qualifier
public @interface MiIdentitySession {
}

Así, finalmente, lo podemos inyectar en nuestro autenticador con un clásico

@Inject @MiIdenitySession private IdentitySession identiySession;

y loguearnos

User user = this.identitySession.getPersistenceManager().findUser(userName);
this.identitySession.getAttributesManager().validatePassword(user, pass);

Con ésto, si bien la duda de configuración de Seam Security para LDAP no está totalmente resulta a mi juicio, por lo menos tenemos una simulación que debiera ser más o menos equivalente en términos de eficiencia.

De todos modos abrí un thread en el foro >> a ver si hay una mejor manera de hacerlo. Veamos si tiene respuesta.

Este sitio utiliza cookies.    Leer más