Add user profile ID to audit log events#141092
Conversation
|
Documentation preview: |
|
@elasticmachine merge upstream (to resolve ci issues caused by Github outage) |
|
Pinging @elastic/kibana-security (Team:Security) |
|
ACK: will review today or tomorrow at the latest |
azasypkin
left a comment
There was a problem hiding this comment.
Looks and works great! I just left two small proposals to improve unit/API integration test coverage a bit before we merge the PR.
Thanks!
| authentication_provider: { type: 'kerberos', name: 'kerberos' }, | ||
| authentication_type: 'token', | ||
| elastic_cloud_user: false, | ||
| profile_uid: jestExpect.any(String), |
There was a problem hiding this comment.
note: Since the user profile UID isn't part of the ES authentication response and we have a custom logic to enrich user with it, it'd be great if instead of jestExpect.any(String) here and in similar API integration tests for other major authentication providers, we could check that profile uid is indeed correct (e.g. fetching it from /internal/security/user_profile before this assertion).
What do you think?
There was a problem hiding this comment.
I agree that it's worth having an end to end test for the enrichment logic but I don't think it's correct to clutter this in with the authentication providers since the logic is independent of provider logic. I have added an end to end test for the enrichment logic to the user profile related functional test suite instead.
| } | ||
| } | ||
|
|
||
| function enrichWithUserProfileId( |
There was a problem hiding this comment.
concern: since we updated authenticated user mock to always populate profile_uid we might not really test this method in Authenticator unit tests. Would you mind adding a few tests for login/authenticate/re-authenticate that explicitly test this logic (e.g. create user mock returned by the provider without profile_uid)?
There was a problem hiding this comment.
Good point, I've added unit tests for this method.
💚 Build Succeeded
Metrics [docs]History
To update your PR or re-run it, just comment with: |
* Add user profile ID to audit log events * Fix merge conflict * Fix integration tests * Fix integration tests * Fix type * Refactor * updated functional tests * updated functional tests * Added tests for enrichment logic Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
* Add user profile ID to audit log events * Fix merge conflict * Fix integration tests * Fix integration tests * Fix type * Refactor * updated functional tests * updated functional tests * Added tests for enrichment logic Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
…258866) I'm working on adding Scout API tests (#258534) and noticed that `created_by_profile_uid` and `updated_by_profile_uid` fields are absent from all Osquery API responses on ECH (Elastic Cloud Hosted), even though the authenticated user clearly has a `profile_uid` available. ## Test it yourself on ECH (dev console) Confirm the user has a `profile_uid`: ```bash GET kbn:/internal/security/me ``` This returns `{ "profile_uid": "u_..." }`. Now create a saved query and check the response keys: ```bash POST kbn:/api/osquery/saved_queries {"id":"profile-uid-test","query":"select 1;","interval":"3600"} ``` The `created_by_profile_uid` and `updated_by_profile_uid` fields are missing from the response on ECH. On local stateful they appear just fine. ## Hypothesis (LLM-assisted) `getUserInfo()` has two code paths for resolving user identity: 1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from the user profile service 2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails or returns `null` The fallback hardcodes `profile_uid: null` instead of reading `user.profile_uid` from the `AuthenticatedUser` object (available since 2022, PR #141092). On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns `null`, so the fallback is always used. The hardcoded `null` then cascades through route handlers: - Converted to `undefined` via `?? undefined` - Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries) ## Why didn't we spot this sooner and why Scout comes to the rescue The existing FTR API tests [[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)] [[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)] covering this ground aren't run on ECH. Scout is designed to be [deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset), so we're easily able to run the same set of tests on different testing surfaces :-)
…lastic#258866) I'm working on adding Scout API tests (elastic#258534) and noticed that `created_by_profile_uid` and `updated_by_profile_uid` fields are absent from all Osquery API responses on ECH (Elastic Cloud Hosted), even though the authenticated user clearly has a `profile_uid` available. ## Test it yourself on ECH (dev console) Confirm the user has a `profile_uid`: ```bash GET kbn:/internal/security/me ``` This returns `{ "profile_uid": "u_..." }`. Now create a saved query and check the response keys: ```bash POST kbn:/api/osquery/saved_queries {"id":"profile-uid-test","query":"select 1;","interval":"3600"} ``` The `created_by_profile_uid` and `updated_by_profile_uid` fields are missing from the response on ECH. On local stateful they appear just fine. ## Hypothesis (LLM-assisted) `getUserInfo()` has two code paths for resolving user identity: 1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from the user profile service 2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails or returns `null` The fallback hardcodes `profile_uid: null` instead of reading `user.profile_uid` from the `AuthenticatedUser` object (available since 2022, PR elastic#141092). On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns `null`, so the fallback is always used. The hardcoded `null` then cascades through route handlers: - Converted to `undefined` via `?? undefined` - Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries) ## Why didn't we spot this sooner and why Scout comes to the rescue The existing FTR API tests [[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)] [[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)] covering this ground aren't run on ECH. Scout is designed to be [deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset), so we're easily able to run the same set of tests on different testing surfaces :-) (cherry picked from commit fe7e247) # Conflicts: # x-pack/platform/plugins/shared/osquery/server/lib/get_user_info.test.ts
…lastic#258866) I'm working on adding Scout API tests (elastic#258534) and noticed that `created_by_profile_uid` and `updated_by_profile_uid` fields are absent from all Osquery API responses on ECH (Elastic Cloud Hosted), even though the authenticated user clearly has a `profile_uid` available. ## Test it yourself on ECH (dev console) Confirm the user has a `profile_uid`: ```bash GET kbn:/internal/security/me ``` This returns `{ "profile_uid": "u_..." }`. Now create a saved query and check the response keys: ```bash POST kbn:/api/osquery/saved_queries {"id":"profile-uid-test","query":"select 1;","interval":"3600"} ``` The `created_by_profile_uid` and `updated_by_profile_uid` fields are missing from the response on ECH. On local stateful they appear just fine. ## Hypothesis (LLM-assisted) `getUserInfo()` has two code paths for resolving user identity: 1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from the user profile service 2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails or returns `null` The fallback hardcodes `profile_uid: null` instead of reading `user.profile_uid` from the `AuthenticatedUser` object (available since 2022, PR elastic#141092). On ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns `null`, so the fallback is always used. The hardcoded `null` then cascades through route handlers: - Converted to `undefined` via `?? undefined` - Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries) ## Why didn't we spot this sooner and why Scout comes to the rescue The existing FTR API tests [[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)] [[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)] covering this ground aren't run on ECH. Scout is designed to be [deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset), so we're easily able to run the same set of tests on different testing surfaces :-)
…back (#258866) (#259258) # Backport This will backport the following commits from `main` to `9.3`: - [[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback (#258866)](#258866) <!--- Backport version: 11.0.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Cesare de Cal","email":"cesare.decal@elastic.co"},"sourceCommit":{"committedDate":"2026-03-20T16:39:00Z","message":"[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback (#258866)\n\nI'm working on adding Scout API tests\n(#258534) and noticed that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted), even\nthough the authenticated user clearly has a `profile_uid` available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the user has a `profile_uid`:\n\n```bash\nGET kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\": \"u_...\" }`.\n\nNow create a saved query and check the response keys:\n\n```bash\nPOST kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select 1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and `updated_by_profile_uid` fields are\nmissing from the response on ECH. On local stateful they appear just\nfine.\n\n## Hypothesis (LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from\nthe user profile service\n2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails\nor returns `null`\n\nThe fallback hardcodes `profile_uid: null` instead of reading\n`user.profile_uid` from the `AuthenticatedUser` object (available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns\n`null`, so the fallback is always used. The hardcoded `null` then\ncascades through route handlers:\n- Converted to `undefined` via `?? undefined`\n- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we spot this sooner and why Scout comes to the rescue\n\nThe existing FTR API tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering this ground aren't run on ECH. Scout is designed to be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso we're easily able to run the same set of tests on different testing\nsurfaces :-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport missing","backport:version","v9.4.0","v9.3.3"],"title":"[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback","number":258866,"url":"https://github.com/elastic/kibana/pull/258866","mergeCommit":{"message":"[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback (#258866)\n\nI'm working on adding Scout API tests\n(#258534) and noticed that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted), even\nthough the authenticated user clearly has a `profile_uid` available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the user has a `profile_uid`:\n\n```bash\nGET kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\": \"u_...\" }`.\n\nNow create a saved query and check the response keys:\n\n```bash\nPOST kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select 1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and `updated_by_profile_uid` fields are\nmissing from the response on ECH. On local stateful they appear just\nfine.\n\n## Hypothesis (LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from\nthe user profile service\n2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails\nor returns `null`\n\nThe fallback hardcodes `profile_uid: null` instead of reading\n`user.profile_uid` from the `AuthenticatedUser` object (available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns\n`null`, so the fallback is always used. The hardcoded `null` then\ncascades through route handlers:\n- Converted to `undefined` via `?? undefined`\n- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we spot this sooner and why Scout comes to the rescue\n\nThe existing FTR API tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering this ground aren't run on ECH. Scout is designed to be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso we're easily able to run the same set of tests on different testing\nsurfaces :-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c"}},"sourceBranch":"main","suggestedTargetBranches":["9.3"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/258866","number":258866,"mergeCommit":{"message":"[Osquery] Fix `profile_uid` dropped in `getUserInfo` authc fallback (#258866)\n\nI'm working on adding Scout API tests\n(#258534) and noticed that\n`created_by_profile_uid` and `updated_by_profile_uid` fields are absent\nfrom all Osquery API responses on ECH (Elastic Cloud Hosted), even\nthough the authenticated user clearly has a `profile_uid` available.\n\n## Test it yourself on ECH (dev console)\n\nConfirm the user has a `profile_uid`:\n\n```bash\nGET kbn:/internal/security/me\n```\n\nThis returns `{ \"profile_uid\": \"u_...\" }`.\n\nNow create a saved query and check the response keys:\n\n```bash\nPOST kbn:/api/osquery/saved_queries\n{\"id\":\"profile-uid-test\",\"query\":\"select 1;\",\"interval\":\"3600\"}\n```\n\nThe `created_by_profile_uid` and `updated_by_profile_uid` fields are\nmissing from the response on ECH. On local stateful they appear just\nfine.\n\n## Hypothesis (LLM-assisted)\n\n`getUserInfo()` has two code paths for resolving user identity:\n\n1. **Primary**: `userProfiles.getCurrent()` — returns `profile_uid` from\nthe user profile service\n2. **Fallback**: `authc.getCurrentUser()` — used when the primary fails\nor returns `null`\n\nThe fallback hardcodes `profile_uid: null` instead of reading\n`user.profile_uid` from the `AuthenticatedUser` object (available since\n2022, PR #141092).\n\nOn ECH (Elastic Cloud Hosted), `userProfiles.getCurrent()` returns\n`null`, so the fallback is always used. The hardcoded `null` then\ncascades through route handlers:\n- Converted to `undefined` via `?? undefined`\n- Stripped by `JSON.stringify` (packs) or `pickBy` (saved queries)\n\n## Why didn't we spot this sooner and why Scout comes to the rescue\n\nThe existing FTR API tests\n[[1](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/saved_queries.ts#L90-L126)]\n[[2](https://github.com/elastic/kibana/blob/main/x-pack/platform/test/api_integration/apis/osquery/packs.ts#L191-L251)]\ncovering this ground aren't run on ECH. Scout is designed to be\n[deployment-agnostic](https://www.elastic.co/docs/extend/kibana/scout/best-practices#design-tests-with-a-cloud-first-mindset),\nso we're easily able to run the same set of tests on different testing\nsurfaces :-)","sha":"fe7e2477ddd0d89e13e5a8ff594a22eb4b8e2d5c"}},{"branch":"9.3","label":"v9.3.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
Resolves #125932
Release notes
Adds
user.idfield to audit log.Testing
kibana.dev.yml:user.idproperty:{ "message": "User [elastic] has logged in using basic provider [name=basic1]" "user": { "id": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "name": "elastic", }, }