2014-07-23 3 views
2

J'ai un petit filtre pour authentifier les demandes avec une approche HMAC vraiment basique.ContainerRequestFilter provoque NPE dans la méthode de service JAX-RS

Tout fonctionnait bien tant qu'il n'y avait pas de charge utile réelle.

Maintenant, quand il y a une charge utile non vide, l'authentification elle-même fonctionne mais le service REST qui est responsable de la requête ne recevra rien. Voici la méthode du filtre:

public void filter(ContainerRequestContext context) 
      throws IOException { 

     // perform check on responsible service - look for @PermitAll and so on 
     if (isAuthenticationRequired(context) == false) { 
      return; 
     } 


     String callerKey = context.getHeaderString("callerKey"); 

     if (callerKey == null) { 
      context.abortWith(Response. 
        status(Response.Status.UNAUTHORIZED) 
        .build()); 
     } 

     UriInfo uriInfo = context.getUriInfo();    
     String absPath = uriInfo.getAbsolutePath().toString(); 

     String checksum = context.getHeaderString("checksum"); 

     // As this is the only action related to the request's entity (payload) 
     // I already played around with it a while. This is a readonly operation, isn't 
     // it?! The stream must not be closed. 
     InputStream entityStream = context.getEntityStream(); 
     Scanner scanner = new Scanner(entityStream).useDelimiter("\\A"); 
     String entity = (scanner.hasNext()) ? scanner.next() : ""; 

     // Collect parameters for underlying business bean that performs the check. 
     RequestAuthenticationOrder order; 
     order = new RequestAuthenticationOrderBuilder() 
       .absolutePath(absPath) 
       .completeEntity(entity) 
       .checksum(checksum) 
       .callerlKey(callerKey) 
       .build(); 
     try { 
      // basically checks if checksum is correct and if that's true make 
      // corresponding user available to the REST-service 
      context.setProperty("authenticatedUser", 
        identificationService.authenticateRequest(order)); 

     } catch (AuthenticationException aux) { 
      Logger.getLogger(AuthenticationFilter.class.getName()).log(Level.SEVERE, null, aux); 
     } 
    } 

Ce ne méthode de service d'argument fonctionne:

@Path("/protected") 
public class ProtectedController extends AbstractResourceController { 

    @GET 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response protect() { 
     // callingUser is the result of the previous filtering. It's defined in 
     // superclass AbstractResourceController 
     return Response.accepted(new ProtectedResponse((callingUser != null) 
       ? callingUser.getNickname() 
       : "no user authenticated?")).build(); 
    } 
} 

Celui-ci ne recevra pas rien:

@Path("/logout") 
public class LogoutController extends AbstractResourceController{ 
    @POST @Consumes(MediaType.APPLICATION_JSON) 
    public void logout (LogoutRequest request) { 
     request.getFoo(); // NPE  
    } 
} 

Notez que les paramètres sont JAXB- simples pojos annotés. Pour une raison quelconque, rien ne se passe ici.

Tout fonctionne sur Wildfly 8 et j'utilise les bibliothèques du serveur (Resteasy, jackson, etc.).

J'espère que vous pouvez me donner un indice ... Merci!

Répondre

1

L'inputStream de ContainerRequestContext nécessaire pour récupérer l'entité complète est consommé dans le filtre. Chaque composant suivant n'obtiendra rien du flux.

Il existe plusieurs solutions possibles. J'ai décidé d'introduire un tampon:

// ... 
InputStream entityStream = new BufferedInputStream(context.getEntityStream()); 
entityStream.mark(1000); // Hmn, what would be a proper limit...Further investigation 
Scanner scanner = new Scanner(entityStream).useDelimiter("\\A"); 
String entity = (scanner.hasNext()) ? scanner.next() : ""; 
entityStream.reset(); 
context.setEntityStream(entityStream); 
// .... 

Je ne sais pas s'il y a de meilleures façons de résoudre cela ... Celui-ci fonctionne.

2

Commentaire précédent est juste, mais l'utilisation sera mieux

ContainerRequest context = (ContainerRequest) containerRequestContext; 
context.bufferEntity(); 
String entity = context.readEntity(String.class); 

parce flux sera fermé et jackson ne sera pas obtenir entité de flux sur point final. et avant de créer l'utilisation de flux jackson ObjectMapper sans que cela u ne peut pas obtenir entité sur endpoint utilisation simple Stream sérialisation native qui n'est pas applicable pour jackson

requestContext.setEntityStream(new ByteArrayInputStream(new ObjectMapper().writeValueAsBytes(entity))); 
+0

Ah, je vous remercie beaucoup de passer votre temps avec un vieux question! Comme je ne travaille pas dans ce domaine pour le moment, je ne peux pas tester votre solution. Par conséquent, je ne peux pas simplement l'accepter. J'espère que ça va pour vous! Au moins upvote! –

Questions connexes