#50570 Issue 50545 - Port fixup-memberuid and add the functionality to CLI and UI
Closed 3 years ago by spichugi. Opened 4 years ago by spichugi.
spichugi/389-ds-base fix-memberuid  into  master

@@ -1,7 +1,21 @@ 

+ import cockpit from "cockpit";

  import React from "react";

- import { Row, Col, Form, noop, FormGroup, Checkbox, ControlLabel } from "patternfly-react";

+ import {

+     Row,

+     Col,

+     Icon,

+     Modal,

+     noop,

+     Form,

+     FormControl,

+     FormGroup,

+     Checkbox,

+     Button,

+     ControlLabel

+ } from "patternfly-react";

  import PropTypes from "prop-types";

  import PluginBasicConfig from "./pluginBasicConfig.jsx";

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

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

  

  class WinSync extends React.Component {
@@ -19,23 +33,93 @@ 

          super(props);

  

          this.handleCheckboxChange = this.handleCheckboxChange.bind(this);

+         this.handleFieldChange = this.handleFieldChange.bind(this);

          this.updateFields = this.updateFields.bind(this);

+         this.runFixup = this.runFixup.bind(this);

+         this.toggleFixupModal = this.toggleFixupModal.bind(this);

  

          this.state = {

              posixWinsyncCreateMemberOfTask: false,

              posixWinsyncLowerCaseUID: false,

              posixWinsyncMapMemberUID: false,

              posixWinsyncMapNestedGrouping: false,

-             posixWinsyncMsSFUSchema: false

+             posixWinsyncMsSFUSchema: false,

+ 

+             fixupModalShow: false,

+             fixupDN: "",

+             fixupFilter: ""

          };

      }

  

+     toggleFixupModal() {

+         this.setState(prevState => ({

+             fixupModalShow: !prevState.fixupModalShow,

+             fixupDN: "",

+             fixupFilter: ""

+         }));

+     }

+ 

+     runFixup() {

+         if (!this.state.fixupDN) {

+             this.props.addNotification("warning", "Fixup DN is required.");

+         } else {

+             let cmd = [

+                 "dsconf",

+                 "-j",

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

+                 "plugin",

+                 "posix-winsync",

+                 "fixup",

+                 this.state.fixupDN

+             ];

+ 

+             if (this.state.fixupFilter) {

+                 cmd = [...cmd, "--filter", this.state.fixupFilter];

+             }

+ 

+             this.props.toggleLoadingHandler();

+             log_cmd("runFixup", "Run Member UID task", cmd);

+             cockpit

+                     .spawn(cmd, {

+                         superuser: true,

+                         err: "message"

+                     })

+                     .done(content => {

+                         this.props.addNotification(

+                             "success",

+                             `Fixup task for ${this.state.fixupDN} was successfull`

+                         );

+                         this.props.toggleLoadingHandler();

+                         this.setState({

+                             fixupModalShow: false

+                         });

+                     })

+                     .fail(err => {

+                         let errMsg = JSON.parse(err);

+                         this.props.addNotification(

+                             "error",

+                             `Fixup task for ${this.state.fixupDN} has failed ${errMsg.desc}`

+                         );

+                         this.props.toggleLoadingHandler();

+                         this.setState({

+                             fixupModalShow: false

+                         });

+                     });

+         }

+     }

+ 

      handleCheckboxChange(e) {

          this.setState({

              [e.target.id]: e.target.checked

          });

      }

  

+     handleFieldChange(e) {

+         this.setState({

+             [e.target.id]: e.target.value

+         });

+     }

