Get jwt-claims in a stateless spring-webflux service - java

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.

Related

How can I get the user_id from the request header instead of passing it as a request parameter? And then send it back through the header

For various REST api endpoints, the user_id will reach the backend, needed for further processing and then, sent back as a response to the front end.
I have a feeling I can do this through the header instead of passing it as a path parameter each time, except I can't seem to find the relevant information yet.
At the moment I send the response as a ResponseEntity. I would like, if possible, to keep this option.
I am using Java and Spring Boot.
example based on
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html
edited to add readign header from request
#RequestMapping("/handle")
public ResponseEntity<String> handle(HttpServletRequest httpRequest) {
String userId= httpRequest.getHeader("user_id");
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("user_id", userId);
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
I have decided that the best approach for my scenario, where I only need to fetch the user id and then respond back with it, is to use the #RequestHeader("userId") Long userId annotation.
Let's have a look at how I had configured the enpoint initially:
#PostMapping(path = "/add-follower/{userIdForFollowing}/{currentUserId}")
public ResponseEntity<String> addFollower(#PathVariable ("userIdForFollowing") Long userIdForFollowing, #PathVariable Long currentUserId)
{
Follow newFollow = followService.returnNewFollow(userIdForFollowing, currentUserId);
newFollow = followService.saveFollowToDb(newFollow);
return new ResponseEntity<>("Follow saved successfully", HttpStatus.OK);
}
Now, let's look at how I refactored the endpoint to fetch the id's from the header and return them in the response:
#PostMapping(path = "/add-follower")
public ResponseEntity<String> addFollower(#RequestHeader("userIdForFollowing") Long userIdForFollowing, #RequestHeader("currentUserId") Long currentUserId)
{
Follow newFollow = followService.returnNewFollow(userIdForFollowing, currentUserId);
newFollow = followService.saveFollowToDb(newFollow);
//here I will add more code which should replace the String in the ResponseEntity.
return new ResponseEntity<>("Follow saved successfully", HttpStatus.OK);
}

Unable to subscribe web-hook for SharePoint online

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

How to define different response models for different status codes in openApi / springfox-swagger2

Given the following REST method with springfox-swagger2 annotations:
#GetMapping(value = "/access", produces = MediaType.APPLICATION_JSON_VALUE)
#ApiOperation(value = "check access allowed")
#ApiResponses({
#ApiResponse(code = 200, message = "okay, there you go", response = AccessResponse.class),
#ApiResponse(code = 204, message = "I got nothing for you", response = Void.class)
})
public ResponseEntity<AccessResponse> access() {
if (!isAccessEnabled()) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
AccessResponse response = new AccessResponse("some data");
return ResponseEntity.ok(response);
}
Notice that there are two states that this method can return:
a response of type AccessResponse
a http 204 - no content response
I want to generate a swagger api documentation that reflects the different response models (AccessResponse vs. Void). Inside the #ApiResponse Annotation I explicitly tell springfox-swagger2 to use different models for each state.
Unfortunately the generated swagger api doc json refers only to the AccessResponse model for both http 200 and 204:
"responses":{
"200":{
"description":"okay, there you go",
"schema":{"$ref":"#/definitions/AccessResponse"}
},
"204":{
"description":"I got nothing for you",
"schema":{"$ref":"#/definitions/AccessResponse"}
}
}
Am I missing something? Is there a way to tell swagger to render two different models for each HTTP/ok status code?
I've changed the return type of the method - removing the generic type:
public ResponseEntity access()
which results in a better (but not perfect) model description:
"204":{
"description": "I got nothing for you",
"schema":{"type":"object"}
}
Swagger UI renders this to
I like that it displays the empty body now. However, the statusCode is a bit irritating.

Can not upload file when using a swagger generated spring server

I want to implement a file readout function on my REST Service. Since I do not know how to use spring myself, I use swagger to generate the server code for me. Normally this works perfectly fine, but when I try to upload files I get the following error:
{
"timestamp": "2018-11-07T12:27:43.119Z",
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.multipart.support.MissingServletRequestPartException",
"message": "Required request part 'file' is not present",
"path": "/requirements/import"
}
My yaml uses the following lines for the import function:
/requirements/import:
post:
consumes:
- multipart/form-data
description:
Returns all requirements contained in the submitted reqIf file.
parameters:
- name: reqIfFile
in: formData
type: file
description: The reqIf file that contains the requirements.
responses:
200:
description: An array of requirements.
schema:
type: array
items:
$ref: 'requirement'
The generated interface (with some added exceptions):
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2018-04-05T07:19:00.887Z")
#Api(value = "requirements", description = "the requirements API")
public interface RequirementsApi {
#ApiOperation(value = "", nickname = "requirementsImportPost", notes = "Returns all requirements contained in the submitted reqIf file.", response = Requirement.class, responseContainer = "List", tags = {})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "An array of requirements.", response = Requirement.class, responseContainer = "List") })
#CrossOrigin(origins = "*")
#RequestMapping(value = "/requirements/import", produces = { "application/json" }, consumes = {
"multipart/form-data" }, method = RequestMethod.POST)
ResponseEntity<List<Requirement>> requirementsImportPost(
#ApiParam(value = "file detail") #Valid #RequestPart("file") MultipartFile reqIfFile)
throws IOException, ContinuumException;
}
The code that actually does the readout:
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2018-04-05T07:19:00.887Z")
#Controller
public class RequirementsApiController implements RequirementsApi {
#Override
public ResponseEntity<List<Requirement>> requirementsImportPost(
#ApiParam(value = "file detail") #Valid #RequestPart("file") final MultipartFile reqIfFile)
throws IOException, ContinuumException {
InputStream fileStream = new BufferedInputStream(reqIfFile.getInputStream());
List<Requirement> list = ReadReqIF.readReqIfFile(fileStream);
return new ResponseEntity<List<Requirement>>(list, HttpStatus.OK);
}
}
Can someone tell me where a possible error is?
I encountered the same problem with my swagger generated spring server.
I was able to workaround the problem by modifying the generated server code to change the name "file" in #RequestPart("file") to the name specified in the swagger spec. In your case, it should be #RequestPart("reqIfFile"). It'd have to be modified in both the interface and controller code.
There is likely a bug in the Spring server generator code in Swagger editor. I can't think of any other reason for the RequestPart annotation to be named "file" which is essentially the "type" and not name of the parameter.

Swagger Is not able to produce documentation for HTTP "PATCH"

I Have followed the below
blog entry:
http://kingsfleet.blogspot.co.uk/2014/02/transparent-patch-support-in-jax-rs-20.html
https://github.com/jersey/jersey/tree/2.6/examples/http-patch
To create end point to support HTTP "PATCH" method in Jersey 2.6
Dependency Versions:
-Jersey: 2.6
-swagger-jersey2-jaxrs_2.10: 1.3.12
Question?
Why Patch end point is not getting listed as part of the swagger ui documentation?
Analysis:
If I am annotating with this annotation, then documentation for that end point getting generated, but no interaction .
#com.wordnik.swagger.jaxrs.PATCH
Configurations
JerssyApplicationInitializer
packages(true, "com.test.account.endpoint", "com.wordnik.swagger.jaxrs.json");
//Swagger Configuration
register(new ApiListingResourceJSON(), 10);
register(JerseyApiDeclarationProvider.class);
register(JerseyResourceListingProvider.class);
//Genson Converter
register(GensonJsonConverter.class, 1);
register(createMoxyJsonResolver());
I am not sure, if I am missing something, any help or guide will be helpful.
Patch method doscumets:
public static final String PATCH_MEDIA_TYPE = "application/json-patch+json";
#PATCH
//#com.wordnik.swagger.jaxrs.PATCH
#PreAuthorize(userAuthenticationRequire=true)
#Consumes(PATCH_MEDIA_TYPE)
#Path("{id: .\\d+}")
#ApiOperation(value = "Update Client Details in UIM System."
, response = State.class
, notes="Requesting User, should be the owner of the Client."
, consumes = PATCH_MEDIA_TYPE)
#ApiResponses({
#ApiResponse(code = _401, message = "If the access token is invalid.", response = String.class),
#ApiResponse(code = _498, message = "If the access token is expired.", response = String.class),
#ApiResponse(code = _420, message = "If Provided Input is not valid according to requirment specification."),
#ApiResponse(code = _404, message = "If no client/app Found."),
#ApiResponse(code = _200, message = "If Client Account has been Updated successfully. ", response=String.class)
})
public State updateClientDetails(#ApiParam(value="Client Id to be Updated.", required=true) #PathParam(CLIENT_ID) String clientId
, #ApiParam(value = "Updated field and Value.", required = true) final State newState){
//LOG.info("[ENTRY]- Received requst for updating Client {} from System.", clientId);
System.out.println("----->" + someBean.test());
//LOG.info("[EXIT]- Client Id {} Updation has been completed.", clientId);
Test t = new Test();
t.name = "Hello Test";
System.out.println(t.name);
return newState;
}
Take a look at your index.html. That controls which HTTP operations are interactive--by changing it to this:
window.swaggerUi = new SwaggerUi({
url: url,
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
You will have interaction on the PATCH method:

Categories