#50565 Issue 50546 - Fix various issues in UI
Closed 2 years ago by spichugi. Opened 2 years ago by mreynolds.
mreynolds/389-ds-base issue50546  into  master

@@ -317,6 +317,7 @@ 

      width: 875px !important;

      min-width: 875px !important;

      vertical-align: middle;

+     margin-left: -100px !important;

  }

  

  .ds-button-right {
@@ -686,6 +687,10 @@ 

      text-align: center;

  }

  

+ .modal {

+   overflow-y:auto;

+ }

+ 

  /* wizard accordions are narrower */

  .ds-wiz-accordion {

      margin-top: 20px;
@@ -826,6 +831,13 @@ 

      transform: translate(-25%, -50%);

  }

  

+ .ds-loading {

+     position: fixed;

+     top: 25%;

+     left: 35%;

+     transform: translate(-25%, -35%);

+ }

+ 

  .ds-popup {

      min-width: 350px !important;

  }
@@ -885,10 +897,6 @@ 

      }

  }

  

- .control-label {

-     text-align: left !important;

- }

- 

  .rbt-token {

      background-color: #ededed;

      color: #363636;

@@ -76,8 +76,14 @@ 

  }

  

  function valid_num (val){

-   // Validate value is a number

-   return !isNaN(val);

+   // Validate value is a number and between 1 and 65535

+   let result = !isNaN(val);

+   if (result) {

+       if (val < 1 || val > 65535) {

+           result = false;

+       }

+   }

+   return result;

  }

  

  function tableize (val) {
@@ -340,7 +346,27 @@ 

  // This is called when any Save button is clicked on the main page.  We call

  // all the save functions for all the pages here.  This is not used for modal forms

  function save_all () {

-   save_config();  // Server Config Page

+     if ("nsslapd-ldapilisten" in config_values || "nsslapd-ldapiautobind" in config_values) {

+         if ( (!$("#nsslapd-ldapilisten").is(":checked") && config_values["nsslapd-ldapilisten"] == "on") ||

+              (!$("#nsslapd-ldapiautobind").is(":checked") && config_values["nsslapd-ldapiautobind"] == "on") )

+         {

+             // Okay we are disabling some form of LDAPI that will break the UI, warn the user

+             popup_confirm("Disabling LDAPI or LDAPI Autobind will make the UI unusable.  Are you sure you want to proceed",

+                 "Confirmation", function (yes)

+             {

+                 if (yes) {

+                     save_config();

+                 } else {

+                     // No, reset config

+                     get_and_set_config();

+                 }

+             });

+         } else {

+             save_config();

+         }

+     } else {

+         save_config();

+     }

  }

  

  function load_repl_suffix_dropdowns() {
@@ -374,6 +400,18 @@ 

    });

  }

  

+ var progress = 10;

+ 

+ function update_progress () {

+     progress += 10;

+     if (progress > 100) {

+         progress = 100;

+     }

+     $("#ds-progress-label").text(progress + "%");

+     $("#ds-progress-bar").attr("aria-valuenow", progress);

+     $("#ds-progress-bar").css("width", progress + "%");

+ }

+ 

  var loading_cfg = 0;

  

  function load_config (refresh){
@@ -382,6 +420,8 @@ 

      return;

    }

    loading_cfg = 1;

+   progress = 10;

+   update_progress();

  

    // Load the configuration for all the pages.

    var dropdowns = ['local-pwp-suffix', 'select-repl-cfg-suffix'];
@@ -415,15 +455,18 @@ 

      get_and_set_config();

      get_and_set_sasl();

      get_and_set_localpwp();

+     update_progress();

  

      // Schema page

      get_and_set_schema_tables();

+     update_progress();

  

      // Replication page

      get_and_set_repl_config();

      get_and_set_repl_agmts();

      get_and_set_repl_winsync_agmts();

      get_and_set_cleanallruv();

+     update_progress();

  

      // Initialize the tabs

      $(".ds-tab-list").css( 'color', '#777');

@@ -33,9 +33,20 @@ 

  

  <body>

    <div id="reload-page" hidden></div>

-   <div id="loading-page" class="ds-center ds-loading-spinner" hidden>

+   <div id="loading-page" class="ds-center ds-loading" hidden>

      <h4 id="loading-msg">Loading Directory Server Configuration...</h4>

      <p><span class="spinner spinner-lg spinner-inline"></span></p>

+ 

+     <div class="progress">

+         <div class="progress-bar" role="progressbar" id="ds-progress-bar"

+             aria-valuenow="20" aria-valuemin="0"

+             aria-valuemax="100" style="width: 20%;"

+         >

+             <span id="ds-progress-label">20%</span>

+         </div>

+     </div>

+ 

+ 

    </div>

    <div id="everything" hidden>

      <div class="ds-nav-bar">
@@ -375,7 +386,7 @@ 

                <p class="ds-modal-error"></p>

                <div class="ds-inline">

                  <div>

-                   <label for="create-inst-serverid" class="ds-config-label" title="The instance name, this is what gets appended to \"slapi-\"">

+                   <label for="create-inst-serverid" class="ds-config-label" title="The instance name, this is what gets appended to 'slapi-'.  The instance name can only contain letters, numbers, and:  # % : - _">

                      Instance Name</label><input class="ds-input ds-inst-input" size="40" type="text" id="create-inst-serverid" placeholder="Your_Instance_Name" required />

                  </div>

                  <div>
@@ -400,12 +411,12 @@ 

                  </div>

                  <hr>

                  <div>

-                   <label for="backend-name" class="ds-config-label" title="The backend name, like 'userroot'">Backend Name (optional)</label><input

-                     class="ds-input ds-inst-input" size="40" type="text" id="backend-name">

+                   <label for="backend-name" class="ds-config-label" title="The name for the backend database, like 'userroot'">Backend Name (optional)</label><input

+                     class="ds-input ds-inst-input" placeholder="e.g. userRoot" size="40" type="text" id="backend-name">

                  </div>

                  <div>

                    <label for="backend-suffix" class="ds-config-label" title="Database suffix, like 'dc=example,dc=com'">Backend Suffix (optional)</label><input

-                     class="ds-input ds-inst-input" size="40" type="text" id="backend-suffix">

+                     class="ds-input ds-inst-input" size="40" placeholder="e.g. dc=example,dc=com" type="text" id="backend-suffix">

                  </div>

                  <div>

                    <label for="create-sample-entries" class="ds-config-label" title="Create sample entries in the suffix">Create Sample Entries </label><input
@@ -445,8 +456,8 @@ 

            </div>

            <div class="modal-body">

              <form class="form-horizontal">

-                 <label for="backup-name" title="Enter a directory name for the backup">

-                   Backup Name:</label><input class="ds-input-auto" type="text" id="backup-name"/>

+                 <label for="backup-name" title="Enter a name for the backup subdirectory located under the server's backup directory (nsslapd-bakdir)">

+                   Name For The Backup</label><input class="ds-input-auto" type="text" id="backup-name"/>

              </form>

              <div id="backup-spinner" class="ds-center" hidden>

                <p></p>

@@ -19,7 +19,7 @@ 

      Row,

      noop

  } from "patternfly-react";

- import { log_cmd } from "../tools.jsx";

+ import { log_cmd, bad_file_name } from "../tools.jsx";

  import PropTypes from "prop-types";

  import "../../css/ds.css";

  
