Skip to content

Commit 970496f

Browse files
committed
fixup! Add unit tests
1 parent d2eeabe commit 970496f

File tree

2 files changed

+159
-2
lines changed

2 files changed

+159
-2
lines changed

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/CrossClusterApiKeySignerReloader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* Responsible for reloading a provided {@link CrossClusterApiKeySigner} when updates are received from the following sources:
4040
* - Dynamic cluster settings
4141
* - Reloadable secure settings
42-
* - File content changes in any of the files pointed to by the cluster settings
42+
* - File changes in any of the files pointed to by the cluster settings
4343
*/
4444
public final class CrossClusterApiKeySignerReloader implements ReloadableSecurityComponent {
4545

@@ -55,7 +55,7 @@ public CrossClusterApiKeySignerReloader(
5555
this.apiKeySigner = apiKeySigner;
5656
clusterSettings.addAffixGroupUpdateConsumer(getDynamicSettings(), (key, val) -> {
5757
apiKeySigner.loadSigningConfig(key, val.getByPrefix(RemoteClusterSettings.REMOTE_CLUSTER_SETTINGS_PREFIX + key + "."), false);
58-
logger.info("Updated signing configuration for [{}] due to update of cluster settings [{}]", key, val);
58+
logger.info("Updated signing configuration for [{}] due to updated cluster settings", key);
5959
watchDependentFilesForClusterAliases(
6060
apiKeySigner::reloadSigningConfigs,
6161
resourceWatcherService,
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
package org.elasticsearch.xpack.security.transport;
8+
9+
import org.elasticsearch.common.settings.ClusterSettings;
10+
import org.elasticsearch.common.settings.MockSecureSettings;
11+
import org.elasticsearch.common.settings.Settings;
12+
import org.elasticsearch.core.TimeValue;
13+
import org.elasticsearch.test.ESTestCase;
14+
import org.elasticsearch.threadpool.TestThreadPool;
15+
import org.elasticsearch.threadpool.ThreadPool;
16+
import org.elasticsearch.watcher.ResourceWatcherService;
17+
import org.junit.After;
18+
19+
import java.io.IOException;
20+
import java.nio.file.Files;
21+
import java.util.HashSet;
22+
import java.util.Map;
23+
import java.util.Set;
24+
25+
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.ArgumentMatchers.anyBoolean;
27+
import static org.mockito.ArgumentMatchers.anyString;
28+
import static org.mockito.Mockito.mock;
29+
import static org.mockito.Mockito.times;
30+
import static org.mockito.Mockito.verify;
31+
import static org.mockito.Mockito.when;
32+
33+
public class CrossClusterApiKeySignerReloaderTests extends ESTestCase {
34+
private CrossClusterApiKeySigner crossClusterApiKeySigner;
35+
private ResourceWatcherService resourceWatcherService;
36+
private ThreadPool threadPool;
37+
38+
@Override
39+
public void setUp() throws Exception {
40+
super.setUp();
41+
crossClusterApiKeySigner = mock(CrossClusterApiKeySigner.class);
42+
Settings settings = Settings.builder().put("resource.reload.interval.high", TimeValue.timeValueMillis(100)).build();
43+
threadPool = new TestThreadPool(getTestName());
44+
resourceWatcherService = new ResourceWatcherService(settings, threadPool);
45+
}
46+
47+
public void testSimpleDynamicSettingsUpdate() throws IOException {
48+
Settings settings = Settings.builder().put("cluster.remote.my_remote.signing.keystore.alias", "mykey").build();
49+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of());
50+
var clusterSettings = new ClusterSettings(settings, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
51+
52+
new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
53+
clusterSettings.applySettings(Settings.builder().put("cluster.remote.my_remote.signing.keystore.alias", "anotherkey").build());
54+
verify(crossClusterApiKeySigner).loadSigningConfig(
55+
"my_remote",
56+
Settings.builder()
57+
.put("cluster.remote.my_remote.signing.keystore.alias", "anotherkey")
58+
.build()
59+
.getByPrefix("cluster.remote.my_remote."),
60+
false
61+
);
62+
verify(crossClusterApiKeySigner, times(2)).getDependentFilesToClusterAliases();
63+
}
64+
65+
public void testDynamicSettingsUpdateWithAddedFile() throws Exception {
66+
var fileToMonitor = createTempFile();
67+
Settings settings = Settings.builder().put("cluster.remote.my_remote.signing.keystore.alias", "mykey").build();
68+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of())
69+
.thenReturn(Map.of(fileToMonitor, Set.of("my_remote")));
70+
71+
var clusterSettings = new ClusterSettings(settings, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
72+
new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
73+
74+
clusterSettings.applySettings(
75+
Settings.builder()
76+
.put("cluster.remote.my_remote.signing.keystore.alias", "mykey")
77+
.put("cluster.remote.my_remote.signing.keystore.path", fileToMonitor)
78+
.build()
79+
);
80+
81+
verify(crossClusterApiKeySigner).loadSigningConfig(
82+
"my_remote",
83+
Settings.builder()
84+
.put("cluster.remote.my_remote.signing.keystore.alias", "mykey")
85+
.put("cluster.remote.my_remote.signing.keystore.path", fileToMonitor)
86+
.build()
87+
.getByPrefix("cluster.remote.my_remote."),
88+
false
89+
);
90+
verify(crossClusterApiKeySigner, times(2)).getDependentFilesToClusterAliases();
91+
verify(crossClusterApiKeySigner, times(0)).reloadSigningConfigs(Set.of("my_remote"));
92+
Files.writeString(fileToMonitor, "some content");
93+
assertBusy(() -> verify(crossClusterApiKeySigner, times(1)).reloadSigningConfigs(Set.of("my_remote")));
94+
}
95+
96+
public void testSimpleSecureSettingsReload() {
97+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of());
98+
var clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
99+
var reloader = new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
100+
101+
MockSecureSettings secureSettings = new MockSecureSettings();
102+
secureSettings.setString("cluster.remote.my_remote.signing.keystore.secure_password", "secret");
103+
Settings settings = Settings.builder().setSecureSettings(secureSettings).build();
104+
reloader.reload(settings);
105+
106+
verify(crossClusterApiKeySigner).loadSigningConfig("my_remote", settings.getByPrefix("cluster.remote.my_remote."), true);
107+
verify(crossClusterApiKeySigner, times(1)).getDependentFilesToClusterAliases();
108+
}
109+
110+
public void testSecureSettingsReloadNoMatchingSecureSettings() {
111+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of());
112+
var clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
113+
var reloader = new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
114+
115+
MockSecureSettings secureSettings = new MockSecureSettings();
116+
secureSettings.setString("not.a.setting", "secret");
117+
Settings settings = Settings.builder().setSecureSettings(secureSettings).build();
118+
reloader.reload(settings);
119+
120+
verify(crossClusterApiKeySigner, times(0)).loadSigningConfig(any(), any(), anyBoolean());
121+
verify(crossClusterApiKeySigner, times(1)).getDependentFilesToClusterAliases();
122+
}
123+
124+
public void testFileUpdatedReloaded() throws Exception {
125+
var fileToMonitor = createTempFile();
126+
Settings settings = Settings.builder().put("cluster.remote.my_remote.signing.keystore.path", fileToMonitor).build();
127+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of(fileToMonitor, Set.of("my_remote")));
128+
129+
var clusterSettings = new ClusterSettings(settings, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
130+
new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
131+
132+
verify(crossClusterApiKeySigner, times(0)).loadSigningConfig(anyString(), any(), anyBoolean());
133+
verify(crossClusterApiKeySigner, times(1)).getDependentFilesToClusterAliases();
134+
Files.writeString(fileToMonitor, "some content");
135+
assertBusy(() -> verify(crossClusterApiKeySigner, times(1)).reloadSigningConfigs(Set.of("my_remote")));
136+
}
137+
138+
public void testFileDeletedReloaded() throws Exception {
139+
var fileToMonitor = createTempFile();
140+
Settings settings = Settings.builder().put("cluster.remote.my_remote.signing.keystore.path", fileToMonitor).build();
141+
when(crossClusterApiKeySigner.getDependentFilesToClusterAliases()).thenReturn(Map.of(fileToMonitor, Set.of("my_remote")));
142+
143+
var clusterSettings = new ClusterSettings(settings, new HashSet<>(CrossClusterApiKeySignerSettings.getDynamicSettings()));
144+
new CrossClusterApiKeySignerReloader(resourceWatcherService, clusterSettings, crossClusterApiKeySigner);
145+
146+
verify(crossClusterApiKeySigner, times(0)).loadSigningConfig(anyString(), any(), anyBoolean());
147+
verify(crossClusterApiKeySigner, times(1)).getDependentFilesToClusterAliases();
148+
Files.delete(fileToMonitor);
149+
assertBusy(() -> verify(crossClusterApiKeySigner, times(1)).reloadSigningConfigs(Set.of("my_remote")));
150+
}
151+
152+
@After
153+
public void tearDownThreadPool() {
154+
terminate(threadPool);
155+
}
156+
157+
}

0 commit comments

Comments
 (0)