ciclo - que es enterprise java beans
Concepto de sesión de inicio de sesión reutilizable en llamadas de rmi ejb (3)
Esta no es una pregunta simple, es solo porque estoy reconsiderando nuestra arquitectura para asegurar nuestro servicio EJB 3.0 mediante un inicio de sesión y seguridad.
Tenemos una aplicación EJB3.0 en JBoss 5.1 que ofrece varios servicios a un cliente SWT para leer y escribir datos. Para usar un servicio, el cliente debe iniciar sesión con un usuario y contraseña válidos que SpringSecurity busca en un servidor LDAP. SpringSecurity genera una identificación de la sesión que se transfiere al cliente para que se resuene en cualquier otra llamada de servicio.
client server
| |
|-> login(user/password)-------->|
| |
| <------- sessionId ------------|
| |
|-->serviceXy(sessionId,param1)->|
La situación parece clara. Almacenamos sessionId en nuestro propio objeto de contexto que es el primer parámetro de cada método de servicio. Hay un interceptor en cada método de servicio que lee el sessionId del objeto de contexto dado y verifica si la sesión todavía es válida. El cliente necesita llamar primero al servicio de inicio de sesión para obtener un objeto de contexto rellenado con el ID de sesión y reutilizar este objeto de contexto en otras llamadas de servicio.
public class OurContext {
private String sessionId;
}
@Stateless
@Interceptors(SecurityInterceptor.class)
public OurServiceImpl implements OurService {
public void doSomething(OurContext context, String param1) {
[...]
}
}
Lo que no me gusta de esta solución es la contaminación de cada método de servicio con el parámetro de contexto. ¿No hay un mecanismo similar como una sesión http en llamadas de rmi? Estoy pensando en poner nuestro objeto de contexto en algún tipo de sesión que se crea en el cliente (?) Justo después del inicio de sesión y se pasa al servidor en cada llamada de servicio para que el SecurityInterceptor pueda leer el sessionId desde este "contexto mágico". ".
Algo como esto:
OurContext ctx = service.login("user","password");
Magical(Jboss)Session.put("securContext", ctx);
service.doSomething("just the string param");
Dado que ya está utilizando un servidor de aplicaciones, parece que debería utilizar los mecanismos de seguridad incorporados de EJB, generalmente provistos a través de JAAS. En la línea 4.x jboss, si implementó su propio complemento JAAS para jboss, podría obtener acceso a un mapa de contexto "especial" (similar a lo que describe) que se transfiere a las solicitudes remotas (mediante el marco de invocación remota de jboss ) No he usado jboss por un tiempo, así que no estoy seguro de cómo se correlaciona con el producto 5.1, pero tengo que imaginar que tiene instalaciones similares. Esto supone, por supuesto, que está dispuesto a implementar algo específico de jboss.
Hay algunos tipos de mecanismos de sesión en EJB, pero todos comienzan cuando se inicia la llamada remota, y finaliza cuando eso termina. En el viejo es el contexto de la transacción (Adam Bien escribió sobre esto hace algún tiempo), y uno más nuevo el Alcance de la sesión del CDI.
Contrariamente a lo que se cree, este alcance no solo refleja el alcance de la sesión http, sino que, en ausencia de una sesión http (como las llamadas remotas), representa una sola cadena de llamadas o entrega de mensajes (para mdbs).
Con una sesión de este tipo, su cliente SWT remoto todavía tiene que pasar el sessionId al servicio remoto, pero los beans locales llamados desde allí pueden recogerlo de esta sesión "cdi".
La otra opción es algo así como lo que dice jtahlborn: con su propio módulo de inicio de sesión puede devolver un principal personalizado, en lugar del predeterminado. Su código puede primero solicitar el principal normal y luego tratar de lanzarlo.
El problema es que esto es específico del contenedor y JBoss siempre se olvida de él. Más o menos se rompe después de cada actualización, y los usuarios tienen que patear y gritar para arreglarlo en alguna próxima versión (solo para verla romper nuevamente en la versión después de eso). Sin JBoss realmente apoyando esto, es una batalla interminable.
Otra opción más es permitir que el usuario inicie sesión con el ID de sesión como nombre. El módulo de inicio de sesión que se encuentra detrás podría ser un módulo simple que acepte todo y simplemente ponga un principal en el contexto de seguridad con sessionId como ''nombre''. Es un poco extraño, pero lo hemos usado con éxito para obtener cualquier dato que pueda ser expresado por una cadena en el contexto de seguridad. Por supuesto, tendría que permitir que su cliente haga una autenticación regular de contenedor aquí, lo que en cierto modo frustra el uso de la seguridad de Spring en primer lugar.
Optamos por otro enfoque que sea portátil y no dependa de un servidor de aplicaciones específico. Además, nuestra implementación de seguridad nos libera de las restricciones del enfoque EJB (que, por cierto, pensé que se habían cerrado hace dos décadas ... pero surgió de nuevo).
Mirando de arriba hacia abajo:
Hay un servidor que proporciona clases con métodos para trabajar con los mismos datos. Los clientes proporcionan los datos e invocan métodos específicos.
Nuestro enfoque es poner todos los datos (y por lo tanto la comunicación entre el cliente y el servidor) en un "Objeto comercial". Cada BO extiende una superclase. Esta superclase contiene una identificación de sesión. El método de inicio de sesión proporciona y devuelve esa identificación. Cada cliente solo tiene que asegurarse de copiar el ID recibido en un BO en el siguiente que envía al servidor. Cada método que se puede invocar de forma remota (o local), primero obtiene el objeto de sesión con el ID recibido. El método para devolver el objeto de sesión también verifica las restricciones de seguridad (que se basan en permisos y no en roles como en el enfoque EKB).