Respect runas realm for ApiKey security operations#52178
Respect runas realm for ApiKey security operations#52178ywangd merged 12 commits intoelastic:masterfrom
Conversation
|
Pinging @elastic/es-security (:Security/Authentication) |
|
Does this change need to be documented somewhere similar to what we do for breaking changes? |
|
This looks good to me, but per your comment on the issue, it looks like there's additional changes needed. Also, given we consider this a bug, I'd like a test for the actual bug. The fact that you can make the change and not need to fix any tests in the API permissions area, shows that we've got a testing gap there. I think we want to duplicate |
...a/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilege.java
Show resolved
Hide resolved
|
Added tests for both get api key and invalidate api key with runas user. Thanks |
albertzaharovits
left a comment
There was a problem hiding this comment.
The overall layout is correct, but there is a small inverted logic of authenticated - lookup that is wrong.
...a/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilege.java
Show resolved
Hide resolved
| "es-security-runas-user", userWithManageOwnApiKeyRole)); | ||
|
|
||
| PlainActionFuture<GetApiKeyResponse> listener = new PlainActionFuture<>(); | ||
| client.execute(GetApiKeyAction.INSTANCE, GetApiKeyRequest.forOwnedApiKeys(), listener); |
There was a problem hiding this comment.
add a test when the owned flag is not set, but the username and realm are.
There was a problem hiding this comment.
I was meant do test without the "owner" flag since the updated logic won't get executed with its presense. Somehow I ended up forgetting it. Will update. Thanks
There was a problem hiding this comment.
Add tests for get and invalidate API key without "owner=true"
| "es-security-runas-user", userWithManageOwnApiKeyRole)); | ||
|
|
||
| PlainActionFuture<InvalidateApiKeyResponse> listener = new PlainActionFuture<>(); | ||
| client.execute(InvalidateApiKeyAction.INSTANCE, InvalidateApiKeyRequest.forOwnedApiKeys(), listener); |
There was a problem hiding this comment.
same as above, we should also test without the owner flag toggled but with the concrete username and realm set.
I would also add a negative test, but this is usually better to do in unit tests, but I sometimes sneak in a negative test in integ tests as well.
There was a problem hiding this comment.
Added negative tests for calling get and invalidate API key with mismatching username and/or realm name.
.../elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java
Outdated
Show resolved
Hide resolved
…security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java Co-Authored-By: Albert Zaharovits <albert.zaharovits@gmail.com>
| private void createUserWithRunAsRole() throws ExecutionException, InterruptedException { | ||
| final PutUserRequest putUserRequest = new PutUserRequest(); | ||
| putUserRequest.username("user_with_run_as_role"); | ||
| putUserRequest.roles("run_as_role"); | ||
| putUserRequest.passwordHash(SecuritySettingsSource.TEST_PASSWORD_HASHED.toCharArray()); | ||
| PlainActionFuture<PutUserResponse> listener = new PlainActionFuture<>(); | ||
| final Client client = client().filterWithHeader(Map.of("Authorization", | ||
| UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_SUPERUSER, | ||
| SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING))); | ||
| client.execute(PutUserAction.INSTANCE, putUserRequest, listener); | ||
| final PutUserResponse putUserResponse = listener.get(); | ||
| assertTrue(putUserResponse.created()); | ||
| } |
There was a problem hiding this comment.
In order to have negative tests for realm name mismatch, user_with_run_as_role needs to be created in a different realm other than file (which is handled by configureUsers()). This new helper method creates the user in the native realm.
There was a problem hiding this comment.
Can we add that explanation to the code?
|
There were some sloppiness in the last change. Thanks @albertzaharovits for catching them. It is now updated accordingly. Thanks! |
...a/org/elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilege.java
Show resolved
Hide resolved
...k/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java
Show resolved
Hide resolved
.../elasticsearch/xpack/core/security/authz/privilege/ManageOwnApiKeyClusterPrivilegeTests.java
Show resolved
Hide resolved
| int noOfApiKeys, TimeValue expiration, String... clusterPrivileges) { | ||
| final Map<String, String> headers = Map.of("Authorization", | ||
| UsernamePasswordToken.basicAuthHeaderValue(runAsUser, SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING), | ||
| "es-security-runas-user", user); |
There was a problem hiding this comment.
These seem backwards to me. You authenticate as runAsUser but run-as user.
I assume the parameters are just strangely named, but it probably makes sense to have authenticatingUser and owningUser or something like that.
There was a problem hiding this comment.
Good point. It does read awkward. Updated.
| private void createUserWithRunAsRole() throws ExecutionException, InterruptedException { | ||
| final PutUserRequest putUserRequest = new PutUserRequest(); | ||
| putUserRequest.username("user_with_run_as_role"); | ||
| putUserRequest.roles("run_as_role"); | ||
| putUserRequest.passwordHash(SecuritySettingsSource.TEST_PASSWORD_HASHED.toCharArray()); | ||
| PlainActionFuture<PutUserResponse> listener = new PlainActionFuture<>(); | ||
| final Client client = client().filterWithHeader(Map.of("Authorization", | ||
| UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_SUPERUSER, | ||
| SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING))); | ||
| client.execute(PutUserAction.INSTANCE, putUserRequest, listener); | ||
| final PutUserResponse putUserResponse = listener.get(); | ||
| assertTrue(putUserResponse.created()); | ||
| } |
There was a problem hiding this comment.
Can we add that explanation to the code?
When user A runs as user B and performs any API key related operations, user B's realm should always be used to associate with the API key. Currently user A's realm is used when getting or invalidating API keys and owner=true. The PR is to fix this bug. resolves: elastic#51975
When user A runs as user B and performs any API key related operations, user B's realm should always be used to associate with the API key. Currently user A's realm is used when getting or invalidating API keys and owner=true. The PR is to fix this bug. resolves: #51975
|
Backported: |
Avoid string comparison when we can use safter enums. This refactor is a follow up for elastic#52178. Resolves: elastic#52511
When user A run as user B and perform any API key related operations,
user B's realm should always be used to associate with the API key.
Currently user A's realm is used when getting or invalidating API keys
and
owner=true. The PR is to fix this bug.resolves: #51975