Skip to content

feat(admin-ui): implement UMA option in Scopes form #351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 10, 2022
6 changes: 5 additions & 1 deletion admin-ui/app/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@
"saml1_uri": "Saml1 URI",
"saml2_uri": "Saml2 URI",
"scope_type": "Scope type",
"umaAuthorizationPolicies": "Authorization Policies",
"umaResourcesScript": "Associated Clients",
"iconUrl": "Icon URL",
"scopes:": "Scopes",
"scripts": "Scripts",
"script_type": "Script Type",
Expand Down Expand Up @@ -405,7 +408,8 @@
"sql_passwordEncryptionMethod": "Add password encryption method.",
"sql_serverTimezone": "Enter server timezone.",
"activate_sql_configuration": "Activate SQL configuration.",
"script_path": "Enter script file path"
"script_path": "Enter script file path",
"iconUrl": "Icon URL"
},
"titles": {
"acrs": "ACRs",
Expand Down
2 changes: 2 additions & 0 deletions admin-ui/app/routes/Apps/Gluu/GluuTypeAheadForDn.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function GluuTypeAheadForDn({
required,
doc_category,
doc_entry,
disabled = false,
allowNew = false,
lsize = 4,
rsize = 8,
Expand All @@ -48,6 +49,7 @@ function GluuTypeAheadForDn({
),
)
}}
disabled={disabled}
id={name}
data-testid={name}
name={name}
Expand Down
183 changes: 143 additions & 40 deletions admin-ui/plugins/auth-server/components/Scopes/ScopeForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,67 @@ import GluuTooltip from 'Routes/Apps/Gluu/GluuTooltip'
import { SCOPE } from 'Utils/ApiResources'
import { useTranslation } from 'react-i18next'
import { ThemeContext } from 'Context/theme/themeContext'
import {
LIMIT,
PATTERN,
} from 'Plugins/auth-server/common/Constants'
import { LIMIT, PATTERN } from 'Plugins/auth-server/common/Constants'
import { getUMAResources } from '../../redux/actions/ScopeActions'

function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
function ScopeForm({ scope, scripts, attributes, handleSubmit }) {
const { t } = useTranslation()
let dynamicScopeScripts = []
let umaResourcesScript = []
let umaAuthorizationPolicies = []

const theme = useContext(ThemeContext)
const selectedTheme = theme.state.theme
const history = useHistory()
const spontaneousClientScopes = scope.attributes.spontaneousClientScopes || []
const dispatch = useDispatch()
const client = useSelector((state) => state.oidcReducer.items)
const dispatch = useDispatch()
const client = useSelector((state) => state.oidcReducer.items)
const umaResources = useSelector((state) => state.scopeReducer.umaResources)
// const scripts = useSelector((state) => state.customScriptReducer.items)
let claims = []
scripts = scripts || []
attributes = attributes || []
dynamicScopeScripts = scripts
.filter((item) => item.scriptType == 'DYNAMIC_SCOPE')
.filter((item) => item.enabled)
.map((item) => ({ dn: item.dn, name: item.name }))

umaAuthorizationPolicies = scripts
.filter((item) => item.scriptType == 'UMA_RPT_POLICY')
.filter((item) => item.enabled)
.map((item) => ({ dn: item.dn, name: item.name }))

umaResourcesScript = umaResources.map((item) => ({
dn: item.dn,
name: item.id,
}))

useEffect(() => {
dispatch(getUMAResources({ pattern: 'scope' }))
}, [])

claims = attributes.map((item) => ({ dn: item.dn, name: item.displayName }))

const [init, setInit] = useState(false)
const [modal, setModal] = useState(false)
const [showClaimsPanel, handleClaimsPanel] = useState(scope.scopeType === 'openid')
const [showDynamicPanel, handleDynamicPanel] = useState(scope.scopeType === 'dynamic')
const [showSpontaneousPanel, handleShowSpontaneousPanel] = useState(scope.scopeType === 'spontaneous')
const [showClaimsPanel, handleClaimsPanel] = useState(
scope.scopeType === 'openid',
)
const [showDynamicPanel, handleDynamicPanel] = useState(
scope.scopeType === 'dynamic',
)
const [showSpontaneousPanel, handleShowSpontaneousPanel] = useState(
scope.scopeType === 'spontaneous',
)
const [showUmaPanel, handleShowUmaPanel] = useState(scope.scopeType === 'UMA')

useEffect(() => {
if (showSpontaneousPanel) {
dispatch(searchClients({ "action_data": makeOptions(1, scope.attributes.spontaneousClientId) }))
dispatch(
searchClients({
action_data: makeOptions(1, scope.attributes.spontaneousClientId),
}),
)
}
}, [showClaimsPanel])

Expand All @@ -89,6 +118,11 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
} else {
handleShowSpontaneousPanel(false)
}
if (type && type === 'UMA') {
handleShowUmaPanel(true)
} else {
handleShowUmaPanel(false)
}
scope.dynamicScopeScripts = ''
scope.claims = ''
scope.attributes.spontaneousClientId = ''
Expand Down Expand Up @@ -143,9 +177,7 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
displayName: Yup.string()
.min(2, 'displayName 2 characters')
.required('Required!'),
id: Yup.string()
.min(2, 'id 2 characters')
.required('Required!'),
id: Yup.string().min(2, 'id 2 characters').required('Required!'),
})}
onSubmit={(values) => {
const result = Object.assign(scope, values)
Expand All @@ -162,19 +194,14 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
>
{(formik) => (
<Form onSubmit={formik.handleSubmit}>

<GluuTooltip doc_category={SCOPE} doc_entry="id">
<FormGroup row>
<GluuLabel label="fields.id" size={4} required />
<Col sm={8}>
<Input
placeholder={t('placeholders.id')}
id="id"
valid={
!formik.errors.id &&
!formik.touched.id &&
init
}
valid={!formik.errors.id && !formik.touched.id && init}
name="id"
defaultValue={scope.id}
onKeyUp={activate}
Expand Down Expand Up @@ -252,8 +279,8 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
/>
</div>
)}
{showSpontaneousPanel ?
(<GluuTooltip doc_category={SCOPE} doc_entry="scopeType">
{showSpontaneousPanel ? (
<GluuTooltip doc_category={SCOPE} doc_entry="scopeType">
<FormGroup row>
<GluuLabel label="fields.scope_type" size={4} />
<Col sm={8}>
Expand All @@ -262,8 +289,9 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
</Badge>
</Col>
</FormGroup>
</GluuTooltip>) :
(<GluuTooltip doc_category={SCOPE} doc_entry="scopeType">
</GluuTooltip>
) : (
<GluuTooltip doc_category={SCOPE} doc_entry="scopeType">
<FormGroup row>
<GluuLabel label="fields.scope_type" size={4} />
<Col sm={8}>
Expand All @@ -282,14 +310,16 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
<option value="oauth">OAuth</option>
<option value="openid">OpenID</option>
<option value="dynamic">Dynamic</option>
<option value="UMA">UMA</option>
</CustomInput>
</InputGroup>
</Col>
<ErrorMessage name="scopeType">
{(msg) => <div style={{ color: 'red' }}>{msg}</div>}
</ErrorMessage>
</FormGroup>
</GluuTooltip>)}
</GluuTooltip>
)}
{showDynamicPanel && (
<GluuTypeAheadForDn
name="dynamicScopeScripts"
Expand Down Expand Up @@ -321,6 +351,63 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
</Accordion.Body>
</Accordion>
)}
{showUmaPanel && (
<>
<FormGroup row>
<GluuLabel label="fields.iconUrl" size={4} />
<Col sm={8}>
<Input
placeholder={t('placeholders.iconUrl')}
id="iconUrl"
name="iconUrl"
defaultValue={scope.iconUrl}
onChange={formik.handleChange}
disabled={scope.inum ? true : false}
/>
</Col>
</FormGroup>
<Accordion className="mb-2 b-primary" initialOpen>
<Accordion.Header className="text-primary">
{t('fields.umaAuthorizationPolicies').toUpperCase()}
</Accordion.Header>
<Accordion.Body>
<FormGroup row> </FormGroup>
<GluuTypeAheadForDn
name="umaAuthorizationPolicies"
label="fields.umaAuthorizationPolicies"
formik={formik}
value={getMapping(
scope.umaAuthorizationPolicies,
umaAuthorizationPolicies,
)}
disabled={scope.inum ? true : false}
options={umaAuthorizationPolicies}
doc_category={SCOPE}
/>
</Accordion.Body>
</Accordion>
<Accordion className="mb-2 b-primary" initialOpen>
<Accordion.Header className="text-primary">
{t('fields.umaResourcesScript').toUpperCase()}
</Accordion.Header>
<Accordion.Body>
<FormGroup row> </FormGroup>
<GluuTypeAheadForDn
name="umaResourcesScript"
label="fields.umaResourcesScript"
formik={formik}
value={getMapping(
scope.umaResourcesScript,
umaResourcesScript,
)}
disabled={scope.inum ? true : false}
options={umaResourcesScript}
doc_category={SCOPE}
/>
</Accordion.Body>
</Accordion>
</>
)}
{showSpontaneousPanel && (
<Accordion className="mb-2 b-primary" initialOpen>
<Accordion.Header className="text-primary">
Expand All @@ -333,14 +420,23 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
doc_entry="spontaneousClientId"
>
<FormGroup row>
<GluuLabel label="fields.spontaneous_client_id" size={4} />
<GluuLabel
label="fields.spontaneous_client_id"
size={4}
/>
<Col sm={8}>
<div>
{scope.attributes.spontaneousClientId}
<IconButton onClick={() => goToClientViewPage(scope.attributes.spontaneousClientId)}>
<IconButton
onClick={() =>
goToClientViewPage(
scope.attributes.spontaneousClientId,
)
}
>
<Visibility />
</IconButton>
</div>
</div>
</Col>
</FormGroup>
</GluuTooltip>
Expand All @@ -350,24 +446,31 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
doc_entry="spontaneousClientScopes"
>
<FormGroup row>
<GluuLabel label="fields.spontaneous_client_scopes" size={4} />
<GluuLabel
label="fields.spontaneous_client_scopes"
size={4}
/>
<Col sm={8}>
{scope?.attributes?.spontaneousClientScopes?.map((item, key) => (
<div style={{ maxWidth: 120, overflow: 'auto' }}>
<Badge key={key} color={`primary-${selectedTheme}`}>
{item}
</Badge>
</div>
))}
{scope?.attributes?.spontaneousClientScopes?.map(
(item, key) => (
<div style={{ maxWidth: 120, overflow: 'auto' }}>
<Badge
key={key}
color={`primary-${selectedTheme}`}
>
{item}
</Badge>
</div>
),
)}
</Col>
</FormGroup>
</GluuTooltip>
</Accordion.Body>
</Accordion>
)}
<FormGroup row></FormGroup>
{!showSpontaneousPanel &&
(<GluuCommitFooter saveHandler={toggle} />)}
{!showSpontaneousPanel && <GluuCommitFooter saveHandler={toggle} />}
<GluuCommitDialog
handler={toggle}
modal={modal}
Expand All @@ -377,8 +480,8 @@ function ScopeForm({ scope, scripts, attributes, handleSubmit}) {
</Form>
)}
</Formik>
</Container >
</Container>
)
}

