Unable to subscribe web-hook for SharePoint online - java

We are unable to subscribe web-hook for SharePoint online from our Spring-Boot application.
Providing valid notification URL(https enabled, publicly accessible, valid domain name, Post method) as parameter while consuming rest API in order to subscribe web-hook.
#PostMapping(value = "/spnotification")
#ResponseBody
public ResponseEntity<String> handleSPValidation(#RequestParam final String validationtoken) {
LOG.info("validationToken : " + validationtoken);
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
.body(validationtoken);
}
And on this notification URL end-point, we are able to receive validation string from share-point as parameter and same string we are retiring in less then 5 sec with content-type text/plain and http status code 200 as response.
still getting 400 bad request with below error message.
400 Bad Request: [{"error":{"code":"-1, System.InvalidOperationException","message":{"lang":"en-US","value":"Failed to validate the notification URL 'https://example.com/notification-listener-service/api/webhook/spnotification'."}}}]
Note : We are following this API documentation to subscribe web-hook.
We tried Graph API also for the same purpose but in that case getting below error.
"error": {
"code": "InvalidRequest",
"message": "The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF"
}
Please find this diagram for more understanding on this issue.
We really appreciate if someone can help us on the same.

Please check the #PostMapping(value = "/notification", headers = { "content-type=text/plain" })
#PostMapping(value = "/notification", headers = { "content-type=text/plain" })
#ResponseBody
public ResponseEntity<String> handleSPValidation(#RequestParam final String validationtoken) {
LOG.info("validationToken : " + validationtoken);
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
.body(validationtoken);
}
GitHub Code

Related

My microservice is not receiving "Authorization" from request header when i use feign-reactive to call it from another microservice

I have 2 microservices, ProductStore and InvoiceStore.
I want ProductStore to provide product information through an API and InvoiceStore to call that API to get product information from ProductStore.
But ProductStore needs Authorization information to check user authentication so I use #RequestHeader("Authorization") String auth as argument variable in my FeignAPI to send it to ProductStore.
But it reported that he did not receive the Authorization data when i test it.
I use #RequestHeader like that because I see it in the examples of feign-reactive all feature
I don't know if I did something wrong somewhere or I misunderstood the usage of #RequestHeader.
Help me please! Here is my code.
My ProductStore provides API to be able to get product information.
#GetMapping("products")
public ResponseEntity<String> test(#RequestHeader("Authorization") String authorization) {
log.debug("Authorization is {}", authorization);
return ResponseEntity.ok().body("all products");
}
And my InvoiceStore call that API with feign-reactive WebReactiveFeign.
I followed the instructions in the readme of Playtika feign-reactive and applied it to my project as follows
First, I write FeignAPI
#Headers({ "Accept: application/json" })
public interface FeignClientAPI {
#RequestLine("GET /products")
Mono<String> getProducts(#RequestHeader("Authorization") String authorization);
}
And then, I build the client in IvoiceService
#Service
#Transactional
public class InvoiceService {
private final FeignClientAPI client = WebReactiveFeign.<FeignClientAPI>builder().target(FeignClientAPI.class, "http://localhost:8082");
public Mono<String> testFeign(String authorization){
log.debug("Call api with authorization: {}", authorization);
return client.getTest(authorization);
}
}
And then, I create an API
#GetMapping("/invoice/test")
public Mono<ResponseEntity<String>> getProducts(#RequestHeader("Authorization") String authorization) {
return invoiceService.testFeign(authorization)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.map(response -> ResponseEntity.ok().body(response));
}
Finally, I shoot an GET request to localhost:8083/invoice/test and I got an error
{
"title": "Internal Server Error",
"status": 500,
"detail": "[400 Bad Request] during [GET] to [http://localhost:8082/products] [FeignClientAPI#getTest(String)]: [{\n \"title\" : \"Bad Request\",\n \"status\" : 400,\n \"detail\" : \"Required request header 'Authorization' for method parameter type String is not present\",\n \"path\" : \"/products\",\n \"message\" : \"error.http.400\"\n}]",
"path": "/invoice/test",
"message": "error.http.500"
}
Tell me where i did wrong, Please!!!
Thank you for everything.
your code is totally wrong and i think you should get compile time error because testFeign(String authorization) need a string input but when you call it ( invoiceService.testFeign().switchIfEmpty ... ) you are not passing any input to it.
i should check the main code ,but i think you are passing null value as authorization in client side ( probably ).
I found the solution to this problem.
I misinterpreted how to use reactive feign before, which resulted in it not working.
I've added #EnableReactiveFeignClients and #EnableFeignClients for my spring boot app
#EnableReactiveFeignClients
#EnableFeignClients
public class AnswerStoreApp {
// main method
}
and then, I create an interface with #ReactiveFeignClient(name = "my-other-service")
#ReactiveFeignClient(name = "my-other-service")
public interface FeignClientService {
#GetMapping("/api/questions/test-feign")
Mono<String> demo(#RequestHeader("Authorization") String authorize);
// More request
}
finally, I can use FeignClientService to get the data that I need
#Autowired
private FeignClientService feignClientService;
// Some method
#GetMapping("/invoice/test")
public Mono<ResponseEntity<String>> getProducts(#RequestHeader("Authorization") String authorization) {
return feignClientService.testFeign(authorization)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.map(response -> ResponseEntity.ok().body(response));
}

Get jwt-claims in a stateless spring-webflux service

Is there an easy way to pick up a jwt-claim in an endpoint built via swagger for a stateless spring-webflux-resource-service without having to manually pick the token from the header and parse it again as it is already done by the framework?
The method definition is similar to this (generated via openapi-generator-maven-plugin):
#Validated
#Api(value = "seller", description = "the seller API")
public interface SellerApi {
#ApiOperation(value = "gets all pricing models for sellers", nickname = "sellerPricingModels", notes = "provides a list of pricing models for the sellers", response = RestPricingModel.class, responseContainer = "List", tags={ "seller","pricing-models", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "picked up all the pricing models from the database", response = RestPricingModel.class, responseContainer = "List"),
#ApiResponse(code = 401, message = "unauthorized", response = RestErrorBody.class) })
#RequestMapping(value = "/seller/pricing-models",
produces = { "application/json" },
method = RequestMethod.GET)
default Mono<ResponseEntity<Flux<RestPricingModel>>> sellerPricingModels(#ApiParam(value = "" ,required=true) #RequestHeader(value="Language-Code", required=true) String languageCode, ServerWebExchange exchange) {
Mono<Void> result = Mono.empty();
exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED);
...
return result.then(Mono.empty());
}
}
I am using as authentication provider auth0 and I am testing it using their downloadable angular sample. I authenticated myself, I can see the token with the correct claims in auth0 debugging console, I can see the claims loaded fine in my test-ui but I am stuck fetching the claims from the token.
What I am trying to do is to have this stateless service and when an authenticated user tries to access an endpoint (i.e. /seller/pricing-models), I want to fetch only resources for this user. To have this done, I need to pick the user-id from the claims. This is not impossible, but I was wondering if I use something already provided by spring. Ideally, this would be something that does not require me to modify the method as it is automatically generated or at least to configure the openapi-generator-maven-plugin to insert it there.

