This is an automated email from the ASF dual-hosted git repository.

madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 19dbc93e5 RANGER-4280 : Update security-zone UI with addition of 
admin-roles and audit-roles
19dbc93e5 is described below

commit 19dbc93e5a74d3682bf6eda691344048cad2b8ca
Author: Dhaval.Rajpara <dhavalrajpara1...@gmail.com>
AuthorDate: Fri Oct 20 15:18:54 2023 +0530

    RANGER-4280 : Update security-zone UI with addition of admin-roles and 
audit-roles
    
    Signed-off-by: Madhan Neethiraj <mad...@apache.org>
---
 .../service/RangerSecurityZoneServiceService.java  |   2 +
 .../src/views/SecurityZone/SecurityZoneForm.jsx    | 268 +++++++++++++++++++--
 .../src/views/SecurityZone/ZoneDisplay.jsx         |  46 ++++
 3 files changed, 293 insertions(+), 23 deletions(-)

diff --git 
a/security-admin/src/main/java/org/apache/ranger/service/RangerSecurityZoneServiceService.java
 
b/security-admin/src/main/java/org/apache/ranger/service/RangerSecurityZoneServiceService.java
index 8acdd9813..ae6833815 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/service/RangerSecurityZoneServiceService.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/service/RangerSecurityZoneServiceService.java
@@ -82,6 +82,8 @@ public class RangerSecurityZoneServiceService extends 
RangerSecurityZoneServiceB
                trxLogAttrs.put("adminUserGroups", new 
VTrxLogAttr("adminUserGroups", "Zone Admin User Groups", false));
                trxLogAttrs.put("auditUsers", new VTrxLogAttr("auditUsers", 
"Zone Audit Users", false));
                trxLogAttrs.put("auditUserGroups", new 
VTrxLogAttr("auditUserGroups", "Zone Audit User Groups", false));
+               trxLogAttrs.put("adminRoles", new VTrxLogAttr("adminRoles", 
"Zone Admin Roles", false));
+               trxLogAttrs.put("auditRoles", new VTrxLogAttr("auditRoles", 
"Zone Audit Roles", false));
                trxLogAttrs.put("description", new VTrxLogAttr("description", 
"Zone Description", false));
                 trxLogAttrs.put("tagServices", new VTrxLogAttr("tagServices", 
"Zone Tag Services", false));
        }
diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx
index 3bf0df71c..91d2a3758 100644
--- 
a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx
@@ -79,6 +79,14 @@ const SecurityZoneForm = () => {
   });
   const [preventUnBlock, setPreventUnblock] = useState(false);
   const [blockUI, setBlockUI] = useState(false);
