diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx
index 4e38038fb68c..18cb6b397980 100644
--- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx
+++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx
@@ -7,6 +7,7 @@ import { CippCallout } from 'src/components/layout/index.js'
import CippAccordionItem from 'src/components/contentcards/CippAccordionItem'
import SettingsCustomRoles from 'src/views/cipp/app-settings/components/SettingsCustomRoles'
import CippButtonCard from 'src/components/contentcards/CippButtonCard'
+import SettingsSAMRoles from './components/SettingsSAMRoles'
export function SettingsSuperAdmin() {
const partnerConfig = useGenericGetRequestQuery({
@@ -65,46 +66,11 @@ export function SettingsSuperAdmin() {
-
-
- Tenant Mode
-
-
>
>
+
>
)
}
diff --git a/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx
new file mode 100644
index 000000000000..ebc8310b6abd
--- /dev/null
+++ b/src/views/cipp/app-settings/components/SettingsSAMRoles.jsx
@@ -0,0 +1,150 @@
+import React, { useEffect, useRef, useState } from 'react'
+import {
+ CButton,
+ CCallout,
+ CCol,
+ CForm,
+ CRow,
+ CAccordion,
+ CAccordionHeader,
+ CAccordionBody,
+ CAccordionItem,
+} from '@coreui/react'
+import { Field, Form, FormSpy } from 'react-final-form'
+import { RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms'
+import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { TenantSelectorMultiple, ModalService, CippOffcanvas } from 'src/components/utilities'
+import PropTypes from 'prop-types'
+import { OnChange } from 'react-final-form-listeners'
+import { useListTenantsQuery } from 'src/store/api/tenants'
+import { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas'
+import CippButtonCard from 'src/components/contentcards/CippButtonCard'
+import GDAPRoles from 'src/data/GDAPRoles'
+
+const SettingsSAMRoles = () => {
+ const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery()
+ const [selectedTenant, setSelectedTenant] = useState([])
+ const tenantSelectorRef = useRef()
+ const {
+ data: tenants = [],
+ isFetching: tenantsFetching,
+ isSuccess: tenantSuccess,
+ } = useListTenantsQuery({
+ showAllTenantSelector: true,
+ })
+
+ const {
+ data: cippSAMRoles = [],
+ isFetching: roleListFetching,
+ isSuccess: roleListSuccess,
+ refetch: refetchRoleList,
+ } = useGenericGetRequestQuery({
+ path: 'api/ExecSAMRoles',
+ })
+
+ const handleTenantChange = (e) => {
+ setSelectedTenant(e)
+ }
+
+ const handleSubmit = async (values) => {
+ //filter on only objects that are 'true'
+ genericPostRequest({
+ path: '/api/ExecSAMRoles?Action=Update',
+ values: {
+ Roles: values.Roles,
+ Tenants: selectedTenant.map((tenant) => tenant.value),
+ },
+ }).then(() => {
+ refetchRoleList()
+ })
+ }
+
+ useEffect(() => {
+ if (roleListSuccess && cippSAMRoles.Tenants.length > 0) {
+ var selectedTenants = []
+ tenants.map((tenant) => {
+ if (cippSAMRoles.Tenants.includes(tenant.customerId)) {
+ selectedTenants.push({ label: tenant.displayName, value: tenant.customerId })
+ }
+ })
+ tenantSelectorRef.current.setValue(selectedTenants)
+ }
+ }, [cippSAMRoles, roleListSuccess, tenantSuccess, tenantSelectorRef, tenants])
+
+ return (
+
+ <>
+
+ Add your CIPP-SAM application Service Principal directly to Admin Roles in the tenant.
+ This is an advanced use case where you need access to additional Graph endpoints or
+ Exchange Cmdlets otherwise unavailable via Delegated permissions.
+
+
+ This functionality is in
+ beta and should be treated as such. Roles are added during the Update Permissions process
+ or a CPV refresh.
+
+
+ {roleListSuccess && (
+
+ )
+}
+
+export default SettingsSAMRoles
diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx
index 3bd663d7e063..669e401a3611 100644
--- a/src/views/identity/administration/Users.jsx
+++ b/src/views/identity/administration/Users.jsx
@@ -589,7 +589,7 @@ const Users = (row) => {
label: 'Revoke sessions',
color: 'info',
modal: true,
- modalUrl: `/api/ExecRevokeSessions?Enable=true&TenantFilter=!Tenant&ID=!userPrincipalName`,
+ modalUrl: `/api/ExecRevokeSessions?Enable=true&TenantFilter=!Tenant&ID=!id&Username=!userPrincipalName`,
modalMessage: 'Are you sure you want to revoke all sessions for these users?',
},
{
diff --git a/src/views/tenant/administration/SecureScore.jsx b/src/views/tenant/administration/SecureScore.jsx
index be036997339c..bfa9d2e751c2 100644
--- a/src/views/tenant/administration/SecureScore.jsx
+++ b/src/views/tenant/administration/SecureScore.jsx
@@ -28,6 +28,8 @@ import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGeneric
import { CippCallout } from 'src/components/layout'
import CippPrettyCard from 'src/components/contentcards/CippPrettyCard'
import { TableModalButton } from 'src/components/buttons'
+import DOMPurify from 'dompurify'
+import ReactHtmlParser from 'react-html-parser'
const SecureScore = () => {
const textRef = useRef()
@@ -66,6 +68,12 @@ const SecureScore = () => {
},
})
+ const sanitizeHtml = (html) => {
+ var sanitizedHtml = DOMPurify.sanitize(html)
+ var parsedHtml = ReactHtmlParser(sanitizedHtml)
+ return parsedHtml
+ }
+
useEffect(() => {
if (isSuccess) {
setTranslatedData(securescore.Results[0])
@@ -341,23 +349,16 @@ const SecureScore = () => {
Description
-
+
+ {sanitizeHtml(`${info.description} ${info.implementationStatus}`)}
+
{info.scoreInPercentage !== 100 && (
Remediation Recommendation
- {
-
- }
+ {{sanitizeHtml(info.remediation)}
}
)}
diff --git a/staticwebapp.config.json b/staticwebapp.config.json
index 74988468595b..0c36ddcac257 100644
--- a/staticwebapp.config.json
+++ b/staticwebapp.config.json
@@ -103,7 +103,7 @@
}
},
"globalHeaders": {
- "content-security-policy": "default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'self' blob:; img-src 'self' blob: data: *"
+ "content-security-policy": "default-src https: blob: 'unsafe-eval' 'unsafe-inline'; object-src 'self' blob:; img-src 'self' blob: data: *"
},
"mimeTypes": {
".json": "text/json"