Springdoc + OpenId Connect = missing client_id from Swagger request - spring-boot

I am integrating a Spring Boot application with OIDC. The customer has an OIDC manifest file, at https://example.biz/.well-known/openid-configuration, which is redacted as displayed later.
Problem
When I attempt to authenticate via Swagger, the authorization endpoint complains that a parameter is missing. I could see that Swagger does not send the client_id parameter in (it's actually empty).
Please note, I expect that 99% of the configuration is handled by Springdoc after the OIDC configuration URL.
Question
Why doesn't Springdoc/Swagger OIDC setup work according to the existing setup and OIDC manifest?
Set up
OIDC manifest I can retrieve from authorization endpoint
{
"client_id": "the-clientid",
"issuer": "https://...",
"authorization_endpoint": "https://...",
"token_endpoint": "https://...",
"userinfo_endpoint": "https://...",
"jwks_uri": "https://...",
"end_session_endpoint": "https://...",
"registration_endpoint": null,
"scopes_supported": [
"openid"
],
"response_types_supported": [
"token",
"id_token",
"id_token token"
],
"response_modes_supported": [
"form_post",
"fragment"
],
"grant_types_supported": [
""
],
"subject_types_supported": [
"pairwise"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic"
],
"claims_supported": [
"sub",
"iss",
"aud",
"exp",
"iat",
"auth_time",
"nonce"
]
}
I import this scheme using Springdoc's #SecurityScheme annotation
#ConditionalOnProperty(...) // I can switch between basic (dev) and oidc authentication (test, uat, prod)
#SecurityScheme(
name = "secured",
type = OPENIDCONNECT,
openIdConnectUrl = "${oidc-url}/.well-known/openid-configuration" //Parameterized URL works here
)
public class OidcConfiguration {
}
Swagger displays me the Authorize button on top of the page.
However, when I see the generated Swagger OpenAPI v3 schema, it looks like the following
{
"openapi": "3.0.1",
"info": {
"title": "API",
"version": "v1"
},
"servers": [
{
"url": "http://localhost:8080",
"description": "Generated server url"
}
],
"paths": {
"/api/v1/.....": {
"patch": {
"tags": [
"...."
],
"operationId": "...",
"responses": {
"200": {
"description": "OK"
}
},
"security": [
{
"secured": []
}
]
}
},
"/health.check": {
"get": {
"tags": [
"probe-controller"
],
"operationId": "healthCheckProbe",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"type": "boolean"
}
}
}
}
},
"security": [
{
"open": []
}
]
}
}
},
"components": {
"securitySchemes": {
"secured": {
"type": "openldConnect",
"openldConnectUrl": "https://...."
}
}
}
}
As you can see, the JSON file points to the remote OIDC configuration, and Swagger retrieves it.
But when I click on the Authentication button, I can see in the popup
secured (OAuth2, )
OpenId Connect URL: https://.....
Flow:
Scopes (select all, select none)
[ ] openid
According to this, I am not prompted with any client id. Clicking on Authorize opens a new window where I can't debug the original URL, as I am immediately redirected and DevTools is not open yet.
But after login request, I could see that the next URL displays ?client_id=&.....
If I manually navigate the URL with the client ID set, I can be redirected.
I also tried to set springdoc.swagger-ui.oauth.clientId=some client id according to linked issue, but it didn't display the input box.

Related

Using google workspace admin API, how to identify slack workspace of the my org users who log into slack using company's email via Gsuite SSO?