+  const [userLoading, setUserLoading] = useState(false);
+  const [groupLoading, setGroupLoading] = useState(false);
+  const [roleLoading, setRoleLoading] = useState(false);
+  const [tagServiceLoading, setTagServiceLoading] = useState(false);
+  const [defaultUserOptions, setDefaultUserOptions] = useState([]);
+  const [defaultGroupOptions, setDefaultGroupOptions] = useState([]);
+  const [defaultRoleOptions, setDefaultRoleOptions] = useState([]);
+  const [defaultTagServiceOptions, setDefaultTagServiceOptions] = useState([]);
 
   useEffect(() => {
     fetchInitalData();
@@ -103,10 +111,18 @@ const SecurityZoneForm = () => {
       }
     }
 
-    if (isEmpty(values.adminUsers) && isEmpty(values.adminUserGroups)) {
+    if (
+      isEmpty(values?.adminUsers) &&
+      isEmpty(values?.adminUserGroups) &&
+      isEmpty(values?.adminRoles)
+    ) {
+      errors.adminRoles = {
+        required: true,
+        text: "Please provide atleast one admin user or group or role !"
+      };
       errors.adminUserGroups = {
         required: true,
-        text: "Please provide atleast one admin user or group!"
+        text: ""
       };
       errors.adminUsers = {
         required: true,
@@ -114,10 +130,18 @@ const SecurityZoneForm = () => {
       };
     }
 
-    if (isEmpty(values.auditUsers) && isEmpty(values.auditUserGroups)) {
+    if (
+      isEmpty(values?.auditUsers) &&
+      isEmpty(values?.auditUserGroups) &&
+      isEmpty(values?.auditRoles)
+    ) {
+      errors.auditRoles = {
+        required: true,
+        text: "Please provide atleast one audit user or group or role !"
+      };
       errors.auditUserGroups = {
         required: true,
-        text: "Please provide atleast one audit user or group!"
+        text: ""
       };
       errors.auditUsers = {
         required: true,
@@ -308,6 +332,20 @@ const SecurityZoneForm = () => {
       }
     }
 
+    if (values.adminRoles) {
+      zoneData.adminRoles = [];
+      for (let key of Object.keys(values.adminRoles)) {
+        zoneData.adminRoles.push(values.adminRoles[key].label || "");
+      }
+    }
+
+    if (values.auditRoles) {
+      zoneData.auditRoles = [];
+      for (let key of Object.keys(values.auditRoles)) {
+        zoneData.auditRoles.push(values.auditRoles[key].label || "");
+      }
+    }
+
     zoneData.tagServices = [];
 
     if (values.tagServices) {
@@ -404,6 +442,20 @@ const SecurityZoneForm = () => {
       );
     }
 
+    zoneData.adminRoles = [];
+    if (zone.adminRoles) {
+      zone.adminRoles.map((name) =>
+        zoneData.adminRoles.push({ label: name, value: name })
+      );
+    }
+
+    zoneData.auditRoles = [];
+    if (zone.auditRoles) {
+      zone.auditRoles.map((name) =>
+        zoneData.auditRoles.push({ label: name, value: name })
+      );
+    }
+
     zoneData.tagServices = [];
     if (zone.tagServices) {
       zone.tagServices.map((name) =>
@@ -474,7 +526,7 @@ const SecurityZoneForm = () => {
     return zoneData;
   };
 
-  const fetchUsers = async (inputValue) => {
+  const fetchUsersData = async (inputValue) => {
     let params = { isVisible: 1 };
     let usersOp = [];
 
@@ -489,7 +541,7 @@ const SecurityZoneForm = () => {
       });
       usersOp = userResp.data?.vXStrings;
     } catch (error) {
-      console.error(`Error occurred while fetching Users ! ${error}`);
+      console.error(`Error occurred while fetching Users! ${error}`);
       serverError(error);
     }
 
@@ -498,7 +550,7 @@ const SecurityZoneForm = () => {
     });
   };
 
-  const fetchGroups = async (inputValue) => {
+  const fetchGroupsData = async (inputValue) => {
     let params = { isVisible: 1 };
     let groupsOp = [];
 
@@ -513,7 +565,7 @@ const SecurityZoneForm = () => {
       });
       groupsOp = groupResp.data?.vXStrings;
     } catch (error) {
-      console.error(`Error occurred while fetching Groups ! ${error}`);
+      console.error(`Error occurred while fetching Groups! ${error}`);
       serverError(error);
     }
 
@@ -522,6 +574,26 @@ const SecurityZoneForm = () => {
     });
   };
 
+  const fetchRolesData = async (inputValue) => {
+    let params = { roleNamePartial: inputValue || "" };
+    let op = [];
+
+    try {
+      const roleResp = await fetchApi({
+        url: "roles/roles",
+        params: params
+      });
+      op = roleResp.data.roles;
+    } catch (error) {
+      console.error(`Error occurred while fetching Roles! ${error}`);
+      serverError(error);
+    }
+    return op.map((obj) => ({
+      label: obj.name,
+      value: obj.name
+    }));
+  };
+
   const fetchTagServices = async (inputValue) => {
     let params = {};
     if (inputValue) {
@@ -631,7 +703,35 @@ const SecurityZoneForm = () => {
       </p>
     ));
   };
+  const onFocusUserSelect = () => {
+    setUserLoading(true);
+    fetchUsersData().then((opts) => {
+      setDefaultUserOptions(opts);
+      setUserLoading(false);
+    });
+  };
 
+  const onFocusGroupSelect = () => {
+    setGroupLoading(true);
+    fetchGroupsData().then((opts) => {
+      setDefaultGroupOptions(opts);
+      setGroupLoading(false);
+    });
+  };
+  const onFocusRoleSelect = () => {
+    setRoleLoading(true);
+    fetchRolesData().then((opts) => {
+      setDefaultRoleOptions(opts);
+      setRoleLoading(false);
+    });
+  };
+  const onFocusTagServiceSelect = () => {
+    setTagServiceLoading(true);
+    fetchTagServices().then((opts) => {
+      setDefaultTagServiceOptions(opts);
+      setTagServiceLoading(false);
+    });
+  };
   return (
     <React.Fragment>
       <div className="clearfix">
@@ -757,14 +857,20 @@ const SecurityZoneForm = () => {
                                   : "auditUsers"
                               }
                               cacheOptions
-                              defaultOptions
-                              loadOptions={fetchUsers}
+                              loadOptions={fetchUsersData}
+                              onFocus={() => {
+                                onFocusUserSelect();
+                              }}
+                              defaultOptions={defaultUserOptions}
+                              noOptionsMessage={() =>
+                                userLoading ? "Loading..." : "No options"
+                              }
                               isMulti
                               components={{
                                 DropdownIndicator: () => null,
                                 IndicatorSeparator: () => null
                               }}
-                              isClearable={false}
+                              isClearable={true}
                               placeholder="Select User"
                             />
                           </Col>
@@ -794,16 +900,66 @@ const SecurityZoneForm = () => {
                                   : "adminUserGroups"
                               }
                               {...input}
-                              defaultOptions
-                              loadOptions={fetchGroups}
+                              cacheOptions
+                              loadOptions={fetchGroupsData}
+                              onFocus={() => {
+                                onFocusGroupSelect();
+                              }}
+                              defaultOptions={defaultGroupOptions}
+                              noOptionsMessage={() =>
+                                groupLoading ? "Loading..." : "No options"
+                              }
                               isMulti
                               components={{
                                 DropdownIndicator: () => null,
                                 IndicatorSeparator: () => null
                               }}
-                              isClearable={false}
+                              isClearable={true}
                               placeholder="Select Group"
-                              required
+                            />
+                          </Col>
+                        </Row>
+                      )}
+                    />
+
+                    <Field
+                      name="adminRoles"
+                      render={({ input, meta }) => (
+                        <Row className="form-group">
+                          <Col xs={3}>
+                            <label className="form-label pull-right">
+                              Admin Roles
+                            </label>
+                          </Col>
+                          <Col xs={4}>
+                            <AsyncSelect
+                              {...input}
+                              styles={
+                                meta.error && meta.touched
+                                  ? selectCustomStyles
+                                  : ""
+                              }
+                              id={
+                                meta.error && meta.touched
+                                  ? "isError"
+                                  : "adminRoles"
+                              }
+                              cacheOptions
+                              loadOptions={fetchRolesData}
+                              onFocus={() => {
+                                onFocusRoleSelect();
+                              }}
+                              defaultOptions={defaultRoleOptions}
+                              noOptionsMessage={() =>
+                                roleLoading ? "Loading..." : "No options"
+                              }
+                              isMulti
+                              components={{
+                                DropdownIndicator: () => null,
+                                IndicatorSeparator: () => null
+                              }}
+                              isClearable={true}
+                              placeholder="Select Role"
                             />
                             {meta.touched && meta.error && (
                               <span className="invalid-field">
@@ -837,14 +993,21 @@ const SecurityZoneForm = () => {
                                   ? "isError"
                                   : "auditUsers"
                               }
-                              defaultOptions
-                              loadOptions={fetchUsers}
+                              cacheOptions
+                              loadOptions={fetchUsersData}
+                              onFocus={() => {
+                                onFocusUserSelect();
+                              }}
+                              defaultOptions={defaultUserOptions}
+                              noOptionsMessage={() =>
+                                userLoading ? "Loading..." : "No options"
+                              }
                               isMulti
                               components={{
                                 DropdownIndicator: () => null,
                                 IndicatorSeparator: () => null
                               }}
-                              isClearable={false}
+                              isClearable={true}
                               placeholder="Select User"
                             />
                           </Col>
@@ -873,16 +1036,67 @@ const SecurityZoneForm = () => {
                                   ? "isError"
                                   : "auditUserGroups"
                               }
-                              defaultOptions
-                              loadOptions={fetchGroups}
+                              cacheOptions
+                              loadOptions={fetchGroupsData}
+                              onFocus={() => {
+                                onFocusGroupSelect();
+                              }}
+                              defaultOptions={defaultGroupOptions}
+                              noOptionsMessage={() =>
+                                groupLoading ? "Loading..." : "No options"
+                              }
                               isMulti
                               components={{
                                 DropdownIndicator: () => null,
                                 IndicatorSeparator: () => null
                               }}
-                              isClearable={false}
+                              isClearable={true}
                               placeholder="Select Group"
                             />
+                          </Col>
+                        </Row>
+                      )}
+                    />
+
+                    <Field
+                      name="auditRoles"
+                      render={({ input, meta }) => (
+                        <Row className="form-group">
+                          <Col xs={3}>
+                            <label className="form-label pull-right">
+                              Auditor Roles
+                            </label>
+                          </Col>
+                          <Col xs={4}>
+                            <AsyncSelect
+                              {...input}
+                              styles={
+                                meta.error && meta.touched
+                                  ? selectCustomStyles
+                                  : ""
+                              }
+                              id={
+                                meta.error && meta.touched
+                                  ? "isError"
+                                  : "auditRoles"
+                              }
+                              cacheOptions
+                              loadOptions={fetchRolesData}
+                              onFocus={() => {
+                                onFocusRoleSelect();
+                              }}
+                              defaultOptions={defaultRoleOptions}
+                              noOptionsMessage={() =>
+                                roleLoading ? "Loading..." : "No options"
+                              }
+                              isMulti
+                              components={{
+                                DropdownIndicator: () => null,
+                                IndicatorSeparator: () => null
+                              }}
+                              isClearable={true}
+                              placeholder="Select Role"
+                            />
                             {meta.error && meta.touched && (
                               <span className="invalid-field">
                                 {meta.error.text}
@@ -892,6 +1106,7 @@ const SecurityZoneForm = () => {
                         </Row>
                       )}
                     />
+
                     <p className="form-header">Services:</p>
                     <Field
                       name="tagServices"
@@ -905,14 +1120,21 @@ const SecurityZoneForm = () => {
                           <Col xs={6}>
                             <AsyncSelect
                               {...input}
-                              defaultOptions
+                              cacheOptions
                               loadOptions={fetchTagServices}
+                              onFocus={() => {
+                                onFocusTagServiceSelect();
+                              }}
+                              defaultOptions={defaultTagServiceOptions}
+                              noOptionsMessage={() =>
+                                tagServiceLoading ? "Loading..." : "No options"
+                              }
                               isMulti
                               components={{
                                 DropdownIndicator: () => null,
                                 IndicatorSeparator: () => null
                               }}
-                              isClearable={false}
+                              isClearable={true}
                               placeholder="Select Tag Services"
                             />
                           </Col>
diff --git 
a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx
 
b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx
index 5a8cbe540..61bc250e8 100644
--- 
a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx
+++ 
b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/ZoneDisplay.jsx
@@ -227,6 +227,29 @@ class ZoneDisplay extends Component {
                           )}
                         </Col>
                       </Form.Group>
+                      <Form.Group as={Row} className="mb-3">
+                        <Form.Label className="text-right" column sm="3">
+                          Admin Roles
+                        </Form.Label>
+                        <Col sm="9" className="pt-2">
+                          {this.props?.zone?.adminRoles?.length > 0 ? (
+                            this.props?.zone.adminRoles?.map((obj) => {
+                              return (
+                                <Badge
+                                  variant="primary"
+                                  className="mr-1 more-less-width 
text-truncate"
+                                  key={obj}
+                                  title={obj}
+                                >
+                                  {obj}
+                                </Badge>
+                              );
+                            })
+                          ) : (
+                            <p className="mt-1">--</p>
+                          )}
+                        </Col>
+                      </Form.Group>
                       <Form.Group as={Row} className="mb-3">
                         <Form.Label className="text-right" column sm="3">
                           Auditor Users
@@ -273,6 +296,29 @@ class ZoneDisplay extends Component {
                           )}
                         </Col>
                       </Form.Group>
+                      <Form.Group as={Row} className="mb-3">
+                        <Form.Label className="text-right" column sm="3">
+                          Auditor Roles
+                        </Form.Label>
+                        <Col sm="9" className="pt-2">
+                          {this.props?.zone?.auditRoles?.length > 0 ? (
+                            this.props?.zone?.auditRoles?.map((obj) => {
+                              return (
+                                <Badge
+                                  variant="primary"
+                                  className="mr-1 more-less-width 
text-truncate"
+                                  key={obj}
+                                  title={obj}
+                                >
+                                  {obj}
+                                </Badge>
+                              );
+                            })
+                          ) : (
+                            <span className="mt-1">--</span>
+                          )}
+                        </Col>
+                      </Form.Group>
                     </Form>
                   </Card.Body>
                 </Accordion.Collapse>

Reply via email to