Skip to content

Commit

Permalink
feat(access): allow more flexible access checks (#873)
Browse files Browse the repository at this point in the history
  • Loading branch information
oyo authored Sep 12, 2024
1 parent 18ec5e7 commit 20b6637
Show file tree
Hide file tree
Showing 38 changed files with 837 additions and 383 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Feature

- **Roles and Permissions**
- Enable more fine grained permission checks by client id and roles
- **Customer Detail Data Overlay**
- implement new UI design for customer detail data overlay
- **Company Subscription Management**
Expand Down
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
<div id="app"></div>
<script>
// Do NOT change 'ENV' without changing 'custom_env_vars_anchor' in scripts/inject-dynamic-env.sh as well
const ENV = {REQUIRE_HTTPS_URL_PATTERN:"true",PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",SSI_CREDENTIAL_URL:"https://ssi-credential-issuer.example.org",BPDM_POOL_API_URL:"https://business-partners.example.org/pool/v6",BPDM_GATE_API_URL:"https://business-partners.example.org/companies/test-company/v6",SEMANTICS_URL:"https://semantics.example.org",MANAGED_IDENTITY_WALLETS_NEW_URL:"https://managed-identity-wallets-new.example.org",REALM:"CX-Central",CLIENT_ID:"Cl2-CX-Portal",CLIENT_ID_SEMANTIC:"Cl3-CX-Semantic",CLIENT_ID_MIW:"Cl5-CX-Custodian",CLIENT_ID_SSI_CREDENTIAL:"Cl24-CX-SSI-CredentialIssuer"}
const ENV = {REQUIRE_HTTPS_URL_PATTERN:"true",PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",SSI_CREDENTIAL_URL:"https://ssi-credential-issuer.example.org",BPDM_POOL_API_URL:"https://business-partners.example.org/pool/v6",BPDM_GATE_API_URL:"https://business-partners.example.org/companies/test-company/v6",SEMANTICS_URL:"https://semantics.example.org",MANAGED_IDENTITY_WALLETS_NEW_URL:"https://managed-identity-wallets-new.example.org",REALM:"CX-Central",CLIENT_ID:"Cl2-CX-Portal",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration",CLIENT_ID_SEMANTIC:"Cl3-CX-Semantic",CLIENT_ID_BPDM:"Cl7-CX-BPDM",CLIENT_ID_MIW:"Cl5-CX-Custodian",CLIENT_ID_SSI_CREDENTIAL:"Cl24-CX-SSI-CredentialIssuer"}
</script>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
</html>
515 changes: 515 additions & 0 deletions providers.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions scripts/inject-dynamic-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
###############################################################

# Define custom variable
custom_env_vars='{REQUIRE_HTTPS_URL_PATTERN:"'$REQUIRE_HTTPS_URL_PATTERN'",PORTAL_ASSETS_URL:"'$PORTAL_ASSETS_URL'",PORTAL_BACKEND_URL:"'$PORTAL_BACKEND_URL'",CENTRALIDP_URL:"'$CENTRALIDP_URL'",SSI_CREDENTIAL_URL:"'$SSI_CREDENTIAL_URL'",BPDM_POOL_API_URL:"'$BPDM_POOL_API_URL'",BPDM_GATE_API_URL:"'$BPDM_GATE_API_URL'",SEMANTICS_URL:"'$SEMANTICS_URL'",MANAGED_IDENTITY_WALLETS_NEW_URL:"'$MANAGED_IDENTITY_WALLETS_NEW_URL'",REALM:"'$REALM'",CLIENT_ID:"'$CLIENT_ID'",CLIENT_ID_SEMANTIC:"'$CLIENT_ID_SEMANTIC'",CLIENT_ID_MIW:"'$CLIENT_ID_MIW'",CLIENT_ID_SSI_CREDENTIAL:"'$CLIENT_ID_SSI_CREDENTIAL'"}'
custom_env_vars='{REQUIRE_HTTPS_URL_PATTERN:"'$REQUIRE_HTTPS_URL_PATTERN'",PORTAL_ASSETS_URL:"'$PORTAL_ASSETS_URL'",PORTAL_BACKEND_URL:"'$PORTAL_BACKEND_URL'",CENTRALIDP_URL:"'$CENTRALIDP_URL'",SSI_CREDENTIAL_URL:"'$SSI_CREDENTIAL_URL'",BPDM_POOL_API_URL:"'$BPDM_POOL_API_URL'",BPDM_GATE_API_URL:"'$BPDM_GATE_API_URL'",SEMANTICS_URL:"'$SEMANTICS_URL'",MANAGED_IDENTITY_WALLETS_NEW_URL:"'$MANAGED_IDENTITY_WALLETS_NEW_URL'",REALM:"'$REALM'",CLIENT_ID:"'$CLIENT_ID'",CLIENT_ID_REGISTRATION:"'$CLIENT_ID_REGISTRATION'",CLIENT_ID_SEMANTIC:"'$CLIENT_ID_SEMANTIC'",CLIENT_ID_BPDM:"'$CLIENT_ID_BPDM'",CLIENT_ID_MIW:"'$CLIENT_ID_MIW'",CLIENT_ID_SSI_CREDENTIAL:"'$CLIENT_ID_SSI_CREDENTIAL'"}'
# Define anchor variable
custom_env_vars_anchor='{REQUIRE_HTTPS_URL_PATTERN:"true",PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",SSI_CREDENTIAL_URL:"https://ssi-credential-issuer.example.org",BPDM_POOL_API_URL:"https://business-partners.example.org/pool/v6",BPDM_GATE_API_URL:"https://business-partners.example.org/companies/test-company/v6",SEMANTICS_URL:"https://semantics.example.org",MANAGED_IDENTITY_WALLETS_NEW_URL:"https://managed-identity-wallets-new.example.org",REALM:"CX-Central",CLIENT_ID:"Cl2-CX-Portal",CLIENT_ID_SEMANTIC:"Cl3-CX-Semantic",CLIENT_ID_MIW:"Cl5-CX-Custodian",CLIENT_ID_SSI_CREDENTIAL:"Cl24-CX-SSI-CredentialIssuer"}'
custom_env_vars_anchor='{REQUIRE_HTTPS_URL_PATTERN:"true",PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",SSI_CREDENTIAL_URL:"https://ssi-credential-issuer.example.org",BPDM_POOL_API_URL:"https://business-partners.example.org/pool/v6",BPDM_GATE_API_URL:"https://business-partners.example.org/companies/test-company/v6",SEMANTICS_URL:"https://semantics.example.org",MANAGED_IDENTITY_WALLETS_NEW_URL:"https://managed-identity-wallets-new.example.org",REALM:"CX-Central",CLIENT_ID:"Cl2-CX-Portal",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration",CLIENT_ID_SEMANTIC:"Cl3-CX-Semantic",CLIENT_ID_BPDM:"Cl7-CX-BPDM",CLIENT_ID_MIW:"Cl5-CX-Custodian",CLIENT_ID_SSI_CREDENTIAL:"Cl24-CX-SSI-CredentialIssuer"}'
# Read content of the reference index.html file into the index_html_reference variable
index_html_reference=`cat /usr/share/nginx/html/index.html.reference`
# Replace the anchor variable with the custom variable in the index.html file
Expand Down
35 changes: 0 additions & 35 deletions src/components/AuthProvider.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions src/components/overlays/CompanyCertificateDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ import { useEffect, useState } from 'react'
import { OVERLAYS, ROLES } from 'types/Constants'
import dayjs from 'dayjs'
import LoadingProgress from 'components/shared/basic/LoadingProgress'
import UserService from 'services/UserService'
import { SortType } from 'components/pages/CompanyCertificates'
import { userHasPortalRole } from 'services/AccessService'

export enum StatusTag {
PENDING = 'Pending',
Expand Down Expand Up @@ -209,7 +209,7 @@ export default function CompanyCertificateDetails({
<Box>
<Button
disabled={
!UserService.hasRole(ROLES.SUBSCRIBE_SERVICE_MARKETPLACE)
!userHasPortalRole(ROLES.SUBSCRIBE_SERVICE_MARKETPLACE)
}
startIcon={<DeleteIcon />}
variant="outlined"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ import {
StatusTag,
Tooltips,
} from '@catena-x/portal-shared-components'
import UserService from 'services/UserService'
import { ROLES } from 'types/Constants'
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'
import { userHasSsiCredentialRole } from 'services/AccessService'

interface FetchHookArgsType {
filterType: string
Expand Down Expand Up @@ -224,7 +224,7 @@ export default function AdminCredentialElements() {
</div>
)
} else if (
UserService.hasRole(ROLES.REVOKE_CREDENTIALS_ISSUER) &&
userHasSsiCredentialRole(ROLES.REVOKE_CREDENTIALS_ISSUER) &&
row.participantStatus === StatusEnum.ACTIVE
) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

import { useSelector, useDispatch } from 'react-redux'
import { useDispatch, useSelector } from 'react-redux'
import {
Typography,
OrderStatusButton,
paletteDefinitions,
} from '@catena-x/portal-shared-components'
import { useTranslation } from 'react-i18next'
import type { AppDetails } from 'features/apps/details/types'
import { userSelector } from 'features/user/slice'
import './AppDetailHeader.scss'
import { OVERLAYS, ROLES } from 'types/Constants'
import { show } from 'features/control/overlay'
Expand All @@ -36,6 +35,7 @@ import { SubscriptionStatus } from 'features/apps/types'
import { useFetchDocumentByIdMutation } from 'features/apps/apiSlice'
import CommonService from 'services/CommonService'
import type { UseCaseType } from 'features/appManagement/types'
import { userHasPortalRole } from 'services/AccessService'
import type { RootState } from 'features/store'

export interface AppDetailHeaderProps {
Expand All @@ -57,7 +57,6 @@ export default function AppDetailHeader({ item }: AppDetailHeaderProps) {
)

const { appId } = useParams()
const user = useSelector(userSelector)
const [image, setImage] = useState('')
const [fetchDocumentById] = useFetchDocumentByIdMutation()
const [buttonLabel, setButtonLabel] = useState(
Expand Down Expand Up @@ -105,10 +104,9 @@ export default function AppDetailHeader({ item }: AppDetailHeaderProps) {
break
default:
btnColor = {
color:
user.roles.indexOf(ROLES.SUBSCRIBE_APP_MARKETPLACE) !== -1
? 'primary'
: 'secondary',
color: userHasPortalRole(ROLES.SUBSCRIBE_APP_MARKETPLACE)
? 'primary'
: 'secondary',
background1: paletteDefinitions.buttons.darkGrey ?? '',
background2: paletteDefinitions.buttons.lightGrey ?? '',
background3: paletteDefinitions.buttons.white ?? '',
Expand Down Expand Up @@ -148,17 +146,15 @@ export default function AppDetailHeader({ item }: AppDetailHeaderProps) {
buttonData={OrderStatusButtonItems}
selectable={
subscribeStatus === SubscriptionStatus.INACTIVE &&
user.roles.indexOf(ROLES.SUBSCRIBE_APP_MARKETPLACE) !== -1
? true
: false
userHasPortalRole(ROLES.SUBSCRIBE_APP_MARKETPLACE)
}
onButtonClick={() => {
if (buttonLabel === t('content.appdetail.requested')) {
return
}
return (
subscribeStatus === SubscriptionStatus.INACTIVE &&
user.roles.indexOf(ROLES.SUBSCRIBE_APP_MARKETPLACE) !== -1 &&
userHasPortalRole(ROLES.SUBSCRIBE_APP_MARKETPLACE) &&
dispatch(show(OVERLAYS.APPMARKETPLACE_REQUEST, appId))
)
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import './AppListGroupView.scss'
import { Box } from '@mui/material'
import { Cards } from '@catena-x/portal-shared-components'
import { multiMapBy } from 'utils/multiMapBy'
import { multiMapBy } from 'utils/dataUtils'
import { useTranslation } from 'react-i18next'
import { AppListGroup } from '../AppListGroup'
import NoItems from 'components/pages/NoItems'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
} from 'features/appSubscription/appSubscriptionApiSlice'
import ReleaseStepper from 'components/shared/basic/ReleaseProcess/stepper'
import { SubscriptionStatus } from 'features/apps/types'
import UserService from 'services/UserService'
import { ROLES } from 'types/Constants'
import { useState } from 'react'
import './style.scss'
Expand All @@ -52,6 +51,7 @@ import { SubscriptionTypes } from 'components/shared/templates/Subscription'
import { useFetchServiceSubDetailQuery } from 'features/serviceSubscription/serviceSubscriptionApiSlice'
import HelpOutlineIcon from '@mui/icons-material/HelpOutline'
import { Link } from 'react-router-dom'
import { userHasPortalRole } from 'services/AccessService'

interface AppSubscriptionDetailProps {
openDialog: boolean
Expand Down Expand Up @@ -217,7 +217,7 @@ const AppSubscriptionDetailOverlay = ({
const renderTenantUrl = (url: string) => {
if (
isAppSubscription &&
UserService.hasRole(ROLES.APPSTORE_EDIT) &&
userHasPortalRole(ROLES.APPSTORE_EDIT) &&
data?.offerSubscriptionStatus === SubscriptionStatus.ACTIVE
) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from 'features/admin/appuserApiSlice'
import type { TenantUser } from 'features/admin/userApiSlice'
import { useTranslation } from 'react-i18next'
import UserService from 'services/UserService'
import { userHasPortalRole } from 'services/AccessService'

export const AppUserDetailsTable = ({
roles,
Expand All @@ -52,7 +52,7 @@ export const AppUserDetailsTable = ({
addButtonDisabled={
!roles ||
roles.length === 0 ||
!UserService.hasRole(ROLES.MODIFY_USER_ACCOUNT)
!userHasPortalRole(ROLES.MODIFY_USER_ACCOUNT)
}
addButtonTooltip={
roles && roles?.length <= 0
Expand All @@ -64,7 +64,7 @@ export const AppUserDetailsTable = ({
fetchHookArgs={{ appId, expr, userRoleResponse, role: true }}
onSearch={setExpr}
onDetailsClick={
UserService.hasRole(ROLES.MODIFY_USER_ACCOUNT)
userHasPortalRole(ROLES.MODIFY_USER_ACCOUNT)
? (row: TenantUser) =>
dispatch(show(OVERLAYS.EDIT_APP_USER_ROLES, row.companyUserId))
: undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ import { useDispatch } from 'react-redux'
import { OVERLAYS, ROLES } from 'types/Constants'
import { show } from 'features/control/overlay'
import dayjs from 'dayjs'
import UserService from 'services/UserService'
import AccessTimeOutlinedIcon from '@mui/icons-material/AccessTimeOutlined'
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'
import CancelRoundedIcon from '@mui/icons-material/CancelRounded'
import CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded'
import WarningRoundedIcon from '@mui/icons-material/WarningRounded'
import { type JSX } from 'react/jsx-runtime'
import { userHasPortalRole } from 'services/AccessService'

enum CompanyCertificateStatus {
INACTIVE = 'INACTIVE',
Expand Down Expand Up @@ -171,7 +171,7 @@ export default function CompanyCertificateCard({
borderRadius: '74px',
}}
onClick={handleDelete}
disabled={!UserService.hasRole(ROLES.SUBSCRIBE_SERVICE_MARKETPLACE)}
disabled={!userHasPortalRole(ROLES.DELETE_CERTIFICATES)}
>
<DeleteOutlinedIcon
style={{
Expand Down Expand Up @@ -202,7 +202,7 @@ export default function CompanyCertificateCard({
<Typography variant="label3" onClick={handleView}>
{t('content.companyCertificate.view')}{' '}
</Typography>
{UserService.hasRole(ROLES.SUBSCRIBE_SERVICE_MARKETPLACE) &&
{userHasPortalRole(ROLES.DELETE_CERTIFICATES) &&
item.companyCertificateStatus ===
CompanyCertificateStatus.ACTIVE && (
<Typography variant="label3" onClick={handleDelete}>
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/CompanyCertificates/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import SortImage from 'components/shared/frame/SortImage'
import './CompanyCertificate.scss'
import { ROLES } from 'types/Constants'
import CompanyCertificateElements from './CompanyCertificateElements'
import UserService from 'services/UserService'
import {
type ComapnyCertificateData,
useFetchCertificatesQuery,
Expand All @@ -38,6 +37,7 @@ import { Box } from '@mui/material'
import UploadCompanyCertificate from './UploadCompanyCerificate'
import LoadingProgress from 'components/shared/basic/LoadingProgress'
import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined'
import { userHasPortalRole } from 'services/AccessService'

interface TabButtonsType {
buttonText: string
Expand Down Expand Up @@ -184,7 +184,7 @@ export default function CompanyCertificates(): JSX.Element {
setUploadModal(true)
}}
disabled={
!UserService.hasRole(ROLES.UPLOAD_COMPANY_CERTIFICATE)
!userHasPortalRole(ROLES.UPLOAD_COMPANY_CERTIFICATE)
}
>
{t('content.companyCertificate.uploadCertificate')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { useTranslation } from 'react-i18next'
import { StaticTable, Typography } from '@catena-x/portal-shared-components'
import { type ActiveSubscriptionDetails } from 'features/apps/types'
import { PAGES, ROLES } from 'types/Constants'
import UserService from 'services/UserService'
import { userHasPortalRole } from 'services/AccessService'

export default function CompanySubscriptionTechnical({
detail,
Expand Down Expand Up @@ -52,7 +52,7 @@ export default function CompanySubscriptionTechnical({
{
icon: false,
clickableLink:
UserService.hasRole(ROLES.VIEW_USER_ACCOUNT) &&
userHasPortalRole(ROLES.VIEW_USER_ACCOUNT) &&
detail.technicalUserData.length
? `/${PAGES.USER_DETAILS}/${detail.technicalUserData[0].id}`
: undefined,
Expand Down
3 changes: 3 additions & 0 deletions src/components/pages/CompanyWallet/RuleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { useTranslation } from 'react-i18next'
import { Box, Grid } from '@mui/material'
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'
import { getAssetBase } from 'services/EnvironmentService'
import { userHasSsiCredentialRole } from 'services/AccessService'
import { ROLES } from 'types/Constants'

type Hash<T> = Record<string, T>

Expand Down Expand Up @@ -61,6 +63,7 @@ export default function RuleCard({

const canShowRevoke = (item: WalletContent) => {
return (
userHasSsiCredentialRole(ROLES.REVOKE_CREDENTIALS_ISSUER) &&
item.status === CredentialSubjectStatus.ACTIVE &&
item?.credentialType !== CredentialType.MEMBERSHIP &&
item.credentialType !== CredentialType.BUSINESS_PARTNER_NUMBER
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/EdcConnector/ConnectorDetailsOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ import { error, success } from 'services/NotifyService'
import EditIcon from '@mui/icons-material/Edit'
import Patterns from 'types/Patterns'
import { download } from 'utils/downloadUtils'
import UserService from 'services/UserService'
import { ROLES } from 'types/Constants'
import { userHasPortalRole } from 'services/AccessService'

interface DeleteConfirmationOverlayProps {
openDialog?: boolean
Expand Down Expand Up @@ -374,7 +374,7 @@ const ConnectorDetailsOverlay = ({
setEnableConnectorUrl(false)
setEnableUrlApiErrorMsg(false)
}}
disabled={!UserService.hasRole(ROLES.MODIFY_CONNECTORS)}
disabled={!userHasPortalRole(ROLES.MODIFY_CONNECTORS)}
>
<EditIcon
sx={{
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/Home/components/MenuInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import CloseIcon from '@mui/icons-material/Close'
import { MobileMenu } from 'components/shared/MobileMenu'
import { Drawer } from '@mui/material'

export const MenuInfo = ({ main }: { main: Tree[] }) => {
export const MenuInfo = ({ main }: { main: Tree[] | undefined }) => {
const { t } = useTranslation()
const visible = useSelector(appearMenuSelector)
const dispatch = useDispatch()
Expand Down
Loading

0 comments on commit 20b6637

Please sign in to comment.