2015-11-18 9 views
5

Sulla base di questo Jaspic Example ho scritto il validateRequest seguente metodo per un ServerAuthModule:JASPIC wildfly 9 validateRequest con sessione

public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, 
     Subject serviceSubject) throws AuthException { 

    boolean authenticated = false; 
    final HttpServletRequest request = 
         (HttpServletRequest) messageInfo.getRequestMessage(); 
    final String token = request.getParameter("token"); 
    TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal(); 

    Callback[] callbacks = new Callback[] { 
      new CallerPrincipalCallback(clientSubject, (TokenPrincipal) null) }; 

    if (principal != null) { 
     callbacks = new Callback[] { 
       new CallerPrincipalCallback(clientSubject, principal) }; 
     authenticated = true; 
    } else { 
     if (token != null && token.length() == Constants.tokenLength) { 
      try { 
       principal = fetchUser(token); 
      } catch (final Exception e) { 
       throw (AuthException) new AuthException().initCause(e); 
      } 
      callbacks = new Callback[] 
         { 
          new CallerPrincipalCallback(clientSubject, principal), 
          new GroupPrincipalCallback(clientSubject, 
                 new String[] { "aRole" }) 
         }; 
      messageInfo.getMap().put("javax.servlet.http.registerSession", "TRUE"); 
      authenticated = true; 
     } 
    } 

    if (authenticated) { 
     try { 
      handler.handle(callbacks); 
     } catch (final Exception e) { 
      throw (AuthException) new AuthException().initCause(e); 
     } 
     return SUCCESS; 
    } 

    return AuthStatus.SEND_FAILURE; 
} 

Questo funziona come previsto, per la prima chiamata di un EJB con @RolesAllowed("aRole") ma per la successiva chiamata questo non funziona affatto Wildfly nega con questo messaggio di errore:

ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation 
    failed on component TestEJB for method public java.lang.String 
    com.jaspic.security.TestEJB.getPrincipalName(): 
    javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User 

Se immagino destra, l'errore occures in: org.jboss.as.security.service.SimpleSecurityManagerline 367 del codice sorgente di wilfly, a causa di line 405, in cui credential è selezionata, ma sembra essere null.

Questo sembra uguale in Wildfly 8/9/10CR (altre versioni non testate).

Ancora una volta non sono sicuro, se sto sbagliando, o se questo è lo stesso bug di https://issues.jboss.org/browse/WFLY-4626? E 'un bug o è un comportamento previsto?

risposta

7

Questo suona anche come un errore, poiché l'identità del chiamante (chiamante/gruppo Principal s) sembra essere mantenuta nelle successive chiamate al web, ma non nel contenitore EJB. Le mie classi JASPIC (che funzionano correttamente su GlassFish 4.1) non riescono per lo stesso motivo su WildFly 9.0.2.Final e 10.0.0.CR4 se usate insieme a un servlet semplice e un SLSB, anche se quest'ultimo è contrassegnato con @PermitAll.

Dato che non sono a mia conoscenza con gli interni di sicurezza WildFly, non posso aiutarti in questo senso. A meno che non sia possibile ottenere questa patch, l'unica soluzione a livello SAM a cui posso pensare per il momento è non utilizzare la proprietà di callback javax.servlet.http.registerSession che sembra attivare il problema, ma invece il CallbackHandler registrare il chiamante Principale i suoi gruppi su ogni chiamata validateRequest(...). Se applicabile al tuo caso d'uso, potresti voler allegare tali informazioni allo HttpSession in modo da velocizzare un po 'il processo; altrimenti ripeti da zero. Così, ad esempio:

public class Sam implements ServerAuthModule { 

    // ... 

    @Override 
    public AuthStatus validateRequest(MessageInfo mi, Subject client, Subject service) throws AuthException { 
     boolean authenticated = false; 
     boolean attachAuthnInfoToSession = false; 
     final String callerSessionKey = "authn.caller"; 
     final String groupsSessionKey = "authn.groups"; 
     final HttpServletRequest req = (HttpServletRequest) mi.getRequestMessage(); 
     TokenPrincipal tp = null; 
     String[] groups = null; 
     String token = null; 
     HttpSession hs = req.getSession(false); 
     if (hs != null) { 
      tp = (TokenPrincipal) hs.getAttribute(callerSessionKey); 
      groups = (String[]) hs.getAttribute(groupsSessionKey); 
     } 
     Callback[] callbacks = null; 
     if (tp != null) { 
      callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) }; 
      authenticated = true; 
     } 
     else if (isValid(token = req.getParameter("token"))) { 
      tp = newTokenPrincipal(token); 
      groups = fetchGroups(tp); 
      callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) }; 
      authenticated = true; 
      attachAuthnInfoToSession = true; 
     } 
     if (authenticated) { 
      try { 
       handler.handle(callbacks); 
       if (attachAuthnInfoToSession && ((hs = req.getSession(false)) != null)) { 
        hs.setAttribute(callerSessionKey, tp); 
        hs.setAttribute(groupsSessionKey, groups); 
       } 
      } 
      catch (IOException | UnsupportedCallbackException e) { 
       throw (AuthException) new AuthException().initCause(e); 
      } 
      return AuthStatus.SUCCESS; 
     } 
     return AuthStatus.SEND_FAILURE; 
    } 

    // ... 

    @Override 
    public void cleanSubject(MessageInfo mi, Subject subject) throws AuthException { 
     // ... 
     // just to be safe 
     HttpSession hs = ((HttpServletRequest) mi.getRequestMessage()).getSession(false); 
     if (hs != null) { 
      hs.invalidate(); 
     } 
    } 

    private boolean isValid(String token) { 
     // whatever 
     return ((token != null) && (token.length() == 10)); 
    } 

    private TokenPrincipal newTokenPrincipal(String token) { 
     // whatever 
     return new TokenPrincipal(token); 
    } 

    private String[] fetchGroups(TokenPrincipal tp) { 
     // whatever 
     return new String[] { "aRole" }; 
    } 

} 

Ho testato il sopra sulle suddette versioni wildfly e nel modo suddetto (cioè con un solo Servlet riferimento a un singolo SLSB contrassegnato @DeclareRoles/metodo livello @RolesAllowed) e sembra funzionare come previsto. Ovviamente non posso garantire che questo approccio non fallirà in altri modi inaspettati.


Consulta anche:

+0

ho provato questa soluzione, ma 'tp = (TokenPrincipal) hs.getAttribute (callerSessionKey);' non restituisce qualcosa di diverso 'null' sembra che Wildfly 9.0.02 non abbia mai la stessa sessione nel mio esempio. – knoe

+1

Domanda sciocca ma solo per essere sicuro - stai creando una sessione da qualche parte, giusto? Siccome non ero sicuro che l'utilizzo della sessione HTTP sarebbe stato un'opzione per te (potresti aver voluto rimanere completamente stateless, HTTP session-wise), l'esempio sopra non lo è, e allega solo il chiamante e i suoi ruoli se lì è già una sessione attiva.Se crei una sessione altrove e il SAM non è ancora in grado di recuperare le informazioni, fammelo sapere e lo ripeterò domani. Altrimenti sull'autenticazione iniziale all'interno del SAM, 'req.getSession (false)' dovrà diventare 'req.getSession()'. – Uux

+2

Non ha funzionato per me, perché nella crittografia 'web.xml'ssl è stata applicata, ma non presente. Grazie! La tua risposta è la soluzione che userò. – knoe

Problemi correlati