#49847 Ticket 49806 - Add SASL functionality to CLI/UI
Closed 2 years ago by spichugi. Opened 3 years ago by mreynolds.
mreynolds/389-ds-base ticket49806  into  master

@@ -407,36 +407,36 @@ 

              <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-\"">

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

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

                </div>

                <div>

                  <label for="create-inst-port" class="ds-config-label" title="The server port number">

-                   Port</label><input class="ds-input" type="text" value="389" id="create-inst-port" required />

+                   Port</label><input class="ds-input ds-inst-input" type="text" value="389" id="create-inst-port" required />

                </div>

                <div>

                  <label for="create-inst-secureport" class="ds-config-label" title="The secure port number for TLS connections">

-                   Secure Port</label><input class="ds-input" type="text" value="636" id="create-inst-secureport" required />

+                   Secure Port</label><input class="ds-input ds-inst-input" type="text" value="636" id="create-inst-secureport" required />

                </div>

                <div>

                  <label for="create-inst-rootdn" class="ds-config-label" title="The DN for the unrestricted  user">

-                   Directory Manager DN</label><input class="ds-input" value="cn=Directory Manager" type="text" id="create-inst-rootdn" required />

+                   Directory Manager DN</label><input class="ds-input ds-inst-input" value="cn=Directory Manager" type="text" id="create-inst-rootdn" required />

                </div>

                <div>

                  <label for="rootdn-pw" class="ds-config-label" title="Directory Manager password.">Directory Manager Password</label><input

-                   class="ds-input" type="password" placeholder="Enter password" id="rootdn-pw" name="name" required>

+                   class="ds-input ds-inst-input" type="password" placeholder="Enter password" id="rootdn-pw" name="name" required>

                </div>

                <div>

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

-                   class="ds-input" type="password" placeholder="Confirm password" id="rootdn-pw-confirm" name="name" required>

+                   class="ds-input ds-inst-input" type="password" placeholder="Confirm password" id="rootdn-pw-confirm" name="name" required>

                </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" type="text" id="backend-name">

+                   class="ds-input ds-inst-input" 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" type="text" id="backend-suffix">

+                   class="ds-input ds-inst-input" 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
@@ -509,6 +509,9 @@ 

      <div id="not-running" class="all-pages ds-center" hidden>

        <h3>This server instance is not running, either start it from the <b>Actions</b> dropdown menu, or choose a different instance</h3>

      </div>

+     <div id="no-connect" class="all-pages ds-center" hidden>

+       <h3>This server instance is running, but we can not connect to it.  Check LDAPI is properly configured on this instance.</h3>

+     </div>

  

      <div id="server-content" class="all-pages" hidden>

      </div>

@@ -442,7 +442,7 @@ 

      }

  

  

-     $(".index-type").attr('readonly', 'readonly');

+     $(".index-type").attr('readonly', true);

  

      if ( $("#manual-cache").is(":checked") ){

        $("#auto-cache-form").hide();

@@ -110,19 +110,29 @@ 

    });

  }

  

