14
14
import org .elasticsearch .action .fieldcaps .FieldCapabilitiesRequest ;
15
15
import org .elasticsearch .action .search .SearchRequest ;
16
16
import org .elasticsearch .action .support .IndicesOptions ;
17
+ import org .elasticsearch .cluster .metadata .AliasMetaData ;
17
18
import org .elasticsearch .cluster .metadata .AliasOrIndex ;
18
19
import org .elasticsearch .cluster .metadata .IndexMetaData ;
19
20
import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
20
21
import org .elasticsearch .cluster .metadata .MetaData ;
21
22
import org .elasticsearch .cluster .service .ClusterService ;
23
+ import org .elasticsearch .common .Strings ;
24
+ import org .elasticsearch .common .collect .ImmutableOpenMap ;
22
25
import org .elasticsearch .common .regex .Regex ;
23
26
import org .elasticsearch .common .settings .ClusterSettings ;
24
27
import org .elasticsearch .common .settings .Settings ;
35
38
import java .util .HashSet ;
36
39
import java .util .List ;
37
40
import java .util .Map ;
41
+ import java .util .Optional ;
38
42
import java .util .Set ;
39
43
import java .util .SortedMap ;
40
44
import java .util .concurrent .CopyOnWriteArraySet ;
41
45
import java .util .stream .Collectors ;
42
46
43
47
import static org .elasticsearch .xpack .core .security .authz .IndicesAndAliasesResolverField .NO_INDEX_PLACEHOLDER ;
44
48
45
- public class IndicesAndAliasesResolver {
49
+ class IndicesAndAliasesResolver {
46
50
47
51
//`*,-*` what we replace indices with if we need Elasticsearch to return empty responses without throwing exception
48
52
private static final String [] NO_INDICES_ARRAY = new String [] { "*" , "-*" };
@@ -51,7 +55,7 @@ public class IndicesAndAliasesResolver {
51
55
private final IndexNameExpressionResolver nameExpressionResolver ;
52
56
private final RemoteClusterResolver remoteClusterResolver ;
53
57
54
- public IndicesAndAliasesResolver (Settings settings , ClusterService clusterService ) {
58
+ IndicesAndAliasesResolver (Settings settings , ClusterService clusterService ) {
55
59
this .nameExpressionResolver = new IndexNameExpressionResolver (settings );
56
60
this .remoteClusterResolver = new RemoteClusterResolver (settings , clusterService .getClusterSettings ());
57
61
}
@@ -85,7 +89,7 @@ public IndicesAndAliasesResolver(Settings settings, ClusterService clusterServic
85
89
* Otherwise, <em>N</em> will be added to the <em>local</em> index list.
86
90
*/
87
91
88
- public ResolvedIndices resolve (TransportRequest request , MetaData metaData , AuthorizedIndices authorizedIndices ) {
92
+ ResolvedIndices resolve (TransportRequest request , MetaData metaData , AuthorizedIndices authorizedIndices ) {
89
93
if (request instanceof IndicesAliasesRequest ) {
90
94
ResolvedIndices .Builder resolvedIndicesBuilder = new ResolvedIndices .Builder ();
91
95
IndicesAliasesRequest indicesAliasesRequest = (IndicesAliasesRequest ) request ;
@@ -116,7 +120,7 @@ ResolvedIndices resolveIndicesAndAliases(IndicesRequest indicesRequest, MetaData
116
120
*/
117
121
assert indicesRequest .indices () == null || indicesRequest .indices ().length == 0
118
122
: "indices are: " + Arrays .toString (indicesRequest .indices ()); // Arrays.toString() can handle null values - all good
119
- resolvedIndicesBuilder .addLocal (((PutMappingRequest ) indicesRequest ). getConcreteIndex (). getName ( ));
123
+ resolvedIndicesBuilder .addLocal (getPutMappingIndexOrAlias ((PutMappingRequest ) indicesRequest , authorizedIndices , metaData ));
120
124
} else if (indicesRequest instanceof IndicesRequest .Replaceable ) {
121
125
IndicesRequest .Replaceable replaceable = (IndicesRequest .Replaceable ) indicesRequest ;
122
126
final boolean replaceWildcards = indicesRequest .indicesOptions ().expandWildcardsOpen ()
@@ -213,7 +217,48 @@ ResolvedIndices resolveIndicesAndAliases(IndicesRequest indicesRequest, MetaData
213
217
return resolvedIndicesBuilder .build ();
214
218
}
215
219
216
- public static boolean allowsRemoteIndices (IndicesRequest request ) {
220
+ /**
221
+ * Special handling of the value to authorize for a put mapping request. Dynamic put mapping
222
+ * requests use a concrete index, but we allow permissions to be defined on aliases so if the
223
+ * request's concrete index is not in the list of authorized indices, then we need to look to
224
+ * see if this can be authorized against an alias
225
+ */
226
+ static String getPutMappingIndexOrAlias (PutMappingRequest request , AuthorizedIndices authorizedIndices , MetaData metaData ) {
227
+ final String concreteIndexName = request .getConcreteIndex ().getName ();
228
+ final List <String > authorizedIndicesList = authorizedIndices .get ();
229
+
230
+ // validate that the concrete index exists, otherwise there is no remapping that we could do
231
+ final AliasOrIndex aliasOrIndex = metaData .getAliasAndIndexLookup ().get (concreteIndexName );
232
+ final String resolvedAliasOrIndex ;
233
+ if (aliasOrIndex == null ) {
234
+ resolvedAliasOrIndex = concreteIndexName ;
235
+ } else if (aliasOrIndex .isAlias ()) {
236
+ throw new IllegalStateException ("concrete index [" + concreteIndexName + "] is an alias but should not be" );
237
+ } else if (authorizedIndicesList .contains (concreteIndexName )) {
238
+ // user is authorized to put mappings for this index
239
+ resolvedAliasOrIndex = concreteIndexName ;
240
+ } else {
241
+ // the user is not authorized to put mappings for this index, but could have been
242
+ // authorized for a write using an alias that triggered a dynamic mapping update
243
+ ImmutableOpenMap <String , List <AliasMetaData >> foundAliases =
244
+ metaData .findAliases (Strings .EMPTY_ARRAY , new String [] { concreteIndexName });
245
+ List <AliasMetaData > aliasMetaData = foundAliases .get (concreteIndexName );
246
+ if (aliasMetaData != null ) {
247
+ Optional <String > foundAlias = aliasMetaData .stream ()
248
+ .map (AliasMetaData ::alias )
249
+ .filter (authorizedIndicesList ::contains )
250
+ .filter (aliasName -> metaData .getAliasAndIndexLookup ().get (aliasName ).getIndices ().size () == 1 )
251
+ .findFirst ();
252
+ resolvedAliasOrIndex = foundAlias .orElse (concreteIndexName );
253
+ } else {
254
+ resolvedAliasOrIndex = concreteIndexName ;
255
+ }
256
+ }
257
+
258
+ return resolvedAliasOrIndex ;
259
+ }
260
+
261
+ static boolean allowsRemoteIndices (IndicesRequest request ) {
217
262
return request instanceof SearchRequest || request instanceof FieldCapabilitiesRequest
218
263
|| request instanceof GraphExploreRequest ;
219
264
}
0 commit comments