@@ -289,19 +289,26 @@ 

      }

  

      doBackup () {

-         this.setState({

-             backupSpinning: true

-         });

- 

          let cmd = [

              "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",

              "backup", "create"

          ];

  

          if (this.state.backupName != "") {

+             if (bad_file_name(this.state.backupName)) {

+                 this.props.addNotification(

+                     "warning",

+                     `Backup name should not be a path.  All backups are stored in the server's backup directory`

+                 );

+                 return;

+             }

              cmd.push(this.state.backupName);

          }

  

+         this.setState({

+             backupSpinning: true

+         });

+ 

          log_cmd("doBackup", "Add backup task", cmd);

          cockpit

                  .spawn(cmd, { superuser: true, err: "message" })
@@ -399,12 +406,25 @@ 

      }

  

      doExport() {

-         let missingArgs = {ldifLocation: false};

-         if (this.state.ldifLocation == "") {

+         let missingArgs = {ldifName: false};

+         if (this.state.ldifName == "") {

              this.props.addNotification(

                  "warning",

                  `LDIF name is empty`

              );

+             missingArgs.ldifName = true;

+             this.setState({

+                 errObj: missingArgs

+             });

+             return;

+         }

+ 

+         // Must not be a path

+         if (bad_file_name(this.state.ldifName)) {

+             this.props.addNotification(

+                 "warning",

+                 `LDIF name should not be a path.  All export files are stored in the server's LDIF directory`

+             );

              missingArgs.ldifLocation = true;

              this.setState({

                  errObj: missingArgs

@@ -6,7 +6,7 @@ 

  import { SuffixReferrals } from "./referrals.jsx";

  import { SuffixIndexes } from "./indexes.jsx";

  import { VLVIndexes } from "./vlvIndexes.jsx";

- import { log_cmd } from "../tools.jsx";

+ import { log_cmd, bad_file_name } from "../tools.jsx";

  import {

      ImportModal,

      ExportModal,
@@ -260,7 +260,20 @@ 

              return;

          }

  

-         // Do import

+         // Must not be a path

+         if (bad_file_name(this.state.ldifLocation)) {

+             this.props.addNotification(

+                 "warning",

+                 `LDIF name should not be a path.  All export files are stored in the server's LDIF directory`

+             );

+             missingArgs.ldifLocation = true;

+             this.setState({

+                 errObj: missingArgs

+             });

+             return;

+         }

+ 

+         // Do Export

          let export_cmd = [

              "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",

              "backend", "export", this.props.suffix, "--ldif=" + this.state.ldifLocation
@@ -289,7 +302,7 @@ 

                  })

                  .fail(err => {

                      let errMsg = JSON.parse(err);

-                     this.loadLDIFs();

+                     this.props.reloadLDIFs();

                      this.props.addNotification(

                          "error",

                          `Error exporting database - ${errMsg.desc}`

@@ -67,7 +67,7 @@ 

                              <TabPane eventKey={1}>

                                  <div className="ds-margin-top-lg">

                                      <Row>

-                                         <Col componentClass={ControlLabel} sm={3}>

+                                         <Col componentClass={ControlLabel} sm={4}>

                                              Server Instance

                                          </Col>

                                          <Col sm={8}>
@@ -75,7 +75,7 @@ 

                                          </Col>

                                      </Row>

                                      <Row className="ds-margin-top">

-                                         <Col componentClass={ControlLabel} sm={3}>

+                                         <Col componentClass={ControlLabel} sm={4}>

                                              Version

                                          </Col>

                                          <Col sm={8}>
@@ -83,7 +83,7 @@ 

                                          </Col>

                                      </Row>

                                      <Row className="ds-margin-top">

-                                         <Col componentClass={ControlLabel} sm={3}>

+                                         <Col componentClass={ControlLabel} sm={4}>

                                              Server Started

                                          </Col>

                                          <Col sm={8}>
@@ -91,7 +91,7 @@ 

                                          </Col>

                                      </Row>

                                      <Row className="ds-margin-top">

-                                         <Col componentClass={ControlLabel} sm={3}>

+                                         <Col componentClass={ControlLabel} sm={4}>

                                              Server Uptime

                                          </Col>

                                          <Col sm={8}>
@@ -105,7 +105,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Worker Threads

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-threads" value={this.props.data.threads} readOnly />

                                          </Col>

                                      </Row>
@@ -113,7 +113,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Threads Waiting To Read

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-readwaiters" value={this.props.data.readwaiters} readOnly />

                                          </Col>

                                      </Row>
@@ -121,7 +121,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Conns At Max Threads

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-currentconnectionsatmaxthreads" value={this.props.data.currentconnectionsatmaxthreads} readOnly />

                                          </Col>

                                      </Row>
@@ -129,7 +129,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Conns Exceeded Max Threads

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-maxthreadsperconnhits" value={this.props.data.maxthreadsperconnhits} readOnly />

                                          </Col>

                                      </Row>
@@ -137,7 +137,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Total Connections

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-totalconnections" value={this.props.data.totalconnections} readOnly />

                                          </Col>

                                      </Row>
@@ -145,7 +145,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Current Conections

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-currentconnections" value={this.props.data.currentconnections} readOnly />

                                          </Col>

                                      </Row>
@@ -153,7 +153,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Operations Started

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-opsinitiated" value={this.props.data.opsinitiated} readOnly />

                                          </Col>

                                      </Row>
@@ -161,7 +161,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Operations Completed

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-opscompleted" value={this.props.data.opscompleted} readOnly />

                                          </Col>

                                      </Row>
@@ -169,7 +169,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Entries Returned To Clients

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-entriessent" value={this.props.data.entriessent} readOnly />

                                          </Col>

                                      </Row>
@@ -177,7 +177,7 @@ 

                                          <Col componentClass={ControlLabel} sm={4}>

                                              Bytes Sent to Clients

                                          </Col>

-                                         <Col sm={7}>

+                                         <Col sm={8}>

                                              <input type="text" className="ds-input-auto" id="monitor-server-bytessent" value={this.props.data.bytessent} readOnly />

                                          </Col>

                                      </Row>

@@ -103,3 +103,11 @@ 

  

      return `${days} days, ${hours} hours, ${minutes} minutes, and ${seconds} seconds`;

  }

+ 

+ export function bad_file_name(file_name) {

+     // file_name must be a string, and not a location/directory

+     if (file_name.includes("/")) {

+         return true;

+     }

+     return false;

+ }

@@ -257,27 +257,27 @@ 

                <div class="ds-inline">

                  <div>

                    <label for="agmt-cn" class="ds-config-label" title="Agreement name (cn).">Agreement Name</label><input

-                     class="ds-input agmt-form-input" type="text" placeholder="Agreement name" id="agmt-cn" name="name"  size="35" required>

+                     class="ds-input agmt-form-input" type="text" placeholder="Agreement name" id="agmt-cn" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="nsds5replicahost" class="ds-config-label" title="Agreement name (nsDS5ReplicaHost).">Consumer Host</label><input

-                     class="ds-input agmt-form-input" type="text" placeholder="Consumer hostname" id="nsds5replicahost" name="port" size="35" required>

+                     class="ds-input agmt-form-input" type="text" placeholder="Consumer hostname" id="nsds5replicahost" name="port" size="40" required>

                  </div>

                  <div>

                    <label for="nsds5replicaport" class="ds-config-label" title="Agreement name (nsDS5ReplicaPort).">Consumer Port</label><input

-                     class="ds-input agmt-form-input" type="text" placeholder="Consumer port number" id="nsds5replicaport" name="name" size="35" required>

+                     class="ds-input agmt-form-input" type="text" placeholder="Consumer port number" id="nsds5replicaport" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="nsds5replicabinddn" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaBindDN).">Replication Bind DN</label><input

-                     class="ds-input agmt-form-input" type="text" autocomplete="username" placeholder="Bind DN" id="nsds5replicabinddn" name="name" size="35" required>

+                     class="ds-input agmt-form-input" type="text" autocomplete="username" placeholder="Bind DN" id="nsds5replicabinddn" name="name" size="40" required>

                  </div>

                  <div>

-                   <label for="nsds5replicacredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Replication Bind DN Credentials</label><input

-                     class="ds-input agmt-form-input" type="password" autocomplete="new-password" placeholder="Enter password" id="nsds5replicacredentials" name="name" size="35" required>

+                   <label for="nsds5replicacredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Bind DN Password</label><input

+                     class="ds-input agmt-form-input" type="password" autocomplete="new-password" placeholder="Enter password" id="nsds5replicacredentials" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="nsds5replicacredentials-confirm" class="ds-config-label" title="Confirm password">Confirm Password</label><input

-                     class="ds-input agmt-form-input" type="password" autocomplete="new-password" placeholder="Confirm password" id="nsds5replicacredentials-confirm" name="name" size="35" required>

+                     class="ds-input agmt-form-input" type="password" autocomplete="new-password" placeholder="Confirm password" id="nsds5replicacredentials-confirm" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="nsds5replicatransportinfo" class="ds-config-label" title="The protocol used to connect to the replica  (nsDS5ReplicaTransportInfo).">Connection Protocol</label><select
@@ -448,7 +448,7 @@ 

    <!-- Winsync Agreement Wizard  -->

  

    <div class="modal fade" id="winsync-agmt-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="winsync-agmt-wizard-title" aria-hidden="true">

-     <div class="modal-dialog ds-modal-wide">

+     <div class="modal-dialog">

        <div class="modal-content">

          <div class="modal-header">

            <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
@@ -462,27 +462,27 @@ 

                <div class="ds-inline">

                  <div>

                    <label for="winsync-agmt-cn" class="ds-config-label" title="Agreement name (cn).">Agreement Name</label><input

-                     class="ds-input" type="text" placeholder="Agreement name" id="winsync-agmt-cn" name="name" required>

+                     class="ds-input" type="text" placeholder="Agreement name" id="winsync-agmt-cn" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds7windowsdomain" class="ds-config-label" title="Agreement name (nsds7WindowsDomain).">Windows Domain Name</label><input

-                     class="ds-input" type="text" placeholder="Windows Domain Name, example:  mydomain.com" id="winsync-nsds7windowsdomain" name="name" required>

+                     class="ds-input" type="text" placeholder="Windows Domain Name, example:  mydomain.com" id="winsync-nsds7windowsdomain" size="40" name="name" required>

                  </div>

                  <div>

                    <label for="winsync-nsds5replicahost" class="ds-config-label" title="Agreement name (nsDS5ReplicaHost).">Windows Host</label><input

-                     class="ds-input" type="text" placeholder="Windows hostname" id="winsync-nsds5replicahost" name="port" required>

+                     class="ds-input" type="text" placeholder="Windows hostname" id="winsync-nsds5replicahost" name="port" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds5replicaport" class="ds-config-label" title="Agreement name (nsDS5ReplicaPort).">Windows Port</label><input

-                     class="ds-input" type="text" placeholder="Windows server port number" id="winsync-nsds5replicaport" name="name" required>

+                     class="ds-input" type="text" placeholder="Windows server port number" id="winsync-nsds5replicaport" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds7windowsreplicasubtree" class="ds-config-label" title="Agreement name (nsds7WindowsReplicaSubtree).">Windows Subtree</label><input

-                     class="ds-input" type="text" placeholder="Active Directory subtree" id="winsync-nsds7windowsreplicasubtree" name="name" required>

+                     class="ds-input" type="text" placeholder="Active Directory subtree" id="winsync-nsds7windowsreplicasubtree" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds7directoryreplicasubtree" class="ds-config-label" title="Agreement name (nsds7DirectoryReplicaSubtree).">Directory Server Subtree</label><input

-                     class="ds-input" type="text" placeholder="The local Directory Server subtree" id="winsync-nsds7directoryreplicasubtree" name="name" required>

+                     class="ds-input" type="text" placeholder="The local Directory Server subtree" id="winsync-nsds7directoryreplicasubtree" name="name" size="40" required>

                  </div>

                  <div>

                    <input type="checkbox" class="ds-config-checkbox" id="winsync-nsds7newwinusersyncenabled-checkbox" checked><label
@@ -502,15 +502,15 @@ 

                  <div>

                    <hr class="ds-hr">

                    <label for="winsync-nsds5replicabinddn" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaBindDN).">Replication Bind DN</label><input

-                     class="ds-input" type="text" autocomplete="username" placeholder="Bind DN" id="winsync-nsds5replicabinddn" name="name" required>

+                     class="ds-input" type="text" autocomplete="username" placeholder="Bind DN" id="winsync-nsds5replicabinddn" name="name" size="40" required>

                  </div>

                  <div>

-                   <label for="winsync-nsds5replicacredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Replication Bind DN Credentials</label><input

-                     class="ds-input" type="password" autocomplete="new-password" placeholder="Enter password" id="winsync-nsds5replicacredentials" name="name" required>

+                   <label for="winsync-nsds5replicacredentials" class="ds-config-label" title="Replication Bind DN (nsDS5ReplicaCredentials).">Bind DN Password</label><input

+                     class="ds-input" type="password" autocomplete="new-password" placeholder="Enter password" id="winsync-nsds5replicacredentials" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds5replicacredentials-confirm" class="ds-config-label" title="Confirm password">Confirm Password</label><input

-                     class="ds-input" type="password"autocomplete="new-password" placeholder="Confirm password" id="winsync-nsds5replicacredentials-confirm" name="name" required>

+                     class="ds-input" type="password"autocomplete="new-password" placeholder="Confirm password" id="winsync-nsds5replicacredentials-confirm" name="name" size="40" required>

                  </div>

                  <div>

                    <label for="winsync-nsds5replicatransportinfo" class="ds-config-label" title="The protocol used to connect to the replica (nsDS5ReplicaTransportInfo).">Connection Protocol</label><select
@@ -581,7 +581,7 @@ 

  

    <!-- Add replication manager Form -->

    <div class="modal fade" id="add-repl-mgr-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="repl-mgr-label" aria-hidden="true">

-     <div class="modal-dialog ds-modal-wide">

+     <div class="modal-dialog">

        <div class="modal-content">

          <div class="modal-header">

            <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
@@ -594,7 +594,7 @@ 

              <div class="ds-inline">

                <div>

                  <label for="add-repl-mgr-dn" class="" title=

-                   "The DN of the replication manager.  The entry should use 'cn' for RDN, and the entry should be under 'cn=config'.  (nsds5replicabinddn)">

+                   "The DN of the replication manager.  The entry should use 'cn' for the RDN, and the entry should be under 'cn=config'.  (nsds5replicabinddn)">

                    Replication Manager DN</label>

                </div>

                <div>
@@ -689,7 +689,7 @@ 

                        <label for="enable-repl-mgr-dn" class="ds-label-sm" title=

                          "The DN of the replication manager.  The DN should use 'cn' for the RDN, 'cn=replication manager,cn=config' (nsds5replicabinddn)">Replication Manager DN</label><input

                          type="text" title="The DN of the replication manager entry.  It must use the RDN attribute 'cn', and it must be located under 'cn=config'.  For example: cn=replication manager,cn=config"

-                         id="enable-repl-mgr-dn" size="40" class="ds-left-margin" />

+                         id="enable-repl-mgr-dn" value="cn=replication manager,cn=config" size="40" class="ds-left-margin" />

                        <p></p>

                      </div>

                      <div>

@@ -109,7 +109,7 @@ 

    $("#select-enable-repl-role").prop("selectedIndex", 0);

    $("#enable-repl-pw").val("");

    $("#enable-repl-pw-confirm").val("");

-   $("#enable-repl-mgr-dn").val("");

+   $("#enable-repl-mgr-dn").val("cn=replication manager,cn=config");

    $("#enable-repl-mgr-checkbox").prop('checked', false);

    $("#enable-repl-mgr-passwd").hide();

  }
@@ -203,6 +203,7 @@ 

      log_cmd('get_and_set_repl_winsync_agmts', 'Get the winsync agmts', cmd);

      cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

        var obj = JSON.parse(data);

+       update_progress();

        for (var idx in obj['items']) {

          var state = "Enabled";

          var con_host = "";
@@ -278,6 +279,7 @@ 

      cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

        repl_agmt_table.clear().draw();

        var obj = JSON.parse(data);

+       update_progress();

        for (var idx in obj['items']) {

          agmt_attrs = obj['items'][idx]['attrs'];

          var agmt_name = agmt_attrs['cn'][0];
@@ -351,6 +353,7 @@ 

    log_cmd('get_and_set_cleanallruv', 'Get the cleanAllRUV tasks', cmd);

    cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

      var tasks = JSON.parse(data);

+     update_progress();

      repl_clean_table.clear().draw();

      for (var idx in tasks['items']) {

        task_attrs = tasks['items'][idx]['attrs'];
@@ -394,6 +397,7 @@ 

        $('#repl-mgr-table').find("tr:gt(0)").remove();

        $(".ds-cfg").val("");

        $("#nsds5replicaprecisetombstonepurging").prop('checked', false);

+       update_progress();

  

        // Set configuration and the repl manager table

        for (var attr in repl['attrs']) {

@@ -65,6 +65,80 @@ 

  

    <!-- Modals/Popups/Wizards -->

  

+     <!-- View Attribute modal -->

+     <div class="modal fade" id="view-attr-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="view-attr-header" aria-hidden="true">

+         <div class="modal-dialog">

+             <div class="modal-content">

+                 <div class="modal-header">

+                     <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">

+                         <span class="pficon pficon-close"></span>

+                     </button>

+                     <h4 class="modal-title">View Attribute</h4>

+                 </div>

+                 <div class="modal-body">

+                     <div class="ds-inline">

+                         <div>

+                             <label for="attr-name-view" class="ds-config-label-lrg" title="The attribute name"><b

+                                 >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name-view" size="40" readonly />

+                         </div>

+                         <div>

+                             <label for="attr-desc-view" class="ds-config-label-lrg" title="The attribute description"><b

+                                 >Description</b></label><input class="ds-input" type="text" id="attr-desc-view" size="40"  readonly />

+                         </div>

+                         <div>

+                             <label for="attr-oid-view" class="ds-config-label-lrg" title="The attribute name"><b

+                                 >OID</b></label><input class="ds-input" type="text" id="attr-oid-view" size="40" readonly />

+                         </div>

+                         <div>

+                             <label for="attr-parent-view" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><input

+                                 class="ds-input" type="text" id="attr-parent-view" size="40" readonly />

+                         </div>

+                         <div>

+                             <label for="attr-syntax-view" class="ds-config-label-lrg" title="The attribute syntax"><b>Attribute Syntax</b></label><input

+                                 class="ds-input" type="text" id="attr-syntax-view" size="40" readonly />

+                         </div>

+                         <div>

+                             <label for="attr-usage-view" class="ds-config-label-lrg" title="The parent attribute"><b>Attribute Usage</b></label><input

+                                 class="ds-input" type="text" id="attr-usage-view" size="40" readonly />

+                         </div>

+                         <div>

+                             <input type="checkbox" class="ds-config-checkbox" id="attr-multivalued-view"  readonly /><label

+                                 for="attr-multivalued-view" class="ds-label"> Attribute Multi-Valued </label>

+                         </div>

+                         <div>

+                             <input type="checkbox" class="ds-config-checkbox" id="attr-no-user-mod-view"  readonly /><label

+                                 for="attr-no-user-mod-view" class="ds-label"> Read-only (NO-USER-MODIFICATION flag) </label>

+                         </div>

+                         <div>

+                             <label for="attr-alias-view" class="ds-config-label-lrg" title="The attribute alias list separated by space"><b

+                                 >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias-view" size="40" readonly />

+                         </div>

+                         <div class="panel panel-default ds-margin-top">

+                             <div class="panel-heading"><strong>Matching rules</strong></div>

+                                 <div class="panel-body">

+                                     <div>

+                                         <label for="attr-eq-mr-select-view" class="ds-config-label-lrg"><b>Equality</b></label><input

+                                             class="ds-input" type="text" id="attr-eq-mr-select-view" size="35" readonly />

+                                     </div>

+                                 <div>

+                                     <label for="attr-order-mr-select-view" class="ds-config-label-lrg"><b>Ordering</b></label><input

+                                         class="ds-input" type="text" id="attr-order-mr-select-view" size="35" readonly />

+                                 </div>

+                                 <div>

+                                     <label for="attr-sub-mr-select-view" class="ds-config-label-lrg"><b>Substring</b></label><input

+                                         class="ds-input" type="text" id="attr-sub-mr-select-view" size="35" readonly />

+                                 </div>

+                             </div>

+                         </div>

+                     </div>

+                     <div class="modal-footer">

+                         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>

+                     </div>

+                 </div>

+             </div>

+         </div>

+     </div>

+ 

    <!-- Add/edit Attribute modal -->

    <div class="modal fade" id="add-edit-attr-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="add-edit-attr-header" aria-hidden="true">

      <div class="modal-dialog">
@@ -79,22 +153,22 @@ 

            <div class="ds-inline">

              <p class="ds-modal-error"></p>

              <div>

-               <label for="attr-parent" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><select

-                     class="btn btn-default dropdown ds-oc-dropdown" id="attr-parent">

-               <option value=""></option>

-             </select>

-             </div>

-             <div>

                <label for="attr-name" class="ds-config-label-lrg" title="The attribute name"><b

                  >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name" size="40"/>

              </div>

              <div>

                <label for="attr-desc" class="ds-config-label-lrg" title="The attribute description"><b

-               >Attribute Description</b></label><input class="ds-input" type="text" id="attr-desc" size="40"/>

+               >Description</b></label><input class="ds-input" type="text" id="attr-desc" size="40"/>

              </div>

              <div>

                <label for="attr-oid" class="ds-config-label-lrg" title="The attribute name"><b

-               >Attribute OID</b></label><input class="ds-input" type="text" id="attr-oid" size="40"/>

+               >OID</b></label><input class="ds-input" type="text" id="attr-oid" size="40"/>

+             </div>

+             <div>

+               <label for="attr-parent" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><select

+                     class="btn btn-default dropdown ds-oc-dropdown" id="attr-parent">

+                 <option value=""></option>

+               </select>

              </div>

              <div>

                <label for="attr-syntax" class="ds-config-label-lrg" title="The attribute syntax"><b>Attribute Syntax</b></label><select
@@ -119,7 +193,7 @@ 

                <label for="attr-alias" class="ds-config-label-lrg" title="The attribute alias list separated by space"><b

                  >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias" size="40"/>

              </div>

-             <div class="panel panel-default">

+             <div class="panel panel-default ds-margin-top">

                  <div class="panel-heading"><strong>Matching rules</strong></div>

                  <div class="panel-body">

                    <div>
@@ -157,6 +231,65 @@ 

    </div>

  

  

+   <!-- View Objectclass -->

+     <div class="modal fade" id="view-objectclass-form" aria-labelledby="view-objectclass-form" data-backdrop="static" tabindex="-1" role="dialog" aria-hidden="true">

+         <div class="modal-dialog">

+             <div class="modal-content">

+                 <div class="modal-header">

+                     <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">

+                         <span class="pficon pficon-close"></span>

+                     </button>

+                     <h4 class="modal-title">View Objectclass</h4>

+                 </div>

+                 <div class="modal-body">

+                     <form class="form-horizontal">

+                         <div class="ds-inline">

+                             <div>

+                                 <label for="oc-name-view" class="ds-config-label-lrg" title="The objectclass name"><b

+                                     >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name-view" size="40" readonly />

+                             </div>

+                             <div>

+                                 <label for="oc-desc-view" class="ds-config-label-lrg" title="The objectClass description"><b

+                                     >Description</b></label><input class="ds-input" type="text" id="oc-desc-view" size="40" readonly/>

+                             </div>

+                             <div>

+                                 <label for="oc-oid-view" class="ds-config-label-lrg" title="Objectclass OID (optional)"><b

+                                     >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid-view" size="40" readonly/>

+                             </div>

+                             <div>

+                                 <label for="oc-parent-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Parent Objectclass</b></label><input

+                                     class="ds-input" value="" type="text" id="oc-parent-view" size="40" readonly />

+                             </div>

+                             <div>

+                                 <label for="oc-kind-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Objectclass Kind</b></label><input

+                                     class="ds-input" value="" type="text" id="oc-kind-view"  size="40" readonly />

+                             </div>

+                             <hr>

+                             <div class="ds-container">

+                                 <div>

+                                     <label class="ds-config-label" for="oc-required-list-view" title=

+                                         "Attributes allowed by the objectclass"><b>Required Attributes</b></label>

+                                     <select id="oc-required-list-view" class="ds-may-must-list" multiple>

+                                     </select>

+                                 </div>

+                                 <div class="ds-divider"></div>

+                                 <div>

+                                     <label class="ds-config-label" for="oc-allowed-list-view" title=

+                                         "Attributes allowed by the objectclass"><b>Allowed Attributes</b></label>

+                                     <select id="oc-allowed-list-view" class="ds-may-must-list" multiple>

+                                     </select>

+                                 </div>

+                             </div>

+                         </div>

+                     </form>

+                     <div class="modal-footer">

+                         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>

+                     </div>

+                 </div>

+             </div>

+         </div>

+     </div>

+ 

    <!-- Add/Edit Objectclass -->

    <div class="modal fade" id="add-edit-oc-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="add-edit-oc-header" aria-hidden="true">

      <div class="modal-dialog">
@@ -172,27 +305,27 @@ 

              <div class="ds-inline">

                <p class="ds-modal-error"></p>

                <div>

-                 <label for="oc-parent" class="ds-config-label-lrg" title="The parent objectclass"><b>Parent Objectclass</b></label><select

-                       class="btn btn-default dropdown ds-oc-dropdown" id="oc-parent">

-               </select>

-               </div>

-               <div>

                  <label for="oc-name" class="ds-config-label-lrg" title="The objectclass name"><b

                    >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name" size="40" required />

                </div>

                <div>

                  <label for="oc-desc" class="ds-config-label-lrg" title="The objectClass description"><b

-                 >ObjectClass Description</b></label><input class="ds-input" type="text" id="oc-desc" size="40"/>

+                 >Description</b></label><input class="ds-input" type="text" id="oc-desc" size="40"/>

                </div>

                <div>

                  <label for="oc-oid" class="ds-config-label-lrg" title="Objectclass OID (optional)"><b

                    >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid" size="40"/>

                </div>

                <div>

+                 <label for="oc-parent" class="ds-config-label-lrg" title="The parent objectclass"><b>Parent Objectclass</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="oc-parent">

+                 </select>

+               </div>

+               <div>

                  <label for="oc-kind" class="ds-config-label-lrg" title="The parent objectclass"><b>Objectclass Kind</b></label><select

                        class="btn btn-default dropdown ds-oc-dropdown" id="oc-kind">

                  <option value=""></option>

-               </select>

+                 </select>

                </div>

                <hr>

                <div class="ds-container">

@@ -251,7 +251,7 @@ 

          }

          $.each(syntax_list, function (i, syntax) {

            if (syntax.id === item.syntax) {

-             syntax_name = '<div title="' + syntax.id + '">' + syntax.name + '</div>';

+             syntax_name = '<div title="' + syntax.name + '">' + syntax.name + '</div>';

            }

          });

          // If attribute is user defined them the action button is enabled
@@ -326,6 +326,7 @@ 

            "visible": false

          }]

        });

+       update_progress();

      }).fail(function(syntax_data) {

          console.log("Get syntaxes failed: " + syntax_data.message);

          check_inst_alive(1);
@@ -353,6 +354,7 @@ 

      });

  

      console.log("Finished loading schema.");

