Merge branch 'master' into RANGER-3923
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
index adb02d5..842cb69 100755
--- a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
+++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js
@@ -883,5 +883,13 @@
   totalUsersSynced: "Total number of users synced",
   totalGroupsSynced: "Total number of groups synced",
   totalUsersDeleted: "Total number of users marked for delete",
-  totalGroupsDeleted: "Total number of groups marked for delete"
+  totalGroupsDeleted: "Total number of groups marked for delete",
+  ldapUrl: "Ldap url",
+  isIncrementalSync: "Incremental sync",
+  userSearchEnabled: "User search enabled",
+  userSearchFilter: "User search filter",
+  groupSearchEnabled: "Group search enabled",
+  groupSearchFilter: "Group search filter",
+  groupSearchFirstEnabled: "Group search first enabled",
+  groupHierarchyLevel: "Group hierarchy level"
 };
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AccessLogDetail.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AccessLogDetail.jsx
index dc75efe..13b7758 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AccessLogDetail.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AccessLogDetail.jsx
@@ -25,34 +25,18 @@
 import { isEmpty } from "lodash";
 import { Loader } from "Components/CommonComponents";
 import { useParams } from "react-router-dom";
+import { getServiceDef } from "../../utils/appState";
 
-function AccessLogDetail(props) {
+function AccessLogDetail() {
   const params = useParams();
   const [access, setAccess] = useState([]);
-  const [serviceDefs, setServiceDefs] = useState([]);
   const [loader, setLoader] = useState(true);
+  const { allServiceDefs } = getServiceDef();
 
   useEffect(() => {
-    fetchServiceDefs();
     fetchAcessLogs();
   }, []);
 
-  const fetchServiceDefs = async () => {
-    let serviceDefsResp = [];
-    try {
-      serviceDefsResp = await fetchApi({
-        url: "plugins/definitions"
-      });
-    } catch (error) {
-      console.error(
-        `Error occurred while fetching Service Definitions or CSRF headers! ${error}`
-      );
-    }
-
-    setServiceDefs(serviceDefsResp.data.serviceDefs);
-    setLoader(false);
-  };
-
   const fetchAcessLogs = async () => {
     let accessResp = {};
     let accessData = {};
@@ -99,7 +83,7 @@
               <div className="wrap">
                 <PolicyViewDetails
                   paramsData={access}
-                  serviceDef={serviceDefs?.find((servicedef) => {
+                  serviceDef={allServiceDefs?.find((servicedef) => {
                     return servicedef.name == access.serviceType;
                   })}
                   policyView={false}
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminModal.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminModal.jsx
index be77362..37a8cd2 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminModal.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/AdminModal.jsx
@@ -39,6 +39,7 @@
   const handleShow = async () => {
     let authlogs = [];
     try {
+      setLoader(true);
       const authResp = await fetchApi({
         url: "xusers/authSessions",
         params: {
@@ -47,8 +48,9 @@
       });
       authlogs = authResp.data.vXAuthSessions;
       setAuthSession(authlogs);
-      authlogs ? setLoader(false) : setLoader(true);
+      setLoader(false);
     } catch (error) {
+      setLoader(false);
       console.error(`Error occurred while fetching Admin logs! ${error}`);
     }
   };
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx
index 5f7fc8a..aa17887 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx
@@ -30,10 +30,11 @@
   scrollToError
 } from "../../components/CommonComponents";
 import { commonBreadcrumb, serverError } from "../../utils/XAUtils";
-import { isEmpty, values } from "lodash";
+import { find, isEmpty, values } from "lodash";
 import withRouter from "Hooks/withRouter";
 import { useLocation, useNavigate } from "react-router-dom";
 import usePrompt from "Hooks/usePrompt";
+import { getServiceDef } from "../../utils/appState";
 
 const initialState = {
   service: {},
@@ -74,6 +75,7 @@
   const [preventUnBlock, setPreventUnblock] = useState(false);
   const [blockUI, setBlockUI] = useState(false);
   const toastId = useRef(null);
+  const { allServiceDefs } = getServiceDef();
 
   useEffect(() => {
     fetchInitialData();
@@ -107,7 +109,6 @@
         }
     }
 
-    let apiError = "Error occurred while creating Key";
     serviceJson.name = values.name;
     serviceJson.cipher = values.cipher;
     serviceJson.length = values.length;
@@ -149,7 +150,6 @@
   };
   const fetchKmsServices = async () => {
     let serviceResp;
-    let kmsDefinition;
     dispatch({
       type: "SET_LOADER",
       loader: true
@@ -161,20 +161,11 @@
     } catch (error) {
       console.error(`Error occurred while fetching Services! ${error}`);
     }
-    try {
-      kmsDefinition = await fetchApi({
-        url: `plugins/definitions/name/${
-          serviceResp.data && serviceResp.data.type
-        }`
-      });
-    } catch (error) {
-      console.error(`Error occurred while fetching Definitions! ${error}`);
-    }
 
     dispatch({
       type: "SET_DATA",
       service: serviceResp,
-      definition: kmsDefinition,
+      definition: find(allServiceDefs, { name: "kms" }),
       loader: false
     });
   };
@@ -194,7 +185,7 @@
   };
   const keyCreateBreadcrumb = () => {
     let serviceDetails = {};
-    serviceDetails["serviceDefId"] = definition.data && definition.data.id;
+    serviceDetails["serviceDefId"] = definition && definition?.id;
     serviceDetails["serviceId"] = service.data && service.data.id;
     serviceDetails["serviceName"] = props.params.serviceName;
     return commonBreadcrumb(
@@ -226,7 +217,6 @@
           handleSubmit,
           form,
           submitting,
-          pristine,
           invalid,
           errors,
           dirty,
@@ -398,7 +388,6 @@
                 <Col sm={{ span: 9, offset: 3 }}>
                   <Button
                     variant="primary"
-                    // type="submit"
                     onClick={() => {
                       if (invalid) {
                         let selector =
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListing.jsx b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListing.jsx
index 2533958..e7e38d3 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListing.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListing.jsx
@@ -72,7 +72,6 @@
 } from "../../components/CommonComponents";
 
 function PolicyListing(props) {
-  //const { serviceDef, serviceData } = props;
   const { serviceDef, serviceData, serviceZone } = props;
   const { state } = useLocation();
   const [policyListingData, setPolicyData] = useState([]);
@@ -229,7 +228,7 @@
         setLoader(false);
       }
     },
-    [updateTable, searchFilterParams, serviceData]
+    [updateTable, searchFilterParams]
   );
 
   const toggleConfirmModalForDelete = (policyID, policyName) => {
@@ -724,26 +723,25 @@
 
   return (
     <div className="wrap">
-      {(props.serviceData.type == "hdfs" || props.serviceData.type == "yarn") &&
-        show && (
-          <Alert variant="warning" onClose={() => setShow(false)} dismissible>
-            <i className="fa-fw fa fa-info-circle d-inline text-dark"></i>
-            <p className="pd-l-10 d-inline">
-              {`By default, fallback to ${
-                alertMessage[props.serviceData.type].label
-              } ACLs are enabled. If access cannot be
+      {(serviceData.type == "hdfs" || serviceData.type == "yarn") && show && (
+        <Alert variant="warning" onClose={() => setShow(false)} dismissible>
+          <i className="fa-fw fa fa-info-circle d-inline text-dark"></i>
+          <p className="pd-l-10 d-inline">
+            {`By default, fallback to ${
+              alertMessage[serviceData.type].label
+            } ACLs are enabled. If access cannot be
               determined by Ranger policies, authorization will fall back to
               ${
-                alertMessage[props.serviceData.type].label
+                alertMessage[serviceData.type].label
               } ACLs. If this behavior needs to be changed, modify ${
-                alertMessage[props.serviceData.type].label
-              }
+              alertMessage[serviceData.type].label
+            }
               plugin config - ${
-                alertMessage[props.serviceData.type].configs
+                alertMessage[serviceData.type].configs
               }-authorization.`}
-            </p>
-          </Alert>
-        )}
+          </p>
+        </Alert>
+      )}
       {pageLoader ? (
         <Loader />
       ) : (
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListingTabView.jsx b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListingTabView.jsx
index 7c6b1c1..6fffb60 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListingTabView.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyListingTabView.jsx
@@ -31,7 +31,7 @@
 } from "Utils/XAUtils";
 import { Loader } from "Components/CommonComponents";
 import TopNavBar from "../SideBar/TopNavBar";
-import { map, sortBy } from "lodash";
+import { isEmpty, map, sortBy } from "lodash";
 import { RangerPolicyType } from "../../utils/XAEnums";
 import { getServiceDef } from "../../utils/appState";
 
@@ -135,12 +135,12 @@
       serviceData: getServiceData?.data,
       serviceDefData: getServiceDefData
     });
-
-    dispatch({
-      type: "SET_LOADER",
-      loader: false
-    });
-
+    if (!isEmpty(getServiceData) && !isEmpty(getServiceDefData)) {
+      dispatch({
+        type: "SET_LOADER",
+        loader: false
+      });
+    }
     document
       .getElementById("resourceSelectedZone")
       ?.classList?.remove("disabledEvents");
@@ -170,7 +170,7 @@
         }
       });
       navigate(
-        `/service/${selectedServiceData?.id}/policies/${RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value}`
+        `/service/${selectedServiceData?.id}/policies/${params.policyType}`
       );
       localStorage.removeItem("zoneDetails");
     }
@@ -198,9 +198,7 @@
     } else {
       localStorage.removeItem("zoneDetails");
     }
-    navigate(
-      `/service/${params.serviceId}/policies/${RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value}`
-    );
+    navigate(`/service/${params.serviceId}/policies/${params.policyType}`);
   };
 
   const getServiceZone = () => {
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Reports/UserAccessLayout.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Reports/UserAccessLayout.jsx
index 19629d6..fda70d9 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/Reports/UserAccessLayout.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/Reports/UserAccessLayout.jsx
@@ -52,6 +52,7 @@
 import { isAuditor, isKeyAdmin, isKMSAuditor } from "../../utils/XAUtils";
 import CustomBreadcrumb from "../CustomBreadcrumb";
 import moment from "moment-timezone";
+import { getServiceDef } from "../../utils/appState";
 
 function UserAccessLayout() {
   const isKMSRole = isKeyAdmin() || isKMSAuditor();
@@ -68,6 +69,7 @@
   const navigate = useNavigate();
   const location = useLocation();
   const searchParams = useQuery();
+  const { allServiceDefs } = getServiceDef();
 
   const showMoreLess = () => {
     setShow(!show);
@@ -92,21 +94,10 @@
   };
 
   const fetchData = async () => {
-    let serviceDefsResp;
     let servicesResp;
     let resourceServices;
 
     try {
-      serviceDefsResp = await fetchApi({
-        url: `plugins/definitions`
-      });
-    } catch (error) {
-      console.error(
-        `Error occurred while fetching Service Definitions ! ${error}`
-      );
-    }
-
-    try {
       servicesResp = await fetchApi({
         url: "plugins/services"
       });
@@ -120,10 +111,8 @@
       );
     }
 
-    let resourceServiceDefs = filter(
-      serviceDefsResp?.data?.serviceDefs,
-      (serviceDef) =>
-        isKMSRole ? serviceDef.name == "kms" : serviceDef.name != "kms"
+    let resourceServiceDefs = filter(allServiceDefs, (serviceDef) =>
+      isKMSRole ? serviceDef.name == "kms" : serviceDef.name != "kms"
     );
 
     let filterResourceServiceDefs = resourceServiceDefs;
@@ -138,12 +127,9 @@
       });
     }
 
-    let serviceDefsList = map(
-      serviceDefsResp?.data?.serviceDefs,
-      function (serviceDef) {
-        return { value: serviceDef.name, label: serviceDef.name };
-      }
-    );
+    let serviceDefsList = map(allServiceDefs, function (serviceDef) {
+      return { value: serviceDef.name, label: serviceDef.name };
+    });
 
     setServiceDefs(resourceServiceDefs);
     setServices(resourceServices);
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 7eb6754..90a257a 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
@@ -48,6 +48,7 @@
   selectCustomStyles
 } from "../../components/CommonComponents";
 import usePrompt from "Hooks/usePrompt";
+import { getServiceDef } from "../../utils/appState";
 
 const noneOptions = {
   label: "None",
@@ -64,7 +65,7 @@
   const navigate = useNavigate();
   const params = useParams();
   const toastId = useRef(null);
-  const [serviceDefs, setServiceDefs] = useState([]);
+  const { allServiceDefs } = getServiceDef();
   const [services, setServices] = useState([]);
   const [zone, setZone] = useState({});
   const [resourceServiceDef, setResourceServiceDef] = useState({});
@@ -161,25 +162,10 @@
   };
 
   const fetchInitalData = async () => {
-    await fetchServiceDefs();
     await fetchResourceServices();
     await fetchZones();
   };
 
-  const fetchServiceDefs = async () => {
-    let servicetypeResp;
-
-    try {
-      servicetypeResp = await fetchApi({
-        url: `plugins/definitions`
-      });
-    } catch (error) {
-      console.error(`Error occurred while fetching Services! ${error}`);
-    }
-
-    setServiceDefs(servicetypeResp.data.serviceDefs);
-  };
-
   const fetchResourceServices = async () => {
     const serviceDefnsResp = await fetchApi({
       url: "plugins/services"
@@ -232,7 +218,7 @@
   };
 
   const renderResourcesModal = (input, serviceType) => {
-    let filterServiceDef = find(serviceDefs, ["name", serviceType]);
+    let filterServiceDef = find(allServiceDefs, ["name", serviceType]);
     let filterService = find(services, ["type", serviceType]);
 
     for (const obj of filterServiceDef.resources) {
@@ -256,7 +242,7 @@
 
   const editResourcesModal = (idx, input, serviceType) => {
     let editData = input.input.value[idx];
-    let filterServiceDef = find(serviceDefs, ["name", serviceType]);
+    let filterServiceDef = find(allServiceDefs, ["name", serviceType]);
     let filterService = find(services, ["type", serviceType]);
 
     for (const obj of filterServiceDef.resources) {
@@ -479,7 +465,7 @@
       let serviceType = find(services, ["name", name]);
       tableValues["serviceType"] = serviceType.type;
 
-      let filterServiceDef = find(serviceDefs, ["name", serviceType.type]);
+      let filterServiceDef = find(allServiceDefs, ["name", serviceType.type]);
 
       for (const obj of filterServiceDef.resources) {
         obj.recursiveSupported = false;
@@ -656,9 +642,9 @@
 
   const showResources = (value, serviceType) => {
     let data = {};
-    let filterdef = serviceDefs.find((obj) => obj.name == serviceType);
+    let filterServiceDef = find(allServiceDefs, ["name", serviceType]);
 
-    for (const obj of filterdef.resources) {
+    for (const obj of filterServiceDef.resources) {
       obj.recursiveSupported = false;
       obj.excludesSupported = false;
       if (obj.level !== 10) {
@@ -666,13 +652,15 @@
       }
     }
 
-    const grpResources = groupBy(filterdef.resources || [], "level");
+    const grpResources = groupBy(filterServiceDef.resources || [], "level");
+
     let grpResourcesKeys = [];
     for (const resourceKey in grpResources) {
       grpResourcesKeys.push(+resourceKey);
     }
     grpResourcesKeys = grpResourcesKeys.sort();
     data.resources = {};
+
     for (const level of grpResourcesKeys) {
       if (
         value[`resourceName-${level}`] &&
@@ -703,6 +691,7 @@
       </p>
     ));
   };
+
   const onFocusUserSelect = () => {
     setUserLoading(true);
     fetchUsersData().then((opts) => {
@@ -718,6 +707,7 @@
       setGroupLoading(false);
     });
   };
+
   const onFocusRoleSelect = () => {
     setRoleLoading(true);
     fetchRolesData().then((opts) => {
@@ -725,6 +715,7 @@
       setRoleLoading(false);
     });
   };
+
   const onFocusTagServiceSelect = () => {
     setTagServiceLoading(true);
     fetchTagServices().then((opts) => {
@@ -732,6 +723,7 @@
       setTagServiceLoading(false);
     });
   };
+
   return (
     <React.Fragment>
       <div className="clearfix">
@@ -1014,6 +1006,7 @@
                         </Row>
                       )}
                     />
+
                     <Field
                       name="auditUserGroups"
                       render={({ input, meta }) => (
@@ -1141,6 +1134,7 @@
                         </Row>
                       )}
                     />
+
                     <Field
                       name="resourceServices"
                       render={({ input }) => (
@@ -1176,6 +1170,7 @@
                         </Row>
                       )}
                     />
+
                     <Table striped bordered>
                       <thead>
                         <tr>
@@ -1309,6 +1304,7 @@
                         </FieldArray>
                       </tbody>
                     </Table>
+
                     <Row className="form-actions">
                       <Col sm={{ span: 9, offset: 3 }}>
                         <Button
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SideBar/TopNavBar.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SideBar/TopNavBar.jsx
index a199c11..2979961 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/SideBar/TopNavBar.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/SideBar/TopNavBar.jsx
@@ -203,6 +203,7 @@
           value={!policyLoader ? getCurrentService(serviceData) : ""}
           menuPlacement="auto"
           placeholder="Select Service Name"
+          hideSelectedOptions
         />
         {!isKMSRole && (
           <React.Fragment>
@@ -219,6 +220,7 @@
               menuPlacement="auto"
               placeholder="Select Zone Name"
               isClearable
+              hideSelectedOptions
             />
           </React.Fragment>
         )}
@@ -260,7 +262,7 @@
             {isAdminRole && (
               <Dropdown.ItemText>
                 <Link
-                  to={`/service/${serviceDefData.id}/edit/${serviceData?.id}`}
+                  to={`/service/${serviceDefData?.id}/edit/${serviceData?.id}`}
                   onClick={(e) => policyLoader && e.preventDefault()}
                   state={allServicesData[0]?.id}
                   disabled={policyLoader ? true : false}
@@ -316,8 +318,8 @@
       <Modal show={showDelete} onHide={hideDeleteModal}>
         <Modal.Header closeButton>
           <span className="text-word-break">
-            Are you sure want to delete service&nbsp;"
-            <b>{`${serviceData?.displayName}`}</b>" ?
+            Are you sure want to delete service&nbsp;&quot;
+            <b>{`${serviceData?.displayName}`}</b>&quot; ?
           </span>
         </Modal.Header>
         <Modal.Footer>
diff --git a/security-admin/src/main/webapp/scripts/collection_bases/RangerZoneListBase.js b/security-admin/src/main/webapp/scripts/collection_bases/RangerZoneListBase.js
index 9f6f390..170be91 100644
--- a/security-admin/src/main/webapp/scripts/collection_bases/RangerZoneListBase.js
+++ b/security-admin/src/main/webapp/scripts/collection_bases/RangerZoneListBase.js
@@ -41,9 +41,6 @@
                         this.modelName = 'RangerZone';
                         this.modelAttrName = 'securityZones';
                         this.bindErrorEvents();
-                },
-                comparator: function(def) {
-                        return def.get('name');
                 }
         },{
                 // static class members
diff --git a/security-admin/src/main/webapp/scripts/controllers/Controller.js b/security-admin/src/main/webapp/scripts/controllers/Controller.js
index 3ceb89c..abfa818 100755
--- a/security-admin/src/main/webapp/scripts/controllers/Controller.js
+++ b/security-admin/src/main/webapp/scripts/controllers/Controller.js
@@ -574,6 +574,9 @@
                 cache: false,
                 async: false,
             });
+            rangerZoneList.models = rangerZoneList.sortBy(function(model) {
+                return model.get('name').toLowerCase();
+            });
             App.rContent.show(new vSecurityZone({
                 rangerService: rangerServiceList,
                 collection: rangerZoneList,
diff --git a/security-admin/src/main/webapp/scripts/controllers/NController.js b/security-admin/src/main/webapp/scripts/controllers/NController.js
index 6f97a31..38d7735 100644
--- a/security-admin/src/main/webapp/scripts/controllers/NController.js
+++ b/security-admin/src/main/webapp/scripts/controllers/NController.js
@@ -552,6 +552,9 @@
                 cache: false,
                 async: false,
             });
+            rangerZoneList.models = rangerZoneList.sortBy(function(model) {
+                return model.get('name').toLowerCase();
+            });
             if (App.rSideBar.currentView) {
                 this.rSidebarContentHideAndShow('SecurityZone');
                 if (!_.isNaN(parseInt(listId))) {
diff --git a/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js b/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
index 4caba8f..47ef022 100644
--- a/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
+++ b/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
@@ -261,6 +261,9 @@
                 minGroupId                      : "Minimum group id",
                 userSearchFilter                : 'User search filter',
                 groupSearchFilter               : 'Group search filter',
+                userSearchEnabled               : 'User search enabled',
+                groupSearchEnabled              : 'Group search enabled',
+                groupSearchFirstEnabled         : 'Group search first enabled',
                 startDate                       : 'Start Date',
                 endDate                         : 'End Date',
                 addValidityPeriod               : ' Add Validity Period',