springdoc / Swagger UI not passing OAuth2 token to API - swagger

I am using springdoc (v1.5.9) to generate Swagger definitions for an API. After authenticating inside the Swagger UI and executing a secured method, the http request received by the Spring Boot app has no Authentication header. I have confirmed via JS debugger that the Swagger UI received and stored a valid authentication token.
Below are the HTTP request, the Swagger api-docs showing the security scheme defined / applied to the method, the springdoc configuration and a controller.
How do I need to change / add to my Spring configuration to get the Authorization passed to the API from the Swagger UI?
HTTP request received
Request received for GET '/foo/1234':
org.apache.catalina.connector.RequestFacade#71c70030
servletPath:/foo/1234
pathInfo:null
headers:
host: localhost:8070
connection: keep-alive
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
accept: application/json
sec-ch-ua-mobile: ?0
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
sec-fetch-site: same-origin
sec-fetch-mode: cors
sec-fetch-dest: empty
referer: http://localhost:8070/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cookie: JSESSIONID=A0F9846102153C06D77D6ED5506CC227
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
BearerTokenAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
api-docs
{
"openapi": "3.0.1",
"info": {
"title": "My App",
"version": "v1"
},
"servers": [
{
"url": "http://localhost:8070",
"description": "Generated server url"
}
],
"paths": {
"/foo/{id}": {
"get": {
"tags": [
"foo"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
},
"security": [
{
"custom": [
]
}
]
}
},
"securitySchemes": {
"access_token": {
"type": "oauth2",
"in": "header",
"scheme": "custom",
"flows": {
"authorizationCode": {
"authorizationUrl": "https://login.myauthsever.com/v2/oauth/authorize",
"tokenUrl": "https://login.myauthsever.com/v2/oauth/token",
"scopes": {
}
}
}
}
}
}
}
OpenAPI config
#OpenAPIDefinition(info = #Info(title = "My App", version = "v1"))
#SecurityScheme(scheme = "custom", type = SecuritySchemeType.OAUTH2, in = SecuritySchemeIn.HEADER, name = "access_token",
flows = #OAuthFlows(authorizationCode = #OAuthFlow(
authorizationUrl = "https://login.myauthsever.com/v2/oauth/authorize",
tokenUrl = "https://login.myauthsever.com/v2/oauth/token", scopes = {})))
public class OpenApiConfig {
}
Controller
#RestController
#Tag(name = "foo")
#SecurityRequirement(name = "custom")
public class SystemSigController {
#GetMapping(path = "/foo/{id}")
String getFoo(#PathVariable String id) {
...
}
}

The #SecurityRequirement.name value must be the same as #SecurityScheme.name.
Since you have #SecurityScheme(..., name = "access_token"...), the controller must use:
#SecurityRequirement(name = "access_token")

Related

Request sent from Swagger UI not resulting in Postman x-www-form-urlencoded response

I'm currently configuring a Swagger file to utilize OAuth to retrieve tokens from a site. For brevity, I have removed my schemes and most of my paths as those are fine.
{
"openapi": "3.0.2",
"info": {
"title": "swagger",
"version": "1.0.0",
"description": ""
},
"servers": [
{
"url": "url"
}
],
"paths": {
"/oauth_token.do": {
"post": {
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object"
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"OAuth": {
"type": "oauth2",
"flows": {
"password": {
"tokenUrl": "/oauth_token.do",
"refreshUrl": "/oauth_token.do",
"scopes": {
"useraccount": "utilize user account"
}
}
}
}
}
}
"security": [
{
"OAuth": ["useraccount"]
}
]
}
The endpoint for this API specifies that I should use x-www-form-urlencoded in the header as the Content-Type. When executing this request in Postman, it returns 200 with the desired response.
However, with https://editor.swagger.io I input the same postman request to get the fetch failed error with my Authorize button. To test for this, I created a custom path that specifies that the content should be x-www-form-urlencoded and this also fails.
So, what am I missing in this case? Any help would be appreciated.
I believe the issue was I did not fill out some portions I added on the response for path. Instead I opted to only leave description for the 200 response.
The main error I'm getting now is CORS related which is unrelated to the original question. I'll mark this answered for now.

Springdoc sends Multipart file as application/x-www-form-urlencoded and not multipart/form-data

I am using the latest version of openapi-ui 1.6.7 and I can't make a file upload endpoint work.
This is my configuration of the parameter :
#PostMapping(
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
#Operation(
summary = "Create a new FileResource",
requestBody = #RequestBody(description = "File to upload")
)
public ResponseEntity<FileResourceIdPublicApiDto> create(
#Parameter(
description = "File to upload",
required = true
)
#RequestPart
MultipartFile file
When I use the "Try out" button in the generated swagger UI, I get a 415 Unsupported Media Type error.
The request headers has content-type : application/x-www-form-urlencoded
I think this is where the error comes from. The generated json from OpenApi looks like this :
{
"operationId": "create_4",
"parameters": [
...
],
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"file"
],
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary",
"description": "File to upload"
}
}
}
}
},
"description": "File to upload"
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FileResourceId"
}
}
},
"description": "OK"
}
},
"summary": "Create a new FileResource",
"tags": [
"File Resource"
]
}
What am I missing to send a correct request with form-data content-type ?
For me replacing RequestPart to RequestParam did the job! btw I was using openapi-ui 1.6.4.
It’s a combination of two things:
Defining “consumes = multipart” and using RequestParam instead of RequestPart.
This wasn’t required when using springfox Swagger 2.0.
It’s really irritating that there is no good migration guide written for 2.0 -> 3.0.

Serilog expression to exclude http 200 and http 302?

