2012-05-11 20 views
8

Pasé todo el día buscando en Google y mirando varias preguntas aquí, tratando de encontrar la mejor solución para implementar autenticación y autorización. He encontrado una parte de la solución ahora, pero espero que alguien pueda llenar los vacíos. Soy consciente de que hay una gran cantidad de texto a continuación, pero por favor tengan paciencia conmigo: O)JSF: Autenticación y autorización, la mejor forma de hacerlo

Antecedentes

He heredado una parte completada la aplicación CRM que actualmente utiliza JSF 2.0, JavaEE 6, JPA y PostgreSQL base de datos. Desafortunadamente, los tipos que originalmente comenzaron a construir esta aplicación web en su sabiduría infinita decidieron que sería mejor dejar la autenticación/autorización hasta el final. Ahora tengo que ponerlo.

La aplicación se divide esencialmente en tres capas: las vistas, los beans gestionados y los DAO. Esto significa que los beans administrados son particularmente "gordos" ya que contienen toda la lógica de lógica de negocios, validación y navegación.

requisitos de autenticación/autorización

  1. autenticación basada en formularios, validando contra credenciales almacenadas en la base de datos PostgreSQL.
  2. La única página que será públicamente accesible (por usuarios anónimos) será la página de inicio de sesión.
  3. Necesito evitar el acceso a ciertas áreas de la aplicación en función del rol de los usuarios. Por ejemplo, solo los usuarios con la función 'Admin' deberían poder acceder a la página de creación/edición del usuario.
  4. También necesito poder restringir el acceso a ciertas áreas de una página. Por ejemplo, un usuario con el rol 'Representante de ventas' debería poder ver los detalles de un cliente, pero el botón Guardar/editar solo debería mostrarse si el usuario tiene el rol 'Servicio al cliente'.

¿Dónde estoy en

La primera cosa que planeo hacer es seguir este ejemplo User Authentication and Authorization using JAAS and Servlet 3.0 Login. Esto creo que cumplirá mis primeros 3 requisitos.

Para mostrar/ocultar los botones de guardar, etc. en las páginas, puedo usar la técnica descrita en this SO answer. Esto resolverá en parte el requisito 4, sin embargo, creo que todavía necesito asegurar los métodos de acción yo los beans administrados. Por ejemplo, me gustaría poder agregar una anotación o algo al método save() en el bean del cliente para asegurar que solo los usuarios con el rol de 'Servicio al cliente' puedan llamarlo, aquí es donde empiezo a tener problemas .

Supongo que una opción sería hacer algo similar a lo que propongo hacer en la vista y usar facesContext para verificar si el usuario actual "está en función". No estoy interesado en esto, ya que solo complicará mi código y preferiría usar anotaciones en su lugar. Si hiciera esta ruta, ¿cómo devolvería un estado http 403?

Las anotaciones javax.annotation.security. * Parecen ser una buena opción para definir declaritivamente el acceso a las áreas de la aplicación, pero, por lo que tengo entendido, solo se pueden agregar a las EJB. Esto significaría que tendría que mover toda mi lógica comercial de los beans administrados donde reside actualmente a los nuevos EJB. Creo que esto tendría el beneficio adicional de separar la lógica comercial en su propio conjunto de clases (delegados, servicios o lo que sea que elija llamarlos).Sin embargo, este sería un refactor bastante grande que no se verá favorecido por la falta de pruebas unitarias o pruebas de integración. No estoy seguro de si la responsabilidad del control de acceso debe ser en este nuevo nivel de servicio tampoco, creo que debería estar en los beans administrados.

Otras alternativas

Durante mi investigación he encontrado mucha gente que citan marcos como la primavera y de la costura. Tengo una experiencia limitada con Seam, creo que hubiera sido una buena opción para este proyecto y, por lo que recuerdo, creo que resuelve los problemas de autorización que estoy teniendo, pero creo que es demasiado tarde para presentarlo ahora. .

También he visto a Shiro mencionar en varios lugares. Después de mirar el 10 minute tutorial, me pareció una buena opción, especialmente en combinación con Deluan Quintao's taglib, pero no he podido encontrar tutoriales ni ejemplos de cómo integrarlo con una aplicación web JSF.

La otra alternativa con la que me he encontrado sorprendentemente habitual es la implementación de una solución personalizada: ¡esto me parece una locura!

Resumen

En resumen, realmente me gustaría alguna orientación acerca de si yo estoy dirigiendo por el camino correcto en cuanto a la implementación de la autenticación y la autorización y cómo rellenar la pieza que falta del individuo asegurar métodos y/o beans gestionados (o al menos el código que delegar a) y/o la forma en que puede volver manualmente un estado HTTP 403.

+1

> No he podido encontrar ningún tutorial o ejemplos de cómo integrarlo con una aplicación web JSF. - Hay uno ahora, pero aún no es ideal: http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html –

Respuesta

3

Después de llevar a cabo una gran cantidad de investigaciones, llegué a la conclusión de que, en primer lugar, los requisitos de mi aplicación se beneficiarían al implementarlos en un servidor de aplicaciones que implemente completamente la especificación Java EE, en lugar de un contenedor de servlets como Tomcat. Como el proyecto en el que estoy trabajando utiliza Maven, la clave aquí fue configurar las dependencias configuradas correctamente: esto no fue fácil y requirió un poco de búsqueda en Google y prueba y error: estoy seguro de que hay un enfoque más científico que podría ser tomado.

