[PkiRealm] Invalidate cache on role mappings change (#31510)
PkiRealm caches successful authentications and provides ways to invalidate the cache. But in some scenario's the cache was not being invalidated on role mapping change. PkiRealm does not inform role mapper to be notified for cache refresh on role mapping updates. The logic in `TransportClearRealmCacheAction#nodeOperation` which gets invoked for refreshing cache on realms, considers null or empty realm names in the request as clear cache on all realms. When LDAP realm is not present then it clears cache for all realms so it works fine, but when LDAP realm is configured then role mapper sends a request with LDAP realm names and so the cache is cleared only for those realms. This commit resolves the issue by registering PkiRealm with role mapper for cache refresh. PkiRealm implements CachingRealm and as it does not extend CachingUsernamePasswordRealm, have modified the interface method `refreshRealmOnChange` to accept CachingRealm.
This commit is contained in:
parent
724438a0b0
commit
009ae48cba
|
@ -86,6 +86,7 @@ public class PkiRealm extends Realm implements CachingRealm {
|
|||
this.trustManager = trustManagers(config);
|
||||
this.principalPattern = PkiRealmSettings.USERNAME_PATTERN_SETTING.get(config.settings());
|
||||
this.roleMapper = roleMapper;
|
||||
this.roleMapper.refreshRealmOnChange(this);
|
||||
this.cache = CacheBuilder.<BytesKey, User>builder()
|
||||
.setExpireAfterWrite(PkiRealmSettings.CACHE_TTL_SETTING.get(config.settings()))
|
||||
.setMaximumWeight(PkiRealmSettings.CACHE_MAX_USERS_SETTING.get(config.settings()))
|
||||
|
|
|
@ -13,6 +13,11 @@ import org.elasticsearch.xpack.core.security.authc.Realm;
|
|||
*/
|
||||
public interface CachingRealm {
|
||||
|
||||
/**
|
||||
* @return The name of this realm.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Expires a single user from the cache identified by the String agument
|
||||
* @param username the identifier of the user to be cleared
|
||||
|
|
|
@ -69,7 +69,7 @@ public class DnRoleMapper implements UserRoleMapper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
|
||||
public void refreshRealmOnChange(CachingRealm realm) {
|
||||
addListener(realm::expireAll);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public interface UserRoleMapper {
|
|||
* the whole cluster depending on whether this role-mapper has node-local data or cluster-wide
|
||||
* data.
|
||||
*/
|
||||
void refreshRealmOnChange(CachingUsernamePasswordRealm realm);
|
||||
void refreshRealmOnChange(CachingRealm realm);
|
||||
|
||||
/**
|
||||
* A representation of a user for whom roles should be mapped.
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.elasticsearch.action.ActionListener;
|
|||
import org.elasticsearch.action.support.GroupedActionListener;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class CompositeRoleMapper implements UserRoleMapper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
|
||||
public void refreshRealmOnChange(CachingRealm realm) {
|
||||
this.delegates.forEach(mapper -> mapper.refreshRealmOnChange(realm));
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingRe
|
|||
import org.elasticsearch.xpack.core.security.authc.support.mapper.ExpressionRoleMapping;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExpressionModel;
|
||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||
|
||||
|
@ -369,7 +369,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol
|
|||
* @see ClearRealmCacheAction
|
||||
*/
|
||||
@Override
|
||||
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
|
||||
public void refreshRealmOnChange(CachingRealm realm) {
|
||||
realmsToRefresh.add(realm.name());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import static org.mockito.Mockito.any;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class PkiRealmTests extends ESTestCase {
|
||||
|
@ -104,6 +105,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
UserRoleMapper roleMapper = mock(UserRoleMapper.class);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
|
||||
new ThreadContext(globalSettings)), roleMapper);
|
||||
verify(roleMapper).refreshRealmOnChange(realm);
|
||||
Mockito.doAnswer(invocation -> {
|
||||
final UserRoleMapper.UserData userData = (UserRoleMapper.UserData) invocation.getArguments()[0];
|
||||
final ActionListener<Set<String>> listener = (ActionListener<Set<String>>) invocation.getArguments()[1];
|
||||
|
@ -144,6 +146,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
|
||||
final int numTimes = invalidate ? 2 : 1;
|
||||
verify(roleMapper, times(numTimes)).resolveRoles(any(UserRoleMapper.UserData.class), any(ActionListener.class));
|
||||
verifyNoMoreInteractions(roleMapper);
|
||||
}
|
||||
|
||||
public void testCustomUsernamePattern() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue