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 <[email protected]>
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 <[email protected]>
---
.../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>