[Connector] Adding internal route for requesting ad-hoc ServiceNow access token#131171
[Connector] Adding internal route for requesting ad-hoc ServiceNow access token#131171ymao1 merged 44 commits intoelastic:mainfrom
Conversation
…ationBase and ExternalIncidentServiceSecretConfiguration
… Still need to update unit tests for services
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…ors/servicenow-itom-oauth
…cenow-token-route
mikecote
left a comment
There was a problem hiding this comment.
I finished my review, the overall structure looks great but I have two questions before giving it a 👍
…ors/servicenow-token-route
…m/ymao1/kibana into connectors/servicenow-token-route
Thanks for the ping, I'll review today |
There was a problem hiding this comment.
I responded to one of Mike's comments, other than that I don't have any concerns about this PR.
I think the overall approach makes sense 👍
There's an SSRF risk here, but I think it's pretty minimal, with the combination of:
- Authorization checks (as suggested in one of the comments above)
- The optional hostname allow-list for connectors
- Additional URL validation (as suggested in my comment below)
- The inability for users to specify arbitrary parameters with the token request
- The logic which does not return the response body to users, it parses the response from the remote server and only returns the access token to users
In reviewing this, I noticed a couple small problems outside of the scope of this PR:
1. URL validation
Here's the implementation for the tokenUrl validation:
kibana/x-pack/plugins/actions/server/actions_config.ts
Lines 70 to 84 in 0998b67
This code ignores network-path references (see URL Confusion Vulnerabilities). In other words, a URL of //my-domain.com/foo would be parsed and the validation function would treat as if it has no hostname, but it actually has a hostname of my-domain.com (in terms of how HTTP clients typically behave).
Fortunately the validation function fails securely; if an allow-list is configured and a URL doesn't contain a hostname, it fails to validate. However, I think you should change the usage of url.parse to include the slashesDenoteHost parameter:
diff --git a/x-pack/plugins/actions/server/actions_config.ts b/x-pack/plugins/actions/server/actions_config.ts
index 35e08bb5cfe..49f1d1fd544 100644
--- a/x-pack/plugins/actions/server/actions_config.ts
+++ b/x-pack/plugins/actions/server/actions_config.ts
@@ -76,7 +76,7 @@ function isAllowed({ allowedHosts }: ActionsConfig, hostname: string | null): bo
function isHostnameAllowedInUri(config: ActionsConfig, uri: string): boolean {
return pipe(
- tryCatch(() => url.parse(uri)),
+ tryCatch(() => url.parse(uri, false /* parseQueryString */, true /* slashesDenoteHost */)),
map((parsedUrl) => parsedUrl.hostname),
mapNullable((hostname) => isAllowed(config, hostname)),
getOrElse<boolean>(() => false)2. JWT assertions
The code to create JWT assertions allows for consumers to specify custom claims that would override the existing claims (subject, audience, issuer, etc.):
It doesn't appear that this customClaims option is being used anywhere. I'm not sure why it was added, but IMO if you want to keep it you should ensure that it can't be used as a vector to overwrite the other claims:
diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/create_jwt_assertion.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/create_jwt_assertion.ts
index b33a2d17ed9..2fcb17c1e18 100644
--- a/x-pack/plugins/actions/server/builtin_action_types/lib/create_jwt_assertion.ts
+++ b/x-pack/plugins/actions/server/builtin_action_types/lib/create_jwt_assertion.ts
@@ -29,12 +29,12 @@ export function createJWTAssertion(
const headerObj = { algorithm: 'RS256' as Algorithm, ...(keyId ? { keyid: keyId } : {}) };
const payloadObj = {
+ ...(customClaims ?? {}),
sub: subject, // subject claim identifies the principal that is the subject of the JWT
aud: audience, // audience claim identifies the recipients that the JWT is intended for
iss: issuer, // issuer claim identifies the principal that issued the JWT
iat, // issued at claim identifies the time at which the JWT was issued
exp: iat + (expireInMilliseconds ?? 3600), // expiration time claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing
- ...(customClaims ?? {}),
};
try {This will prevent us from accidentally introducing a vulnerability in the future 😄
|
@jportner Thanks for reviewing! I've pushed changes based on your feedback:
Added
Removed ability to specify |
jportner
left a comment
There was a problem hiding this comment.
LGTM, thanks for the quick turnaround!
…ors/servicenow-token-route
💛 Build succeeded, but was flakyFailed CI StepsTest Failures
Metrics [docs]Public APIs missing exports
History
To update your PR or re-run it, just comment with: cc @ymao1 |
…hromium-to-print-pdf-part-1 * 'main' of github.com:elastic/kibana: (59 commits) [Cloud Posture] Enabled findings group by feature (elastic#131780) [EBT] Fix `userId` generation (elastic#131701) [RAM] Add shareable rule tag filter (elastic#130710) Optimize package installation performance, phase 2 (elastic#131627) [Screenshotting] instrument for benchmark tests using new EventLogger class (elastic#130356) [Connector] Adding internal route for requesting ad-hoc ServiceNow access token (elastic#131171) [ci] bump kibana-buildkite-library (elastic#131754) [Synthetics] UI clean up (elastic#131598) [RsponseOps] Fix flaky rules list test (elastic#131567) [Cases] Add severity field to create case (elastic#131626) [Discover] Monospace font in Document Explorer (elastic#131513) Sessions tab improvements (elastic#131583) Add cloud icon "ess-icon" at the end of the config keys in "alerting" documentation (elastic#131735) [DOCS] Updates deprecation text for legacy APIs (elastic#131741) [ci] break out skip patterns so they can change without triggering CI (elastic#131726) Adjust search session management page font size (elastic#131291) [Unified search] Fix uptime css problem (elastic#131730) [Actionable Observability] Link to filtered rules page (elastic#131629) Add openAPI specifications for cases endpoint (elastic#131275) Display rule API key owner to users who can manage API keys (elastic#131662) ... # Conflicts: # x-pack/plugins/screenshotting/server/formats/pdf/index.ts # x-pack/plugins/screenshotting/server/screenshots/observable.ts
…cess token (elastic#131171) * Adding new OAuth fields to ServiceNow ExternalIncidentServiceConfigurationBase and ExternalIncidentServiceSecretConfiguration * Creating new function in ConnectorTokenClient for updating or replacing token * Update servicenow executors to get Oauth access tokens if configured. Still need to update unit tests for services * Creating wrapper function for createService to only create one axios instance * Fixing translation check error * Adding migration for adding isOAuth to service now connectors * Fixing unit tests * Fixing functional test * Not requiring privateKeyPassword * Fixing tests * Adding functional tests for connector creation * Adding functional tests * Fixing functional test * PR feedback * Adding route for requesting access token using OAuth credentials * Fixing test * Adding functional test * Fixing functional test * Fixing checks * Using existing private key * Refactoring get access token utilities to be more generic * Checking tokenurl against allowlist * Restricting access to users with ability to update connectors * Adding slashesDenotesHost parameter to url.parse * Removing ability to specify custom claims for jwt assertion * Verifying that token url contains hostname and uses https Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Towards #130306
Summary
Addresses item 6 from #130306:
Expose new actions API HTTP route, which allow to fetch an access token for not saved connectors.This PR adds an internal route to request an ad-hoc access token from a ServiceNow instance without requiring a saved connector. This allows the Create ServiceNow connector UI to request information from the
api/x_elas2_inc_int/elastic_api/healthendpoint during the ServiceNow connector creation process.To Verify
Bearer <accessToken>Checklist