1414import org .elasticsearch .action .fieldcaps .FieldCapabilitiesRequest ;
1515import org .elasticsearch .action .search .SearchRequest ;
1616import org .elasticsearch .action .support .IndicesOptions ;
17+ import org .elasticsearch .cluster .metadata .AliasMetaData ;
1718import org .elasticsearch .cluster .metadata .AliasOrIndex ;
1819import org .elasticsearch .cluster .metadata .IndexMetaData ;
1920import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
2021import org .elasticsearch .cluster .metadata .MetaData ;
2122import org .elasticsearch .cluster .service .ClusterService ;
23+ import org .elasticsearch .common .Strings ;
24+ import org .elasticsearch .common .collect .ImmutableOpenMap ;
2225import org .elasticsearch .common .regex .Regex ;
2326import org .elasticsearch .common .settings .ClusterSettings ;
2427import org .elasticsearch .common .settings .Settings ;
3538import java .util .HashSet ;
3639import java .util .List ;
3740import java .util .Map ;
41+ import java .util .Optional ;
3842import java .util .Set ;
3943import java .util .SortedMap ;
4044import java .util .concurrent .CopyOnWriteArraySet ;
4145import java .util .stream .Collectors ;
4246
4347import static org .elasticsearch .xpack .core .security .authz .IndicesAndAliasesResolverField .NO_INDEX_PLACEHOLDER ;
4448
45- public class IndicesAndAliasesResolver {
49+ class IndicesAndAliasesResolver {
4650
4751 //`*,-*` what we replace indices with if we need Elasticsearch to return empty responses without throwing exception
4852 private static final String [] NO_INDICES_ARRAY = new String [] { "*" , "-*" };
@@ -51,7 +55,7 @@ public class IndicesAndAliasesResolver {
5155 private final IndexNameExpressionResolver nameExpressionResolver ;
5256 private final RemoteClusterResolver remoteClusterResolver ;
5357
54- public IndicesAndAliasesResolver (Settings settings , ClusterService clusterService ) {
58+ IndicesAndAliasesResolver (Settings settings , ClusterService clusterService ) {
5559 this .nameExpressionResolver = new IndexNameExpressionResolver (settings );
5660 this .remoteClusterResolver = new RemoteClusterResolver (settings , clusterService .getClusterSettings ());
5761 }
@@ -85,7 +89,7 @@ public IndicesAndAliasesResolver(Settings settings, ClusterService clusterServic
8589 * Otherwise, <em>N</em> will be added to the <em>local</em> index list.
8690 */
8791
88- public ResolvedIndices resolve (TransportRequest request , MetaData metaData , AuthorizedIndices authorizedIndices ) {
92+ ResolvedIndices resolve (TransportRequest request , MetaData metaData , AuthorizedIndices authorizedIndices ) {
8993 if (request instanceof IndicesAliasesRequest ) {
9094 ResolvedIndices .Builder resolvedIndicesBuilder = new ResolvedIndices .Builder ();
9195 IndicesAliasesRequest indicesAliasesRequest = (IndicesAliasesRequest ) request ;
@@ -116,7 +120,7 @@ ResolvedIndices resolveIndicesAndAliases(IndicesRequest indicesRequest, MetaData
116120 */
117121 assert indicesRequest .indices () == null || indicesRequest .indices ().length == 0
118122 : "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 ));
120124 } else if (indicesRequest instanceof IndicesRequest .Replaceable ) {
121125 IndicesRequest .Replaceable replaceable = (IndicesRequest .Replaceable ) indicesRequest ;
122126 final boolean replaceWildcards = indicesRequest .indicesOptions ().expandWildcardsOpen ()
@@ -213,7 +217,48 @@ ResolvedIndices resolveIndicesAndAliases(IndicesRequest indicesRequest, MetaData
213217 return resolvedIndicesBuilder .build ();
214218 }
215219
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 ) {
217262 return request instanceof SearchRequest || request instanceof FieldCapabilitiesRequest
218263 || request instanceof GraphExploreRequest ;
219264 }
0 commit comments