bool AuthzManagerExternalStateMongod::needsLockForUserName(OperationContext* opCtx,
                                                           const UserName& name) {
    return (shouldUseRolesFromConnection(opCtx, name) == false);
}
Status AuthzManagerExternalStateMongos::getUserDescription(OperationContext* opCtx,
                                                           const UserName& userName,
                                                           BSONObj* result) {
    if (!shouldUseRolesFromConnection(opCtx, userName)) {
        BSONObj usersInfoCmd =
            BSON("usersInfo" << BSON_ARRAY(BSON(AuthorizationManager::USER_NAME_FIELD_NAME
                                                << userName.getUser()
                                                << AuthorizationManager::USER_DB_FIELD_NAME
                                                << userName.getDB()))
                             << "showPrivileges"
                             << true
                             << "showCredentials"
                             << true);
        BSONObjBuilder builder;
        const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
            opCtx, "admin", usersInfoCmd, &builder);
        BSONObj cmdResult = builder.obj();
        if (!ok) {
            return getStatusFromCommandResult(cmdResult);
        }

        std::vector<BSONElement> foundUsers = cmdResult["users"].Array();
        if (foundUsers.size() == 0) {
            return Status(ErrorCodes::UserNotFound,
                          "User \"" + userName.toString() + "\" not found");
        }

        if (foundUsers.size() > 1) {
            return Status(ErrorCodes::UserDataInconsistent,
                          str::stream() << "Found multiple users on the \"" << userName.getDB()
                                        << "\" database with name \""
                                        << userName.getUser()
                                        << "\"");
        }
        *result = foundUsers[0].Obj().getOwned();
        return Status::OK();
    } else {
        // Obtain privilege information from the config servers for all roles acquired from the X509
        // certificate.
        BSONArrayBuilder userRolesBuilder;
        auto& sslPeerInfo = SSLPeerInfo::forSession(opCtx->getClient()->session());
        for (const RoleName& role : sslPeerInfo.roles) {
            userRolesBuilder.append(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
                                         << role.getRole()
                                         << AuthorizationManager::ROLE_DB_FIELD_NAME
                                         << role.getDB()));
        }
        BSONArray providedRoles = userRolesBuilder.arr();

        BSONObj rolesInfoCmd = BSON("rolesInfo" << providedRoles << "showPrivileges"
                                                << "asUserFragment");

        BSONObjBuilder cmdResultBuilder;
        const bool cmdOk = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
            opCtx, "admin", rolesInfoCmd, &cmdResultBuilder);
        BSONObj cmdResult = cmdResultBuilder.obj();
        if (!cmdOk || !cmdResult["userFragment"].ok()) {
            return Status(ErrorCodes::FailedToParse,
                          "Unable to get resolved X509 roles from config server: " +
                              getStatusFromCommandResult(cmdResult).toString());
        }
        cmdResult = cmdResult["userFragment"].Obj().getOwned();
        BSONElement userRoles = cmdResult["roles"];
        BSONElement userInheritedRoles = cmdResult["inheritedRoles"];
        BSONElement userInheritedPrivileges = cmdResult["inheritedPrivileges"];

        if (userRoles.eoo() || userInheritedRoles.eoo() || userInheritedPrivileges.eoo() ||
            !userRoles.isABSONObj() || !userInheritedRoles.isABSONObj() ||
            !userInheritedPrivileges.isABSONObj()) {
            return Status(
                ErrorCodes::UserDataInconsistent,
                "Recieved malformed response to request for X509 roles from config server");
        }

        *result = BSON("_id" << userName.getUser() << "user" << userName.getUser() << "db"
                             << userName.getDB()
                             << "credentials"
                             << BSON("external" << true)
                             << "roles"
                             << BSONArray(cmdResult["roles"].Obj())
                             << "inheritedRoles"
                             << BSONArray(cmdResult["inheritedRoles"].Obj())
                             << "inheritedPrivileges"
                             << BSONArray(cmdResult["inheritedPrivileges"].Obj()));
        return Status::OK();
    }
}