---
setup:
  - requires:
      test_runner_features: ["headers", "allowed_warnings"]
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"

  - do:
      cluster.health:
        wait_for_status: yellow

  - do:
      security.put_role:
        name: "data_stream_role"
        body:  >
          {
            "indices": [
              { "names": ["simple*", "easy*"], "privileges": ["read", "write", "create_index", "view_index_metadata", "monitor", "delete_index"] }
            ]
          }

  - do:
      security.put_role:
        name: "data_stream_role2"
        body:  >
          {
            "indices": [
              { "names": ["matches_none"], "privileges": ["read", "write", "create_index", "view_index_metadata", "monitor", "delete_index"] }
            ]
          }

  - do:
      security.put_role:
        name: "data_stream_ingest_role"
        body:  >
          {
            "indices": [
              { "names": ["create-doc-data-stream*"], "privileges": ["create_doc"] },
              { "names": ["write-data-stream*"], "privileges": ["write"] }
            ]
          }

  - do:
      security.put_user:
        username: "test_user"
        body:  >
          {
            "password" : "x-pack-test-password",
            "roles" : [ "data_stream_role", "data_stream_ingest_role" ],
            "full_name" : "user with privileges on some data streams"
          }

  - do:
      security.put_user:
        username: "no_authz_user"
        body:  >
          {
            "password" : "x-pack-test-password",
            "roles" : [ "data_stream_role2" ],
            "full_name" : "user with privileges on no data streams"
          }

  - do:
      allowed_warnings:
        - "index template [my-template1] has index patterns [s*, easy-data-stream1, create-doc-data-stream1, write-data-stream1] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template1] will take precedence during new index creation"
      indices.put_index_template:
        name: my-template1
        body:
          index_patterns: [s*, easy-data-stream1, create-doc-data-stream1, write-data-stream1]
          template:
            mappings:
              properties:
                '@timestamp':
                  type: date
                'foo':
                  type: keyword
          data_stream: {}

---
teardown:
  - do:
      security.delete_user:
        username: "test_user"
        ignore: 404

  - do:
      security.delete_user:
        username: "test_user2"
        ignore: 404

  - do:
      security.delete_role:
        name: "data_stream_role"
        ignore: 404

  - do:
      security.delete_role:
        name: "data_stream_role2"
        ignore: 404

  - do:
      security.delete_role:
        name: "data_stream_ingest_role"
        ignore: 404

---
"Test backing indices inherit parent data stream privileges":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"
      test_runner_features: ["headers"]

  - do: # superuser
      indices.create_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      index:
        index:  simple-data-stream1
        id:       "1"
        op_type:  create
        body:   { foo: bar, "@timestamp": "2020-12-12" }

  - set: { _seq_no: seqno }
  - set: { _primary_term: primary_term }

  - do: # superuser
      indices.refresh:
        index: simple-data-stream1

  # save the backing index names for later use
  - do:
      indices.get_data_stream:
        name: simple-data-stream1
  - set: { data_streams.0.indices.0.index_name: idx0name }

  # should succeed since the search request is on the data stream itself
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      search:
        rest_total_hits_as_int: true
        index: $idx0name

  - match: { hits.total: 1 }

  # should succeed since the backing index inherits the data stream's privileges
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      search:
        rest_total_hits_as_int: true
        index: $idx0name

  - match: { hits.total: 1 }

  # should succeed since the backing index inherits the data stream's privileges
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  $idx0name
        id: "1"
        if_seq_no: $seqno
        if_primary_term: $primary_term
        op_type:  index
        body:   { foo: bar2, "@timestamp": "2020-12-12" }

  - match: { _version: 2 }

  - do: # superuser
      indices.delete_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

---
"Test that requests not supporting data streams do not include data streams among authorized indices":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"
      test_runner_features: ["headers"]

  - do: # superuser
      indices.create_data_stream:
        name: easy-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.create:
        index: easy-index
        body:
          aliases:
            easy-alias: {}

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.get:
        index: easy*

  - match: {easy-index.aliases.easy-alias: {}}
  - is_false: easy-data-stream1

  - do: # superuser
      indices.delete_data_stream:
        name: easy-data-stream1
  - is_true: acknowledged

---
"Test auto mapping updates unauthorized for create_doc privilege":
  - requires:
      cluster_features: ["gte_v8.0.0"]
      reason: "change to 7.8.99 after backport"

  - do: # superuser
      indices.create_data_stream:
        name: create-doc-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.create_data_stream:
        name: write-data-stream1
  - is_true: acknowledged

# unmapped field on empty data stream
  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  create-doc-data-stream1
        body:   { bar: baz, "@timestamp": "2000-12-12" }

# mapped field does not update the mapping, hence it's authorized
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  create-doc-data-stream1
        body:   { foo: bar, "@timestamp": "2555-12-12" }

  - set: { _seq_no: seqno }
  - set: { _primary_term: primary_term }

# unmapped new field on non-empty data stream with create_doc privilege is not authorized
  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  create-doc-data-stream1
        body:   { bar: baz, "@timestamp": "2000-12-12" }

  # save the backing index names for later use
  - do:
      indices.get_data_stream:
        name: create-doc-data-stream1
  - set: { data_streams.0.indices.0.index_name: idx0name }

# unmapped new field on backing index when update with create_doc privilege is not allowed
  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  $idx0name
        id:       "1"
        op_type:  index
        if_seq_no: $seqno
        if_primary_term: $primary_term
        body:   { foo: bar, bar: baz, "@timestamp": "2333-12-12" }

