Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ oas_docs/output/kibana.serverless.tmp*.yaml
oas_docs/output/kibana.tmp*.yaml
oas_docs/output/kibana.new.yaml
oas_docs/output/kibana.serverless.new.yaml
oas_docs/bundle.json
oas_docs/bundle.serverless.json

.codeql
.dependency-graph-log.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { omitBy, isUndefined } from 'lodash';
import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server';
import type { Logger, SavedObjectsClientContract } from '@kbn/core/server';
import { SavedObjectsUtils } from '@kbn/core/server';
import { escapeQuotes } from '@kbn/es-query';
import { OAUTH_STATE_SAVED_OBJECT_TYPE } from '../constants/saved_objects';

const STATE_EXPIRATION_MS = 10 * 60 * 1000; // 10 minutes
Expand Down Expand Up @@ -134,14 +135,17 @@ export class OAuthStateClient {
*/
public async get(stateParam: string): Promise<OAuthState | null> {
try {
const sanitisedStateParam = escapeQuotes(stateParam);
const result = await this.unsecuredSavedObjectsClient.find<OAuthStateAttributes>({
type: OAUTH_STATE_SAVED_OBJECT_TYPE,
filter: `${OAUTH_STATE_SAVED_OBJECT_TYPE}.attributes.state: "${stateParam}"`,
filter: `${OAUTH_STATE_SAVED_OBJECT_TYPE}.attributes.state: "${sanitisedStateParam}"`,
perPage: 1,
});

if (result.saved_objects.length === 0) {
this.logger.warn(`OAuth state not found for state parameter: ${stateParam}`);
this.logger.warn(
`OAuth state not found for state parameter: ${stateParam}. Sanitised parameter: ${sanitisedStateParam}`
);
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { schema } from '@kbn/config-schema';
import type { CoreSetup, IRouter, Logger } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import { escape } from 'lodash';
import type { ActionsPluginsStart } from '../plugin';
import type { ILicenseState } from '../lib';
import { BASE_ACTION_API_PATH } from '../../common';
Expand Down Expand Up @@ -104,14 +105,18 @@ function generateOAuthCallbackPage({
}): string {
const iconColor = isSuccess ? '#00BFB3' : '#BD271E';
const icon = isSuccess ? '✓' : '✕';
const sanitisedTitle = escape(title);
const sanitisedHeading = escape(heading);
const sanitisedMessage = escape(message);
const sanitisedDetails = details ? escape(details) : '';

return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
<title>${sanitisedTitle}</title>
<style>
* {
margin: 0;
Expand Down Expand Up @@ -191,9 +196,9 @@ function generateOAuthCallbackPage({
<body>
<div class="container">
<div class="icon">${icon}</div>
<h1>${heading}</h1>
<p>${message}</p>
${details ? `<div class="details">${details}</div>` : ''}
<h1>${sanitisedHeading}</h1>
<p>${sanitisedMessage}</p>
${sanitisedDetails ? `<div class="details">${sanitisedDetails}</div>` : ''}
${
autoClose
? '<p style="display: none; margin-top: 16px;" class="auto-close-message">This window will close automatically, or you can close it manually.</p>'
Expand Down