amitection
amitection

Reputation: 2943

Manipulate InputStream of ContainerRequestFilter

I have a encrypted string being sent by a client. I am trying to intercept the string using ContainerRequestFilter then decrypt it and set the InputStream again so that it can be used by Jackson to map to a POJO.

Illustration:

My Resource

@Path("auth")
public class AuthResource {

@POST
public Response testResource(@Auth AuthUser auth, Person person) {

    System.out.println("Recieved Resource:: "+ new Gson().toJson(person));

    return null;
    }
}

Person.java

public class Person {

    private String name;
    private int age;

    public Person() {};

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

My Filter

@Provider
public class MyFilter implements ContainerRequestFilter {

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException {

        InputStream inputStream = requestContext.getEntityStream();

        StringWriter writer = new StringWriter();
        IOUtils.copy(inputStream, writer, "UTF-8");
        String theString = writer.toString();

        String decryptedMessage = "";
        try {
            decryptedMessage = JwtToken.decryptPayload(theString);
            System.err.println("Decrypted Message: "+decryptedMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }

        InputStream stream = new ByteArrayInputStream(decryptedMessage.getBytes(StandardCharsets.UTF_8));
        requestContext.setEntityStream(stream);
    }

}

I understand that once the InputStream is utilized it cannot be used again. But using requestContext.setEntityStream(stream); I am trying to set the InputStream again to be utilized by Jackson.

Inspite of that I am still unable to get the person object in my resource. The decryption is working fine as I have tested it using a debugger.

I get the following error: 415: Unsupported Media Type


Edit 1: I am using Adavanced Rest Client to hit the url

http://localhost:8080/auth

Header:

authorization: Basic ZXlKaGRYUm9iM0pwZW1GMGFXOXVJam9pWVcxcGRDSXNJbUZzWnlJNklraFRNalUySW4wLmUzMC5MLUtmOUxQNjFSQ21Bektob2lTR0V4bEJ3RXRUMXhrR3A3bUpIZmFSeV9FOnBhc3M=

Raw Payload:

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g

The payload is encrypted simply using JWT:

Jwts.builder().setPayload(new Gson().toJson(new  Person("Amit",22))).signWith(SignatureAlgorithm.HS256, key).compact();

Upvotes: 0

Views: 1024

Answers (2)

cassiomolin
cassiomolin

Reputation: 130977

Your request payload is not a JSON. It's a JWT token which contains a JSON encoded as Base64. It's a piece of text. Hence, the Content-Type of the request should be text/plain instead of application/json:

POST /api/auth HTTP/1.1
Host: example.org
Content-Type: text/plain

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g

Your filter modifies the payload of the request: the filter gets the JWT token from the request payload, gets the token payload, decodes the token payload into a JSON string and sets the JSON string to the request payload.

After the executing of the filter, the request will contain a JSON string and not just a piece of text. Hence, after that, the Content-Type of the request should be modified to application/json. It could be achieved with the following lines:

requestContext.getHeaders().remove(HttpHeaders.CONTENT_TYPE);
requestContext.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);

To ensure the filter will be executed before the resource matching, annotate your filter with @PreMatching.

And don't forget to annotate your resource method with @Consumes(MediaType.APPLICATION_JSON).

Upvotes: 3

amitection
amitection

Reputation: 2943

I tried changing the payload to a JSON document as:

"temp":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQW1pdCIsImFnZSI6MjJ9.-rO6yhYJ--3ZzVCaHFw1hF-s533foYY6vVAuyRh3Q9g"

and extracted the encrypted payload using the below code in my filter:

JsonObject jsonObject = new Gson().fromJson(theString, JsonObject.class);
        theString = jsonObject.get("temp").getAsString();

Also changed the resource to @Consumes(MediaType.APPLICATION_JSON)

And it worked!

I guess the reason was as mentioned by pandaadb that Jersey was unable to recognize it as a JSON document and hence was unable to Map it to the Person POJO.

Upvotes: 0

Related Questions