# unmapped new field when write privilege is allowed
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        id:       "2"
        op_type:  create
        index:  write-data-stream1
        body:   { foo: bar, bar: baz, "@timestamp": "2000-12-12" }

  - set: { _seq_no: seqno }
  - set: { _primary_term: primary_term }

  # save the backing index names for later use
  - do:
      indices.get_data_stream:
        name: write-data-stream1
  - set: { data_streams.0.indices.0.index_name: idx1name }


  # unmapped new field on backing index update when write is allowed
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  $idx1name
        id:       "2"
        op_type:  index
        if_seq_no: $seqno
        if_primary_term: $primary_term
        body:   { new: field, bar: baz, "@timestamp": "2333-12-12" }

  - do: # superuser
      indices.delete_data_stream:
        name: create-doc-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.delete_data_stream:
        name: write-data-stream1
  - is_true: acknowledged

---
"Test that create data stream is limited to authorized namespace":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.create_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.delete_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.create_data_stream:
        name: outside_of_namespace

---
"Test that get data stream is limited to authorized namespace":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"

  - do: # superuser
      indices.create_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.create_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.get_data_stream:
        name: simple-data-stream1

  - length: { data_streams: 1 }
  - match: { data_streams.0.name: simple-data-stream1 }

  - do: # superuser
      indices.get_data_stream:
        name: "*"

  # superuser should be authorized for both data streams
  - length: { data_streams: 2 }
  - match: { data_streams.0.name: s-outside-of-authed-namespace }
  - match: { data_streams.1.name: simple-data-stream1 }

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.get_data_stream:
        name: "*"

  # test_user should be authorized for only one data stream
  - length: { data_streams: 1 }
  - match: { data_streams.0.name: simple-data-stream1 }

  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.get_data_stream:
        name: s-outside-of-authed-namespace

  - do:
      headers: { Authorization: "Basic bm9fYXV0aHpfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # no_authz_user
      indices.get_data_stream: {}

  # no_authz_user should not be authorized for any data streams
  - length: { data_streams: 0 }

  - do: # superuser
      indices.delete_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.delete_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

---
"Test that delete data stream is limited to authorized namespace":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"

  - do: # superuser
      indices.create_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.create_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.delete_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.delete_data_stream:
        name: s-outside-of-authed-namespace

  - do:
      catch: forbidden
      headers: { Authorization: "Basic bm9fYXV0aHpfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # no_authz_user
      indices.delete_data_stream:
        name: simple-data-stream1

  - do: # superuser
      indices.delete_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

---
"Test that data streams stats is limited to authorized namespace":
  - requires:
      cluster_features: ["gte_v8.0.0"]
      reason: "change to 7.8.99 after backport"

  - do: # superuser
      indices.create_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.create_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

  - do: # superuser
      indices.data_streams_stats: {}
  - match: { data_stream_count: 2 }
  - match: { backing_indices: 2 }
  - length: { data_streams: 2 }
  - match: { data_streams.0.data_stream: 'simple-data-stream1' }
  - match: { data_streams.0.backing_indices: 1 }
  - match: { data_streams.0.maximum_timestamp: 0 }
  - match: { data_streams.1.data_stream: 's-outside-of-authed-namespace' }
  - match: { data_streams.1.backing_indices: 1 }
  - match: { data_streams.1.maximum_timestamp: 0 }

  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      indices.data_streams_stats: {}
  - match: { data_stream_count: 1 }
  - match: { backing_indices: 1 }
  - length: { data_streams: 1 }
  - match: { data_streams.0.data_stream: 'simple-data-stream1' }
  - match: { data_streams.0.backing_indices: 1 }
  - match: { data_streams.0.maximum_timestamp: 0 }

  - do:
      headers: { Authorization: "Basic bm9fYXV0aHpfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # no_authz_user
      indices.data_streams_stats: {}
  - match: { data_stream_count: 0 }
  - match: { backing_indices: 0 }
  - length: { data_streams: 0 }

  - do: # superuser
      indices.delete_data_stream:
        name: simple-data-stream1
  - is_true: acknowledged

  - do: # superuser
      indices.delete_data_stream:
        name: s-outside-of-authed-namespace
  - is_true: acknowledged

---
"auto_configure privilege permits auto-create of data streams":
  - requires:
      cluster_features: ["gte_v7.9.0"]
      reason: "data streams available in 7.9+"
      test_runner_features: ["headers", "allowed_warnings"]

  - do:
      allowed_warnings:
        - "index template [my-template1] has index patterns [simple*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template1] will take precedence during new index creation"
      indices.put_index_template:
        name: my-template1
        body:
          index_patterns: [simple*]
          template:
            mappings:
              properties:
                '@timestamp':
                  type: date
          data_stream: {}

  - do:
      security.put_role:
        name: "data_stream_role"
        body:  >
          {
            "indices": [
              { "names": ["simple-allows-auto-configure"], "privileges": ["create_doc", "auto_configure"] },
              { "names": ["simple-data-stream1"], "privileges": ["create_doc"] }
            ]
          }

  - do:
      security.clear_cached_roles:
        name: "data_stream_role"

  # should succeed because test_user is authorized for auto_configure on simple-allows-auto-configure
  - do:
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  simple-allows-auto-configure
        id:       "1"
        op_type:  create
        body:   { foo: bar, "@timestamp": "2020-12-12" }

  # should fail because test_user is not authorized for auto_configure on simple-data-stream1
  - do:
      catch: forbidden
      headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
      index:
        index:  simple-data-stream1
        id:       "1"
        op_type:  create
        body:   { foo: bar, "@timestamp": "2020-12-12" }

  - do: # superuser
      indices.delete_data_stream:
        name: simple-allows-auto-configure
  - is_true: acknowledged
