I cannot get the Sendgrid public key verification to work in my application. I already have all the prerequisites configured. (API key is added, Signed webhook is enabled etc)
This is my approach to test the webhook.
I register a webhook.site url as the webhook in Sendgrid
I invoke the webhook from Sendgrid so that I get the call to webook.site
I export the request received to webhook.site as a Curl.
I import it into Postman
In Postman, I change the URL to a one from a backend service that is running in my localhost and invoke the call from Postman.
Here is my code to verify the signature. This is a exact copy of what Sendgrid has provided here.
public boolean VerifySignature(ECPublicKey publicKey, byte[] payload, String signature, String timestamp)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, IOException {
// prepend the payload with the timestamp
final ByteArrayOutputStream payloadWithTimestamp = new ByteArrayOutputStream();
payloadWithTimestamp.write(timestamp.getBytes());
payloadWithTimestamp.write(payload);
// create the signature object
final Signature signatureObject = Signature.getInstance("SHA256withECDSA", "BC");
signatureObject.initVerify(publicKey);
signatureObject.update(payloadWithTimestamp.toByteArray());
// decode the signature
final byte[] signatureInBytes = Base64.getDecoder().decode(signature);
// verify the signature
return signatureObject.verify(signatureInBytes);
}
Now this method always returns false when it is called from below controller method.
#PostMapping("/sendgrid-callback")
public boolean acceptSendgridCallback(
#RequestBody String rawData,
#RequestHeader("X-Twilio-Email-Event-Webhook-Timestamp") String timestamp,
#RequestHeader("X-Twilio-Email-Event-Webhook-Signature") String signature
) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, SignatureException, IOException, InvalidKeyException {
System.out.println("Req body = \n" + rawData);
ECPublicKey ecdsaKey = eventWebhook.ConvertPublicKeyToECDSA
("public key taken from sendgrid");
boolean b = eventWebhook.VerifySignature(ecdsaKey, rawData, signature, timestamp);
return b;
}
I am unable to find the cause for that honestly.
Can someone help here.
You will need to add the \r\n with the request body to pass the verification if you are testing using unit test or your own http request. You don't need to add that if you are testing using actual sendgrid webhook request.
Related
I'm developing a C# application that needs to contact a web-based API. When contacting the API, the first thing it does is try to get an authorization code from an authorization server. Using RestSharp, my code is this:
static string GetAuthCode(string authUri, string clientId, string scope, Guid state, string callbackUri)
{
var client = new RestClient(authUri);
var request = new RestRequest("", Method.Post);
client.Options.MaxTimeout = -1;
request.AddParameter("client_id", clientId);
request.AddParameter("response_type", "code");
request.AddParameter("scope", scope);
request.AddParameter("state", state);
request.AddParameter("redirect_uri", callbackUri);
RestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
string code = HttpUtility.ParseQueryString(response.ResponseUri.Query).Get("code");
return code;
}
else
throw new Exception(response.Content);
}
When I call this method, the response is successful, however I was expecting that the resulting authorization code would be appended to the ResponseUri property of the response (in its Query property). But it's not. The ResponseUri property is set to the authorization Uri (authUri). Am I looking in the wrong spot for the authorization code? Where can I find the actual authorization code?
It should be in the query parameters:
If the resource owner grants the access request, the authorization
server issues an authorization code and delivers it to the client by
adding the following parameters to the query component of the
redirection URI using the "application/x-www-form-urlencoded" format,
per Appendix B:
4.1 Authorization Code Grant - 4.1.2 Authorization Response
We've been using Spring Cloud Gateway for about 2 years in production. We're in the process of adding rate limiting support but we've run into a road block. One of the key endpoints we want to rate limit is our /oauth2/token endpoint. The trick here is this endpoint has credentials contained in the body that we need for our KeyResolver (to determine alleged identity). So we implemented the following KeyResolver:
public class OAuth2KeyResolver implements KeyResolver {
#Override
public Mono<String> resolve(ServerWebExchange exchange) {
String ipAddress = exchange.getRequest().getRemoteAddress().getHostName();
ServerRequest serverRequest = ServerRequest.create(exchange,
HandlerStrategies.withDefaults().messageReaders());
return serverRequest.bodyToMono(String.class).flatMap(requestBody -> {
JsonNode json = jackson.readTree(requestBody);
String clientId = json.path("clientId").asText(null);
return clientId != null ?
Mono.just(String.format("%s/%s", ipAddress, clientId) :
Mono.empty();
});
}
}
This works great to read the body and produce the desired key. However we quickly discovered that doing this consumes the body from the DataBuffer contained within the ServerHttpRequest. This seems to leave Spring Cloud Gateway unable to send the request to the downstream auth service.
Given the interface of this class, I don't think I can mutate the exchange instance to return the contents to the buffer.
How can I safely parse the body here?
Each request in my app goes through the custom interceptor where it validates the sessionid filed value which is passed as the one of the parameters in the request payload(post method).
If it is url paramter then we can use following snippet to catch the parameter.
Map<String, Object> parameters =
actionInvocation.getInvocationContext().getParameters();
String sessionid = parameters.get("sessionId");
What could be the way to catch this parameter in interceptor if "sessionId" being sent as part request payload.
I tired below code snippet to catch in the interceptor and it is working fine but in later stages in action classes body is not available to read.if we read twice then request body is not available for the second time to read.
public String intercept(ActionInvocation actionInvocation) throws Exception {
Log.debug(getClass().getName(), "intercept", "Debug enter");
ActionContext context = actionInvocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
RestPostBody restBody= new Gson().fromJson(request.getReader(), RestPostBody.class);
}
I'm trying to make a call to a number using the Twilio service using a Trial Account.
I'm following the Java example here: https://www.twilio.com/docs/quickstart/java/rest/call-request
I've configured the example with my API credentials, the provided Twilio number, the destination number and the TwiML instructions url.
When I run the MakeCall class the destination number get called.
When I respond to the call I get the "trial account" message, then it asks me to press any key. When I press a key the call is dropped.
As I can see the TwiML instructions url is not called by Twilio.
I've tested also with the Test Credentials with no success.
Any idea on why the TwiML instructions url is not called?
Using the twilio-java helper library and following code from the docs you mentioned above:
We then instantiate a new client object, set the request method to
'POST', fill in the 'From', 'To' and 'Url' parameters in an
associative array, and fire off the request to Twilio!
Aside from any potential issues with your URL...did you also set the request method to POST while configuring your twilio number in the console?
import java.util.Map;
import java.util.HashMap;
import com.twilio.sdk.TwilioRestClient;
import com.twilio.sdk.TwilioRestException;
import com.twilio.sdk.resource.instance.Account;
import com.twilio.sdk.resource.instance.Call;
import com.twilio.sdk.resource.factory.CallFactory;
public class MakeCall {
public static final String ACCOUNT_SID = "AC123";
public static final String AUTH_TOKEN = "456bef";
public static void main(String[] args) throws TwilioRestException {
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
Account mainAccount = client.getAccount();
CallFactory callFactory = mainAccount.getCallFactory();
Map<String, String> callParams = new HashMap<String, String>();
callParams.put("To", "5105551212"); // Replace with your phone number
callParams.put("From", "(510) 555-1212"); // Replace with a Twilio number
callParams.put("Url", "http://demo.twilio.com/welcome/voice/"); // Configure your own URL with TwiML instructions using TwiML Bins
// Make the call
Call call = callFactory.create(callParams);
// Print the call SID (a 32 digit hex like CA123..)
System.out.println(call.getSid());
}
}
I am simply trying to send credentials to a restful service that takes in a json formatted username and password and will return an access token. No matter what I try, I get a 400 error and the error returned from the server is "Must supply a body." Here's the last snippet I tried:
#Component
public class LoginRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
String jsonCredentials = "{\"username\":\"username\",\"password\":\"password\",\"grant_type\":\"password\",\"scope\":\"admin\"}";
from("timer://login?repeatCount=1")
.setBody(constant(jsonCredentials))
.setHeader(Exchange.HTTP_METHOD, constant(org.apache.camel.component.http4.HttpMethods.POST))
.to("http://URL");
}
}
I have confirmed my credentials work fine in Postman and receive the proper response, with access token. I believe the service I am trying to connect to is using Oauth2.
Try marshalling. For me this worked:
// your custom defined bean
Credentials creds = new Credentials(username, password, ...);
from(...).setBody(creds).marshal().json(JsonLibrary.Jackson).to(...