From 26d22f993016f4f570cd2aed524fc9df7172ad2c Mon Sep 17 00:00:00 2001 From: faisalsiddique4400 Date: Mon, 27 Oct 2025 19:15:57 +0500 Subject: [PATCH 1/5] feat(admin-ui): add Default ACR tab in Authn screen similar to TUI (#2250) --- .../components/AuthN/DefaultAcr.js | 129 ++++++++++++++++++ .../components/AuthN/helper/acrUtils.js | 27 ++++ .../auth-server/components/AuthN/index.js | 4 + .../Configuration/DefaultAcrInput.js | 16 ++- .../auth-server/redux/features/acrSlice.js | 24 +++- .../auth-server/redux/sagas/AcrsSaga.js | 30 +++- .../user-management/redux/audit/Resources.ts | 1 + 7 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 admin-ui/plugins/auth-server/components/AuthN/DefaultAcr.js create mode 100644 admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js diff --git a/admin-ui/plugins/auth-server/components/AuthN/DefaultAcr.js b/admin-ui/plugins/auth-server/components/AuthN/DefaultAcr.js new file mode 100644 index 0000000000..41f7e1cc27 --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/DefaultAcr.js @@ -0,0 +1,129 @@ +import React, { useContext, useEffect, useState, useMemo } from 'react' +import { useSelector, useDispatch } from 'react-redux' +import { useCedarling } from '@/cedarling' +import GluuViewWrapper from 'Routes/Apps/Gluu/GluuViewWrapper' +import { useTranslation } from 'react-i18next' +import { ACR_READ, ACR_WRITE } from 'Utils/PermChecker' +import SetTitle from 'Utils/SetTitle' +import { getAcrsConfig, editAcrs } from 'Plugins/auth-server/redux/features/acrSlice' +import { getAgama } from 'Plugins/auth-server/redux/features/agamaSlice' +import GluuCommitDialog from 'Routes/Apps/Gluu/GluuCommitDialog' +import { buildPayload } from 'Utils/PermChecker' +import { Button, Form } from 'Components' +import GluuLoader from '@/routes/Apps/Gluu/GluuLoader' +import { ThemeContext } from '@/context/theme/themeContext' +import DefaultAcrInput from '../Configuration/DefaultAcrInput' +import { getScripts } from 'Redux/features/initSlice' +import { buildAgamaFlowsArray, buildDropdownOptions } from './helper/acrUtils' + +function DefaultAcr() { + const { hasCedarPermission, authorize } = useCedarling() + const dispatch = useDispatch() + + const { acrReponse: acrs } = useSelector((state) => state.acrReducer) + const scripts = useSelector((state) => state.initReducer.scripts) + const loadingScripts = useSelector((state) => state.initReducer.loadingScripts) + const { agamaList, loading: agamaLoading } = useSelector((state) => state.agamaReducer) + + const { t } = useTranslation() + + const [modal, setModal] = useState(false) + const [put, setPut] = useState(null) + const userAction = {} + const theme = useContext(ThemeContext) + const selectedTheme = theme.state.theme + + SetTitle(t('titles.acr_management')) + + useEffect(() => { + const initializeAcr = async () => { + try { + await authorize([ACR_WRITE, ACR_READ]) + } catch (error) { + console.error('Error authorizing ACR permissions:', error) + } + } + + initializeAcr() + const userAction = {} + dispatch(getScripts({ action: userAction })) + dispatch(getAgama()) + dispatch(getAcrsConfig()) + }, [authorize, dispatch]) + + const authScripts = useMemo(() => { + const filteredScripts = (scripts || []) + .filter((item) => item?.scriptType === 'person_authentication' && item?.enabled) + .map((item) => ({ key: item.name, value: item.name })) + const agamaFlows = buildAgamaFlowsArray(agamaList) + const dropdownOptions = buildDropdownOptions(filteredScripts, agamaFlows) + + return dropdownOptions + }, [scripts, agamaList]) + + const toggle = () => { + setModal(!modal) + } + + const putHandler = (putData) => { + setPut(putData) + } + + const handleSubmit = (e) => { + e.preventDefault() + setModal(true) + } + + const handleSaveClick = () => { + setModal(true) + } + + const submitForm = (userMessage) => { + toggle() + + if (put?.value) { + const opts = {} + opts['authenticationMethod'] = { defaultAcr: put.value } + + buildPayload(userAction, userMessage, opts) + dispatch(editAcrs({ data: opts, action: userAction })) + } + } + + return ( + +
+ +
+ + + + {hasCedarPermission(ACR_WRITE) && ( + + )} +
+ +
+ ) +} + +export default DefaultAcr diff --git a/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js b/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js new file mode 100644 index 0000000000..05760024a1 --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js @@ -0,0 +1,27 @@ +import { SIMPLE_PASSWORD_AUTH } from 'Plugins/auth-server/common/Constants' + +export const buildAgamaFlowsArray = (agamaList) => { + const agamaFlows = [] + if (Array.isArray(agamaList)) { + agamaList.forEach((flow) => { + const configs = flow?.details?.projectMetadata?.configs + const noDirectLaunch = flow?.details?.projectMetadata?.noDirectLaunch || [] + + if (configs) { + Object.keys(configs).forEach((key) => { + if (!noDirectLaunch.includes(key)) { + const qualifiedName = `agama_${key}` + agamaFlows.push(qualifiedName) + } + }) + } + }) + } + return agamaFlows +} + +export const buildDropdownOptions = (filteredScripts, agamaFlows) => { + const scriptNames = filteredScripts.map((s) => s.key) + + return [...scriptNames, SIMPLE_PASSWORD_AUTH, ...agamaFlows].sort() +} diff --git a/admin-ui/plugins/auth-server/components/AuthN/index.js b/admin-ui/plugins/auth-server/components/AuthN/index.js index 7ad864712c..1b328271bd 100644 --- a/admin-ui/plugins/auth-server/components/AuthN/index.js +++ b/admin-ui/plugins/auth-server/components/AuthN/index.js @@ -7,11 +7,13 @@ import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle' import AgamaListPage from '../Agama/AgamaListPage' import AliasesListPage from '../Agama/AgamaAliasListPage' +import DefaultAcr from './DefaultAcr' function AuthNPage() { const { t } = useTranslation() const tabNames = [ + { name: 'default acr', path: '' }, { name: t('menus.builtIn'), path: '', @@ -29,6 +31,8 @@ function AuthNPage() { const tabToShow = (tabName) => { switch (tabName) { + case 'default acr': + return case t('menus.builtIn'): return case t('menus.acrs'): diff --git a/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js b/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js index 4c1e23899b..54dbc7809a 100644 --- a/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js +++ b/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js @@ -16,6 +16,7 @@ function DefaultAcrInput({ handler, options, path, + showSaveButtons = true, }) { const { t } = useTranslation() const theme = useContext(ThemeContext) @@ -33,6 +34,15 @@ function DefaultAcrInput({ const onValueChanged = (data) => { setShow(true) setData(data) + + if (!showSaveButtons && data) { + const put = {} + put[PATH] = path + put[VALUE] = isArray ? (Array.isArray(data) ? data : [data]) : data + put['op'] = 'replace' + handler(put) + setShow(false) + } } const onAccept = () => { const put = {} @@ -76,7 +86,9 @@ function DefaultAcrInput({ > {options.map((item, key) => ( - + ))} @@ -84,7 +96,7 @@ function DefaultAcrInput({ - {show && ( + {show && showSaveButtons && ( <>