- function check_inst_alive () {

+ function check_inst_alive (connect_err) {

    // Check if this instance is started, if not hide configuration pages

+   if (connect_err === undefined) {

+     connect_err = 0;

+   }

    cmd = ['status-dirsrv', server_inst];

-   console.log("MARK cmd: " + cmd);

    cockpit.spawn(cmd, { superuser: true }).done(function () {

-     $(".all-pages").hide();

-     $("#ds-navigation").show();

-     $("#server-content").show();

-     $("#server-config").show();

-     //$("#no-instances").hide();

-     //$("#no-package").hide();

-     $("#not-running").hide();

-     console.log("Running");

+     if (connect_err) {

+       $("#ds-navigation").hide();

+       $(".all-pages").hide();

+       $("#no-connect").show();

+ 

+     } else {

+       $(".all-pages").hide();

+       $("#ds-navigation").show();

+       $("#server-content").show();

+       $("#server-config").show();

+       //$("#no-instances").hide();

+       //$("#no-package").hide();

+       $("#not-running").hide();

+       $("#no_connect").hide();

+       console.log("Running");

+     }

    }).fail(function(data) {

      $("#ds-navigation").hide();

      $(".all-pages").hide();
@@ -180,7 +190,7 @@ 

        $("#server-config").show();

        server_id = insts[0];

        server_inst = insts[0].replace("slapd-", "");

-       get_and_set_config();

+       load_config();

      }

  

      $("body").show();
@@ -256,6 +266,7 @@ 

  function load_config (){

    // TODO - set all the pages

    get_and_set_config(); // cn=config stuff

+   get_and_set_sasl();  // Fill in sasl mapping table

  }

  

  $(window.document).ready(function() {

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

        '<span class="caret"></span>' +

      '</button>' +

      '<ul class="dropdown-menu ds-agmt-dropdown" role="menu" aria-labelledby="dropdownMenu1">' +

-       '<li role=""><a role="menuitem" class="sasl-edit-btn" tabindex="0" href="#">Edit Mapping</a></li>' +

-       '<li role=""><a role="menuitem" class="sasl-verify-btn" tabindex="0" href="#">Test Mapping</a></li>' +

+       '<li role=""><a role="menuitem" class="sasl-edit-btn" tabindex="2" href="#">Edit Mapping</a></li>' +

        '<li role=""><a role="menuitem" class="sasl-del-btn" tabindex="1" href="#">Delete Mapping</a></li>' +

      '</ul>' +

    '</div>';
@@ -74,77 +73,30 @@ 

    "self_sign_cert = SELF_SIGN\n";

  

  

+ var sasl_table;

+ 

  function load_server_config() {

    var mark = document.getElementById("server-config-title");

    mark.innerHTML = "Configuration for server: <b>" + server_id + "</b>";

  }

  

- function server_hide_all(){

-   // Jquery can problem do this better using names/roles

-   $("#server-config").hide();

-   $("#server-security").hide();

-   $("#server-logs").hide();

-   $("#server-pwpolicy").hide();

-   $("#server-tuning").hide();

-   $("#server-tuning").hide();

- };

- 

  function clear_sasl_map_form () {

-   $("#sasl-map-name").val("");

-   $("#sasl-map-regex").val("");

-   $("#sasl-map-base").val("");

-   $("#sasl-map-filter").val("");

-   $("#sasl-map-priority").val("");

+   $(".ds-modal-error").hide();

+   $(".sasl-input").val("");

+   $(".sasl-input").css("border-color", "initial");

  }

  

  function clear_local_pwp_form () {

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

-   $("#local-passwordtrackupdatetime").prop('checked', false);

-   $("#local-passwordadmindn").val("");

-   $("#local-passwordchange").prop('checked', false);

-   $("#local-passwordmustchange").prop('checked', false);

-   $("#local-passwordhistory").prop('checked', false);

-   $("#local-passwordinhistory").val("");

-   $("#local-passwordminage").val("");

-   $("#local-passwordexp").prop('checked', false);

-   $("#local-passwordmaxage").val("");

-   $("#local-passwordgracelimit").val("");

-   $("#local-passwordwarning").val("");

-   $("#local-passwordsendexpiringtime").prop('checked', false);

-   $("#local-passwordlockout").prop('checked', false);

-   $("#local-passwordmaxfailure").val("");

-   $("#local-passwordresetfailurecount").val("");

-   $("#local-passwordunlock").prop('checked', false);

-   $("#local-passwordlockoutduration").val("");

-   $("#local-passwordchecksyntax").prop('checked', false);

-   $("#local-passwordminlength").val("");

-   $("#local-passwordmindigits").val("");

-   $("#local-passwordminalphas").val("");

-   $("#local-passwordminuppers").val("");

-   $("#local-passwordminlowers").val("");

-   $("#local-passwordminspecials").val("");

-   $("#local-passwordmin8bit").val("");

-   $("#local-passwordmaxrepeats").val("");

-   $("#local-passwordmincategories").val("");

-   $("#local-passwordmintokenlength").val("");

+   $(".ds-pwp-input").val("");

+   $(".ds-pwp-checkbox").prop('checked', false);

    $("#local-passwordstoragescheme").prop('selectedIndex',0);

-   $("#subtree-pwp-radio").prop('checked', true);

    $("#subtree-pwp-radio").attr('disabled', false);

    $("#user-pwp-radio").attr('disabled', false);

  }

  

  function clear_inst_input() {

    // Reset the color of the fields

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

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

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

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

-   $("#create-inst-user").css("border-color", "initial");

-   $("#create-inst-group").css("border-color", "initial");

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

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

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

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

+   $(".ds-inst-input").css("border-color", "initial");

  }

  

  function clear_inst_form() {
@@ -159,10 +111,9 @@ 

    $("#backend-name").val("");

    $("#create-sample-entries").prop('checked', false);

    $("#create-inst-tls").prop('checked', true);

-   clear_inst_input();

+   $(".ds-inst-input").css("border-color", "initial");

  }

  

- 

  function get_and_set_config () {

    var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','config', 'get'];

    cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
@@ -186,7 +137,40 @@ 

      check_inst_alive();

    }).fail(function(data) {

        console.log("failed: " + data.message);

-       check_inst_alive();

+       check_inst_alive(1);

+   });

+ }

+ 

+ function get_and_set_sasl () {

+   // First empty the table

+   $("#sasl-table").find("tr:gt(0)").empty();

+ 

+   var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'list'];

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

+     var obj = JSON.parse(data);

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

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

+       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') ){

+           sasl_priority = map_obj['attrs'].nssaslmappriority

+         }

+         sasl_table.row.add( [

+           map_obj['attrs'].cn,

+           map_obj['attrs'].nssaslmapregexstring,

+           map_obj['attrs'].nssaslmapbasedntemplate,

+           map_obj['attrs'].nssaslmapfiltertemplate,

+           sasl_priority,

+           sasl_action_html

+         ] ).draw( false );

+       });

+     }

+   }).fail(function(data) {

+       console.log("failed: " + data.message);

+       check_inst_alive(1);

    });

  }

  
@@ -386,7 +370,7 @@ 

          }

      });

  

-     var sasl_table = $('#sasl-table').DataTable( {

+     sasl_table = $('#sasl-table').DataTable( {

        "paging": true,

        "bAutoWidth": false,

        "dom": '<"pull-left"f><"pull-right"l>tip',
@@ -403,19 +387,51 @@ 

  

      $("#create-sasl-map-btn").on("click", function () {

        clear_sasl_map_form();

+       $("#sasl-map-name").prop("readonly", false);

+     });

+ 

+     $("#test-sasl-regex").change(function() {

+       if(this.checked) {

+         // Test SASL mapping

+         $("#sasl-test-div").show();

+       } else {

+         $("#sasl-test-div").hide();

+       }

+     });

+ 

+     // Test SASL Mapping Regex

+     $("#sasl-test-regex-btn").on('click', function () {

+       var result = "No match!"

+       var regex = $("#sasl-map-regex").val().replace(/\\\(/g, '(').replace(/\\\)/g, ')');

+       var test_string = $("#sasl-test-regex-string").val();

+       var sasl_regex = RegExp(regex);

+       if (sasl_regex.test(test_string)){

+         popup_msg("Match", "The text matches the regular expression");

+       } else {

+         popup_msg("No Match", "The text does not match the regular expression");

+       }

      });

  

      // Edit SASL mapping

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

-         // TODO - get this working

-         e.preventDefault();

-         clear_sasl_map_form();

-         var data = sasl_table.row( $(this).parents('tr') ).data();

-         var edit_sasl_name = data[0];

- 

-         $("#sasl-header").html("Edit SASL Mapping");

-         $("#sasl-map-name").val(edit_sasl_name);

-         $("#sasl-map-form").modal("toggle");

+       // Load the Edit form

+       e.preventDefault();

+       clear_sasl_map_form();

+       var data = sasl_table.row( $(this).parents('tr') ).data();

+       var edit_sasl_name = data[0];

+       var edit_sasl_regex = data[1];

+       var edit_sasl_base = data[2];

+       var edit_sasl_filter = data[3];

+       var edit_sasl_priority = data[4];

+ 

+       $("#sasl-header").html("Edit SASL Mapping");

+       $("#sasl-map-name").val(edit_sasl_name);

+       $("#sasl-map-name").prop("readonly", true);

+       $("#sasl-map-regex").val(edit_sasl_regex);

+       $("#sasl-map-base").val(edit_sasl_base);

+       $("#sasl-map-filter").val(edit_sasl_filter);

+       $("#sasl-map-priority").val(edit_sasl_priority);

+       $("#sasl-map-form").modal("toggle");

      });

  

      // Verify SASL Mapping regex - open modal and ask for "login" to test regex mapping
@@ -434,10 +450,14 @@ 

          var sasl_row = $(this); // Store element for callback

          popup_confirm("Are you sure you want to delete sasl mapping: <b>" + del_sasl_name + "</b>", "Confirmation", function (yes) {

          if (yes) {

-           // TODO Delete mapping from DS

- 

-           // Update html table

-           sasl_table.row( sasl_row.parents('tr') ).remove().draw( false );

+           var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'delete', del_sasl_name];

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

+             sasl_table.row( sasl_row.parents('tr') ).remove().draw( false );

+             popup_success("Removed SASL mapping <b>" + del_sasl_name + "</b>");

+           }).fail(function(data) {

+             popup_err("Failure Deleting SASL Mapping",

+                       "Failed To Delete SASL Mapping: <b>" + del_sasl_name + "</b>: \n" + data.message);

+           });

          }

        });

      });