+     update_progress();

    }).fail(function(oc_data) {

        console.log("Get all schema objects failed: " + oc_data.message);

        check_inst_alive(1);
@@ -738,13 +740,50 @@ 

        $("#add-edit-attr-form").modal('toggle');

      }

  

+     function load_view_attr_form(element) {

+       clear_attr_form();

+       var data = schema_at_table.row(element.parents('tr') ).data();

+       var edit_attr_name = data[0];

+       var edit_attr_oid = data[1];

+       var edit_attr_syntax = $.parseHTML(data[2])[0].title;

+       var edit_attr_multivalued = data[3];

+       var edit_attr_desc = data[5];

+       var edit_attr_aliases = data[6];

+       var edit_attr_x_origin = data[7];

+       var edit_attr_usage = data[8];

+       var edit_attr_no_user_mod = data[9];

+       var edit_attr_parent = data[10];

+       var edit_attr_eq_mr = data[11];

+       var edit_attr_order_mr = data[12];

+       var edit_attr_sub_mr = data[13];

+ 

+       $("#attr-name-view").val(edit_attr_name);

+       $("#attr-oid-view").val(edit_attr_oid);

+       $("#attr-usage-view")[0].value = edit_attr_usage;

+       $("#attr-parent-view")[0].value = edit_attr_parent;

+       $("#attr-desc-view").val(edit_attr_desc);

+       if (edit_attr_aliases) {

+         $("#attr-alias-view").val(edit_attr_aliases.join(" "));

+       }

+       $("#attr-syntax-view").val(edit_attr_syntax);

+       $("#attr-multivalued-view").prop('checked', false);

+       if (edit_attr_multivalued == "yes") {

+         $("#attr-multivalued-view").prop('checked', true);

+       }

+       $("#attr-no-user-mod-view").prop('checked', false);

+       if (edit_attr_no_user_mod) {

+         $("#attr-no-user-mod-view").prop('checked', true);

+       }

+       $("#attr-eq-mr-select-view").val(edit_attr_eq_mr);

+       $("#attr-order-mr-select-view").val(edit_attr_order_mr);

+       $("#attr-sub-mr-select-view").val(edit_attr_sub_mr);

+ 

+       $("#view-attr-form").modal('toggle');

+     }

+ 

      $(document).on('click', '.attr-view-btn', function(e) {

        e.preventDefault();

-       load_attr_form($(this));

-       var edit_attr_name = schema_at_table.row($(this).parents('tr') ).data()[0];

-       $("#add-edit-attr-header").html('View Attribute: ' + edit_attr_name);

-       $("#save-attr-button").attr('title', 'Only user-defined attributes can be modified');

-       $("#save-attr-button").attr('disabled', true);

+       load_view_attr_form($(this));

      });

  

      $(document).on('click', '.attr-edit-btn', function(e) {
@@ -772,6 +811,44 @@ 

        });

      });

  