+ 

      updateFields() {

          if (this.props.rows.length > 0) {

              const pluginRow = this.props.rows.find(row => row.cn[0] === "Posix Winsync API");
@@ -71,7 +155,10 @@ 

              posixWinsyncLowerCaseUID,

              posixWinsyncMapMemberUID,

              posixWinsyncMapNestedGrouping,

-             posixWinsyncMsSFUSchema

+             posixWinsyncMsSFUSchema,

+             fixupModalShow,

+             fixupDN,

+             fixupFilter

          } = this.state;

  

          let specificPluginCMD = [
@@ -94,6 +181,69 @@ 

          ];

          return (

              <div>

+                 <Modal show={fixupModalShow} onHide={this.toggleFixupModal}>

+                     <div className="ds-no-horizontal-scrollbar">

+                         <Modal.Header>

+                             <button

+                                 className="close"

+                                 onClick={this.toggleFixupModal}

+                                 aria-hidden="true"

+                                 aria-label="Close"

+                             >

+                                 <Icon type="pf" name="close" />

+                             </button>

+                             <Modal.Title>MemberOf Task</Modal.Title>

+                         </Modal.Header>

+                         <Modal.Body>

+                             <Row>

+                                 <Col sm={12}>

+                                     <Form horizontal>

+                                         <FormGroup controlId="fixupDN" key="fixupDN">

+                                             <Col sm={3}>

+                                                 <ControlLabel title="Base DN that contains entries to fix up">

+                                                     Base DN

+                                                 </ControlLabel>

+                                             </Col>

+                                             <Col sm={9}>

+                                                 <FormControl

+                                                     type="text"

+                                                     value={fixupDN}

+                                                     onChange={this.handleFieldChange}

+                                                 />

+                                             </Col>

+                                         </FormGroup>

+                                         <FormGroup controlId="fixupFilter" key="fixupFilter">

+                                             <Col sm={3}>

+                                                 <ControlLabel title="Filter for entries to fix up. If omitted, all entries with objectclass inetuser/inetadmin/nsmemberof under the specified base will have their memberOf attribute regenerated.">

+                                                     Filter DN

+                                                 </ControlLabel>

+                                             </Col>

+                                             <Col sm={9}>

+                                                 <FormControl

+                                                     type="text"

+                                                     value={fixupFilter}

+                                                     onChange={this.handleFieldChange}

+                                                 />

+                                             </Col>

+                                         </FormGroup>

+                                     </Form>

+                                 </Col>

+                             </Row>

+                         </Modal.Body>

+                         <Modal.Footer>

+                             <Button

+                                 bsStyle="default"

+                                 className="btn-cancel"

+                                 onClick={this.toggleFixupModal}

+                             >

+                                 Cancel

+                             </Button>

+                             <Button bsStyle="primary" onClick={this.runFixup}>

+                                 Run

+                             </Button>

+                         </Modal.Footer>

+                     </div>

+                 </Modal>

                  <PluginBasicConfig

                      rows={this.props.rows}

                      serverId={this.props.serverId}
@@ -115,7 +265,7 @@ 

                                  >

                                      <Col

                                          componentClass={ControlLabel}

-                                         sm={3}

+                                         sm={6}

                                          title="Sets whether to run the memberOf fix-up task immediately after a sync run in order to update group memberships for synced users"

                                      >

                                          Create MemberOf Task
@@ -134,7 +284,7 @@ 

                                  >

                                      <Col

                                          componentClass={ControlLabel}

-                                         sm={3}

+                                         sm={6}

                                          title="Sets whether to store (and, if necessary, convert) the UID value in the memberUID attribute in lower case"

                                      >

                                          Lower Case UID
@@ -153,7 +303,7 @@ 

                                  >

                                      <Col

                                          componentClass={ControlLabel}

-                                         sm={3}

+                                         sm={6}

                                          title="Sets whether to map the memberUID attribute in an Active Directory group to the uniqueMember attribute in a Directory Server group"

                                      >

                                          Map Member UID
@@ -173,7 +323,7 @@ 

                                      <Col

                                          title="Manages if nested groups are updated when memberUID attributes in an Active Directory POSIX group change"

                                          componentClass={ControlLabel}

-                                         sm={3}

+                                         sm={6}

                                      >

                                          Map Nested Grouping

                                      </Col>
@@ -191,7 +341,7 @@ 

                                  >

                                      <Col

                                          componentClass={ControlLabel}

-                                         sm={3}

+                                         sm={6}

                                          title="Sets whether to the older Microsoft System Services  for Unix 3.0 (msSFU30) schema when syncing Posix attributes  from Active Directory"

                                      >

                                          Microsoft System Services for Unix 3.0 (msSFU30) schema
@@ -207,6 +357,17 @@ 

                              </Form>

                          </Col>

                      </Row>

+                     <Row>

+                         <Col sm={12}>

+                             <Button

+                                 bsStyle="primary"

+                                 onClick={this.toggleFixupModal}

+                                 title="Corrects mismatched member and uniquemember values"

+                             >

+                                 Run MemberOf Task

+                             </Button>

+                         </Col>

+                     </Row>

                  </PluginBasicConfig>

              </div>

          );

@@ -24,6 +24,21 @@ 

      generic_object_edit(plugin, log, args, arg_to_attr)

  

  

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

+     plugin = POSIXWinsyncPlugin(inst)

+     log.info('Attempting to add task entry...')

+     if not plugin.status():

+         log.error(f"'{plugin.rdn}' is disabled. Fix up task can't be executed")

+         return

+     fixup_task = plugin.fixup(args.DN, args.filter)

+     fixup_task.wait()

+     exitcode = fixup_task.get_exit_code()

+     if exitcode != 0:

+         log.error(f'MemberUID task for {args.DN} has failed. Please, check logs')

+     else:

+         log.info('Successfully added task entry')

+ 

+ 

  def _add_parser_args(parser):

      parser.add_argument('--create-memberof-task', choices=['true', 'false'], type=str.lower,

                          help='Sets whether to run the memberOf fix-up task immediately after a sync run in order '
@@ -51,3 +66,10 @@ 

      edit.set_defaults(func=winsync_edit)

      _add_parser_args(edit)

  

+     fixup = subcommands.add_parser('fixup', help='Run the memberOf fix-up task to correct mismatched member and uniquemember values for synced users')

+     fixup.set_defaults(func=do_fixup)

+     fixup.add_argument('DN', help="Base DN that contains entries to fix up")

+     fixup.add_argument('-f', '--filter',

+                        help='Filter for entries to fix up.\n If omitted, all entries with objectclass '

+                             'inetuser/inetadmin/nsmemberof under the specified base will have '

+                             'their memberOf attribute regenerated.')

@@ -1340,6 +1340,25 @@ 

      def __init__(self, instance, dn="cn=Posix Winsync API,cn=plugins,cn=config"):

          super(POSIXWinsyncPlugin, self).__init__(instance, dn)

  

+     def fixup(self, basedn, _filter=None):

+         """Create a memberuid task

+ 

+         :param basedn: Basedn to fix up

+         :type basedn: str

+         :param _filter: a filter for entries to fix up

+         :type _filter: str

+ 

+         :returns: an instance of Task(DSLdapObject)

+         """

+ 

+         task = tasks.MemberUidFixupTask(self._instance)

+         task_properties = {'basedn': basedn}

+         if _filter is not None:

+             task_properties['filter'] = _filter

+         task.create(properties=task_properties)

+ 

+         return task

+ 

  

  class PAMPassThroughAuthPlugin(Plugin):

      """A single instance of PAM Pass Through Auth plugin entry

@@ -139,6 +139,21 @@ 

          super(FixupLinkedAttributesTask, self).__init__(instance, dn)

  

  

+ class MemberUidFixupTask(Task):

+     """A single instance of memberOf task entry

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     """

+ 

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

+         self.cn = 'memberUid_fixup_' + Task._get_task_date()

+         dn = f"cn={self.cn},cn=memberuid task,cn=tasks,cn=config"

+ 

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

+         self._must_attributes.extend(['basedn'])

+ 

+ 

  class MemberOfFixupTask(Task):

      """A single instance of memberOf task entry

  

Description: fixup-memberuid.pl script corrects mismatched member and uniquemember values.
Port to existing CLI tools and add the button (similar to memberOf fixup task) to UI.

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

Reviewed by: ?

rebased onto 0a34389

4 years ago

Pull-Request has been merged by spichugi

4 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/3626

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

3 years ago