@@ -854,27 +874,105 @@ 

  

      // SASL Mappings Form

      $("#sasl-map-save").on("click", function() {

-       var sasl_name = $("#sasl-map-name").val();

-       var sasl_regex = $("#sasl-map-regex").val();

-       var sasl_base = $("#sasl-map-base").val();

+       var sasl_map_name = $("#sasl-map-name").val();

+       var sasl_regex =  $("#sasl-map-regex").val();

+       var sasl_base =  $("#sasl-map-base").val();

        var sasl_filter = $("#sasl-map-filter").val();

        var sasl_priority = $("#sasl-map-priority").val();

  

-       // TODO - Add mapping to DS

- 

-       // Update html table

-       sasl_table.row.add( [

-         sasl_name,

-         sasl_regex,

-         sasl_base,

-         sasl_filter,

-         sasl_priority,

-         sasl_action_html

-       ] ).draw( false );

- 

-       // Done

-       //$("#sasl-map-form").css('display', 'none');

-       $("#sasl-map-form").modal('toggle');

+       // Validate values

+       if (sasl_map_name == '') {

+         report_err($("#sasl-map-name"), 'You must provide an mapping name');

+         return;

+       }

+       if (sasl_map_name == '') {

+         report_err($("#sasl-map-regex"), 'You must provide an regex');

+         return;

+       }

+       if (sasl_regex == '') {

+         report_err($("#sasl-map-base"), 'You must provide a base DN template');

+         return;

+       }

+       if (sasl_filter == '') {

+         report_err($("#sasl-map-filter"), 'You must provide an filter template');

+         return;

+       }

+       if (sasl_priority == '') {

+         sasl_priority = '100'

+       } else if (valid_num(sasl_priority)) {

+         var priority = Number(sasl_priority);

+         if (priority < 1 || priority > 100) {

+           report_err($("#sasl-map-priority"), 'You must provide a number between 1 and 100');

+           return;

+         }

+       } else {

+         report_err($("#sasl-map-priority"), 'You must provide a number between 1 and 100');

+         return;

+       }

+ 

+       // Build command line args

+       var sasl_name_cmd = "--cn=" + sasl_map_name ;

+       var sasl_regex_cmd = "--nsSaslMapRegexString=" + sasl_regex;

+       var sasl_base_cmd = "--nsSaslMapBaseDNTemplate=" + sasl_base;

+       var sasl_filter_cmd = "--nsSaslMapFilterTemplate=" + sasl_filter;

+       var sasl_priority_cmd = "--nsSaslMapPriority=" + sasl_priority;

+ 

+       if ( $("#sasl-header").html().includes("Create") ) {

+         // Create new mapping and update table

+         var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'create',

+                    sasl_name_cmd, sasl_regex_cmd, sasl_base_cmd, sasl_filter_cmd, sasl_priority_cmd];

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

+           // Update html table

+           sasl_table.row.add( [

+             sasl_map_name,

+             sasl_regex,

+             sasl_base,

+             sasl_filter,

+             sasl_priority,

+             sasl_action_html

+           ] ).draw( false );

+           popup_success("Successfully added new SASL mapping");

+           $("#sasl-map-form").modal('toggle');

+         }).fail(function(data) {

+           popup_err("Failure Adding SASL Mapping",

+                     "Failed To Add SASL Mapping: <b>" + sasl_map_name + "</b>: \n" + data.message);

+           $("#sasl-map-form").modal("toggle");

+         });

+       } else {

+         // Editing mapping.  First delete the old mapping

+         var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'delete', sasl_map_name];

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

+           // Remove row from old

+           sasl_table.rows( function ( idx, data, node ) {

+             return data[0] == sasl_map_name;

+           }).remove().draw();

+ 

+           // Then add new mapping and update table

+           var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','sasl', 'create',

+                      sasl_name_cmd, sasl_regex_cmd, sasl_base_cmd, sasl_filter_cmd, sasl_priority_cmd];

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

+             // Update html table

+             sasl_table.row.add( [

+               sasl_map_name,

+               sasl_regex,

+               sasl_base,

+               sasl_filter,

+               sasl_priority,

+               sasl_action_html

+             ] ).draw( false );

+             popup_success("Successfully added new SASL mapping");

+             $("#sasl-map-form").modal('toggle');

+           }).fail(function(data) {

+             popup_err("Failure Adding SASL Mapping",

+                       "Failed To Add SASL Mapping: <b>" + sasl_map_name + "</b>: \n" + data.message);

+             $("#sasl-map-form").modal("toggle");

+           });

+         }).fail(function(data) {

+           popup_err("Failure Deleting Old SASL Mapping",

+                     "Failed To Delete SASL Mapping: <b>" + sasl_map_name + "</b>: \n" + data.message);

+           $("#sasl-map-form").modal("toggle");

+         });

