Skip to content

Commit

Permalink
Merge pull request #2427 from JohnDuprey/jit-admin
Browse files Browse the repository at this point in the history
JIT Admin frontend
  • Loading branch information
JohnDuprey authored May 9, 2024
2 parents d1ae131 + 41bc439 commit 2c4f0aa
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/_nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const _nav = [
name: 'Roles',
to: '/identity/administration/roles',
},
{
component: CNavItem,
name: 'JIT Admin',
to: '/identity/administration/users/jit-admin',
},
{
component: CNavItem,
name: 'Offboarding Wizard',
Expand Down
3 changes: 2 additions & 1 deletion src/importsMap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React from 'react'
"/identity/administration/users/edit": React.lazy(() => import('./views/identity/administration/EditUser')),
"/identity/administration/users/view": React.lazy(() => import('./views/identity/administration/ViewUser')),
"/identity/administration/users/InviteGuest": React.lazy(() => import('./views/identity/administration/InviteGuest')),
"/identity/administration/users/jit-admin": React.lazy(() => import('./views/identity/administration/DeployJITAdmin')),
"/identity/administration/ViewBec": React.lazy(() => import('./views/identity/administration/ViewBEC')),
"/identity/administration/users": React.lazy(() => import('./views/identity/administration/Users')),
"/identity/administration/devices": React.lazy(() => import('./views/identity/administration/Devices')),
Expand Down Expand Up @@ -142,4 +143,4 @@ import React from 'react'
"/tenant/administration/tenant-offboarding-wizard": React.lazy(() => import('./views/tenant/administration/TenantOffboardingWizard')),
"/tenant/administration/tenant-onboarding-wizard": React.lazy(() => import('./views/tenant/administration/TenantOnboardingWizard')),
}
export default importsMap
export default importsMap
6 changes: 6 additions & 0 deletions src/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@
"component": "views/identity/administration/InviteGuest",
"allowedRoles": ["admin", "editor", "readonly"]
},
{
"path": "/identity/administration/users/jit-admin",
"name": "JIT Admin",
"component": "views/identity/administration/DeployJITAdmin",
"allowedRoles": ["admin", "editor", "readonly"]
},
{
"path": "/identity/administration/ViewBec",
"name": "View BEC",
Expand Down
213 changes: 213 additions & 0 deletions src/views/identity/administration/DeployJITAdmin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import React, { useState } from 'react'
import { CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react'
import { useSelector } from 'react-redux'
import { Field, Form, FormSpy } from 'react-final-form'
import { Condition, RFFCFormRadio, RFFCFormSwitch, RFFSelectSearch } from 'src/components/forms'
import {
useGenericGetRequestQuery,
useLazyGenericGetRequestQuery,
useLazyGenericPostRequestQuery,
} from 'src/store/api/app'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCircleNotch, faEdit, faEye } from '@fortawesome/free-solid-svg-icons'
import { CippContentCard, CippPage, CippPageList } from 'src/components/layout'
import { CellTip } from 'src/components/tables/CellGenericFormat'
import 'react-datepicker/dist/react-datepicker.css'
import { CippActionsOffcanvas, ModalService, TenantSelector } from 'src/components/utilities'
import arrayMutators from 'final-form-arrays'
import DatePicker from 'react-datepicker'
import 'react-datepicker/dist/react-datepicker.css'
import { useListUsersQuery } from 'src/store/api/users'
import { useListConditionalAccessPoliciesQuery } from 'src/store/api/tenants'
import GDAPRoles from 'src/data/GDAPRoles'

const DeployJITAdmin = () => {
const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery()
const currentDate = new Date()
const [startDate, setStartDate] = useState(currentDate)
const [endDate, setEndDate] = useState(currentDate)

const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName)
const [refreshState, setRefreshState] = useState(false)
const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery()

const onSubmit = (values) => {
const startTime = Math.floor(startDate.getTime() / 1000)
const endTime = Math.floor(endDate.getTime() / 1000)
const shippedValues = {
tenantFilter: tenantDomain,
UserId: values.UserId?.value,
PolicyId: values.PolicyId?.value,
StartDate: startTime,
EndDate: endTime,
ExpireAction: values?.expireAction ?? 'delete',
}
genericPostRequest({ path: '/api/ExecJITAdmin', values: shippedValues }).then((res) => {
setRefreshState(res.requestId)
})
}

const {
data: users = [],
isFetching: usersIsFetching,
error: usersError,
} = useListUsersQuery({ tenantDomain })

return (
<CippPage title={`Add JIT Admin`} tenantSelector={false}>
<>
<CRow>
<CCol md={4}>
<CippContentCard title="Add JIT Admin" icon={faEdit}>
<Form
onSubmit={onSubmit}
mutators={{
...arrayMutators,
}}
render={({ handleSubmit, submitting, values }) => {
return (
<CForm onSubmit={handleSubmit}>
<p>
JIT Admin creates an account that is usable for a specific period of time.
Enter a username, select admin roles, date range and expiration action.
</p>
<CRow className="mb-3">
<CCol>
<label>Tenant</label>
<Field name="tenantFilter">{(props) => <TenantSelector />}</Field>
</CCol>
</CRow>
<CRow>
<hr />
</CRow>
<CRow className="mb-3">
<CCol>
<RFFCFormRadio
value="create"
name="useraction"
label="Create User"
validate={false}
/>
<RFFCFormRadio
value="select"
name="useraction"
label="Select User"
validate={false}
/>
</CCol>
</CRow>
<CRow className="mb-3">
<CCol>

<RFFSelectSearch
label={'Users in ' + tenantDomain}
values={users?.map((user) => ({
value: user.id,
name: `${user.displayName} <${user.userPrincipalName}>`,
}))}
placeholder={!usersIsFetching ? 'Select user' : 'Loading...'}
name="UserId"
isLoading={usersIsFetching}
/>
</CCol>
</CRow>
<CRow className="mb-3">
<CCol>
<RFFSelectSearch
label="Administrative Roles"
values={GDAPRoles?.map((role) => ({
value: role.ObjectId,
name: role.Name,
}))}
multi={true}
placeholder="Select Roles"
name="AdminRoles"
/>
</CCol>
</CRow>
<CRow className="mb-3">
<CCol>
<label>Scheduled Start Date</label>
<DatePicker
className="form-control mb-3"
selected={startDate}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}
dateFormat="Pp"
onChange={(date) => setStartDate(date)}
/>
</CCol>
<CCol>
<label>Scheduled End Date</label>
<DatePicker
className="form-control mb-3"
selected={endDate}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}
dateFormat="Pp"
onChange={(date) => setEndDate(date)}
/>
</CCol>
</CRow>
<CRow className="mb-3">
<CCol>
<RFFSelectSearch
label="Expiration Action"
values={[
{ value: 'removeroles', name: 'Remove Admin Roles' },
{ value: 'disable', name: 'Disable' },
{ value: 'delete', name: 'Delete' },
]}
placeholder="Select action for when JIT expires"
name="expireAction"
/>
</CCol>
</CRow>
<CRow>
<CCol md={6}>
<CButton type="submit" disabled={submitting}>
Add JIT Admin
{postResults.isFetching && (
<FontAwesomeIcon
icon={faCircleNotch}
spin
className="ms-2"
size="1x"
/>
)}
</CButton>
</CCol>
</CRow>
{postResults.isSuccess && (
<CCallout color="success">
<li>{postResults.data.Results}</li>
</CCallout>
)}
{getResults.isFetching && (
<CCallout color="info">
<CSpinner>Loading</CSpinner>
</CCallout>
)}
{getResults.isSuccess && (
<CCallout color="info">{getResults.data?.Results}</CCallout>
)}
{getResults.isError && (
<CCallout color="danger">
Could not connect to API: {getResults.error.message}
</CCallout>
)}
</CForm>
)
}}
/>
</CippContentCard>
</CCol>
</CRow>
</>
</CippPage>
)
}

export default DeployJITAdmin

0 comments on commit 2c4f0aa

Please sign in to comment.