-
Notifications
You must be signed in to change notification settings - Fork 24.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Respect runas realm for ApiKey security operations #52178
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a test when the owned
flag is not set, but the username
and realm
are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add that explanation to the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
There were some sloppiness in the last change. Thanks @albertzaharovits for catching them. It is now updated accordingly. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
...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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add that explanation to the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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