+       }

      });

  

      /*
@@ -1069,7 +1167,7 @@ 

      // Create Instance

      $("#create-inst-save").on("click", function() {

        $(".ds-modal-error").hide();

-       clear_inst_input();

+       $(".ds-inst-input").css("border-color", "initial");

  

        /*

         * Validate settings and update the INF settings

@@ -184,7 +184,7 @@ 

            class="ds-input" type="text" id="nsslapd-sasl-max-buffer-size" size="40"/>

        </div>

        <div>

-         <label for="nsslapd-allowed-sasl-mechanisms" class="ds-config-label" title="A list of SASL mechanisms the server will accept (nsslapd-allowed-sasl-mechanisms).">Allowed SASL Mechanisms</label><input

+         <label for="nsslapd-allowed-sasl-mechanisms" class="ds-config-label" title="A list of SASL mechanisms the server will only accept (nsslapd-allowed-sasl-mechanisms).">Allowed SASL Mechanisms</label><input

            class="ds-input" type="text" id="nsslapd-allowed-sasl-mechanisms" size="40"/>

        </div>

        <div>
@@ -209,26 +209,6 @@ 

              <th>Action</th>

          </thead>

          <tbody id="sasl-mappings">

-           <tr>

-             <td>Kerberos UID Mapping</td>

-             <td>\(.*\)@\(.*\)\.\(.*\)</td>

-             <td>dc=\2,dc=\3</td>

-             <td>(uid=\1)</td>

-             <td></td>

-             <td>

-               <div class="dropdown">

-                 <button class="btn btn-default dropdown-toggle ds-agmt-dropdown-button" type="button" data-toggle="dropdown">

-                   Choose Action...

-                   <span class="caret"></span>

-                 </button>

-                 <ul class="dropdown-menu ds-agmt-dropdown" role="menu">

-                   <li><a role="menuitem" class="sasl-edit-btn">Edit Mapping</a></li>

-                   <li><a role="menuitem" class="sasl-verify-btn">Test Mapping</a></li>

-                   <li><a role="menuitem" class="sasl-del-btn">Delete Mapping</a></li>

-                 </ul>

-               </div>

-             </td>

-           </tr>

          </tbody>

        </table>

        <button class="btn btn-default" data-toggle="modal" data-target="#sasl-map-form" id="create-sasl-map-btn">Create SASL Mapping</button>
@@ -1017,8 +997,8 @@ 

  

  

    <!-- Create SASL Mapping -->

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

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

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

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

        <div class="modal-content">

          <div class="modal-header">

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

          <div class="modal-body">

            <form class="form-horizontal">

              <div class="ds-inline">

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

                <div>

                  <label for="sasl-map-name" class="ds-config-label" title="SASL mapping name">

-                   SASL Mapping Name</label><input class="ds-input" type="text" id="sasl-map-name"/>

+                   SASL Mapping Name</label><input class="ds-input sasl-input" type="text" id="sasl-map-name"/>

                </div>

                <div>

                  <label for="sasl-map-regex" class="ds-config-label" title="SASL mapping regular expression">

-                   SASL Mapping Regex</label><input class="ds-input" type="text" id="sasl-map-regex"/>

+                   SASL Mapping Regex</label><input class="ds-input sasl-input" type="text" id="sasl-map-regex"/><label

+                   for="test-sasl-regex" class="ds-left-margin">Test Regex</label><input type="checkbox"

+                   class="ds-left-margin ds-checkbox-group" id="test-sasl-regex">

+               </div>

+               <div id="sasl-test-div" hidden>

+                 <div class="ds-inline">

+                   <div>

+                     <label for="sasl-test-regex" class="ds-config-label" title="SASL mapping name">

+                       </label><input class="ds-input sasl-test-input" placeholder="Enter text to test" type="text" id="sasl-test-regex-string"/><button

+                       type="button" class="btn btn-default ds-trailing-btn" id="sasl-test-regex-btn">Test It</button>

+                     <hr>

+                   </div>

+                 </div>

                </div>

                <div>

                  <label for="sasl-map-base" class="ds-config-label" title=

                    "The search base or a specific entry DN to match against the constructed DN">

-                   SASL Mapping Base</label><input class="ds-input" type="text" id="sasl-map-base"/>

+                   SASL Mapping Base</label><input class="ds-input sasl-input" type="text" id="sasl-map-base"/>

                </div>

                <div>

                  <label for="sasl-map-filter" class="ds-config-label" title="SASL mapping filter">

-                   SASL Mapping Filter</label><input class="ds-input" type="text" id="sasl-map-filter"/>

+                   SASL Mapping Filter</label><input class="ds-input sasl-input" type="text" id="sasl-map-filter"/>

                </div>

                <div>

                  <label for="sasl-map-priority" class="ds-config-label" title=

                    "SASL mapping priority.  1 is highest priority, and 100 is lowest">

-                   SASL Mapping Priority</label><input class="ds-input" type="text" id="sasl-map-priority"/>

+                   SASL Mapping Priority</label><input class="ds-input sasl-input" type="text" id="sasl-map-priority"/>

                </div>

              </div>

            </form>
@@ -1063,7 +1056,7 @@ 

    </div>

  

  

-   <!-- Create Local PA\assword Policy -->

+   <!-- Create Local Password Policy -->

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

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

        <div class="modal-content">
@@ -1077,7 +1070,7 @@ 

            <form class="form-horizontal">

              <div class="ds-inline">

                <div>

-                 <label title="Create a subtree elevel password policy" for="subtree-pwp-radio"><input

+                 <label title="Create a subtree level password policy" for="subtree-pwp-radio"><input

                    class="ds-radio pwp-role" type="radio" id="subtree-pwp-radio" name="pwp-role" value="subtree" checked="checked"> Subtree Password Policy</label>

                </div>

                <div>
@@ -1086,10 +1079,10 @@ 

                </div>

                <div>

                  <div>

-                   <label for="local-entry-dn" class="ds-config-label" title="The entry to apply a local policy to.">Entry for Password Policy</label>

+                   <label for="local-entry-dn" class="ds-config-label ds-pwp-input" title="The entry to apply a local policy to.">Entry for Password Policy</label>

                  </div>

                  <div class="ds-inline">

-                   <input class="ds-input" type="text" id="local-entry-dn" size="70" required /><button class="btn btn-default ds-trailing-btn" type="button">Pick Entry</button>

+                   <input class="ds-input ds-pwp-input" type="text" id="local-entry-dn" size="70" required /><button class="btn btn-default ds-trailing-btn" type="button">Pick Entry</button>

                  </div>

                  <hr>

                <div>
@@ -1120,17 +1113,17 @@ 

                        </select>

                    </div>

                    <div>

-                     <input type="checkbox" class="ds-config-checkbox" id="local-passwordtrackupdatetime"><label

+                     <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordtrackupdatetime"><label

                        for="local-passwordtrackupdatetime" class="ds-label" title=

                        "Record a separate timestamp specifically for the last time that the password for an entry was changed. If this is enabled, then it adds the pwdUpdateTime operational attribute to the user account entry (passwordTrackUpdateTime)."> Track Password Update Time</label>

                    </div>

                    <div>

-                     <input type="checkbox" class="ds-config-checkbox" id="nsslapd-allow-hashed-passwords"><label

+                     <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="nsslapd-allow-hashed-passwords"><label

                        for="local-nsslapd-allow-hashed-passwords" class="ds-label" title="Allow anyone to add a prehashed password (nsslapd-allow-hashed-passwords)."> Allow Adding Pre-Hashed Passwords</label>

                    </div>

                    <div>

                      <label for="local-passwordadmindn" class="ds-labelZ" title="The DN for a password administrator or administrator group (passwordAdminDN)">Password Administrator</label><input

-                       class="ds-input" type="text" id="local-passwordadmindn" size="40"/>

+                       class="ds-input ds-pwp-input" type="text" id="local-passwordadmindn" size="40"/>

                    </div>

                  </div>

                </div>
@@ -1140,21 +1133,21 @@ 

                  <hr class="ds-hr">

                  <div class="ds-inline">

                    <div>

-                     <input type="checkbox" class="ds-config-checkbox" id="local-passwordchange"><label

+                     <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordchange"><label

                        for="local-passwordchange" class="ds-label" title="Allow user's to change their passwords (passwordChange)."> Allow Users To Change Their Passwords</label>

                    </div>

                    <div>

-                     <input type="checkbox" class="ds-config-checkbox" id="local-passwordmustchange"><label

+                     <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordmustchange"><label

                        for="local-passwordmustchange" class="ds-label" title="User must change its password after its been reset by an administrator (passwordMustChange).">User Must Change Password After Reset</label>

                    </div>

                    <div>

-                     <input type="checkbox" class="ds-config-checkbox" id="local-passwordhistory"><label

+                     <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordhistory"><label

                        for="local-passwordhistory" class="ds-label" title="Maintain a password history (passwordHistory).">Keep Password History</label>

                    </div>

                    <div>

-                     <input class="ds-history-input" type="text" id="local-passwordinhistory" size="2"/>Passwords In History

+                     <input class="ds-history-input ds-pwp-input" type="text" id="local-passwordinhistory" size="2"/>Passwords In History

                      <label for="local-passwordminage" class="ds-minage-label" title="Indicates the number of seconds that must pass before a user can change their password. (passwordMinAge)">Allow Password Changes (in seconds)</label><input

-                      class="ds-input" type="text" id="local-passwordminage" size="10"/>

+                      class="ds-input ds-pwp-input" type="text" id="local-passwordminage" size="10"/>

                     </div>

                  </div>

                </div>
@@ -1163,16 +1156,16 @@ 

                <div class="ds-split">

                  <h4><br>Password Expiration Settings</h4>

                  <hr class="ds-hr">

-                 <input type="checkbox" class="ds-config-checkbox" id="local-passwordexp"><label

+                 <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordexp"><label

                    for="local-passwordexp" class="ds-label" title="Enable a password expiration policy (passwordExp).">Enable Password Expiration</label>

                  <div class="ds-expired-div" id="local-expiration-attrs">

                    <label for="local-passwordmaxage" class="ds-expire-label" title="The server's local hostname (passwordMaxAge).">Password Expiration Time (in seconds)</label><input

-                     class="ds-input" type="text" id="local-passwordmaxage" size="5"/>

+                     class="ds-input ds-pwp-input" type="text" id="local-passwordmaxage" size="5"/>

                    <label for="local-passwordgracelimit" class="ds-expire-label" title="The server's local hostname (passwordGraceLimit).">Allowed Logins After Password Expires</label><input

-                     class="ds-input" type="text" id="local-passwordgracelimit" size="5"/>

+                     class="ds-input ds-pwp-input" type="text" id="local-passwordgracelimit" size="5"/>

                    <label for="local-passwordwarning" class="ds-expire-label" title="Set the time (in seconds), before a password is about to expire, to send a warning. (passwordWarning).">Send Password Expiring Warning (in seconds)</label><input

-                     class="ds-input" type="text" id="local-passwordwarning" size="5"/>

-                   <input type="checkbox" class="ds-send-expiring-checkbox" id="local-passwordsendexpiringtime"><label

+                     class="ds-input ds-pwp-input" type="text" id="local-passwordwarning" size="5"/>

+                   <input type="checkbox" class="ds-send-expiring-checkbox ds-pwp-checkbox" id="local-passwordsendexpiringtime"><label

                      for="local-passwordsendexpiringtime" class="ds-label" title=

                      "Always return a password expiring control when requested (passwordSendExpiringTime).">Always Send <i>Password Expiring Control</i></label>

                  </div>
@@ -1181,21 +1174,21 @@ 

                <div class="ds-split">

                  <h4><br>Account Lockout Settings</h4>

                  <hr class="ds-hr">

-                 <input type="checkbox" class="ds-config-checkbox" id="local-passwordlockout"><label

+                 <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordlockout"><label

                    for="local-passwordlockout" class="ds-label" title="Enable account lockout (passwordLockout).">Enable Account Lockout</label>

                  <div class="ds-expired-div" id="local-lockout-attrs">

                    <label for="local-passwordmaxfailure" class="ds-expire-label" title=

                      "The maximum number of failed logins before account gets locked (passwordMaxFailure).">Number of Failed Logins to Lockout Account</label><input

-                     class="ds-input" type="text" id="local-passwordmaxfailure" size="5"/>

+                     class="ds-input ds-pwp-input" type="text" id="local-passwordmaxfailure" size="5"/>

                    <label for="local-passwordresetfailurecount" class="ds-expire-label" title=

                      "The number of seconds until an accounts failure count is reset (passwordResetFailureCount).">Time Before Failure Count Reset </label><input

-                     class="ds-input" type="text" id="local-passwordresetfailurecount" size="5"/>

+                     class="ds-input ds-pwp-input" type="text" id="local-passwordresetfailurecount" size="5"/>

                    <div>

                      <label title="Lock out the account forever (passwordUnlock)." for="local-passwordunlock" ><input

                        class="ds-radio" type="radio" id="local-passwordunlock" value="passwordunlock" name="account-lockout" checked="checked"> Lockout Account Forever</label>

                      <label title="The number of seconds before account gets unlocked (passwordLockoutDuration)." for="local-passwordlockoutduration"><input

                        class="ds-radio" type="radio" name="account-lockout" value="passwordlockoutduration"> Time Until Account Unlocked <input

-                       class="ds-input" type="text" id="local-passwordlockoutduration" size="5"/></label>

+                       class="ds-input ds-pwp-input" type="text" id="local-passwordlockoutduration" size="5"/></label>

                    </div>

                  </div>

                  <p></p>
@@ -1204,44 +1197,44 @@ 

  

              <h4><br>Password Syntax Settings</h4>

              <hr class="ds-hr">

-             <input type="checkbox" class="ds-config-checkbox" id="local-passwordchecksyntax"><label

+             <input type="checkbox" class="ds-config-checkbox ds-pwp-checkbox" id="local-passwordchecksyntax"><label

                for="local-passwordchecksyntax" class="ds-label" title="Enable account lockout (passwordCheckSyntax).">Check Password Syntax</label>

              <div class="ds-container ds-expired-div" id="local-syntax-attrs">

                <div>

                  <label for="local-passwordminlength" class="ds-expire-label" title=

                    "The minimum number of characters in the password (passwordMinLength).">Password Minimum Length </label><input

-                   class="ds-input" type="text" id="local-passwordminlength" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordminlength" size="5"/>

                  <label for="local-passwordmindigits" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many digit characters (0-9) (passwordMinDigits).">Minimum Digit Characters </label><input

-                   class="ds-input" type="text" id="local-passwordmindigits" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordmindigits" size="5"/>

                  <label for="local-passwordminalphas" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many alpha characters (passwordMinAlphas).">Minimum Alpha Characters </label><input

-                   class="ds-input" type="text" id="local-passwordminalphas" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordminalphas" size="5"/>

                  <label for="local-passwordminuppers" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many uppercase characters (passwordMinUppers).">Minimum Uppercase Characters </label><input

-                   class="ds-input" type="text" id="local-passwordminuppers" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordminuppers" size="5"/>

                  <label for="local-passwordminlowers" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many lowercase characters (passwordMinLowers).">Minimum Lowercase Characters </label><input

-                   class="ds-input" type="text" id="local-passwordminlowers" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordminlowers" size="5"/>

                </div>

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

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

                <div>

                  <label for="local-passwordminspecials" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many special non-alphanumeric characters (passwordMinSpecials).">Minimum Special Characters </label><input

-                   class="ds-input" type="text" id="local-passwordminspecials" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordminspecials" size="5"/>

                  <label for="local-passwordmin8bit" class="ds-expire-label" title=

                    "Reject passwords with fewer than this many 8-bit or multi-byte characters (passwordMin8Bit).">Minimum 8-bit Characters </label><input

-                   class="ds-input" type="text" id="local-passwordmin8bit" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordmin8bit" size="5"/>

                  <label for="local-passwordmaxrepeats" class="ds-expire-label" title=

                    "The maximum number of times the same character can sequentially appear in a password (passwordMaxRepeats).">Maximum Number Of Repeated Characters </label><input

-                   class="ds-input" type="text" id="local-passwordmaxrepeats" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordmaxrepeats" size="5"/>

                  <label for="local-passwordmincategories" class="ds-expire-label" title=

                    "The minimum number of character categories that a password must contain (categories are upper, lower, digit, special, and 8-bit) (passwordMinCategories).">Minimum Required Character Categories </label><input

-                   class="ds-input" type="text" id="local-passwordmincategories" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordmincategories" size="5"/>

                  <label for="local-passwordmintokenlength" class="ds-expire-label" title=

                    "The smallest attribute value used when checking if the password contains any of the user's account information (passwordMinTokenLength).">Minimum Token Length </label><input

-                   class="ds-input" type="text" id="local-passwordmintokenlength" size="5"/>

+                   class="ds-input ds-pwp-input" type="text" id="local-passwordmintokenlength" size="5"/>

                </div>

              </div>

            </form>

file modified
+3 -1
@@ -27,6 +27,7 @@ 

  from lib389.cli_conf import plugin as cli_plugin

  from lib389.cli_conf import schema as cli_schema

  from lib389.cli_conf import health as cli_health

+ from lib389.cli_conf import saslmappings as cli_sasl

  from lib389.cli_conf.plugins import memberof as cli_memberof

  from lib389.cli_conf.plugins import usn as cli_usn

  from lib389.cli_conf.plugins import rootdn_ac as cli_rootdn_ac
@@ -79,6 +80,7 @@ 

  cli_whoami.create_parser(subparsers)

  cli_referint.create_parser(subparsers)

  cli_automember.create_parser(subparsers)

+ cli_sasl.create_parser(subparsers)

  argcomplete.autocomplete(parser)

  

  # handle a control-c gracefully
@@ -128,7 +130,7 @@ 

      except Exception as e:

          log.debug(e, exc_info=True)

          if args and args.json:

-             sys.stderr.write(str(e))

+             sys.stderr.write(str(e) + '\n')

          else:

              log.error("Error: %s" % str(e))

          result = False

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

  # My logger

  logger = logging.getLogger(__name__)

  

+ 

  # Initiate the paths object here. Should this be part of the DirSrv class

  # for submodules?

  def wrapper(f, name):
@@ -309,6 +310,7 @@ 

          from lib389.index import IndexLegacy as Index

          from lib389.monitor import Monitor, MonitorLDBM

          from lib389.rootdse import RootDSE

+         from lib389.saslmap import SaslMapping, SaslMappings

  

          # Need updating

          self.agreement = Agreement(self)
@@ -321,6 +323,7 @@ 

          self.schema = Schema(self)

          self.plugins = Plugins(self)

          self.tasks = Tasks(self)

+         self.saslmap = SaslMapping(self)

          # Do we have a certdb path?

          # if MAJOR < 3:

          self.monitor = Monitor(self)
@@ -335,6 +338,7 @@ 

          self.ds_access_log = DirsrvAccessLog(self)

          self.ds_error_log = DirsrvErrorLog(self)

          self.ldclt = Ldclt(self)

+         self.saslmaps = SaslMappings(self)

  

      def __init__(self, verbose=False, external_log=None):

          """

@@ -167,6 +167,10 @@ 

          str_attrs = {}

          for k in attrs:

              str_attrs[ensure_str(k)] = ensure_list_str(attrs[k])

+ 

+         # ensure all the keys are lowercase

+         str_attrs = dict((k.lower(), v) for k, v in str_attrs.items())

+ 

          response = json.dumps({"type": "entry", "dn": ensure_str(self._dn), "attrs": str_attrs})

  

          return response
@@ -662,9 +666,10 @@ 

  

          # I think this needs to be made case insensitive

          # How will this work with the dictionary?

-         for attr in self._must_attributes:

-             if properties.get(attr, None) is None:

-                 raise ldap.UNWILLING_TO_PERFORM('Attribute %s must not be None' % attr)

+         if self._must_attributes is not None:

+             for attr in self._must_attributes:

+                 if properties.get(attr, None) is None:

+                     raise ldap.UNWILLING_TO_PERFORM('Attribute %s must not be None' % attr)

  

          # Make sure the naming attribute is present

          if properties.get(self._rdn_attribute, None) is None and rdn is None:
@@ -677,7 +682,7 @@ 

                  pass

              else:

                  # Turn it into a list instead.

-                 properties[k] = [v,]

+                 properties[k] = [v, ]

  

          # This change here, means we can pre-load a full dn to _dn, or we can

          # accept based on the rdn

@@ -50,7 +50,7 @@ 

      kwargs = {}

      while len(kws) > 0:

          kw, msg, priv = kws.pop(0)

- 

+         kw = kw.lower()

          if args is not None and len(args) > 0:

              kwargs[kw] = args.pop(0)

          else:
@@ -69,12 +69,15 @@ 

          # in many places, so we have to normalise this.

          attr_normal = attr.replace('-', '_')

          if args is not None and hasattr(args, attr_normal) and getattr(args, attr_normal) is not None:

+             attr = attr.lower()

              kwargs[attr] = getattr(args, attr_normal)

          else:

              if attr.lower() == 'userpassword':

                  kwargs[attr] = getpass("Enter value for %s : " % attr)

              else:

-                 kwargs[attr] = _input("Enter value for %s : " % attr)

+                 attr_normal = attr.lower()

+                 kwargs[attr_normal] = _input("Enter value for %s : " % attr)

+ 

      return kwargs

  

  

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

  # --- END COPYRIGHT BLOCK ---

  

  from lib389.backend import Backend, Backends

+ from lib389.utils import ensure_str

  from lib389.cli_base import (

      populate_attr_arguments,

      _generic_list,
@@ -45,8 +46,20 @@ 

  

  

  def backend_delete(inst, basedn, log, args, warn=True):

-     dn = _get_arg(args.dn, msg="Enter dn to delete")

-     if warn:

+     found = False

+     be_insts = Backends(inst).list()

+     for be in be_insts:

+         cn = ensure_str(be.get_attr_val('cn')).lower()

+         suffix = ensure_str(be.get_attr_val('nsslapd-suffix')).lower()

+         del_be_name = args.be_name.lower()

+         if cn == del_be_name or suffix == del_be_name:

+             dn = be.dn

+             found = True

+             break

+     if not found:

+         raise ValueError("Unable to find a backend with the name: ({})".format(args.be_name))

+ 

+     if warn and args.json is False:

          _warn(dn, msg="Deleting %s %s" % (SINGULAR.__name__, dn))

      _generic_delete(inst, basedn, log.getChild('backend_delete'), SINGULAR, dn, args)

  
@@ -73,6 +86,6 @@ 

  

      delete_parser = subcommands.add_parser('delete', help='deletes the object')

      delete_parser.set_defaults(func=backend_delete)

-     delete_parser.add_argument('dn', nargs='?', help='The dn to delete')

+     delete_parser.add_argument('be_name', help='The backend name or suffix to delete')

  

  

@@ -0,0 +1,81 @@ 

+ # --- BEGIN COPYRIGHT BLOCK ---

+ # Copyright (C) 2018 Red Hat, Inc.

+ # All rights reserved.

+ #

+ # License: GPL (version 3 or any later version).

+ # See LICENSE for details.

+ # --- END COPYRIGHT BLOCK ---

+ 

+ from lib389.saslmap import SaslMapping, SaslMappings

+ from lib389.utils import ensure_str

+ from lib389.cli_base import (

+     populate_attr_arguments,

+     _generic_list,

+     _generic_get,

+     _generic_create,

+     _generic_delete,

+     _get_arg,

+     _get_attributes,

+     _warn,

+     )

+ 

+ SINGULAR = SaslMapping

+ MANY = SaslMappings

+ RDN = 'cn'

+ 

+ 

+ def sasl_map_list(inst, basedn, log, args):

+     _generic_list(inst, basedn, log.getChild('sasl_map_list'), MANY, args)

+ 

+ 

+ def sasl_map_get(inst, basedn, log, args):

+     rdn = _get_arg(args.selector, msg="Enter %s to retrieve" % RDN)

+     _generic_get(inst, basedn, log.getChild('sasl_map_get'), MANY, rdn, args)

+ 

+ 

+ def sasl_map_create(inst, basedn, log, args):

+     kwargs = _get_attributes(args, SaslMapping._must_attributes)

+     if kwargs['nssaslmappriority'] == '':

+         kwargs['nssaslmappriority'] = '100'  # Default

+     _generic_create(inst, basedn, log.getChild('sasl_map_create'), MANY, kwargs, args)

+ 

+ 

+ def sasl_map_delete(inst, basedn, log, args, warn=True):

+     found = False

+     mappings = SaslMappings(inst).list()

+     map_name = args.map_name.lower()

+ 

+     for saslmap in mappings:

+         cn = ensure_str(saslmap.get_attr_val('cn')).lower()

+         if cn == map_name:

+             dn = saslmap.dn

+             found = True

+             break

+     if not found:

+         raise ValueError("Unable to find a SASL mapping with the name: ({})".format(args.map_name))

+ 

+     if warn and args.json is False:

+         _warn(dn, msg="Deleting %s %s" % (SINGULAR.__name__, dn))

+     _generic_delete(inst, basedn, log.getChild('sasl_map_delete'), SINGULAR, dn, args)

+ 

+ 

+ def create_parser(subparsers):

+     sasl_parser = subparsers.add_parser('sasl', help='Query and manipulate sasl mappings')

+ 

+     subcommands = sasl_parser.add_subparsers(help='sasl')

+ 

+     list_mappings_parser = subcommands.add_parser('list', help='List avaliable SASL mappings')

+     list_mappings_parser.set_defaults(func=sasl_map_list)

+ 

+     get_parser = subcommands.add_parser('get', help='get')

+     get_parser.set_defaults(func=sasl_map_get)

+     get_parser.add_argument('selector', nargs='?', help='SASL mapping name to get')

+ 

+     create_parser = subcommands.add_parser('create', help='create')

+     create_parser.set_defaults(func=sasl_map_create)

+     populate_attr_arguments(create_parser, SaslMapping._must_attributes)

+ 

+     delete_parser = subcommands.add_parser('delete', help='deletes the object')

+     delete_parser.set_defaults(func=sasl_map_delete)

+     delete_parser.add_argument('map_name', help='The SASL Mapping name ("cn" value)')

+ 

@@ -644,6 +644,12 @@ 

          if self.verbose:

              self.log.info("ACTION: Creating certificate database is %s", slapd['cert_dir'])

  

+         # Get suffix for sasl map entries (template-sasl.ldif)

+         if len(backends) > 0:

+             ds_suffix = backends[0]['suffix']

+         else:

+             ds_suffix = ''

+ 

          # Create dse.ldif with a temporary root password.

          # The template is in slapd['data_dir']/dirsrv/data/template-dse.ldif

          # Variables are done with %KEY%.
@@ -655,6 +661,11 @@ 

              for line in template_dse.readlines():

                  dse += line.replace('%', '{', 1).replace('%', '}', 1)

  

+         if ds_suffix != '':

+             with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-sasl.ldif')) as template_sasl:

+                 for line in template_sasl.readlines():

+                     dse += line.replace('%', '{', 1).replace('%', '}', 1)

+ 

          with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:

              file_dse.write(dse.format(

                  schema_dir=slapd['schema_dir'],
@@ -672,7 +683,7 @@ 

                  rootdn=slapd['root_dn'],

                  # ds_passwd=slapd['root_password'],

                  ds_passwd=self._secure_password,  # We set our own password here, so we can connect and mod.

-                 ds_suffix='',

+                 ds_suffix=ds_suffix,

                  config_dir=slapd['config_dir'],

                  db_dir=slapd['db_dir'],

              ))

file modified
+5 -4
@@ -13,24 +13,25 @@ 

  """

  

  from ldap.sasl import sasl, CB_AUTHNAME, CB_PASS, CB_USER

- 

  from lib389.utils import ensure_bytes

  

+ 

  class LdapSSOTokenSASL(sasl):

      """

      This class handles draft-wibrown-ldapssotoken-01 authentication.

      """

  

-     def __init__(self,token):

-         auth_dict = { CB_PASS:token }

+     def __init__(self, token):

+         auth_dict = {CB_PASS: token}

          sasl.__init__(self, auth_dict, "LDAPSSOTOKEN")

  

+ 

  class PlainSASL(sasl):

      """

      This class handles PLAIN sasl authentication

      """

  

      def __init__(self, authz_id, passwd):

-         auth_dict = { CB_AUTHNAME:authz_id, CB_PASS:passwd }

+         auth_dict = {CB_AUTHNAME: authz_id, CB_PASS: passwd}

          sasl.__init__(self, auth_dict, "PLAIN")

  

file modified
+10 -5
@@ -8,6 +8,7 @@ 

  

  from lib389._mapped_object import DSLdapObject, DSLdapObjects

  

+ 

  class SaslMapping(DSLdapObject):

      """A sasl map providing a link from a sasl user and realm

      to a valid directory server entry.
@@ -18,21 +19,25 @@ 

      :type dn: str

      """

  

-     def __init__(self, instance, dn=None):

-         super(SaslMapping, self).__init__(instance, dn)

-         self._rdn_attribute = 'cn'

-         self._must_attributes = [

+     _must_attributes = [

              'cn',

              'nsSaslMapRegexString',

              'nsSaslMapBaseDNTemplate',

              'nsSaslMapFilterTemplate',

+             'nsSaslMapPriority'

          ]

+ 

+     def __init__(self, instance, dn=None):

+         super(SaslMapping, self).__init__(instance, dn)

+         self._rdn_attribute = 'cn'

+ 

          self._create_objectclasses = [

              'top',

              'nsSaslMapping',

          ]

          self._protected = False

  

+ 

  class SaslMappings(DSLdapObjects):

      """DSLdapObjects that represents SaslMappings in the server.

  
@@ -42,7 +47,7 @@ 

      :type basedn: str

      """

  

-     def __init__(self, instance):

+     def __init__(self, instance, dn=None):

          super(SaslMappings, self).__init__(instance)

          self._objectclasses = [

              'nsSaslMapping',

Description: Add SASL functionality to dsconf and UI

          Improved installer to load the template-sasl ldif
          file.

          Also cleaned up some of the "clear form" functions
          to be more efficient using jquery.

https://pagure.io/389-ds-base/issue/49806

Reviewed by: ?

rebased onto 2037f4707dc063da71b9a14c0a8354bb1315791e

3 years ago

rebased onto 127a58d90f58cfb21b5d3ef06cea1c85176cbf89

3 years ago

Besides the small issue with SASL mapping datatables, the one we discussed on IRC, I am okay with your code. Ack from me.

P.S. the small issue is about the thing that we have the message under the table 'Showing 1 to 3 of 3 Items', but we have two items there actually.

rebased onto e8a34342efa77c22dd9c5407c7ad4e2161d447bc

3 years ago

rebased onto 0738b0576672b587b4338a2cfdbe59f3bcc3aae9

3 years ago

@spichugi - changes made, please review...

The rest of the code looks good to me.

Yes, that's my MARK debug logging - I'll get this removed...

rebased onto ba5900e

3 years ago

Pull-Request has been merged by mreynolds

3 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/2906

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