sghaskell / rest-storage-passwords-manager

Splunk app with Javascript CRUD interface to storage/passwords REST endpoint
8 stars 5 forks source link

Table population race condition #9

Open atownson opened 3 weeks ago

atownson commented 3 weeks ago

In our Splunk environment, we're seeing an issue where the Credential Management table will populate and then the content will be removed a fraction of a second later. I took a look at the code a found the problematic blocks in the populateTable() function. The search is stored as two different variables, search1 and mainSearch, both with their event handlers creating a race condition. This update to populateTable() removes the second reference to the search and fixes the issue:

    // Run search to populate and call create table
    function populateTable() {
        // Initialize
        window.sessionStorage.setItem("formOpen", "false");
        var contextMenuDiv = '#context-menu';
        var passwordTableDiv = '#password-table';

        var search1 = new SearchManager({
                    "id": "search1",
                    "cancelOnUnload": true,
                    "status_buckets": 0,
                    "earliest_time": "-24h@h",
                    "latest_time": "now",
                    "sample_ratio": 1,
                    "search": "| rest /servicesNS/-/-/configs/conf-passwords splunk_server=local \
                        | rex field=title \"credential:(?<realm>.*?):(?<username>.*?):\" \
                        | eval uri_base=\"/en-US/splunkd/__raw\" | rex field=id \"(?<rest_uri>/servicesNS.*?$)\" | eval rest_uri = uri_base + rest_uri \
                        | fields username, eai:userName, password, realm, eai:acl.app, eai:acl.owner, eai:acl.perms.read, eai:acl.perms.write, eai:acl.sharing, realm, rest_uri \
                        | rename eai:userName as user, eai:acl.app as app, eai:acl.owner as owner, eai:acl.perms.read as acl_read, eai:acl.perms.write as acl_write, eai:acl.sharing as acl_sharing \
                        | table username, password, realm, app, owner, acl_read, acl_write, acl_sharing, rest_uri \
                        | fillnull value=\"\"",
                    "app": utils.getCurrentApp(),
                    "auto_cancel": 90,
                    "preview": true,
                    "tokenDependencies": {
                    },
                    "runWhenTimeIsUndefined": false
                }, {tokens: true, tokenNamespace: "submitted"});

        var myResults = search1.data('results', { output_mode:'json', count:0 });

        myResults.on("data", function() {
            var data = myResults.data().results;
            createTable(passwordTableDiv, contextMenuDiv, data);
        });
    }
atownson commented 3 weeks ago

The same is true for showPassword()

    function showPassword(row) {
        var dfd = $.Deferred();

        var splunkJsComponent = mvc.Components.getInstance("passwordSearch");

        if(splunkJsComponent) {
            splunkJsComponent.dispose();
        }

        var passwordSearch = new SearchManager({
            "id": "passwordSearch",
            "cancelOnUnload": true,
            "status_buckets": 0,
            "earliest_time": "-24h@h",
            "latest_time": "now",
            "sample_ratio": 1,
            "search": "| rest /servicesNS/-/-/storage/passwords splunk_server=local \
                | search title=" + row.realm + ":" + row.username + ": \
                | table clear_password",
            "app": utils.getCurrentApp(),
            "auto_cancel": 90,
            "preview": true,
            "tokenDependencies": {
            },
            "runWhenTimeIsUndefined": false
        }, {tokens: true, tokenNamespace: "submitted"});

        var myResults = passwordSearch.data('results', { output_mode:'json', count:0 });

        myResults.on("data", function() {
            var data = myResults.data().results;
            if (data === undefined || data.length == 0)
            {
                return renderModal("password-not-found",
                                    "Not Found",
                                    "<div class=\"alert alert-warning\"><i class=\"icon-alert\"></i>No password found. Verify <b>list_storage_passwords</b> capability role is enabled.</div>",
                                    "Close");
            }
            else {
                dfd.resolve(renderModal("show-password",
                                        "Password",
                                        "<h3>" + data[0].clear_password + "</h3>",
                                        "Close"));
            }
        });

        return dfd.promise();
    }