What could cause a header to be set to null as a result of getting it from the exchange?
My current workaround is to set the header again after reading but this is terribly hacky.
Example:
String header = exchange.getIn().getHeader("headerKey", String.class);
String theSameHeader = exchange.getIn().getHeader("headerKey", String.class);
System.out.printf("header is %s.\n", (header == null) ? "null" : "not null");
System.out.printf("theSameHeader is %s.\n", (theSameHeader == null) ? "null" : "not null");
Output:
header is not null.
theSameHeader is null.
Are you header a String type, it does however smell as if the header type is streaming based, and then you end up as what is described in this FAQ:
http://camel.apache.org/why-is-my-message-body-empty.html
Related
I am wondering if anyone knows best practices for handling Plaid webhooks with Java Springboot?
Does the Plaid SDK offer any easy way to convert the webhook request object to a model object for the given event type? I only see they have Node Express examples which seems to only deconstruct the JSON request object by key.
Also wondering if their is anyway to verify the incoming webhook request is actually from Plaid
#PostMapping(value = "/webhook/plaid", produces =
MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity plaidWebhook(#RequestBody String payload) {
JSONParser parser = new JSONParser(payload);
JSONObject plaidWebhookRequest = null;
try {
plaidWebhookRequest = (JSONObject) parser.parse();
String webhookType = plaidWebhookRequest.has("webhook_type") ? (String) plaidWebhookRequest.get("webhook_type") : null;
String webhookCode = plaidWebhookRequest.has("webhook_code") ? (String) plaidWebhookRequest.get("webhook_code") : null;
String error = plaidWebhookRequest.has("error") ? (String) plaidWebhookRequest.get("error") : null;
String itemID = plaidWebhookRequest.has("item_id") ? (String) plaidWebhookRequest.get("item_id") : null;
if (webhookType != null && webhookCode != null && webhookType.equals(WebhookType.ITEM.name())) {
switch (webhookCode) {
case ERROR_WEBCODE:
log.info("Plaid webhook received: " + ERROR_WEBCODE);
break;
case PENDING_EXPIRATION:
log.info("Plaid webhook received: " + PENDING_EXPIRATION);
break;
case USER_PERMISSION_REVOKED:
log.info("Plaid webhook received: " + USER_PERMISSION_REVOKED);
break;
}
}
} catch (ParseException e) {
log.debug("Plaid webhook object failed to convert to JSONObject");
}
return ResponseEntity.status(HttpStatus.OK).body("");
}
I am not a Java expert but I can speak to some of the other parts of your question:
You can use the webhook verification endpoint to verify that the webhook is from Plaid: https://plaid.com/docs/api/webhooks/webhook-verification/ although I will admit the process is not as easy as most of the other things you can do with the Plaid API.
As an alternative option -- for a situation like this, you can always check the Item status by calling /item/get to confirm that the Item needs to be updated before sending the user through update mode. As a rule, Plaid doesn't ever send sensitive information in webhooks, and information in webhooks can be verified by calling endpoints that are free to call, so you should never need to "trust" a Plaid webhook without verifying it if you don't want to. This is generally smart to do anyway, for example: even if you got a webhook indicating that the Item is in an error state, the user may have resolved it or it may have self-healed in the interim.
I got a java.lang.AssertionError when I was attempting to verify the href. The response body looks fine,
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {"itemName":"ThinkPad","links":[{"rel":"self","href":"http://localhost/items/001"}]}
Forwarded URL = null
Redirected URL = null
Cookies = []
but when called this sentence: andExpect(jsonPath("$.links[0].href", hasItem(endsWith("/items/001"))))
The error occured:
java.lang.AssertionError: JSON path "$.links[0].href"
Expected: a collection containing ""
but: was "http://localhost/items/001"
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:74)
at org.springframework.test.web.servlet.result.JsonPathResultMatchers$1.match(JsonPathResultMatchers.java:86)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at scnz.api.controller.ItemDispatchControllerTest.getCurrentStock(ItemDispatchControllerTest.java:62)
Here is the test code:
#Test
public void getCurrentStock() throws Exception {
Item item = new Item("001", "ThinkPad");
when(service.retrieve("001")).thenReturn(item);
mockMvc.perform(get("/items/001"))
.andDo(print())
.andExpect(jsonPath("$.itemName", is(item.getItemName())))
.andExpect(jsonPath("$.links[0].href", hasItem(endsWith("/items/001"))))
.andExpect(status().isOk());
Can anyone figure out where is wrong?
The actual result of jsonPath(...) for "$.links[0].href" is just a String as stated in the AssertionError.
The expected result for hasItem(...) is a collection as stated in the AssertionError.
In your case therefore just use endsWith(...) withouch hasItem(...). If your expression for jsonPath(...) returns a collection (e.g. via "$.links[*].href") instead of a single item you should use hasItem(...).
If we try to parse an expired JWT, results in expired exception.
Is there a way to read claims even the JWT was expired.
Below is used to parse JWT in java:
Jwts.parser().setSigningKey(secret.getBytes()).parseClaimsJws(token).getBody();
There is a better approach to do this.
if you see JWT Exception handler object e.g. ExpiredJwtException, expection object itself contains the following:-
header, claims and message
so claims can easily extracted through this object i.e. e.getClaims().getId() where e is ExpiredJwtException object.
ExpiredJwtException consturct is as follow:-
public ExpiredJwtException(Header header, Claims claims, String message) {
super(header, claims, message);
}
Example:-
try{
// executable code
}catch(ExpiredJwtException e){
System.out.println("token expired for id : " + e.getClaims().getId());
}
JWT objects are Base64URL encoded. This means that you can always read headers and payload by manually Base64URL-decoding it. In this case you will simply ignore exp attribute.
For instance you can do like this (I'm using Java8 built-in Base64 class, but you can use any external library, such as Apache Commons Codec):
Base64.Decoder decoder = Base64.getUrlDecoder();
String src = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImV4cCI6IjEzMDA4MTkzODAifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.2GpoV9q_uguSg0Ku6peI5aZ2qBxO5qOA42zaS25gq_c";
String[] parts = src.split("\\."); // Splitting header, payload and signature
System.out.println("Headers: "+new String(decoder.decode(parts[0]))); // Header
System.out.println("Payload: "+new String(decoder.decode(parts[1]))); // Payload
and the output is:
Headers: {"alg":"HS256","typ":"JWT","exp":"1300819380"}
Payload: {"sub":"1234567890","name":"John Doe","admin":true}
Please note also that the exp attribute is set to 1300819380, which corresponds to 16 january 2016.
this might be old but for anyone whose facing this issue, the java's io.jsonwebtoken
ExpiredJwtException already got the claims in it, you can get it by calling e.getClaims().
If you use io.jsonwebtoken you try my function:
public Claims getClaimsFromToken(String token) {
try {
// Get Claims from valid token
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
} catch (ExpiredJwtException e) {
// Get Claims from expired token
return e.getClaims();
}
}
If Someone comes in looking for jose4j library then below works:
invalidJwtException.getJwtContext().getJwtClaims()
Just set the ValidateLifetime property of the TokenValidationParameters to false before calling ValidateToken.
TokenValidationParameters tokenValidationParameters = new TokenValidationParameters();
tokenValidationParameters.ValidateLifetime = false;
JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
Then you can read the claims like this:
string name = principal.Claims.FirstOrDefault(e => e.Type.Equals(ClaimTypes.Name)).Value;
string email = principal.Claims.FirstOrDefault(e => e.Type.Equals(ClaimTypes.Email)).Value;
<%String dest = request.getParameter("destination").toUpperCase();%>
Hello...
I got a little bit problem here. I am using the above code to get value from form. When use the code without toUpperCase(), it was a success. But, when I add toUpperCase() I got HTTP Status 500 - An exception occured processing JSP page.
When you get value null from request.getParameter("destination"), apply toUpperCase() to a null value gives an error.
Try to do like this:
<%String dest = request.getParameter("destination");
if(dest!=null){
dest = dest.toUpperCase();
}
%>
The request.getParameter() returns String value or a null value from client.
More than likely, request.getParameter("destination") is returning null in your code, which would be why it's throwing an error. If the parameter is not found, then null is returned, otherwise a String is returned.
So you'll want to verify that it's not null
<% String dest = request.getParameter("destination");
if(dest != null) {
dest = dest.toUpperCase();
}
%>
I am creating some nodes within a transaction in neo4j using the rest api. After all nodes have been created (typically between 3 and 5 in one transaction), I have to create some relationships between them. To do this I need, of course the location of the nodes, and this is the source of my problem. I can't figure out how to get this location.
According to documentation, I should be able to get the location of a node from the response-object, after creating the node, like so:
nodeLocation = response.getLocation();
But in a transaction, this of course returns the url of the transaction:
http://localhost:7474/db/data/transaction/108
Then I thought, if I query for the just created node, maybe in that response I can find the location. Again, according to documentation, the node location should be presented in the json-structure extensions in the field self.
"self" : "http://localhost:7474/db/data/node/357",
But my response to the query does not seem to contain an extension structure.
This is the query I'm using:
{"statements": [ {"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p"} ] }
I send it to the open transaction, and I get this back:
GET to http://localhost:7474/db/data/transaction/108 returned status code 200, returned data: {"commit":"http://localhost:7474/db/data/transaction/108/commit","results":[{"columns":["p"],"data":[]}],"transaction":{"expires":"Mon, 24 Nov 2014 20:40:34 +0000"},"errors":[]}
Just for completeness, this is the code for my query:
String payload = "{\"statements\": "
+ "[ "
+ "{\"statement\": "
+ "\"MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p\""
+ "} "
+ "] "
+ "}";
logger.trace("sending cypher {} to endpoint {}", payload, endpointLoc);
WebResource resource = Client.create().resource( endpointLoc );
ClientResponse response = resource
.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( payload )
.get(ClientResponse.class);
//.post( ClientResponse.class );
String responseEntity = response.getEntity(String.class).toString();
int responseStatus = response.getStatus();
logger.trace("GET to {} returned status code {}, returned data: {}",
endpointLoc, responseStatus,
responseEntity);
JSONParser reponseParser = new JSONParser();
Object responseObj = reponseParser.parse(responseEntity);
JSONObject jsonResponseObj = responseObj instanceof JSONObject ?(JSONObject) responseObj : null;
if(jsonResponseObj == null)
throw new ParseException(0, "returned json object is null");
String result = (String) jsonResponseObj.get("results").toString();
logger.trace("result is {} ", result);
String error = (String) jsonResponseObj.get("errors").toString();
Am I missing something? Do I need to use a special call?
Can someone help me with this? Thanks in advance,
Christian
What do you need the node-URL for?
That's the old RESTful representation. You can either get it by using the old HTTP endpoint /db/data/cypher or better by specifying the (very verbose) resultDataContents type REST
You can also specify other types like "row" and "graph" in parallel.
{"statements": [
{"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p",
"resultDataContents":["REST"]}
] }