Uploaded image for project: 'Couchbase Server'
  1. Couchbase Server
  2. MB-46260

FTS - Apply RBAC only for target collections in a multi-collection index

    XMLWordPrintable

Details

    • Improvement
    • Status: Closed
    • Critical
    • Resolution: Fixed
    • Cheshire-Cat
    • Neo, 7.0.2
    • fts
    • 1

    Description

      Today, any query against a multi collection index is authenticated against all the source collections.

      This may not be a very effective model for supporting the multi-tenant capability of the FTS multi-collection index.

      RBAC rules could be slightly changed in this case,

      1 - Blanket query (no target collections in query)

      Authenticate against all source collections in the index definition.

      2 - Collection scoped/targetted query.

      Authenticate against only the target collections in the query.

      (as against all source collections in the index definition before.)

       

      We acknowledge that this is a bit late in the cycle, but the change should be 

      of lesser risk and could a desirable change for making the multi-collection index

      really multi-tenant)

      Tagging Evgeny Makarenko/Keshav Murthy for inputs.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          I have the following collections structure:

           

          b1.s1.c1
          b1.s1.c2
          

          where b1 is bucket, s1 is scope, c1 and c2 are collections

          I have the following user:

           

          name: b1s1c1
          roles: Search Reader [b1:b1s1:b1s1c1]
          

          So, this user can read from collection c1 and cannot read from collection c2.

          I have multi-collection index on b1.s1.c1 and b1.s1.c2:

          {
           "name": "b1s1c1b1s1c2",
           "type": "fulltext-index",
           "params": {
            "doc_config": {
             "docid_prefix_delim": "",
             "docid_regexp": "",
             "mode": "scope.collection.type_field",
             "type_field": "type"
            },
            "mapping": {
             "default_analyzer": "standard",
             "default_datetime_parser": "dateTimeOptional",
             "default_field": "_all",
             "default_mapping": {
              "dynamic": true,
              "enabled": false
             },
             "default_type": "_default",
             "docvalues_dynamic": false,
             "index_dynamic": true,
             "store_dynamic": false,
             "type_field": "_type",
             "types": {
              "b1s1.b1s1c1": {
               "dynamic": true,
               "enabled": true
              },
              "b1s1.b1s1c2": {
               "dynamic": true,
               "enabled": true
              }
             }
            },
            "store": {
             "indexType": "scorch",
             "segmentVersion": 15
            }
           },
           "sourceType": "gocbcore",
           "sourceName": "b1",
           "sourceUUID": "9a487e606d543ac9260c51d187fd7a29",
           "sourceParams": {},
           "planParams": {
            "maxPartitionsPerPIndex": 1024,
            "indexPartitions": 1,
            "numReplicas": 0
           },
           "uuid": "7a766768cf03e582"
          }
          

          The following query fails for both pre and post fix builds:

          curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}}'
          

          with the same reason:

          {
            "message": "Forbidden. User needs one of the following permissions",
            "permissions": [
              "cluster.collection[b1:b1s1:b1s1c2].fts!read"
            ]
          }
          

          This is what I'm expecting to see

          If I'm using targeted query:

          curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["b1.s1.c1"]}'
          

          or

          curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["c1"]}'
          

          or even

          curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["default:b1.s1.c1"]}'
          

          both, pre and post fix builds return this:

          {
            "status": {
              "total": 1,
              "failed": 0,
              "successful": 1
            },
            "request": {
              "query": {
                "query": "click:to edit"
              },
              "size": 10,
              "from": 0,
              "highlight": null,
              "fields": null,
              "facets": null,
              "explain": false,
              "sort": [
                "-_score"
              ],
              "includeLocations": false,
              "search_after": null,
              "search_before": null
            },
            "hits": [],
            "total_hits": 0,
            "max_score": 0,
            "took": 132155,
            "facets": null
          }
          

          0 hits.

          But if I'm using c1 index (single collection):

          {
           "name": "b1s1c1",
           "type": "fulltext-index",
           "params": {
            "doc_config": {
             "docid_prefix_delim": "",
             "docid_regexp": "",
             "mode": "scope.collection.type_field",
             "type_field": "type"
            },
            "mapping": {
             "default_analyzer": "standard",
             "default_datetime_parser": "dateTimeOptional",
             "default_field": "_all",
             "default_mapping": {
              "dynamic": true,
              "enabled": false
             },
             "default_type": "_default",
             "docvalues_dynamic": false,
             "index_dynamic": true,
             "store_dynamic": false,
             "type_field": "_type",
             "types": {
              "b1s1.b1s1c1": {
               "dynamic": true,
               "enabled": true
              }
             }
            },
            "store": {
             "indexType": "scorch",
             "segmentVersion": 15
            }
           },
           "sourceType": "gocbcore",
           "sourceName": "b1",
           "sourceUUID": "9a487e606d543ac9260c51d187fd7a29",
           "sourceParams": {},
           "planParams": {
            "maxPartitionsPerPIndex": 1024,
            "indexPartitions": 1,
            "numReplicas": 0
           },
           "uuid": "e2254c824c4d6749"
          }
          

          for the following query

          curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/b1s1c1/query -d '{"query": {"query": "click:to edit"}, "collections":["b1.s1.c1"]}'
          

          I'm getting 1 hit, exactly as expected.

          Forgot to mention: all collections including _default have 1 document.

          Pre fix version used: 7.1.0-1000

          Post fix version used: 7.1.0-1138

           

           

          evgeny.makarenko Evgeny Makarenko (Inactive) added a comment - - edited I have the following collections structure:   b1.s1.c1 b1.s1.c2 where b1 is bucket, s1 is scope, c1 and c2 are collections I have the following user:   name: b1s1c1 roles: Search Reader [b1:b1s1:b1s1c1] So, this user can read from collection c1 and cannot read from collection c2. I have multi-collection index on b1.s1.c1 and b1.s1.c2: { "name" : "b1s1c1b1s1c2" , "type" : "fulltext-index" , "params" : { "doc_config" : { "docid_prefix_delim" : "" , "docid_regexp" : "" , "mode" : "scope.collection.type_field" , "type_field" : "type" }, "mapping" : { "default_analyzer" : "standard" , "default_datetime_parser" : "dateTimeOptional" , "default_field" : "_all" , "default_mapping" : { "dynamic" : true , "enabled" : false }, "default_type" : "_default" , "docvalues_dynamic" : false , "index_dynamic" : true , "store_dynamic" : false , "type_field" : "_type" , "types" : { "b1s1.b1s1c1" : { "dynamic" : true , "enabled" : true }, "b1s1.b1s1c2" : { "dynamic" : true , "enabled" : true } } }, "store" : { "indexType" : "scorch" , "segmentVersion" : 15 } }, "sourceType" : "gocbcore" , "sourceName" : "b1" , "sourceUUID" : "9a487e606d543ac9260c51d187fd7a29" , "sourceParams" : {}, "planParams" : { "maxPartitionsPerPIndex" : 1024 , "indexPartitions" : 1 , "numReplicas" : 0 }, "uuid" : "7a766768cf03e582" } The following query fails for both pre and post fix builds: curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}}' with the same reason: { "message" : "Forbidden. User needs one of the following permissions" , "permissions" : [ "cluster.collection[b1:b1s1:b1s1c2].fts!read" ] } This is what I'm expecting to see If I'm using targeted query: curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["b1.s1.c1"]}' or curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["c1"]}' or even curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/b1s1c1b1s1c2/query -d '{"query": {"query": "click:to edit"}, "collections":["default:b1.s1.c1"]}' both, pre and post fix builds return this: { "status" : { "total" : 1 , "failed" : 0 , "successful" : 1 }, "request" : { "query" : { "query" : "click:to edit" }, "size" : 10 , "from" : 0 , "highlight" : null , "fields" : null , "facets" : null , "explain" : false , "sort" : [ "-_score" ], "includeLocations" : false , "search_after" : null , "search_before" : null }, "hits" : [], "total_hits" : 0 , "max_score" : 0 , "took" : 132155 , "facets" : null } 0 hits. But if I'm using c1 index (single collection): { "name" : "b1s1c1" , "type" : "fulltext-index" , "params" : { "doc_config" : { "docid_prefix_delim" : "" , "docid_regexp" : "" , "mode" : "scope.collection.type_field" , "type_field" : "type" }, "mapping" : { "default_analyzer" : "standard" , "default_datetime_parser" : "dateTimeOptional" , "default_field" : "_all" , "default_mapping" : { "dynamic" : true , "enabled" : false }, "default_type" : "_default" , "docvalues_dynamic" : false , "index_dynamic" : true , "store_dynamic" : false , "type_field" : "_type" , "types" : { "b1s1.b1s1c1" : { "dynamic" : true , "enabled" : true } } }, "store" : { "indexType" : "scorch" , "segmentVersion" : 15 } }, "sourceType" : "gocbcore" , "sourceName" : "b1" , "sourceUUID" : "9a487e606d543ac9260c51d187fd7a29" , "sourceParams" : {}, "planParams" : { "maxPartitionsPerPIndex" : 1024 , "indexPartitions" : 1 , "numReplicas" : 0 }, "uuid" : "e2254c824c4d6749" } for the following query curl -XPOST -u b1s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/b1s1c1/query -d '{"query": {"query": "click:to edit"}, "collections":["b1.s1.c1"]}' I'm getting 1 hit, exactly as expected. Forgot to mention: all collections including _default have 1 document. Pre fix version used: 7.1.0-1000 Post fix version used: 7.1.0-1138    

          Evgeny Makarenko I find your comment pretty confusing.

          • Per your index definition - your bucket name is b1, your scope name is b1s1 and your collections are: ["b1s1c1", "b1s1c2"].
          • So when you want to run a collection specific query, you gotta do ..

          {"query": {"query": "edit"}, "collections": ["b1s1c1"]} 

          • None of your queries above align to the name of the collection you've set up.
          abhinav Abhinav Dangeti added a comment - Evgeny Makarenko  I find your comment pretty confusing. Per your index definition - your bucket name is b1, your scope name is b1s1 and your collections are: ["b1s1c1", "b1s1c2"] . So when you want to run a collection specific query, you gotta do .. { "query" : { "query" : "edit" }, "collections" : [ "b1s1c1" ]} None of your queries above align to the name of the collection you've set up.

          Feature works fine for indexes, tested it using lots of different combinations of RBAC roles, indexed collections, collection names specified in fts requests. 

          Though, this feature does not work for aliases.

          I have the following user:

          b1s1c1b2s1c1    Search Reader [b2:s1:b2s1c1] , Search Reader [b1:b1s1:b1s1c1]
          

          he is granted to read from b1s1c1 collection.

          I have 2 single collection indexes for b1s1c1 and b1s1c2 collections respectively:

          {
           "name": "b1s1c1",
           "type": "fulltext-index",
           "params": {
            "doc_config": {
             "docid_prefix_delim": "",
             "docid_regexp": "",
             "mode": "scope.collection.type_field",
             "type_field": "type"
            },
            "mapping": {
             "default_analyzer": "standard",
             "default_datetime_parser": "dateTimeOptional",
             "default_field": "_all",
             "default_mapping": {
              "dynamic": true,
              "enabled": false
             },
             "default_type": "_default",
             "docvalues_dynamic": false,
             "index_dynamic": true,
             "store_dynamic": false,
             "type_field": "_type",
             "types": {
              "b1s1.b1s1c1": {
               "dynamic": true,
               "enabled": true
              }
             }
            },
            "store": {
             "indexType": "scorch",
             "segmentVersion": 15
            }
           },
           "sourceType": "gocbcore",
           "sourceName": "b1",
           "sourceUUID": "9a487e606d543ac9260c51d187fd7a29",
           "sourceParams": {},
           "planParams": {
            "maxPartitionsPerPIndex": 1024,
            "indexPartitions": 1,
            "numReplicas": 0
           },
           "uuid": "e2254c824c4d6749"
          }
          

          {
           "name": "b1s1c2",
           "type": "fulltext-index",
           "params": {
            "doc_config": {
             "docid_prefix_delim": "",
             "docid_regexp": "",
             "mode": "scope.collection.type_field",
             "type_field": "type"
            },
            "mapping": {
             "default_analyzer": "standard",
             "default_datetime_parser": "dateTimeOptional",
             "default_field": "_all",
             "default_mapping": {
              "dynamic": true,
              "enabled": false
             },
             "default_type": "_default",
             "docvalues_dynamic": false,
             "index_dynamic": true,
             "store_dynamic": false,
             "type_field": "_type",
             "types": {
              "b1s1.b1s1c2": {
               "dynamic": true,
               "enabled": true
              }
             }
            },
            "store": {
             "indexType": "scorch",
             "segmentVersion": 15
            }
           },
           "sourceType": "gocbcore",
           "sourceName": "b1",
           "sourceUUID": "9a487e606d543ac9260c51d187fd7a29",
           "sourceParams": {},
           "planParams": {
            "maxPartitionsPerPIndex": 1024,
            "indexPartitions": 1,
            "numReplicas": 0
           },
           "uuid": "3e623a0d491f19e6"
          }
          

          Those 2 indexes are aggregated into the following alias alias_b1b2:

          {
           "name": "alias_b1b2",
           "type": "fulltext-alias",
           "params": {
            "targets": {
             "b1s1c1": {},
             "b1s1c2": {}
            }
           },
           "sourceType": "nil",
           "sourceUUID": "",
           "sourceParams": null,
           "planParams": {},
           "uuid": "e7d7b57a351d14f1"
          }
          

          And the following query

          curl -XPOST -u b1s1c1b2s1c1:password -H "Content-Type: application/json" http://172.23.107.35:8094/api/index/alias_b1b2/query -d '{"query": {"query": "click:to edit"}, "collections":["b1s1c1"]}'
          

          returns RBAC violation error:

          {
            "message": "Forbidden. User needs one of the following permissions",
            "permissions": [
              "cluster.collection[b1:b1s1:b1s1c2].fts!read"
            ]
          }
          

          So, we might consider 2 possibilities: either document that this feature is not supported by index aliases, or implement this support.

           

          evgeny.makarenko Evgeny Makarenko (Inactive) added a comment - Feature works fine for indexes, tested it using lots of different combinations of RBAC roles, indexed collections, collection names specified in fts requests.  Though, this feature does not work for aliases. I have the following user: b1s1c1b2s1c1 Search Reader [b2:s1:b2s1c1] , Search Reader [b1:b1s1:b1s1c1] he is granted to read from  b1s1c1  collection. I have 2 single collection indexes for  b1s1c1 and  b1s1c2  collections respectively: { "name" : "b1s1c1" , "type" : "fulltext-index" , "params" : { "doc_config" : { "docid_prefix_delim" : "" , "docid_regexp" : "" , "mode" : "scope.collection.type_field" , "type_field" : "type" }, "mapping" : { "default_analyzer" : "standard" , "default_datetime_parser" : "dateTimeOptional" , "default_field" : "_all" , "default_mapping" : { "dynamic" : true , "enabled" : false }, "default_type" : "_default" , "docvalues_dynamic" : false , "index_dynamic" : true , "store_dynamic" : false , "type_field" : "_type" , "types" : { "b1s1.b1s1c1" : { "dynamic" : true , "enabled" : true } } }, "store" : { "indexType" : "scorch" , "segmentVersion" : 15 } }, "sourceType" : "gocbcore" , "sourceName" : "b1" , "sourceUUID" : "9a487e606d543ac9260c51d187fd7a29" , "sourceParams" : {}, "planParams" : { "maxPartitionsPerPIndex" : 1024 , "indexPartitions" : 1 , "numReplicas" : 0 }, "uuid" : "e2254c824c4d6749" } { "name" : "b1s1c2" , "type" : "fulltext-index" , "params" : { "doc_config" : { "docid_prefix_delim" : "" , "docid_regexp" : "" , "mode" : "scope.collection.type_field" , "type_field" : "type" }, "mapping" : { "default_analyzer" : "standard" , "default_datetime_parser" : "dateTimeOptional" , "default_field" : "_all" , "default_mapping" : { "dynamic" : true , "enabled" : false }, "default_type" : "_default" , "docvalues_dynamic" : false , "index_dynamic" : true , "store_dynamic" : false , "type_field" : "_type" , "types" : { "b1s1.b1s1c2" : { "dynamic" : true , "enabled" : true } } }, "store" : { "indexType" : "scorch" , "segmentVersion" : 15 } }, "sourceType" : "gocbcore" , "sourceName" : "b1" , "sourceUUID" : "9a487e606d543ac9260c51d187fd7a29" , "sourceParams" : {}, "planParams" : { "maxPartitionsPerPIndex" : 1024 , "indexPartitions" : 1 , "numReplicas" : 0 }, "uuid" : "3e623a0d491f19e6" } Those 2 indexes are aggregated into the following alias alias_b1b2 : { "name" : "alias_b1b2" , "type" : "fulltext-alias" , "params" : { "targets" : { "b1s1c1" : {}, "b1s1c2" : {} } }, "sourceType" : "nil" , "sourceUUID" : "" , "sourceParams" : null , "planParams" : {}, "uuid" : "e7d7b57a351d14f1" } And the following query curl -XPOST -u b1s1c1b2s1c1:password -H "Content-Type: application/json" http: //172.23.107.35:8094/api/index/alias_b1b2/query -d '{"query": {"query": "click:to edit"}, "collections":["b1s1c1"]}' returns RBAC violation error: { "message" : "Forbidden. User needs one of the following permissions" , "permissions" : [ "cluster.collection[b1:b1s1:b1s1c2].fts!read" ] } So, we might consider 2 possibilities: either document that this feature is not supported by index aliases, or implement this support.  

          Ya .. don't think we'll want to support the "collections" specific queries for index aliases, as index aliases can transcend scopes and buckets.

          Best document this for now.

          abhinav Abhinav Dangeti added a comment - Ya .. don't think we'll want to support the "collections" specific queries for index aliases, as index aliases can transcend scopes and buckets. Best document this for now.

          Tested for both 7.1.0-1138 and 7.0.1-6008

          evgeny.makarenko Evgeny Makarenko (Inactive) added a comment - Tested for both 7.1.0-1138 and 7.0.1-6008

          People

            evgeny.makarenko Evgeny Makarenko (Inactive)
            Sreekanth Sivasankaran Sreekanth Sivasankaran
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                PagerDuty