|
17 | 17 | import org.elasticsearch.common.util.CollectionUtils; |
18 | 18 | import org.elasticsearch.common.util.concurrent.ThreadContext; |
19 | 19 | import org.elasticsearch.common.util.set.Sets; |
| 20 | +import org.elasticsearch.core.Tuple; |
20 | 21 | import org.elasticsearch.env.Environment; |
21 | 22 | import org.elasticsearch.env.TestEnvironment; |
22 | 23 | import org.elasticsearch.license.License; |
@@ -125,16 +126,7 @@ public void init() throws Exception { |
125 | 126 |
|
126 | 127 | threadContext = new ThreadContext(Settings.EMPTY); |
127 | 128 |
|
128 | | - ThreadPool threadPool = mock(ThreadPool.class); |
129 | | - when(threadPool.getThreadContext()).thenReturn(threadContext); |
130 | | - |
131 | | - reservedRealm = new ReservedRealm( |
132 | | - mock(Environment.class), |
133 | | - Settings.EMPTY, |
134 | | - mock(NativeUsersStore.class), |
135 | | - new AnonymousUser(Settings.EMPTY), |
136 | | - threadPool |
137 | | - ); |
| 129 | + reservedRealm = buildReservedRealm(); |
138 | 130 | allowAllRealms(); |
139 | 131 | } |
140 | 132 |
|
@@ -408,27 +400,6 @@ public void testRealmAssignedToMultipleDomainsNotPermitted() { |
408 | 400 | ); |
409 | 401 | } |
410 | 402 |
|
411 | | - public void testReservedRealmIsAlwaysDomainless() throws Exception { |
412 | | - int realmId = randomIntBetween(0, randomRealmTypesCount - 1); |
413 | | - Settings settings = Settings.builder() |
414 | | - .put("xpack.security.authc.realms.type_" + realmId + ".reserved.order", 2) |
415 | | - .put("xpack.security.authc.domains.domain_reserved.realms", "reserved") |
416 | | - .put("xpack.security.authc.realms." + NativeRealmSettings.TYPE + ".disabled_native.enabled", false) |
417 | | - .put("xpack.security.authc.realms." + FileRealmSettings.TYPE + ".disabled_file.enabled", false) |
418 | | - .put("path.home", createTempDir()) |
419 | | - .build(); |
420 | | - Environment env = TestEnvironment.newEnvironment(settings); |
421 | | - Realms realms = new Realms(settings, env, factories, licenseState, threadContext, reservedRealm); |
422 | | - Iterator<Realm> iterator = realms.iterator(); |
423 | | - assertThat(iterator.hasNext(), is(true)); |
424 | | - Realm realm = iterator.next(); |
425 | | - assertThat(realm, is(reservedRealm)); |
426 | | - realm = iterator.next(); |
427 | | - assertThat(realm.type(), is("type_" + realmId)); |
428 | | - assertThat(realm.name(), is("reserved")); |
429 | | - assertThat(realm.realmRef().getDomain().name(), is("domain_reserved")); |
430 | | - } |
431 | | - |
432 | 403 | public void testDomainWithUndefinedRealms() { |
433 | 404 | Settings settings = Settings.builder() |
434 | 405 | .put("xpack.security.authc.domains.test_domain.realms", "reserved, default_file") |
@@ -1097,6 +1068,147 @@ public void testWarningsForReservedPrefixedRealmNames() throws Exception { |
1097 | 1068 | ); |
1098 | 1069 | } |
1099 | 1070 |
|
| 1071 | + public void testExplicitlyConfiguredRealmNamesMustNotClashWithDefaultRealmNames() throws Exception { |
| 1072 | + final Tuple<String, String> defaultRealm = randomFrom( |
| 1073 | + new Tuple<>("reserved", "reserved"), |
| 1074 | + new Tuple<>("file", "default_file"), |
| 1075 | + new Tuple<>("native", "default_native") |
| 1076 | + ); |
| 1077 | + |
| 1078 | + final String configuredRealmType = randomValueOtherThan(defaultRealm.v1(), () -> randomAlphaOfLengthBetween(3, 18)); |
| 1079 | + factories.put(configuredRealmType, DummyRealm::new); |
| 1080 | + final String realmSettingKey = "xpack.security.authc.realms." + configuredRealmType + "." + defaultRealm.v2(); |
| 1081 | + |
| 1082 | + // The name of an explicitly configured realm must not be either default_native, default_file or "reserved" |
| 1083 | + final Settings settings1 = Settings.builder() |
| 1084 | + .put("path.home", createTempDir()) |
| 1085 | + .put(realmSettingKey + ".order", randomInt()) |
| 1086 | + .build(); |
| 1087 | + final IllegalArgumentException e1 = expectThrows( |
| 1088 | + IllegalArgumentException.class, |
| 1089 | + () -> new Realms( |
| 1090 | + settings1, |
| 1091 | + TestEnvironment.newEnvironment(settings1), |
| 1092 | + factories, |
| 1093 | + licenseState, |
| 1094 | + threadContext, |
| 1095 | + buildReservedRealm() |
| 1096 | + ) |
| 1097 | + ); |
| 1098 | + assertThat( |
| 1099 | + e1.getMessage(), |
| 1100 | + containsString( |
| 1101 | + "Found realm configured with name clashing with the [" + defaultRealm.v2() + "] realm: [" + realmSettingKey + "]" |
| 1102 | + ) |
| 1103 | + ); |
| 1104 | + |
| 1105 | + // It is OK if the explicitly configured realm is disabled |
| 1106 | + final Settings settings2 = Settings.builder() |
| 1107 | + .put("path.home", createTempDir()) |
| 1108 | + .put(realmSettingKey + ".order", randomInt()) |
| 1109 | + .put(realmSettingKey + ".enabled", false) |
| 1110 | + .build(); |
| 1111 | + final Realms realms2 = new Realms( |
| 1112 | + settings2, |
| 1113 | + TestEnvironment.newEnvironment(settings2), |
| 1114 | + factories, |
| 1115 | + licenseState, |
| 1116 | + threadContext, |
| 1117 | + buildReservedRealm() |
| 1118 | + ); |
| 1119 | + assertThat(realms2.getActiveRealms().stream().map(Realm::type).toList(), containsInAnyOrder("reserved", "file", "native")); |
| 1120 | + |
| 1121 | + // This block of tests do not apply to reserved realm since it is not configurable |
| 1122 | + if ("file".equals(defaultRealm.v1()) || "native".equals(defaultRealm.v1())) { |
| 1123 | + final String autoEnabledRealmType = "file".equals(defaultRealm.v1()) ? "native" : "file"; |
| 1124 | + |
| 1125 | + // It is OK if the default file or native realm is disabled |
| 1126 | + final Settings settings3 = Settings.builder() |
| 1127 | + .put("path.home", createTempDir()) |
| 1128 | + .put(realmSettingKey + ".order", randomInt()) |
| 1129 | + .put("xpack.security.authc.realms." + defaultRealm.v1() + "." + randomAlphaOfLengthBetween(3, 18) + ".enabled", false) |
| 1130 | + .build(); |
| 1131 | + final Realms realms3 = new Realms( |
| 1132 | + settings3, |
| 1133 | + TestEnvironment.newEnvironment(settings3), |
| 1134 | + factories, |
| 1135 | + licenseState, |
| 1136 | + threadContext, |
| 1137 | + buildReservedRealm() |
| 1138 | + ); |
| 1139 | + assertThat( |
| 1140 | + realms3.getActiveRealms().stream().map(Realm::type).toList(), |
| 1141 | + containsInAnyOrder("reserved", configuredRealmType, autoEnabledRealmType) |
| 1142 | + ); |
| 1143 | + |
| 1144 | + // It is OK if file or native realm is named something else |
| 1145 | + final Settings settings4 = Settings.builder() |
| 1146 | + .put("path.home", createTempDir()) |
| 1147 | + .put(realmSettingKey + ".order", randomInt()) |
| 1148 | + .put("xpack.security.authc.realms." + defaultRealm.v1() + "." + randomAlphaOfLengthBetween(3, 18) + ".order", randomInt()) |
| 1149 | + .build(); |
| 1150 | + final Realms realms4 = new Realms( |
| 1151 | + settings4, |
| 1152 | + TestEnvironment.newEnvironment(settings4), |
| 1153 | + factories, |
| 1154 | + licenseState, |
| 1155 | + threadContext, |
| 1156 | + buildReservedRealm() |
| 1157 | + ); |
| 1158 | + assertThat( |
| 1159 | + realms4.getActiveRealms().stream().map(Realm::type).toList(), |
| 1160 | + containsInAnyOrder("reserved", configuredRealmType, "file", "native") |
| 1161 | + ); |
| 1162 | + |
| 1163 | + // All explicitly configured realm names still must be unique |
| 1164 | + final Settings settings5 = Settings.builder() |
| 1165 | + .put("path.home", createTempDir()) |
| 1166 | + .put(realmSettingKey + ".order", randomInt()) |
| 1167 | + .put("xpack.security.authc.realms." + defaultRealm.v1() + "." + defaultRealm.v2() + ".order", randomInt()) |
| 1168 | + .build(); |
| 1169 | + final IllegalArgumentException e5 = expectThrows( |
| 1170 | + IllegalArgumentException.class, |
| 1171 | + () -> new Realms( |
| 1172 | + settings5, |
| 1173 | + TestEnvironment.newEnvironment(settings5), |
| 1174 | + factories, |
| 1175 | + licenseState, |
| 1176 | + threadContext, |
| 1177 | + buildReservedRealm() |
| 1178 | + ) |
| 1179 | + ); |
| 1180 | + assertThat(e5.getMessage(), containsString("Found multiple realms configured with the same name")); |
| 1181 | + } |
| 1182 | + |
| 1183 | + // It is OK to explicitly configure file to be default_file and native to be default_native |
| 1184 | + final Settings settings6 = Settings.builder() |
| 1185 | + .put("path.home", createTempDir()) |
| 1186 | + .put("xpack.security.authc.realms.file.default_file.order", randomInt()) |
| 1187 | + .put("xpack.security.authc.realms.native.default_native.order", randomInt()) |
| 1188 | + .build(); |
| 1189 | + final Realms realms6 = new Realms( |
| 1190 | + settings6, |
| 1191 | + TestEnvironment.newEnvironment(settings6), |
| 1192 | + factories, |
| 1193 | + licenseState, |
| 1194 | + threadContext, |
| 1195 | + buildReservedRealm() |
| 1196 | + ); |
| 1197 | + assertThat(realms6.getActiveRealms().stream().map(Realm::type).toList(), containsInAnyOrder("reserved", "file", "native")); |
| 1198 | + } |
| 1199 | + |
| 1200 | + private ReservedRealm buildReservedRealm() { |
| 1201 | + final ThreadPool threadPool = mock(ThreadPool.class); |
| 1202 | + when(threadPool.getThreadContext()).thenReturn(threadContext); |
| 1203 | + return new ReservedRealm( |
| 1204 | + mock(Environment.class), |
| 1205 | + Settings.EMPTY, |
| 1206 | + mock(NativeUsersStore.class), |
| 1207 | + new AnonymousUser(Settings.EMPTY), |
| 1208 | + threadPool |
| 1209 | + ); |
| 1210 | + } |
| 1211 | + |
1100 | 1212 | private boolean randomDisableRealm(Settings.Builder builder, String type) { |
1101 | 1213 | final boolean disabled = randomBoolean(); |
1102 | 1214 | if (disabled) { |
|
0 commit comments