+     function load_view_oc_form(element) {

+       clear_oc_form();

+       var data = schema_oc_table.row(element.parents('tr') ).data();

+       var edit_oc_name = data[0];

+       var edit_oc_oid = data[1];

+       var edit_oc_required = data[2].split(" ");

+       var edit_oc_allowed = data[3].split(" ");

+       var edit_oc_x_origin = data[5];

+       var edit_oc_kind = data[6];

+       var edit_oc_desc = data[7];

+       var edit_oc_parent = data[8];

+ 

+       $("#oc-name-view").val(edit_oc_name);

+       $("#oc-oid-view").val(edit_oc_oid);

+       $("#oc-kind-view")[0].value = edit_oc_kind;

+       $("#oc-desc-view").val(edit_oc_desc);

+       $("#oc-parent-view")[0].value = edit_oc_parent;

+       $.each(edit_oc_required, function (i, item) {

+         if (item) {

+           $("#oc-required-list-view").append($('<option>', {

+             value: item,

+             text : item

+           }));

+         }

+       });

+       $.each(edit_oc_allowed, function (i, item) {

+         if (item) {

+           $("#oc-allowed-list-view").append($('<option>', {

+             value: item,

+             text : item

+           }));

+         }

+       });

+ 

+       // Update modal html header and fields and show()

+       $("#view-objectclass-form").modal('toggle');

+     }