Luego tuve que llamar a create a mysql module para hablar correctamente con la base de datos y luego eliminar la fábrica que se había implementado para crear DAO y convertirlos a EJB. También tuve que actualizar hibernate.cfg.xml para hacer referencia al origen de datos que agregué y persistence.xml para establecer el tipo de transacción en JTA y también hacer referencia al origen de datos de JTA. La única otra complicación era que se estaba utilizando el patrón Abrir sesión en vista, lo que significaba que terminé con errores de inicialización de hibernación cuando se accedía a las entidades en las vistas. Reimplementé el filtro como se muestra en la parte inferior de esta respuesta, para evitar esto. Veo esto como una medida temporal para hacer que las cosas funcionen nuevamente antes de poder refactorizar esta área y eliminar la necesidad del filtro.

Pasar a JBoss tomó poco más de un día y estoy seguro de que podría haberse hecho mucho más rápido si tuviera más experiencia con Java EE y Maven. Ahora que estoy en ese punto, estoy en una buena posición para poder incluir la seguridad de seam 3 en el proyecto y utilizar eso, en lugar de tratar de hackear juntos una solución que es esencialmente la dirección que iba a tomar. Lo bueno de Seam 3 es que, hasta cierto punto, puedes elegir qué módulos usar en lugar de tener que agregar todo el framework (como Seam 2). Creo que algunos de los otros módulos también serán útiles y me ayudarán, entre otras cosas, a eliminar la sesión abierta en el patrón de vista.

Una cosa que me preocupó con el uso de Seam fue que me dijeron acerca de DeltaSpike. Esto parece como si probablemente reemplazaría la costura y no hay planes para más versiones de costura. He decidido que, dado que la costura todavía es compatible y si DeltaSpike tarda tanto en llegar a buen término como la costura 3, entonces es bastante seguro usar la costura 3.

Espero poder escribir una publicación de blog adecuada que describa esta migración en el detalle apropiado.

public class OSVRequestFilter implements Filter { 

    private static final String UserTransaction = "java:comp/UserTransaction"; 

    private static Logger logger = LoggerFactory.getLogger(EntityManagerRequestFilter.class); 

    public void init(FilterConfig config) throws ServletException { 
    } 

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     if (request instanceof HttpServletRequest) { 
      doFilter(request, response, chain, getUserTransaction()); 
     } 
    } 

    private UserTransaction getUserTransaction() throws ServletException { 
     try { 
      Context ctx = new InitialContext(); 
      return (UserTransaction)PortableRemoteObject.narrow(ctx.lookup(UserTransaction), UserTransaction.class); 
     } 
     catch (NamingException ex) { 
      logger.error("Failed to get " + UserTransaction, ex); 
      throw new ServletException(ex); 
     } 
    } 

    private void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, UserTransaction utx) throws IOException, ServletException { 
     try { 
      utx.begin(); 

      chain.doFilter(request, response); 

      if (utx.getStatus() == Status.STATUS_ACTIVE) 
       utx.commit(); 
      else 
       utx.rollback(); 
     } 
     catch (ServletException ex) { 
      onError(utx); 
      throw ex; 
     } 
     catch (IOException ex) { 
      onError(utx); 
      throw ex; 
     } 
     catch (RuntimeException ex) { 
      onError(utx); 
      throw ex; 
     } 
     catch (Throwable ex){ 
      onError(utx); 
      throw new ServletException(ex); 
     } 
    } 

    private void onError(UserTransaction utx) throws IOException, ServletException { 
     try { 
      if ((utx != null) && (utx.getStatus() == Status.STATUS_ACTIVE)) 
       utx.rollback(); 
     } 
     catch (Throwable e1) { 
      logger.error("Cannot rollback transaction", e1); 
     } 
    } 

    public void destroy() { 
    } 
} 
2

¿Ha probado nada con Spring Security - Últimas ser la versión 3

http://janistoolbox.typepad.com/blog/2010/03/j2ee-security-java-serverfaces-jsf-spring-security.html

http://ocpsoft.org/java/jsf-java/spring-security-what-happens-after-you-log-in/

en lugar de utilizar un filtro de solicitud o el uso de JAAS, la seguridad de primavera es un marco de seguridad integral que va a resolver la mayoría de sus problemas de seguridad. Puede usarlo para autenticar a un usuario utilizando un dominio db, autorizarlo y redireccionar según sea necesario en función de la información de autenticación proporcionada.

se puede asegurar con métodos que ha escrito http://blog.solidcraft.eu/2011/03/spring-security-by-example-securing.html

@PreAuthorize ("hasRole ('ROLE_XXX')") es la forma

para hacer que ciertos elementos de una página segura .. // contenido

más lectura y ejemplos http://static.springsource.org/spring-security/site/petclinic-tutorial.html

+0

Gracias por su respuesta. Estoy tomando su consejo pero con un giro ligero, voy a usar seguridad de costura en su lugar: O) – s1mm0t

Cuestiones relacionadas