API call with Java + STS returning "Content type 'application/octet-stream' not supported"

I am working on part of an API, which requires making a call to another external API to retrieve data for one of its functions. The call was returning an HTTP 500 error, with description "Content type 'application/octet-stream' not supported." The call is expected to return a type of 'application/json."
I found that this is because the response received doesn't explicitly specify a content type in its header, even though its content is formatted as JSON, so my API defaulted to assuming it was an octet stream.
The problem is, I'm not sure how to adjust for this. How would I get my API to treat the data it receives from the other API as an application/json even if the other API doesn't specify a content type? Changing the other API to include a contenttype attribute in its response is infeasible.
Code:
The API class:
#RestController
#RequestMapping(path={Constants.API_DISPATCH_PROFILE_CONTEXT_PATH},produces = {MediaType.APPLICATION_JSON_VALUE})
public class GetProfileApi {
#Autowired
private GetProfile GetProfile;
#GetMapping(path = {"/{id}"})
public Mono<GetProfileResponse> getProfile(#Valid #PathVariable String id){
return GetProfile.getDispatchProfile(id);
}
The service calling the external API:
#Autowired
private RestClient restClient;
#Value("${dispatch.api.get_profile}")
private String getDispatchProfileUrl;
#Override
public Mono<GetProfileResponse> getDispatchProfile(String id) {
return Mono.just(id)
.flatMap(aLong -> {
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return restClient.get(getDispatchProfileUrl, headers);
}).flatMap(clientResponse -> {
HttpStatus status = clientResponse.statusCode();
log.info("HTTP Status : {}", status.value());
return clientResponse.bodyToMono(GetProfileClientResponse.class);
// the code does not get past the above line before returning the error
}).map(GetProfileClientResponse -> {
log.debug("Response : {}",GetProfileClientResponse);
String id = GetProfileClientResponse.getId();
log.info("SubscriberResponse Code : {}",id);
return GetProfileResponse.builder()
// builder call to be completed later
.build();
});
}
The GET method for the RestClient:
public <T> Mono<ClientResponse> get(String baseURL, MultiValueMap<String,String> headers){
log.info("Executing REST GET method for URL : {}",baseURL);
WebClient client = WebClient.builder()
.baseUrl(baseURL)
.defaultHeaders(httpHeaders -> httpHeaders.addAll(headers))
.build();
return client.get()
.exchange();
}
One solution I had attempted was setting produces= {MediaType.APPLICATION_JSON_VALUE} in the #RequestMapping of the API to produces= {MediaType.APPLICATION_OCTET_STREAM_VALUE}, but this caused a different error, HTTP 406 Not Acceptable. I found that the server could not give the client the data in a representation that was requested, but I could not figure out how to correct it.
How would I be able to treat the response as JSON successfully even though it does not come with a content type?
Hopefully I have framed my question well enough, I've kinda been thrust into this and I'm still trying to figure out what's going on.
Are u using jackson library or jaxb library for marshalling/unmarshalling?
Try annotating Mono entity class with #XmlRootElement and see what happens.

Mapping incoming JSON to a class in spring boot

I'm struggling to understand why I'm getting the following error when I call my spring boot end point
{
"timestamp": 1489573322678,
"status": 406,
"error": "Not Acceptable",
"exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
"message": "Could not find acceptable representation",
"path": "/quotes"
}
This is the request that I'm sending to the server
POST /quotes HTTP/1.1
Host: localhost:8080
tamid: 5
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 94370a3f-6165-106f-f27f-44a44093e0d5
{
"test": "works"
}
I would like the incoming JSON request body to map to a java class I have defined. Here is the class.
#Embedded
public class QuoteVersion {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public void validate() {
}
}
I'm using the #Embedded annotation for use with a mongodb mapping library that I'm hoping is unrelated to the issue I'm facing
Here is the controller method
#RequestMapping(
path = "/quotes",
method = RequestMethod.POST,
headers = "Accept=application/json",
produces = "application/json"
)
public #ResponseBody QuoteStatus create (#RequestHeader(value = "tamid") String tamId,
#RequestBody QuoteVersion firstQuoteVersion) {
// final QuoteVersion firstQuoteVersion = this.quoteFactory.createQuoteVersion(incomingQuote);
final User currentUser = User.getFromTamId(tamId);
currentUser.can(Permissions.CREATE_QUOTE);
firstQuoteVersion.validate();
final Quote newQuote = new Quote();
newQuote.addVersion(firstQuoteVersion);
this.dataRepository.save(newQuote);
QuoteStatus qs = new QuoteStatus(newQuote);
return qs;
}
I'm guessing that Spring Boot for some reason does not understand how to map the incoming payload to the class I have defined but I have no idea how to fix the issue. Thanks in advance for any help you may have to offer.
Spring clearly indicates this problem:
HttpMediaTypeNotAcceptableException
This means that in your content-type header you provided the wrong information or made a syntactical mistake. Try putting there something like application/json.
Also
Make sure the other end will accept it. You currently only accepting requests with an accept header with value application/json. I don't think that is what you want.
So either remove that requirement or add this header to the request.