I am capturing the logins of my org users into slack using google workspace admin reports API as mentioned in the doc here: https://developers.google.com/admin-sdk/reports/v1/appendix/activity/saml#login_success
I want to identify the workspace that these users are login into. How can I identify this?
Here's the sample response that I get from the reports API:
{
"kind": "admin#reports#activities",
"etag": "\"SsISqFfgRYY11XaGpPyQF5FTf1EAwqUmKLMPaD85FHw/evu1UTmScwnBzMj7rPtBftM3N2k\"",
"items": [
{
"kind": "admin#reports#activity",
"id": {
"time": "2022-05-25T17:51:08.913Z",
"uniqueQualifier": "35251594669533645",
"applicationName": "token",
"customerId": "C02a9qd29"
},
"etag": "\"SsISqFfgRYY11XaGpPyQF5FTf1EAwqUmKLMPaD85FHw/U-RQigEfldlDShA5VdJAIizlnsQ\"",
"actor": {
"email": "vibhu#cloudeagle.ai",
"profileId": "116721330888590133060"
},
"ipAddress": "18.206.76.246",
"events": [
{
"name": "authorize",
"parameters": [
{
"name": "client_id",
"value": "606092904014-s1u3idjanlbhr4ns5b1hcjgfn63cr9nh.apps.googleusercontent.com"
},
{
"name": "app_name",
"value": "Slack"
},
{
"name": "client_type",
"value": "WEB"
},
{
"name": "scope_data",
"multiMessageValue": [
{
"parameter": [
{
"name": "scope_name",
"value": "openid"
},
{
"name": "product_bucket",
"multiValue": [
"IDENTITY"
]
}
]
},
{
"parameter": [
{
"name": "scope_name",
"value": "https://www.googleapis.com/auth/userinfo.email"
},
{
"name": "product_bucket",
"multiValue": [
"IDENTITY"
]
}
]
},
{
"parameter": [
{
"name": "scope_name",
"value": "https://www.googleapis.com/auth/userinfo.profile"
},
{
"name": "product_bucket",
"multiValue": [
"IDENTITY"
]
}
]
}
]
},
{
"name": "scope",
"multiValue": [
"openid",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]
}
]
}
]
},
}
I am wondering if it is possible to identify the slack workspace from the above response or would it need other API endpoints and parameters.
keep in mind SAML is an authentication method that allows a Service Provider such as Slack in this scenario, use Google credentials as Identity Provider (IdP). That being said once the Authentication flow is completed usually the IdP doesn't have any control or access to the app activity.
In other words once the login is completed Google is blind about what users do in the app interface.
For that reason I am afraid what you are trying to achieve is not possible. In the Google Reports API link you shared data you can obtain is limited to failed/successful login details.
Testing the call to the Reports API you can see there is no additional details useful to your purpose:

ApiKey with role_descriptors to access Kibana

I would like to use the ApiKey authentication to create a reverse proxy for Kibana. The Reverse Proxy is needed to inject a custom role with some filters.
The proxy creates an ApiKey first with this post:
POST /_security/api_key
{
"name": "kb-1234-9876",
"expiration": "1d",
"role_descriptors": {
"role-a": {
"cluster": ["all"],
"indices": [
{
"names": ["*"],
"privileges": ["read"],
"query": "\"bool\": { \"filter\": { \"terms\": { \"customer.id_customer\": [ \"1234\", \"9876\" ] } }}"
}
]
}
}
After that the authentication header with the APIKEY Base64 string is passed to the backend.
Apparently the ApiKey does not have permission to access the Kibana Dashboard.
Is there any way to create the Kibana feature authorisation within the ApiKey as described in Kibana Role Management API?
Some other workaround?
I found that the "old" Kibana authorisation with the applications privileges work. So my new Post of the ApiKey is like this:
POST /_security/api_key
{
"name": "kb-1234-9876",
"expiration": "1d",
"role_descriptors": {
"role-a": {
"cluster": ["all"],
"indices": [
{
"names": ["*"],
"privileges": ["read"],
"query": "\"bool\": { \"filter\": { \"terms\": { \"customer.id_customer\": [ \"1234\", \"9876\" ] } }}"
}
],
"applications": [
{
"application": "kibana-.kibana",
"privileges": [
"read"
],
"resources": ["*"]
}
]
}
}
}

Microsoft Teams Connector: HttpPOST on MessageCard returns ODataContentTypeException

We set up a new Microsoft Teams Connector and successfully set the settings to POST cards to the received WebhookUrl.
In the body that we send, we included the option to make HttpPost requests to a defined target URL (using ngrok.io tunnel for development). You can see the sent messageCard below:
{
"#type": "MessageCard",
"#context": "https://schema.org/extensions",
"summary": "Card \"Test card\"",
"themeColor": "0078D7",
"title": "Card created: \"Just another test\"",
"potentialAction": [
{
"#type": "ActionCard",
"name": "Add a comment",
"inputs": [
{
"#type": "TextInput",
"id": "comment",
"isMultiline": true,
"title": "Enter your comment"
}
],
"actions": [
{
"#type": "HttpPOST",
"name": "Ok",
"target": "https://dd846f80.ngrok.io/teamshooks/actions",
"body": "{\"Comment\":\"This is a test\"}",
"headers": [
{
"Content-Type": "application/json"
},
{
"aw-teamid": "00000000-0000-0000-0000-000000000001"
}
]
}
]
}
]
}
The card is displayed correctly in the channel in Microsoft Teams.
When a user clicks on this button, to make a HttpPOST to the specified url, we never receive the request on our side but can see that Microsoft returns the following response to the internal "executeAction" request:
The request was sent on: Fri, 13 Dec 2019 11:09:48 GMT
{
"status": "Failed",
"actionId": "c520b20a-3e04-4e21-b4fd-c3a2f760c533",
"properties":
{
"displayMessage": "<p>Could not complete the requested action. Please try again later.</p>\n",
"errorCode": "ODataContentTypeException"
}
}
The following settings are set-up in the Connectors Developer Dashboard (and in the manifest.json):
"connectors": [
{
"connectorId": "6b2ba9c0-7c0a-4524-9e6d-64f061350aa4",
"scopes": [
"team"
],
"configurationUrl": "https://dd846f80.ngrok.io/msteams/aworkConnector/config.html"
}
]
"validDomains": [
"dd846f80.ngrok.io"
]
Do you want to enable actions on your Connector cards? - Yes
Actions Url: https://dd846f80.ngrok.io/teamshooks/actions
Is there anything we are currently doing wrong or does anyone have an idea on how to solve the returned ODataContentTypeException? We need to receive the request in our backend, in order to integrate Micorsoft Teams into our software.
Upload the manifest.json from an admin account, and add the ngrok url in the valid domains. Microsoft teams have blocked custom connectors from performing actions when uploaded by non admin users

spring boot swagger springfox generates invalid spec for oauth/token endpoint

I want to add token endpoint oauth/token into my API documentation so I configured Docket like this:
public Docket api(UserProperties userProperties) {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error")))
.paths(Predicates.not(PathSelectors.regex("/oauth/authorize")))
.paths(Predicates.not(PathSelectors.regex("/oauth/check_token")))
.paths(Predicates.not(PathSelectors.regex("/oauth/token_key")))
.paths(Predicates.not(PathSelectors.regex("/oauth/confirm_access")))
.paths(Predicates.not(PathSelectors.regex("/oauth/error")))
.build().apiInfo(apiInfo());
}
swagger-ui display page correctly, however 3rd party validator claims that:
Swagger schema validation failed.
Data does not match any schemas from 'oneOf' at #/paths//oauth/token/post/parameters/1
Data does not match any schemas from 'oneOf' at #/paths//oauth/token/post/parameters/1
Missing required property: schema at #/
Missing required property: type at #/
Missing required property: $ref at #/paths//oauth/token/post/parameters/1
JSON_OBJECT_VALIDATION_FAILED
The swagger.json taken from /api/v2/api-docs:
"/oauth/token": {
"get": {
...
},
"post": {
"tags": [
"token-endpoint"
],
"summary": "postAccessToken",
"operationId": "postAccessTokenUsingPOST",
"consumes": [
"application/json"
],
"produces": [
"*/*"
],
"parameters": [
{
"name": "name",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "parameters",
"in": "query",
"description": "parameters",
"required": true,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
],
"responses": {
...
},
"deprecated": false
}
},
Why springfox generates invalid schema?

Accessing VSTS service endpoints from javascript

I am trying to access the service endpoint setup in my extension code.
The extension is as follows:
{
"manifestVersion": 1,
"id": "vsts-extensions-myExtensions",
"version": "0.5.1",
"name": "xxx Projects Time Entry",
"description": "Record time spent in xxx Projects",
"publisher": "xxx",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"icons": {
"default": "img/logo.png"
},
"contributions":
[
{
"id": "xxTimeEntry",
"type": "ms.vss-dashboards-web.widget",
...
},
{
"id": "service-endpoint",
"description": "Service Endpoint type for xx connections",
"type": "ms.vss-endpoint.service-endpoint-type",
"targets": [ "ms.vss-endpoint.endpoint-types" ],
"properties": {
"name": "xxxyyy",
"displayName": "xx server connection",
"url": {
"displayName": "Server Url",
"helpText": "Url for the xxx server to connect to."
},
"dataSources": [
{
"name": "xxx Projects",
"endpointUrl": "{{endpoint.url}}api/timesheetwidgetprojects",
"resultSelector": "jsonpath:$[*].nm"
}
],
"authenticationSchemes": [
{
"type": "ms.vss-endpoint.endpoint-auth-scheme-basic",
"inputDescriptors": [
{
"id": "username",
"name": "Username",
"description": "Username",
"inputMode": "textbox",
"validation": {
"isRequired": false,
"dataType": "string"
}
},
{
"id": "password",
"name": "Password",
"description": "Password",
"inputMode": "passwordbox",
"isConfidential": true,
"validation": {
"isRequired": false,
"dataType": "string"
}
}
]
}
]
}
}
],
...
The code to access the service endpoint is something like :
VSS.require(["VSS/Service", "VSS/WebApi/RestClient"],
function (VSS_Service, RestClient) {
var webContext = VSS.getWebContext();
var client = VSS_Service.getCollectionClient(DistributedTask.TaskAgentRestClient);
client.getServiceEndpoints(webContext.project.id).then(
function (endpoints) {
alert('endpoints')
}
);
}
);
however I am not using a task and just have my endpoint in the main vss-extension.json.
Any ideas?
Thanks
Martin
Based on the supported scopes, there isn’t the scope for service endpoint, so you can’t do it.
I submit a user voice here: VSTS extension service endpoint scope, you can vote and follow up.
The workaround is that you can call REST API by using JS code with Personal Access Token in your extension.
Simple code to call REST API:
$.ajax({
url: 'https://fabrikam.visualstudio.com/defaultcollection/_apis/projects?api-version=1.0',
dataType: 'json',
headers: {
'Authorization': 'Basic ' + btoa("" + ":" + myPatToken)
}
}).done(function( results ) {
console.log( results.value[0].id + " " + results.value[0].name );
});
The scope has been added now and it is "vso.serviceendpoint"

Resources