I'm using serilog and it's nicely logging http requests to my asp.net core web application.
However I want to filter out the noise of http 200 and http 302 (basically only interested in 5xx and 4xx).
I've tried a lot of variations on the following:
... snip ...
"Using": [ "Serilog.Expressions" ],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "#l = 'Information' and Properties.StatusCode in ['200', '302']"
}
}
],
... snip ...
But to no success.
The LogEvent properties looks like (:
{
"TimeStamp": "2021-12-09T09:00:18.1586954",
"Level": "Information",
"Message": "HTTP \"GET\" \"/xxx/yyy\" responded 200 in 50.2048 ms",
"MessageTemplate": "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms",
"Properties": {
"RequestMethod": "GET",
"RequestPath": "/xxx/yyy",
"StatusCode": 200,
"Elapsed": 50.2048,
"SourceContext": "Serilog.AspNetCore.RequestLoggingMiddleware",
"RequestId": "8000050f-0006-eb00-b63f-84710c7967bb"
},
"Renderings": {
"Elapsed": [
{
"Format": "0.0000",
"Rendering": "50.2048"
}
]
}
}
Serilog is paying attention if I use a filter like "#l = 'Information'", but any attempt to filter based upon LogEvent properties does not work.
Any help would be appreciated!
Serilog.Expressions doesn't require dotting through a Properties subobject: all of the event's properties are top-level names.
StatusCode is also a number, not a string, so you don't need quotes within the array of status code values to exclude.
Your expression should look like:
#l = 'Information' and StatusCode in [200, 302]

Cannot create a VSTS webhook subscription for punlisherId = tfs and eventId tfvc.checkin via the REST API

I am trying to create a VSTS webhook subscription for publisherId= tfs and eventType= tfvc.checkin. Here's the sample Post request :
Url : https://testvstsaccount.visualstudio.com/_apis/hooks/subscriptions?api-version=1.0
Request Body :
{
"publisherId": "tfs",
"eventType": "tfvc.checkin",
"resourceVersion": "1.0-preview.1",
"consumerId": "webHooks",
"consumerActionId": "httpRequest",
"publisherInputs": {
"path": "$/"
},
"consumerInputs": {
"url": "https://myservice/myhookeventreceiver"
}
}
I am getting 400 Bad Request in response.
Response body :
{
"$id": "1",
"innerException": null,
"message": "Subscription input 'path' is not supported at scope 'collection'.",
"typeName": "Microsoft.VisualStudio.Services.ServiceHooks.WebApi.SubscriptionInputException, Microsoft.VisualStudio.Services.ServiceHooks.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"typeKey": "SubscriptionInputException",
"errorCode": 0,
"eventId": 4501
}
Can someone please help me understand the correct way to create this webhook.
The path is filtering to checkins that change one or more files under the specified path. It should look like $/TeamProject, or $/TeamProject/Project, or $/TeamProject/Project/.... $/ is not supported. Check my example below:
POST https://xxx.visualstudio.com/DefaultCollection/_apis/hooks/subscriptions?api-version=1.0
Content-Type: application/json
{
"consumerActionId": "httpRequest",
"consumerId": "webHooks",
"consumerInputs": { "url": "https://xxx.visualstudio.com" },
"eventType": "tfvc.checkin",
"publisherId": "tfs",
"publisherInputs": {
"path": "$/TestCase/TestCaseProject",
"projectId": "1decf66b-1974-43e3-xxxx-ba9a3fd2xxxx"
},
"resourceVersion": "1.0",
"scope": 1
}

GET /entity.svc failed in batch

I defined a service in dataSources
"dataSources": {
"mainService": {
"uri": "/backend/service/v1/entity.svc/",
"type": "OData",
}
}
"models": {
"": {
"dataSource": "mainService",
"preload": true,
"settings" : {
"sizeLimit" : 500,
"useBatch" : false,
"refreshAfterChange": false,
"defaultBindingMode": "TwoWay",
"defaultCountMode" : "None",
"defaultUpdateMethod" : "Put"
}
}
}
But for some reason I don't know, ui5 project will call GET /backend/service/v1/entity.svc/ when initial load, which returns several <collection>.
But when I set UseBatch to true, the batched GET request will fail, with payload like this:
--batch_67d5-9dc2-70e0
Content-Type: application/http
Content-Transfer-Encoding: binary
GET HTTP/1.1
sap-contextid-accept: header
Accept: application/json
Accept-Language: en-US
DataServiceVersion: 2.0
MaxDataServiceVersion: 2.0
sap-cancel-on-close: true
--batch_67d5-9dc2-70e0-
As it seems like a GET nothing request, the batch request will certainly fail. Is there any UI5/oData expert can tell me what's the point of GET /entity.svc, how to fix this batch or how to skip this request ?
I found that it is cause by data binding in sap.m.Table
_bindView : function (sObjectPath) {
var sAssignedPath = sObjectPath + "/assignedThings",
this._oModel.read(sAssignedPath , {
success : this._handleGetAssignedSuccess.bind(this, sAssignedPath),
error : this._handleGetAssignedError.bind(this)
});
oTable.setModel(this._oModel);
}
_handleGetAssignedSuccess : function (sAssignedPath, oMsg) {
var oTable = this.getView().byId("tableView").byId("assignTable"),
oJSONModel = new JSONModel(oMsg.results);
oAssignTable.setModel(oJSONModel);
},
//AssignTable.view.xml
<Table
id="assignTable"
inset="true"
items="{
path: '/'
}"
>
items="{path: '/'}" is mean to use in JSON Model data binding, but it also triggered an oData GET '/' Request.

Resources