how to get email id using oauth

I'm trying to get user profile information by using following code. I'm using scribe to get the information. I'm able to get familyName and givenName etc. but it is not returning me the email id.
I'm using the following code:
OAuthRequest request = new OAuthRequest(
Verb.GET,
"https://social.yahooapis.com/v1/me/guid? format=xml"
);
service.signRequest(accessToken, request);
request.addHeader("realm", "yahooapis.com");
Response response = request.send();
And this is the response I got:
{
"profile": {
"guid":"CGGT5LNT7NXGFK64QW7FQN5UQM",
"ageCategory":"A",
"familyName":"gto",
"givenName":"CTSDemo",
"image": {
"height":192,
"imageUrl":"https://s.yimg.com/dh/ap/social/profile/profile_b192.png",
"size":"192x192",
"width":192
},
"intl":"us",
"jurisdiction":"us",
"lang":"en-US",
"location":"Bangalore",
"memberSince":"2014-08-03T08:23:27Z",
"nickname":"CTSDemo",
"notStored":false,
"nux":"3",
"profileMode":"PUBLIC",
"profileStatus":"ACTIVE",
"profileUrl":"http://profile.yahoo.com/CGGT5LNT7NXGFK64QW7FQN5UQM",
"updated":"2014-08-29T12:00:44Z",
"isConnected":false,
"profileHidden":false,
"bdRestricted":true,
"profilePermission":"PUBLIC",
"uri":"https://social.yahooapis.com/v1/user/CGGT5LNT7NXGFK64QW7FQN5UQM/profile",
"cache":true
}
}
I Found Solution!
You need to change your application's permission in the yahoo.
Url, which provide user info: https://social.yahooapis.com/v1/user/me/profile
And don't forget to add header Authorization: Bearer [your_access_token]

Categories