Password changes are only allowed when the user is currently authenticated by a realm (that permits the password to be changed) and not when authenticated by a bearer token or an API key.
This commit is contained in:
parent
7f21ade924
commit
23af171cf8
|
@ -539,9 +539,12 @@ public class RBACEngine implements AuthorizationEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert realmType != null;
|
assert realmType != null;
|
||||||
// ensure the user was authenticated by a realm that we can change a password for. The native realm is an internal realm and
|
// Ensure that the user is not authenticated with an access token or an API key.
|
||||||
// right now only one can exist in the realm configuration - if this changes we should update this check
|
// Also ensure that the user was authenticated by a realm that we can change a password for. The native realm is an internal realm
|
||||||
return ReservedRealm.TYPE.equals(realmType) || NativeRealmSettings.TYPE.equals(realmType);
|
// and right now only one can exist in the realm configuration - if this changes we should update this check
|
||||||
|
final Authentication.AuthenticationType authType = authentication.getAuthenticationType();
|
||||||
|
return (authType.equals(Authentication.AuthenticationType.REALM)
|
||||||
|
&& (ReservedRealm.TYPE.equals(realmType) || NativeRealmSettings.TYPE.equals(realmType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class RBACAuthorizationInfo implements AuthorizationInfo {
|
static class RBACAuthorizationInfo implements AuthorizationInfo {
|
||||||
|
|
|
@ -102,6 +102,7 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
final String action = changePasswordRequest ? ChangePasswordAction.NAME : AuthenticateAction.NAME;
|
final String action = changePasswordRequest ? ChangePasswordAction.NAME : AuthenticateAction.NAME;
|
||||||
final Authentication authentication = mock(Authentication.class);
|
final Authentication authentication = mock(Authentication.class);
|
||||||
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.REALM);
|
||||||
when(authentication.getUser()).thenReturn(user);
|
when(authentication.getUser()).thenReturn(user);
|
||||||
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
when(authenticatedBy.getType())
|
when(authenticatedBy.getType())
|
||||||
|
@ -125,9 +126,10 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
when(authentication.getUser()).thenReturn(user);
|
when(authentication.getUser()).thenReturn(user);
|
||||||
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
when(authenticatedBy.getType())
|
final String authenticationType = changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealmSettings.TYPE) :
|
||||||
.thenReturn(changePasswordRequest ? randomFrom(ReservedRealm.TYPE, NativeRealmSettings.TYPE) :
|
randomAlphaOfLengthBetween(4, 12);
|
||||||
randomAlphaOfLengthBetween(4, 12));
|
when(authenticatedBy.getType()).thenReturn(authenticationType);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.REALM);
|
||||||
|
|
||||||
assertThat(request, instanceOf(UserRequest.class));
|
assertThat(request, instanceOf(UserRequest.class));
|
||||||
assertFalse(engine.checkSameUserPermissions(action, request, authentication));
|
assertFalse(engine.checkSameUserPermissions(action, request, authentication));
|
||||||
|
@ -180,6 +182,7 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
final Authentication authentication = mock(Authentication.class);
|
final Authentication authentication = mock(Authentication.class);
|
||||||
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
final Authentication.RealmRef lookedUpBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef lookedUpBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.REALM);
|
||||||
when(authentication.getUser()).thenReturn(user);
|
when(authentication.getUser()).thenReturn(user);
|
||||||
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
|
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
|
||||||
|
@ -198,6 +201,7 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
final String action = ChangePasswordAction.NAME;
|
final String action = ChangePasswordAction.NAME;
|
||||||
final Authentication authentication = mock(Authentication.class);
|
final Authentication authentication = mock(Authentication.class);
|
||||||
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.REALM);
|
||||||
when(authentication.getUser()).thenReturn(user);
|
when(authentication.getUser()).thenReturn(user);
|
||||||
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
when(authenticatedBy.getType()).thenReturn(randomFrom(LdapRealmSettings.LDAP_TYPE, FileRealmSettings.TYPE,
|
when(authenticatedBy.getType()).thenReturn(randomFrom(LdapRealmSettings.LDAP_TYPE, FileRealmSettings.TYPE,
|
||||||
|
@ -209,6 +213,47 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
verify(authenticatedBy).getType();
|
verify(authenticatedBy).getType();
|
||||||
verify(authentication).getAuthenticatedBy();
|
verify(authentication).getAuthenticatedBy();
|
||||||
verify(authentication, times(2)).getUser();
|
verify(authentication, times(2)).getUser();
|
||||||
|
verify(authentication).getAuthenticationType();
|
||||||
|
verifyNoMoreInteractions(authenticatedBy, authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSameUserPermissionDoesNotAllowChangePasswordForApiKey() {
|
||||||
|
final User user = new User("joe");
|
||||||
|
final ChangePasswordRequest request = new ChangePasswordRequestBuilder(mock(Client.class)).username(user.principal()).request();
|
||||||
|
final String action = ChangePasswordAction.NAME;
|
||||||
|
final Authentication authentication = mock(Authentication.class);
|
||||||
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getUser()).thenReturn(user);
|
||||||
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.API_KEY);
|
||||||
|
when(authenticatedBy.getType()).thenReturn(ApiKeyService.API_KEY_REALM_TYPE);
|
||||||
|
|
||||||
|
assertThat(request, instanceOf(UserRequest.class));
|
||||||
|
assertFalse(engine.checkSameUserPermissions(action, request, authentication));
|
||||||
|
verify(authenticatedBy).getType();
|
||||||
|
verify(authentication).getAuthenticatedBy();
|
||||||
|
verify(authentication, times(2)).getUser();
|
||||||
|
verify(authentication).getAuthenticationType();
|
||||||
|
verifyNoMoreInteractions(authenticatedBy, authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSameUserPermissionDoesNotAllowChangePasswordForAccessToken() {
|
||||||
|
final User user = new User("joe");
|
||||||
|
final ChangePasswordRequest request = new ChangePasswordRequestBuilder(mock(Client.class)).username(user.principal()).request();
|
||||||
|
final String action = ChangePasswordAction.NAME;
|
||||||
|
final Authentication authentication = mock(Authentication.class);
|
||||||
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getUser()).thenReturn(user);
|
||||||
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.TOKEN);
|
||||||
|
when(authenticatedBy.getType()).thenReturn(NativeRealmSettings.TYPE);
|
||||||
|
|
||||||
|
assertThat(request, instanceOf(UserRequest.class));
|
||||||
|
assertFalse(engine.checkSameUserPermissions(action, request, authentication));
|
||||||
|
verify(authenticatedBy).getType();
|
||||||
|
verify(authentication).getAuthenticatedBy();
|
||||||
|
verify(authentication, times(2)).getUser();
|
||||||
|
verify(authentication).getAuthenticationType();
|
||||||
verifyNoMoreInteractions(authenticatedBy, authentication);
|
verifyNoMoreInteractions(authenticatedBy, authentication);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +265,7 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
final Authentication authentication = mock(Authentication.class);
|
final Authentication authentication = mock(Authentication.class);
|
||||||
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef authenticatedBy = mock(Authentication.RealmRef.class);
|
||||||
final Authentication.RealmRef lookedUpBy = mock(Authentication.RealmRef.class);
|
final Authentication.RealmRef lookedUpBy = mock(Authentication.RealmRef.class);
|
||||||
|
when(authentication.getAuthenticationType()).thenReturn(Authentication.AuthenticationType.REALM);
|
||||||
when(authentication.getUser()).thenReturn(user);
|
when(authentication.getUser()).thenReturn(user);
|
||||||
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
when(authentication.getAuthenticatedBy()).thenReturn(authenticatedBy);
|
||||||
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
|
when(authentication.getLookedUpBy()).thenReturn(lookedUpBy);
|
||||||
|
@ -232,6 +278,7 @@ public class RBACEngineTests extends ESTestCase {
|
||||||
verify(authentication).getLookedUpBy();
|
verify(authentication).getLookedUpBy();
|
||||||
verify(authentication, times(2)).getUser();
|
verify(authentication, times(2)).getUser();
|
||||||
verify(lookedUpBy).getType();
|
verify(lookedUpBy).getType();
|
||||||
|
verify(authentication).getAuthenticationType();
|
||||||
verifyNoMoreInteractions(authentication, lookedUpBy, authenticatedBy);
|
verifyNoMoreInteractions(authentication, lookedUpBy, authenticatedBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
setup:
|
||||||
|
- skip:
|
||||||
|
features: headers
|
||||||
|
- do:
|
||||||
|
cluster.health:
|
||||||
|
wait_for_status: yellow
|
||||||
|
- do:
|
||||||
|
security.put_user:
|
||||||
|
username: "token_joe"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"password": "s3krit",
|
||||||
|
"roles" : [ "token_admin" ]
|
||||||
|
}
|
||||||
|
- do:
|
||||||
|
security.put_role:
|
||||||
|
name: "token_admin"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"cluster": ["manage_token"],
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"names": "*",
|
||||||
|
"privileges": ["all"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
---
|
||||||
|
teardown:
|
||||||
|
- do:
|
||||||
|
security.delete_user:
|
||||||
|
username: "token_joe"
|
||||||
|
ignore: 404
|
||||||
|
- do:
|
||||||
|
security.delete_role:
|
||||||
|
name: "token_admin"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test user changing their password authenticating with token not allowed":
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic dG9rZW5fam9lOnMza3JpdA=="
|
||||||
|
security.get_token:
|
||||||
|
body:
|
||||||
|
grant_type: "password"
|
||||||
|
username: "token_joe"
|
||||||
|
password: "s3krit"
|
||||||
|
|
||||||
|
- match: { type: "Bearer" }
|
||||||
|
- is_true: access_token
|
||||||
|
- set: { access_token: token }
|
||||||
|
- match: { expires_in: 1200 }
|
||||||
|
- is_false: scope
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: Bearer ${token}
|
||||||
|
catch: forbidden
|
||||||
|
security.change_password:
|
||||||
|
username: "joe"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"password" : "s3krit2"
|
||||||
|
}
|
Loading…
Reference in New Issue