export default ScopeForm
export default ScopeForm
2 changes: 2 additions & 0 deletions admin-ui/plugins/auth-server/plugin-metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import jsonSaga from './redux/sagas/JsonConfigSaga'
import jwksSaga from './redux/sagas/JwksSaga'
import acrSaga from './redux/sagas/AcrsSaga'
import loggingSaga from './redux/sagas/LoggingSaga'
import umaResourceSaga from './redux/sagas/UMAResourcesSaga'

import {
ACR_READ,
Expand Down Expand Up @@ -143,6 +144,7 @@ const pluginMetadata = {
jwksSaga(),
acrSaga(),
loggingSaga(),
umaResourceSaga(),
],
}

Expand Down
10 changes: 10 additions & 0 deletions admin-ui/plugins/auth-server/redux/actions/ScopeActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
GET_SCOPE_BY_PATTERN,
GET_SCOPE_BY_PATTERN_RESPONSE,
SEARCH_SCOPES,
GET_UMA_RESOURCES,
GET_UMA_RESOURCES_RESPONSE,
} from './types'

export const getScopes = (action) => ({
Expand Down Expand Up @@ -84,3 +86,11 @@ export const setCurrentItem = (item) => ({
type: SET_ITEM,
payload: { item },
})
export const getUMAResources = (item) => ({
type: GET_UMA_RESOURCES,
payload: { item },
})
export const getUMAResourcesResponse = (data) => ({
type: GET_UMA_RESOURCES_RESPONSE,
payload: { data },
})
2 changes: 2 additions & 0 deletions admin-ui/plugins/auth-server/redux/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const RESET = 'RESET'
export const SET_ITEM = 'SET_ITEM'
export const USERINFO_REQUEST = 'USERINFO_REQUEST'
export const USERINFO_RESPONSE = 'USERINFO_RESPONSE'
export const GET_UMA_RESOURCES = 'GET_UMA_RESOURCES'
export const GET_UMA_RESOURCES_RESPONSE = 'GET_UMA_RESOURCES_RESPONSE'

// scopes
export const GET_SCOPES = 'GET_SCOPES'
Expand Down
1 change: 1 addition & 0 deletions admin-ui/plugins/auth-server/redux/api/ScopeApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default class ScopeApi {
}

getAllScopes = (options) => {
options['withAssociatedClients'] = true
return new Promise((resolve, reject) => {
this.api.getOauthScopes(options, (error, data) => {
this.handleResponse(error, reject, resolve, data)
Expand Down
Loading