Skip to content

Commit 009ae48

Browse files
authored
[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.
1 parent 724438a commit 009ae48

File tree

7 files changed

+15
-6
lines changed

7 files changed

+15
-6
lines changed

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public PkiRealm(RealmConfig config, ResourceWatcherService watcherService, Nativ
8686
this.trustManager = trustManagers(config);
8787
this.principalPattern = PkiRealmSettings.USERNAME_PATTERN_SETTING.get(config.settings());
8888
this.roleMapper = roleMapper;
89+
this.roleMapper.refreshRealmOnChange(this);
8990
this.cache = CacheBuilder.<BytesKey, User>builder()
9091
.setExpireAfterWrite(PkiRealmSettings.CACHE_TTL_SETTING.get(config.settings()))
9192
.setMaximumWeight(PkiRealmSettings.CACHE_MAX_USERS_SETTING.get(config.settings()))

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingRealm.java

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
*/
1414
public interface CachingRealm {
1515

16+
/**
17+
* @return The name of this realm.
18+
*/
19+
String name();
20+
1621
/**
1722
* Expires a single user from the cache identified by the String agument
1823
* @param username the identifier of the user to be cleared

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DnRoleMapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public DnRoleMapper(RealmConfig config, ResourceWatcherService watcherService) {
6969
}
7070

7171
@Override
72-
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
72+
public void refreshRealmOnChange(CachingRealm realm) {
7373
addListener(realm::expireAll);
7474
}
7575

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/UserRoleMapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public interface UserRoleMapper {
4444
* the whole cluster depending on whether this role-mapper has node-local data or cluster-wide
4545
* data.
4646
*/
47-
void refreshRealmOnChange(CachingUsernamePasswordRealm realm);
47+
void refreshRealmOnChange(CachingRealm realm);
4848

4949
/**
5050
* A representation of a user for whom roles should be mapped.

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/CompositeRoleMapper.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import org.elasticsearch.action.support.GroupedActionListener;
1717
import org.elasticsearch.watcher.ResourceWatcherService;
1818
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
19-
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
19+
import org.elasticsearch.xpack.security.authc.support.CachingRealm;
2020
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
2121
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
2222

@@ -48,7 +48,7 @@ public void resolveRoles(UserData user, ActionListener<Set<String>> listener) {
4848
}
4949

5050
@Override
51-
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
51+
public void refreshRealmOnChange(CachingRealm realm) {
5252
this.delegates.forEach(mapper -> mapper.refreshRealmOnChange(realm));
5353
}
5454

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import org.elasticsearch.xpack.core.security.authc.support.mapper.ExpressionRoleMapping;
3535
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExpressionModel;
3636
import org.elasticsearch.xpack.core.security.client.SecurityClient;
37-
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
37+
import org.elasticsearch.xpack.security.authc.support.CachingRealm;
3838
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
3939
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
4040

@@ -369,7 +369,7 @@ public void resolveRoles(UserData user, ActionListener<Set<String>> listener) {
369369
* @see ClearRealmCacheAction
370370
*/
371371
@Override
372-
public void refreshRealmOnChange(CachingUsernamePasswordRealm realm) {
372+
public void refreshRealmOnChange(CachingRealm realm) {
373373
realmsToRefresh.add(realm.name());
374374
}
375375
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import static org.mockito.Mockito.mock;
5151
import static org.mockito.Mockito.times;
5252
import static org.mockito.Mockito.verify;
53+
import static org.mockito.Mockito.verifyNoMoreInteractions;
5354
import static org.mockito.Mockito.when;
5455

5556
public class PkiRealmTests extends ESTestCase {
@@ -104,6 +105,7 @@ private void assertSuccessfulAuthentication(Set<String> roles) throws Exception
104105
UserRoleMapper roleMapper = mock(UserRoleMapper.class);
105106
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings, TestEnvironment.newEnvironment(globalSettings),
106107
new ThreadContext(globalSettings)), roleMapper);
108+
verify(roleMapper).refreshRealmOnChange(realm);
107109
Mockito.doAnswer(invocation -> {
108110
final UserRoleMapper.UserData userData = (UserRoleMapper.UserData) invocation.getArguments()[0];
109111
final ActionListener<Set<String>> listener = (ActionListener<Set<String>>) invocation.getArguments()[1];
@@ -144,6 +146,7 @@ private void assertSuccessfulAuthentication(Set<String> roles) throws Exception
144146

145147
final int numTimes = invalidate ? 2 : 1;
146148
verify(roleMapper, times(numTimes)).resolveRoles(any(UserRoleMapper.UserData.class), any(ActionListener.class));
149+
verifyNoMoreInteractions(roleMapper);
147150
}
148151

149152
public void testCustomUsernamePattern() throws Exception {

0 commit comments

Comments
 (0)