meesenger4j how to handle request from diffrent facbook app - spring-boot

I would like to create a rest api that handle user messenger app credential (token,appsecret,verifToken) as parameters instead of define them as env variable.
So that more than one user (facebook app) can subscribe to my rest api throw messenger webhook .
Is that possible?
First, i tried with credential in app.prop and injected the Messenger4j client in Restcontroller constructor and it works like charm (webhook call, conversation...).
Now is it possible to do that for more than one facebook app to communicate with my rest api :
the logic will be:
first connect(accesToken,appSecret) to our backend and save app credential and get response with myBackendApiUrl and generate verifToken.
#RequestMapping(value = "/connect", method = RequestMethod.POST)
public ResponseEntity<String> connect(#RequestParam final String pageAccessToken,
#RequestParam final String appSecret,
) {
logger.debug(" connect ");
try {
logger.debug("********");
//Messenger messenger = Messenger.create(pageAccessToken, appSecret, verifyToken).;
String verifyToken= UUID.randomUUID().toString();
MessengerCredentials msgerCred = new MessengerCredentials(pageAccessToken,appSecret,verifyToken);
messengerCredentialRepo.save(msgerCred);
return ResponseEntity.ok("webhookurl: myurl"+ "verifToken:"+verifyToken);
} catch (Exception e) {
logger.warn("failed to connect", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
After that the user should configure messenger app webhook with url and verif token recived in the response body method connect() to avonke the webhook handler and this is how it may be like
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> verifyWebhook(#RequestParam(MODE_REQUEST_PARAM_NAME) final String mode,
#RequestParam(CHALLENGE_REQUEST_PARAM_NAME) final String challenge,
#RequestParam(VERIFY_TOKEN_REQUEST_PARAM_NAME) final String verifyToken
) {
logger.debug("Received Webhook verification request - mode: {} | verifyToken: {} | challenge: {}", mode, verifyToken, challenge);
try {
logger.debug("********");
this.messenger.verifyWebhook(mode, verifyToken);
return ResponseEntity.ok(challenge);
} catch (MessengerVerificationException e) {
logger.warn("Webhook verification failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
Is that possible?!
and how can i deal with post handler to handel users events it my Messenger4j bean not instanciate yet.

Related

how to costum meesenjer4j single api for multiple messenger bot

I try to develop an API server with spring boot for multiple Facebook apps or an app with multiple pages like botFule or flowXo
I tried messenger4j. it works for a unique app and unique webhook
#Bean
public Messenger messenger(#Value("${messenger4j.pageAccessToken}") String pageAccessToken,
#Value("${messenger4j.appSecret}") final String appSecret,
#Value("${messenger4j.verifyToken}") final String verifyToken) {
return Messenger.create(pageAccessToken, appSecret, verifyToken);
}
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> verifyWebhook(#RequestParam(MODE_REQUEST_PARAM_NAME) final String mode,
#RequestParam(CHALLENGE_REQUEST_PARAM_NAME) final String challenge,
#RequestParam(VERIFY_TOKEN_REQUEST_PARAM_NAME) final String verifyToken
) {
logger.debug("Received Webhook verification request - mode: {} | verifyToken: {} | challenge: {}", mode, verifyToken, challenge);
try {
logger.debug("********");
this.messenger.verifyWebhook(mode, verifyToken);
return ResponseEntity.ok(challenge);
} catch (MessengerVerificationException e) {
logger.warn("Webhook verification failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
/**
* Callback endpoint responsible for processing the inbound messages and events.
*/
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Void> handleCallback(#RequestBody final String payload,
#RequestHeader(SIGNATURE_HEADER_NAME) final String signature
// ,#RequestParam(VERIFY_TOKEN_REQUEST_PARAM_NAME) final String verifyToken
) {
try {
this.messenger.onReceiveEvents(payload, of(signature), event ->
{event.recipientId();
if (event.isTextMessageEvent()) {
handleTextMessageEvent(event.asTextMessageEvent());
}}
Now how can I switch between pages or apps
I tried a basic way like that and had error signature verification
String pageId= j.getAsJsonArray().get(0).getAsJsonObject().get("id").getAsString();
logger.info("pageId {}", j.getAsJsonArray().get(0).getAsJsonObject().get("id"));
if (pageId=="109149861733036" ) {
messenger = Messenger.create("tok1", appSecret1, verifyToken1);
}else
messenger = Messenger.create("tok2", appSecret1, verifyToken1);
Processing of callback payload failed: pageId"101389035856068"
Processing of callback payload failed: Signature verification failed.
Provided signature does not match calculated signature.

how to decode error code in spring boot fiegn client

I have to implement a error decode for feign client I went to through this link
in that, decode function needs response but how to get this response from fiegn client, below is my feign client.
#FeignClient(name="userservice")
public interface UserClient {
#RequestMapping(
method= RequestMethod.GET,
path = "/userlist")
String getUserByid(#RequestParam(value ="id") String id);
}
I call feign client like this, whenever there is a error FeignException will be caught, but I want to get the proper error codes, like 400, 403 etc .
try {
String str = userClient.getUserByid(id);
return str;
}
catch(FeignException e)
{
logger.error("Failed to get user", id);
}
catch (Exception e)
{
logger.error("Failed to get user", id);
}

How to implement the observer pattern for REST API's?

I'm looking to create a REST API to which clients subscribe to certain data. When the data changes (due to some external event) I want to notify the clients (observers) with the new data.
I want to use Spring for the REST API's, I have no clue how to register and notify the observers though.
Some guidance and or good practises would be very helpful.
Thank you
In spring boot you can register call back urls, an example controller is:
#RestController
public class Controller {
private List<Listener> listeners = new ArrayList<>();
#RequestMapping(value = "/register/{name}", method = RequestMethod.POST)
public ResponseEntity<Void> register(#PathVariable("name") String name, #RequestParam("callbackurl") String callBackUrl) throws Exception {
System.out.println("register, name=" + name + ", callBackUrl=" + callBackUrl);
Listener listener = new Listener(name, URLDecoder.decode(callBackUrl, "UTF-8"));
listeners.add(listener);
System.out.println(listener);
return new ResponseEntity<>(HttpStatus.OK);
}
#RequestMapping(value = "/callback/*", method = RequestMethod.POST)
public ResponseEntity callBack(#RequestBody String message) {
System.out.println("call back with message=" + message);
return new ResponseEntity(HttpStatus.OK);
}
#Scheduled(fixedRate = 10000)
public void notifyListeners() {
System.out.println("notifying listeners");
for (Listener listener : listeners) {
System.out.println("listener " + listener);
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(listener.getCallBackUrl());
try {
httpPost.setEntity(new StringEntity("hello listener " + listener));
CloseableHttpResponse response = client.execute(httpPost);
client.close();
} catch (Exception e) {
}
}
}
}
Can be tested like so, register 2 call backs, the URL http://127.0.0.1:8080/callback/app1 is encoded so it can be a paramter.
curl -X POST http://127.0.0.1:8080/register/listener1?callbackurl=http%3A%2F%2F127.0.0.1%3A8080%2Fcallback%2Fapp1
curl -X POST http://127.0.0.1:8080/register/listener1?callbackurl=http%3A%2F%2F127.0.0.1%3A8080%2Fcallback%2Fapp2
In my case for simplicity the client and server are the same application, but they could be different.
You can use Spring 5 with WebFlux. It's a combination of an Iterator and the Observer pattern. The client always gets a new Object, whenever there is one on the server. You can start learning more on that on the Spring documentation pages or on e.g.
New in Spring 5: Functional Web Framework

Why OAuth2AccessTokenSupport always send POST request ??

I'm working with a Spring Boot + Spring Security OAuth2 to consume the Restful Oauth2 service.
Our Oauth2 service is always expects HTTP GET But OAuth2AccessTokenSupport always sending HTTP POST.
Result:
resulted in 405 (Method Not Allowed); invoking error handler
protected OAuth2AccessToken retrieveToken(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) throws OAuth2AccessDeniedException {
try {
this.authenticationHandler.authenticateTokenRequest(resource, form, headers);
this.tokenRequestEnhancer.enhance(request, resource, form, headers);
AccessTokenRequest copy = request;
ResponseExtractor delegate = getResponseExtractor();
ResponseExtractor extractor = new ResponseExtractor(copy, delegate) {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().containsKey("Set-Cookie")) {
this.val$copy.setCookie(response.getHeaders().getFirst("Set-Cookie"));
}
return ((OAuth2AccessToken) this.val$delegate.extractData(response));
}
};
return ((OAuth2AccessToken) getRestTemplate().execute(getAccessTokenUri(resource, form), getHttpMethod(),
getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()));
} catch (OAuth2Exception oe) {
throw new OAuth2AccessDeniedException("Access token denied.", resource, oe);
} catch (RestClientException rce) {
throw new OAuth2AccessDeniedException("Error requesting access token.", resource, rce);
}
}
<b>protected HttpMethod getHttpMethod() {
return HttpMethod.POST;
}</b>
protected String getAccessTokenUri(OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) {
String accessTokenUri = resource.getAccessTokenUri();
if (this.logger.isDebugEnabled()) {
this.logger.debug(new StringBuilder().append("Retrieving token from ").append(accessTokenUri).toString());
}
StringBuilder builder = new StringBuilder(accessTokenUri);
String separator;
if (getHttpMethod() == HttpMethod.GET) {
separator = "?";
if (accessTokenUri.contains("?")) {
separator = "&";
}
for (String key : form.keySet()) {
builder.append(separator);
builder.append(new StringBuilder().append(key).append("={").append(key).append("}").toString());
separator = "&";
}
}
return builder.toString();
}
Can Anyone explain me why OAuth2AccessTokenSupport always returns POST and
How to send HTTP GET request
To enable GET requests for the token endpoint, you need to add the following in your AuthorizationServerConfigurerAdapter:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
As for why only POST by default: I think that is due to GET requests potentially sending username and password information as request params (this is certainly the case for password grant). These may well be visible in web server logs, while POST body data is not.
Indeed the RFC for OAuth2 declares that the client must use HTTP POST when requesting an access token (https://www.rfc-editor.org/rfc/rfc6749#section-3.2)

unable to call a REST webservice..Full authentication required

I am currently working on spring application and REST webservices.
I have created a REST webservice in one application and want to access that service from other applications.
Below is the error its showing when trying to access the webservice.
RestClientException : org.springframework.web.client.HttpClientErrorException: 401 Full authentication is required to access this resource
Below is my webservice code:
#RequestMapping(value = MyRequestMapping.GET_ACC_DATA, method = RequestMethod.GET)
#ResponseBody
public MyResponseDTO getSigDataValues(#PathVariable final String acc, final HttpServletResponse response) throws Exception {
MyResponseDTO responseDTO = null;
try {
//logic goes here
//responseDTO = ..
} catch (Exception e) {
LOG.error("Exception" + e);
}
return responseDTO;
}
I am calling above webservice from another application.In the below mentioned method I am calling the webservice and its throwing me the exception org.springframework.web.client.HttpClientErrorException.
public MyResponseDTO getAccData(String acc){
try{
list= (List<String>)restTemplate.postForObject(MyDataURL.GET_ACC_DATA.value(), MyResponseDTO.class, acc);
}
catch (final RestClientException e)
{
LOG.info("RestClientException :" + e);
}
Please suggest, what am I missing.
You would need to authenticate against the REST service. One of the most common ways is Basic Authentication. If this is what the service is using you would need to create an AUTHORIZATION header with Base 64 encoded usernamen + password.
RestTemplate allow to set customer headers before the request gets sent.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
private HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {
private static final long serialVersionUID = -1704024310885506847L;
{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}
};
}
Then, sending a request becomes just as simple:
ResponseEntity<Dados> response = restTemplate.exchange(uriComponents.toUriString(), HttpMethod.GET,
new HttpEntity<Dados>(createHeaders(usuario, senha)), Dados.class);

Resources