+ 

      function load_oc_form(element) {

        clear_oc_form();

        var data = schema_oc_table.row(element.parents('tr') ).data();
@@ -789,9 +866,9 @@ 

        $("#oc-name").attr('disabled', true);

        $("#oc-name").val(edit_oc_name);

        $("#oc-oid").val(edit_oc_oid);

-       $("#oc-kind")[0].value = edit_oc_kind;

+       $("#oc-kind").val(edit_oc_kind);

        $("#oc-desc").val(edit_oc_desc);

-       $("#oc-parent")[0].value = edit_oc_parent;

+       $("#oc-parent").val(edit_oc_parent);

        $.each(edit_oc_required, function (i, item) {

          if (item) {

            $("#oc-required-list").append($('<option>', {
@@ -816,11 +893,7 @@ 

  

      $(document).on('click', '.oc-view-btn', function(e) {

        e.preventDefault();

-       load_oc_form($(this));

-       var edit_oc_name = schema_oc_table.row($(this).parents('tr') ).data()[0];

-       $("#add-edit-oc-header").html('View Objectclass: ' + edit_oc_name);

-       $("#save-oc-button").attr('title', 'Only user-defined objectClasses can be modified');

-       $("#save-oc-button").attr('disabled', true);

+       load_view_oc_form($(this));

      });

  

      $(document).on('click', '.oc-edit-btn', function(e) {

@@ -599,7 +599,7 @@ 

                  configPage =

                      <div>

                          <Row className="ds-margin-top" title="The server's secure port number (nsslapd-secureport).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Server Secure Port

                              </Col>

                              <Col sm={4}>
@@ -607,7 +607,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="This parameter can be used to restrict the Directory Server instance to a single IP interface (hostname, or IP address).  This parameter specifically sets what interface to use for TLS traffic.  Requires restart. (nsslapd-securelistenhost).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Secure Listen Host

                              </Col>

                              <Col sm={4}>
@@ -615,7 +615,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="The name, or nickname, of the server certificate inthe NSS datgabase the server should use (nsSSLPersonalitySSL).">

-                             <Col className="ds-no-padding" sm={2}>

+                             <Col className="ds-no-padding" sm={3}>

                                  <ControlLabel>Server Certificate Name</ControlLabel>

                              </Col>

                              <Col sm={4}>
@@ -631,7 +631,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="The minimum SSL/TLS version the server will accept (sslversionmin).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Minimum TLS Version

                              </Col>

                              <Col sm={4}>
@@ -646,7 +646,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="The maximum SSL/TLS version the server will accept (sslversionmax).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Maximum TLS Version

                              </Col>

                              <Col sm={4}>
@@ -661,7 +661,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="Sets how the Directory Server enforces TLS client authentication (nsSSLClientAuth).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Client Authentication

                              </Col>

                              <Col sm={4}>
@@ -673,7 +673,7 @@ 

                              </Col>

                          </Row>

                          <Row className="ds-margin-top" title="Validate server's certificate expiration date (nsslapd-validate-cert).">

-                             <Col componentClass={ControlLabel} sm={2}>

+                             <Col componentClass={ControlLabel} sm={3}>

                                  Validate Certificate

                              </Col>

                              <Col sm={4}>

@@ -95,24 +95,24 @@ 

         <div class="ds-divider"></div>

         <div class="ds-inline">

           <div>

-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-attribute-name-exceptions" checked><label

+            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-attribute-name-exceptions"><label

               for="nsslapd-attribute-name-exceptions" class="ds-label" title="Allows non-standard characters in attribute names to be used for backwards compatibility with older servers"> Allow Attribute Naming Exceptions </label>

           </div>

           <div>

-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-dn-validate-strict" checked><label

+            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-dn-validate-strict"><label

               for="nsslapd-dn-validate-strict" class="ds-label" title="Enables strict syntax validation for DNs, according to section 3 in RFC 4514 (nsslapd-dn-validate-strict)."> Enable Strict DN Syntax Validation</label>

           </div>

           <div>

-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-entryusn-global" checked><label

+            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-entryusn-global"><label

               for="nsslapd-entryusn-global" class="ds-label" title="For USN plugin - maintain unique USNs across all back end databases (nsslapd-entryusn-global)."> Enable Unique USNs Across All Backends</label>

           </div>

           <div>

-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-ignore-time-skew" checked><label

+            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-ignore-time-skew"><label

               for="nsslapd-ignore-time-skew" class="ds-label" title="Ignore time skew when generating CSNs"> Ignore CSN Time Skew</label>

           </div>

           <div>

-            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-readonly-server" checked><label

-              for="nsslapd-readonly-server" class="ds-label" title="Make entire server read-only (nsslapd-readonly)"> Server Read-Only</label>

+            <input type="checkbox" class="ds-config-checkbox" id="nsslapd-readonly"><label

+              for="nsslapd-readonly" class="ds-label" title="Make entire server read-only (nsslapd-readonly)"> Server Read-Only</label>

           </div>

  

         </div>

@@ -165,6 +165,7 @@ 

      $(".ds-accesslog-table").prop('checked', false);

      $(".ds-errorlog-table").prop('checked', false);

      config_values = {};

+     update_progress();

  

      for (var attr in obj['attrs']) {

        var val = obj['attrs'][attr][0];
@@ -189,6 +190,7 @@ 

  

        // Do the log level tables

        if (attr == "nsslapd-accesslog-level") {

+         config_values[attr] = val;

          var level_val = parseInt(val);

          for ( var level in accesslog_levels ) {

            if (level_val & accesslog_levels[level]) {
@@ -196,6 +198,7 @@ 

            }

          }

        } else if (attr == "nsslapd-errorlog-level") {

+         config_values[attr] = val;

          var level_val = parseInt(val);

          for ( var level in errorlog_levels ) {

            if (level_val & errorlog_levels[level]) {
@@ -232,6 +235,7 @@ 

            $("#" + dropdowns[list]).append('<option value="' + obj['items'][idx] + '" selected="selected">' + obj['items'][idx] +'</option>');

          }

        }

+       update_progress();

    }).fail(function(data) {

        if (quiet === undefined) {

          popup_err("Error", "Failed to get backend suffix list\n" + data.message);
@@ -251,6 +255,7 @@ 

    log_cmd('get_and_set_localpwp', 'Get local password policies', cmd);

    cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

      var obj = JSON.parse(data);

+     update_progress();

      // Empty table

      pwp_table.clear().draw();

  
@@ -276,13 +281,13 @@ 

    log_cmd('get_and_set_sasl', 'Get SASL mappings', cmd);

    cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

      var obj = JSON.parse(data);

+     update_progress();

      sasl_table.clear().draw();

      for (var idx in obj['items']) {

        var map_cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'get', obj['items'][idx] ];

        log_cmd('get_and_set_sasl', 'Get SASL mapping', map_cmd);

        cockpit.spawn(map_cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

          var map_obj = JSON.parse(data);

- 

          // Update html table

          var sasl_priority = '100';

          if ( map_obj['attrs'].hasOwnProperty('nssaslmappriority') ){
@@ -357,14 +362,29 @@ 

        var val = $("#" + attr).val();

  

        // But first check for rootdn-pw changes and check confirm input matches

-       if (attr == "nsslapd-rootpw" && (val != config_values[attr] || val != $("#nsslapd-rootpw-confirm").val())) {

-         // Password change, make sure passwords match

-         if (val != $("#nsslapd-rootpw-confirm").val()){

-           popup_msg("Passwords do not match!", "The Directory Manager passwords do not match, please correct before saving again.");

-           return;

+       if (attr == "nsslapd-rootpw") {

+         if (val != config_values[attr] || val != $("#nsslapd-rootpw-confirm").val()) {

+             // Password change, make sure passwords match

+             if (val != $("#nsslapd-rootpw-confirm").val()){

+               popup_msg("Passwords do not match!", "The Directory Manager passwords do not match, please correct before saving again.");

+               return;

+             }

+         }

+         if (val.length < 8) {

+             popup_msg("Password is too short!", "The Directory Manager password must be at least 8 characters long.");

+             $("#nsslapd-rootpw").val(config_values[attr]);

+             $("#nsslapd-rootpw-confirm").val(config_values[attr]);

+             return;

          }

        }

  

+       if (attr == "nsslapd-port") {

+           if (!valid_num(config_values[attr])) {

+               popup_msg("Port number is not valid");

+               $("#nsslapd-port").val(config_values[attr]);

+           }

+       }

+ 

        if ( val && val != config_values[attr]) {

          mod['attr'] = attr;

          mod['val'] = val;
@@ -382,10 +402,15 @@ 

        access_log_level += val;

      }

    });

-   mod = {}

-   mod['attr'] = "nsslapd-accesslog-level";

-   mod['val'] = access_log_level;

-   mod_list.push(mod);

+   if (config_values["nsslapd-accesslog-level"] === undefined) {

+       config_values["nsslapd-accesslog-level"] = "256";

+   }

+   if (config_values["nsslapd-accesslog-level"] != access_log_level) {

+       mod = {}

+       mod['attr'] = "nsslapd-accesslog-level";

+       mod['val'] = access_log_level;

+       mod_list.push(mod);

+   }

  

    // Save error log levels

    var error_log_level = 0;
@@ -396,10 +421,17 @@ 

        error_log_level += val;

      }

    });

-   mod = {}

-   mod['attr'] = "nsslapd-errorlog-level";

-   mod['val'] = error_log_level;

-   mod_list.push(mod);

+   if (config_values["nsslapd-errorlog-level"] === undefined ||

+       config_values["nsslapd-errorlog-level"] == "16384")

+   {

+       config_values["nsslapd-errorlog-level"] = "0";

+   }

+   if (config_values["nsslapd-errorlog-level"] != error_log_level) {

+       mod = {}

+       mod['attr'] = "nsslapd-errorlog-level";

+       mod['val'] = error_log_level;

+       mod_list.push(mod);

+   }

  

    // Build dsconf commands to apply all the mods

    if (mod_list.length) {
@@ -1007,6 +1039,10 @@ 

         * Get all the current values from the form.

         */

        var policy_name = $("#local-entry-dn").val();

+       if (policy_name == "" || !valid_dn(policy_name)) {

+         popup_msg("Error", "You must enter a valid DN for the local password policy");

+         return;

+       }

        var pwp_track = "off";

        if ( $("#local-passwordtrackupdatetime").is(":checked") ) {

          pwp_track = "on";
@@ -1479,19 +1515,33 @@ 

        var new_server_id = $("#create-inst-serverid").val();

        if (new_server_id == ""){

          report_err($("#create-inst-serverid"), 'You must provide an Instance name');

+         $("#create-inst-serverid").css("border-color", "red");

          return;

        } else {

          new_server_id = new_server_id.replace(/^slapd-/i, "");  // strip "slapd-"

-         setup_inf = setup_inf.replace('INST_NAME', new_server_id);

+         if (new_server_id.length > 128) {

+             report_err($("#create-inst-serverid"), 'Instance name is too long, it must not exceed 128 characters');

+             $("#create-inst-serverid").css("border-color", "red");

+             return;

+         }

+         if (new_server_id.match(/^[#%:-A-Za-z0-9_]+$/g)) {

+             setup_inf = setup_inf.replace('INST_NAME', new_server_id);

+         } else {

+             report_err($("#create-inst-serverid"), 'Instance name can only contain letters, numbers, and:  # % : - _');

+             $("#create-inst-serverid").css("border-color", "red");

+             return;

+         }

        }

  

        // Port

        var server_port = $("#create-inst-port").val();

        if (server_port == ""){

          report_err($("#create-inst-port"), 'You must provide a port number');

+         $("#create-inst-port").css("border-color", "red");

          return;

        } else if (!valid_num(server_port)) {

-         report_err($("#create-inst-port"), 'Port must be a number!');

+         report_err($("#create-inst-port"), 'Port must be a number between 1 and 65534!');

+         $("#create-inst-port").css("border-color", "red");

          return;

        } else {

          setup_inf = setup_inf.replace('PORT', server_port);
@@ -1501,9 +1551,11 @@ 

        var secure_port = $("#create-inst-secureport").val();

        if (secure_port == ""){

          report_err($("#create-inst-secureport"), 'You must provide a secure port number');

+         $("#create-inst-secureport").css("border-color", "red");

          return;

        } else if (!valid_num(secure_port)) {

          report_err($("#create-inst-secureport"), 'Secure port must be a number!');

+         $("#create-inst-secureport").css("border-color", "red");

          return;

        } else {

          setup_inf = setup_inf.replace('SECURE_PORT', secure_port);
@@ -1513,6 +1565,7 @@ 

        var server_rootdn = $("#create-inst-rootdn").val();

        if (server_rootdn == ""){

          report_err($("#create-inst-rootdn"), 'You must provide a Directory Manager DN');

+         $("#create-inst-rootdn").css("border-color", "red");

          return;

        } else {

          setup_inf = setup_inf.replace('ROOTDN', server_rootdn);
@@ -1536,6 +1589,10 @@ 

          report_err($("#rootdn-pw"), 'Directory Manager password can not be empty!');

          $("#rootdn-pw-confirm").css("border-color", "red");

          return;

+       } else if (root_pw.length < 8) {

+         report_err($("#rootdn-pw"), 'Directory Manager password must have at least 8 characters');

+         $("#rootdn-pw-confirm").css("border-color", "red");

+         return;

        } else {

          setup_inf = setup_inf.replace('ROOTPW', root_pw);

        }
@@ -1546,9 +1603,11 @@ 

        if ( (backend_name != "" && backend_suffix == "") || (backend_name == "" && backend_suffix != "") ) {

          if (backend_name == ""){

            report_err($("#backend-name"), 'If you specify a backend suffix, you must also specify a backend name');

+           $("#backend-name").css("border-color", "red");

            return;

          } else {

            report_err($("#backend-suffix"), 'If you specify a backend name, you must also specify a backend suffix');

+           $("#backend-suffix").css("border-color", "red");

            return;

          }

        }

file modified
+1 -1
@@ -64,7 +64,7 @@ 

          return DN_CONFIG

  

      def replace(self, key, value):

-         if key.lower() == 'nsslapd-secureport' and selinux_present():

+         if selinux_present() and (key.lower() == 'nsslapd-secureport' or key.lower() == 'nsslapd-port'):

              # Get old port and remove label

              old_port = self.get_attr_val_utf8(key)

              self.log.debug("Removing old port's selinux label...")

@@ -166,8 +166,9 @@ 

          self._helptext['root_password'] = ("Sets the password of the account specified in the \"root_dn\" parameter. " +

                                             "You can either set this parameter to a plain text password dscreate hashes " +

                                             "during the installation or to a \"{algorithm}hash\" string generated by the " +

-                                            "pwdhash utility. Note that setting a plain text password can be a security " +

-                                            "risk if unprivileged users can read this INF file!")

+                                            "pwdhash utility. The password must be at least 8 characters long.  Note " +

+                                            "that setting a plain text password can be a security risk if unprivileged " +

+                                            "users can read this INF file!")

  

          self._options['prefix'] = ds_paths.prefix

          self._type['prefix'] = str

@@ -105,7 +105,10 @@ 

          _log.debug(f"CMD: {' '.join(result.args)} ; STDOUT: {result.stdout} ; STDERR: {result.stderr}")

  

          _log.debug("Removing %s" % tmpfiles_d_path)

-         shutil.rmtree(tmpfiles_d_path, ignore_errors=True)

+         try:

+             os.remove(tmpfiles_d_path)

+         except OSError as e:

+             _log.debug("Failed to remove tmpfile: " + str(e))

  

      # Nor can we assume we have selinux. Try docker sometime ;)

      if dirsrv.ds_paths.with_selinux:

@@ -243,8 +243,11 @@ 

          print('===========================================')

  

          # Set the defaults

-         general = {'config_version': 2, 'full_machine_name': socket.getfqdn(),

-                    'strict_host_checking': False, 'selinux': True, 'systemd': ds_paths.with_systemd,

+         general = {'config_version': 2,

+                    'full_machine_name': socket.getfqdn(),

+                    'strict_host_checking': False,

+                    'selinux': True,

+                    'systemd': ds_paths.with_systemd,

                     'defaults': '999999999', 'start': True}

  

          slapd = {'self_sign_cert_valid_months': 24,
@@ -394,6 +397,11 @@ 

                  print('Password can not be empty')

                  continue

  

+             if len(rootpw1) < 8:

+                 print('Password must be at least 8 characters long')

+                 continue

+ 

+ 

              rootpw2 = getpass.getpass('Confirm the Directory Manager Password: ').rstrip()

              if rootpw1 != rootpw2:

                  print('Passwords do not match')
@@ -568,6 +576,9 @@ 

          assert_c(is_a_dn(slapd['root_dn']), "root_dn in section [slapd] is not a well formed LDAP DN")

          assert_c(slapd['root_password'] is not None and slapd['root_password'] != '',

                   "Configuration attribute 'root_password' in section [slapd] not found")

+         if len(slapd['root_password']) < 8:

+             raise ValueError("root_password must be at least 8 characters long")

+ 

          # Check if pre-hashed or not.

          # !!!!!!!!!!!!!!

  

Description: This patch addresses several issues:

  • 50546 - Exports from Cockpit can be stored outside of /var/lib/dirsrv/slapd-instance_name/ldif/
  • 50418 - dsctl remove does not cleanup /etc/tmpfiles.d
  • 50554 - Cockpit incorrectly shows that a server is in read-only mode
  • 49856 - Changing port should adjust selinux labels

This also enforces a minimum password length for root DN

relates: https://pagure.io/389-ds-base/issue/50546

If a short password specified, UI prints an error Failed to create instance! with an empty infobox without any details.

While trying to export a suffix (Database -> Suffixes -> Suffix Tasks -> Export)
the next error is given to the browser console:

Uncaught TypeError: Cannot read property 'includes' of undefined
at bad_file_name (index.js:173505)
at Suffix.doExport (index.js:150315)
at HTMLUnknownElement.callCallback (index.js:107984)
at Object.invokeGuardedCallbackDev (index.js:108034)
at invokeGuardedCallback (index.js:108091)
at invokeGuardedCallbackAndCatchFirstError (index.js:108105)
at executeDispatch (index.js:108396)
at executeDispatchesInOrder (index.js:108415)
at executeDispatchesAndRelease (index.js:108515)
at executeDispatchesAndReleaseTopLevel (index.js:108523)

And a small nitpick... Could you please specify all of the issue links in the commit message? It will make tracking easier in the future.

This is not correct - if we can't remove the tmpfiles, we have to raise the exception so the tools crash. That way the marker file is not incorrectly removed unless we really really have removed the instance.

What's the problem you are trying to solve here?

I think the pw quality check should not be in setup.py because that's confusing the job/responsibilities of this module I think. Perhaps this should be "higher up" in the process, IE at the cli level or similar? It depends what problem you are trying to solve here.

I think the pw quality check should not be in setup.py because that's confusing the job/responsibilities of this module I think. Perhaps this should be "higher up" in the process, IE at the cli level or similar? It depends what problem you are trying to solve here.

This is for the interactive installer. It is silly to wait to the end of the questions to say, oh wait your root DN password is too short. All interactive installers do this check as soon as a invalid password is used.

Also password policy is not checked for root DN only normal users :-)

This is not correct - if we can't remove the tmpfiles, we have to raise the exception so the tools crash. That way the marker file is not incorrectly removed unless we really really have removed the instance.
What's the problem you are trying to solve here?

Well in my /etc/tmpfile.d I have 150+ dirsrv-instance conf files. We should be removing these are instance removal, and the using shutil.rmtree fails when trying to remove a single file. So I had to change it to os.remove(). I hope that clears things up ;-)

rebased onto 3f6eb1fcab629f8d8d332bf6360e086e40777b33

2 years ago

Revised, please review...

rebased onto 0040332

2 years ago

Pull-Request has been merged by mreynolds

2 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3621

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

2 years ago