text: /**
   * This test checks that authentication restrictions can be set and respected.
   * @tags: [requires_sharding, requires_replication]
   */
  
  (function() {
      'use strict';
  
      // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session.
      TestData.disableImplicitSessions = true;
  
      function testConnection(
          conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) {
          load("jstests/libs/host_ipaddr.js");
  
          // Create a session which observes an eventually consistent view of user data
          var eventualDb = eventuallyConsistentConn.getDB("admin");
  
          // Create a session for modifying user data during the life of the test
          var adminSession = new Mongo("localhost:" + conn.port);
          var admin = adminSession.getDB("admin");
          assert.commandWorked(admin.runCommand({
              createUser: "admin",
              pwd: "Password@a1b",
              roles: [{role: "root", db: "admin"}], "digestPassword": true
          }));
          assert(admin.auth("admin", "Password@a1b"));
  
          // Create a strongly consistent session for consuming user data
          var db = conn.getDB("admin");
  
          // Create a strongly consistent session for consuming user data, with a non-localhost
          // source IP.
          var externalMongo = new Mongo(get_ipaddr() + ":" + conn.port);
          var externalDb = externalMongo.getDB("admin");
  
          assert.commandWorked(admin.runCommand({
              createUser: "user2",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions: [{clientSource: ["127.0.0.1"]}], "digestPassword": true
          }));
          assert.commandWorked(admin.runCommand(
              {createUser: "user3", pwd: "Password@a1b", roles: [], "digestPassword": true}));
          assert.commandWorked(admin.runCommand(
              {updateUser: "user3", authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}]}));
  
          print("=== User creation tests");
          print(
              "When a client creates users with empty authenticationRestrictions, the operation succeeds, though it has no effect");
          assert.commandWorked(admin.runCommand({
              createUser: "user4",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions: [], "digestPassword": true
          }));
          assert(!Object.keys(admin.system.users.findOne({user: "user4"}))
                      .includes("authenticationRestrictions"));
  
          print(
              "When a client updates a user's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field");
          assert.commandWorked(admin.runCommand(
              {createUser: "user5", pwd: "Password@a1b", roles: [], "digestPassword": true}));
          assert.commandWorked(
              admin.runCommand({updateUser: "user5", authenticationRestrictions: []}));
          assert(!Object.keys(admin.system.users.findOne({user: "user5"}))
                      .includes("authenticationRestrictions"));
          assert.commandWorked(admin.runCommand(
              {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]}));
          assert(Object.keys(admin.system.users.findOne({user: "user5"}))
                     .includes("authenticationRestrictions"));
          assert.commandWorked(
              admin.runCommand({updateUser: "user5", authenticationRestrictions: []}));
          assert(!Object.keys(admin.system.users.findOne({user: "user5"}))
                      .includes("authenticationRestrictions"));
  
          print(
              "When a client updates a user's authenticationRestrictions to be null or undefined, the operation fails");
          assert.commandWorked(admin.runCommand(
              {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]}));
          assert(Object.keys(admin.system.users.findOne({user: "user5"}))
                     .includes("authenticationRestrictions"));
          assert.commandFailed(
              admin.runCommand({updateUser: "user5", authenticationRestrictions: null}));
          assert(Object.keys(admin.system.users.findOne({user: "user5"}))
                     .includes("authenticationRestrictions"));
          assert.commandFailed(
              admin.runCommand({updateUser: "user5", authenticationRestrictions: undefined}));
          assert(Object.keys(admin.system.users.findOne({user: "user5"}))
                     .includes("authenticationRestrictions"));
  
          print(
              "When a client creates users, it may use clientSource and serverAddress authenticationRestrictions");
          assert.commandWorked(admin.runCommand({
              createUser: "user6",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions: [{clientSource: ["127.0.0.1"]}], "digestPassword": true
          }));
          assert.commandWorked(admin.runCommand({
              createUser: "user7",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}], "digestPassword": true
          }));
          assert.commandWorked(admin.runCommand({
              createUser: "user8",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions:
                  [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}],
              "digestPassword": true
          }));
          assert.commandWorked(admin.runCommand({
              createUser: "user9",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions:
                  [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}],
              "digestPassword": true
          }));
          assert.commandFailed(admin.runCommand({
              createUser: "user10",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}],
              "digestPassword": true
          }));
  
          print("=== Localhost access tests");
  
          print(
              "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\"}, it will succeed");
          assert(db.auth("user6", "Password@a1b"));
  
          print(
              "When a client on the loopback authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will succeed");
          assert(db.auth("user7", "Password@a1b"));
  
          print(
              "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will succeed");
          assert(db.auth("user8", "Password@a1b"));
  
          print("=== Remote access tests");
          print(
              "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\"}, it will fail");
          assert(!externalDb.auth("user6", "Password@a1b"));
  
          print(
              "When a client on the external interface authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will fail");
          assert(!externalDb.auth("user7", "Password@a1b"));
  
          print(
              "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will fail");
          assert(!externalDb.auth("user8", "Password@a1b"));
  
          print("=== Invalidation tests");
          print(
              "When a client removes all authenticationRestrictions from a user, authentication will succeed");
          assert.commandWorked(admin.runCommand({
              createUser: "user11",
              pwd: "Password@a1b",
              roles: [],
              authenticationRestrictions:
                  [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}],
              "digestPassword": true
          }));
          assert(!externalDb.auth("user11", "Password@a1b"));
          assert.commandWorked(
              admin.runCommand({updateUser: "user11", authenticationRestrictions: []}));
          assert(externalDb.auth("user11", "Password@a1b"));
  
          print(
              "When a client sets authenticationRestrictions on a user, authorization privileges are revoked");
          assert.commandWorked(admin.runCommand({
              createUser: "user12",
              pwd: "Password@a1b",
              roles: [{role: "readWrite", db: "test"}], "digestPassword": true
          }));
  
          assert(db.auth("user12", "Password@a1b"));
          assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
  
          sleepUntilUserDataPropagated();
          assert(eventualDb.auth("user12", "Password@a1b"));
          assert.commandWorked(
              eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
  
          assert.commandWorked(admin.runCommand(
              {updateUser: "user12", authenticationRestrictions: [{clientSource: ["192.0.2.0"]}]}));
  
          assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
  
          sleepUntilUserDataRefreshed();
          assert.commandFailed(
              eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0}));
      }
  
      print("Testing standalone");
      var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""});
      testConnection(conn, conn, function() {}, function() {});
      MongoRunner.stopMongod(conn);
  
      var keyfile = "jstests/libs/key1";
  
      print("Testing replicaset");
      var rst = new ReplSetTest(
          {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile});
      var nodes = rst.startSet();
      rst.initiate();
      rst.awaitSecondaryNodes();
      var awaitReplication = function() {
          authutil.asCluster(nodes, "jstests/libs/key1", function() {
              rst.awaitReplication();
          });
      };
  
      testConnection(rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication);
      rst.stopSet();
  
      print("Testing sharded cluster");
      // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
      var st = new ShardingTest({
          mongos: 2,
          config: 3,
          shard: 1,
          keyFile: keyfile,
          other: {
              mongosOptions: {bind_ip_all: "", auth: null},
              configOptions: {auth: null},
              shardOptions: {auth: null},
              shardAsReplicaSet: false
          }
      });
      testConnection(st.s0,
                     st.s1,
                     function() {},
                     function() {
                         sleep(40 * 1000);  // Wait for mongos user cache invalidation
                     });
      st.stop();
  
  }());
  