From 93d32e176bd0886e0c873279c03e10c38668e09f Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 21 Oct 2022 10:06:28 -0700 Subject: [PATCH 01/93] Initial commit --- ui/public/assets/data/registrations.json | 18 ++++ ui/src/app/App.js | 8 +- ui/src/app/dashboard/view/Dashboard.js | 16 +++- .../dashboard/view/DynamicRegistrationsTab.js | 43 +++++++++ .../DynamicRegistration.js | 38 ++++++++ .../component/DynamicRegistrationList.js | 5 + .../hoc/DynamicRegistrationContext.js | 91 +++++++++++++++++++ 7 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 ui/public/assets/data/registrations.json create mode 100644 ui/src/app/dashboard/view/DynamicRegistrationsTab.js create mode 100644 ui/src/app/dynamic-registration/DynamicRegistration.js create mode 100644 ui/src/app/dynamic-registration/component/DynamicRegistrationList.js create mode 100644 ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js diff --git a/ui/public/assets/data/registrations.json b/ui/public/assets/data/registrations.json new file mode 100644 index 000000000..c3c60440c --- /dev/null +++ b/ui/public/assets/data/registrations.json @@ -0,0 +1,18 @@ +[ + { + "name": "Foobar", + "redirect_uris": [], + "response_types": [], + "grant_types": "", + "application_type": "", + "contacts": "", + "subject_type": "", + "jwks": "", + "jwks_uri": "", + "token_endpoint_auth_method": "", + "logo_uri": "", + "policy_uri": "", + "tos_uri": "", + "scope": "" + } +] diff --git a/ui/src/app/App.js b/ui/src/app/App.js index ca70ee51a..0f6057141 100644 --- a/ui/src/app/App.js +++ b/ui/src/app/App.js @@ -35,7 +35,8 @@ import { Groups } from './admin/Groups'; import { BASE_PATH } from './App.constant'; import { ProtectRoute } from './core/components/ProtectRoute'; import { IdpConfiguration } from './admin/IdpConfiguration'; - +import { DynamicRegistration } from './dynamic-registration/DynamicRegistration'; +import { DynamicRegistrationsApi } from './dynamic-registration/hoc/DynamicRegistrationContext'; function App() { @@ -83,6 +84,11 @@ function App() { + + + + + } /> diff --git a/ui/src/app/dashboard/view/Dashboard.js b/ui/src/app/dashboard/view/Dashboard.js index 7644b6def..4db3f8327 100644 --- a/ui/src/app/dashboard/view/Dashboard.js +++ b/ui/src/app/dashboard/view/Dashboard.js @@ -15,6 +15,8 @@ import { useCurrentUserLoading, useIsAdmin } from '../../core/user/UserContext'; import useFetch from 'use-http'; import API_BASE_PATH from '../../App.constant'; import { useNonAdminSources } from '../../metadata/hooks/api'; +import { DynamicRegistrationsApi } from '../../dynamic-registration/hoc/DynamicRegistrationContext'; +import { DynamicRegistrationsTab } from './DynamicRegistrationsTab'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSpinner } from '@fortawesome/free-solid-svg-icons'; import Badge from 'react-bootstrap/Badge'; @@ -76,12 +78,19 @@ export function Dashboard () { {isAdmin && - <> Metadata Providers + } + + + Dynamic Registration + + + {isAdmin && + <> Admin @@ -102,6 +111,11 @@ export function Dashboard () { + + + + + } /> diff --git a/ui/src/app/dashboard/view/DynamicRegistrationsTab.js b/ui/src/app/dashboard/view/DynamicRegistrationsTab.js new file mode 100644 index 000000000..97b88e3be --- /dev/null +++ b/ui/src/app/dashboard/view/DynamicRegistrationsTab.js @@ -0,0 +1,43 @@ +import React from 'react'; +// import { useDynamicRegistrationDispatcher } from '../../dynamic-registration/hoc/DynamicRegistrationContext'; +import Translate from '../../i18n/components/translate'; +import { Ordered } from '../component/Ordered'; +import { Search } from '../component/Search'; + +import {DynamicRegistrationList} from '../../dynamic-registration/component/DynamicRegistrationList'; + +const searchProps = ['name']; + +export function DynamicRegistrationsTab () { + + // const dispatcher = useDynamicRegistrationDispatcher(); + + /*eslint-disable react-hooks/exhaustive-deps*/ + // React.useEffect(() => { loadRegistrations() }, []); + const registrations = []; + + return ( +
+
+ <> +
+ + Dynamic Registrations + +
+
+ + {(ordered, first, last, onOrderUp, onOrderDown) => + + {(searched) => + + } + + } + +
+ +
+
+ ) +} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/DynamicRegistration.js b/ui/src/app/dynamic-registration/DynamicRegistration.js new file mode 100644 index 000000000..95d753d99 --- /dev/null +++ b/ui/src/app/dynamic-registration/DynamicRegistration.js @@ -0,0 +1,38 @@ +import React from 'react'; +import { useDynamicRegistrationDispatcher } from './hoc/DynamicRegistrationContext'; +import Translate from '../i18n/components/translate'; +import { Search } from '../dashboard/component/Search'; + +import {DynamicRegistrationList} from './component/DynamicRegistrationList'; + +const searchProps = ['name']; + +export function DynamicRegistration () { + + // const dispatcher = useDynamicRegistrationDispatcher(); + + /*eslint-disable react-hooks/exhaustive-deps*/ + // React.useEffect(() => { loadRegistrations() }, []); + const registrations = []; + + return ( +
+
+ <> +
+ + Dynamic Registrations + +
+
+ + {(searched) => + + } + +
+ +
+
+ ) +} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js b/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js new file mode 100644 index 000000000..f06d7f240 --- /dev/null +++ b/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js @@ -0,0 +1,5 @@ +import React from 'react'; + +export function DynamicRegistrationList ({entities}) { + return <>
{JSON.stringify(entities, null, 4)}
+} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js b/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js new file mode 100644 index 000000000..ff19ae8ef --- /dev/null +++ b/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js @@ -0,0 +1,91 @@ +import React from 'react'; + + +const initialState = { + registrations: [], + selected: null, +}; + +const DynamicRegistrationContext = React.createContext(); + +const { Provider, Consumer } = DynamicRegistrationContext; + +export const DynamicRegistrationActions = { + LOAD_REGISTRATIONS: 'load dynamic registrations (list GET)', + SELECT_REGISTRATION: 'load dynamic registration (single GET)', + CREATE_REGISTRATION: 'create dynamic registration (POST)', + UPDATE_REGISTRATION: 'update dynamic registration (PUT)', + DELETE_REGISTRATION: 'delete dynamic registration (DELETE)' +}; + +export const loadRegistrations = (payload) => { + return { + type: DynamicRegistrationActions.LOAD_REGISTRATIONS, + payload + } +} + +export const selectRegistration = (payload) => { + return { + type: DynamicRegistrationActions.SELECT_REGISTRATION, + payload + } +} + +export const createRegistration = (payload) => { + return { + type: DynamicRegistrationActions.CREATE_REGISTRATION, + payload + } +} + +export const updateRegistration = (payload) => { + return { + type: DynamicRegistrationActions.UPDATE_REGISTRATION, + payload + } +} + +export const deleteRegistration = (payload) => { + return { + type: DynamicRegistrationActions.DELETE_REGISTRATION, + payload + } +} + +function reducer(state, action) { + switch (action.type) { + default: + return state; + } +} + +/*eslint-disable react-hooks/exhaustive-deps*/ +function DynamicRegistrationsApi({ children, initial = {} }) { + + const [contextValue, setContextValue] = React.useState({...initialState}); + + return ( + + {children} + + ); +} + + +function useDynamicRegistrationContext () { + return React.useContext(DynamicRegistrationContext); +} + +function useDynamicRegistrationDispatcher () { + const { dispatch } = useDynamicRegistrationContext(); + return dispatch; +} + +export { + DynamicRegistrationsApi, + useDynamicRegistrationContext, + useDynamicRegistrationDispatcher, + Provider as MetadataFormProvider, + Consumer as MetadataFormConsumer +}; \ No newline at end of file From 5eacee31c451bfcad493094361b0abea851dff78 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 21 Oct 2022 14:49:11 -0700 Subject: [PATCH 02/93] Initial implementation --- ui/public/assets/data/registration.json | 20 +++ ui/public/assets/data/registrations.json | 1 + .../schema/dynamic-registration/oidc.json | 13 ++ ui/src/app/App.js | 4 +- ui/src/app/core/components/Header.js | 4 + ui/src/app/dashboard/view/Dashboard.js | 4 +- .../dashboard/view/DynamicRegistrationsTab.js | 7 +- .../DynamicRegistration.js | 49 +++---- ui/src/app/dynamic-registration/api.js | 26 ++++ .../component/DynamicRegistrationForm.js | 58 ++++++++ .../component/DynamicRegistrationList.js | 33 ++++- .../hoc/DynamicRegistrationContext.js | 107 +++++++++++++- .../view/DynamicRegistrationCreate.js | 82 +++++++++++ .../view/DynamicRegistrationDetail.js | 138 ++++++++++++++++++ .../view/DynamicRegistrationEdit.js | 89 +++++++++++ .../app/metadata/component/MetadataSection.js | 3 - 16 files changed, 595 insertions(+), 43 deletions(-) create mode 100644 ui/public/assets/data/registration.json create mode 100644 ui/public/assets/schema/dynamic-registration/oidc.json create mode 100644 ui/src/app/dynamic-registration/api.js create mode 100644 ui/src/app/dynamic-registration/component/DynamicRegistrationForm.js create mode 100644 ui/src/app/dynamic-registration/view/DynamicRegistrationCreate.js create mode 100644 ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js create mode 100644 ui/src/app/dynamic-registration/view/DynamicRegistrationEdit.js diff --git a/ui/public/assets/data/registration.json b/ui/public/assets/data/registration.json new file mode 100644 index 000000000..e7434acd6 --- /dev/null +++ b/ui/public/assets/data/registration.json @@ -0,0 +1,20 @@ +{ + "resourceId": "foobar", + "name": "Foobar", + "redirect_uris": [], + "response_types": [], + "grant_types": "", + "application_type": "", + "contacts": "", + "subject_type": "", + "jwks": "", + "jwks_uri": "", + "token_endpoint_auth_method": "", + "logo_uri": "", + "policy_uri": "", + "tos_uri": "", + "scope": "", + "enabled": true, + "modifiedDate": "2022-10-21T11:57:24.391649", + "createdData": "2022-10-21T11:57:24.391649" +} diff --git a/ui/public/assets/data/registrations.json b/ui/public/assets/data/registrations.json index c3c60440c..90dd2b1af 100644 --- a/ui/public/assets/data/registrations.json +++ b/ui/public/assets/data/registrations.json @@ -1,5 +1,6 @@ [ { + "resourceId": "foobar", "name": "Foobar", "redirect_uris": [], "response_types": [], diff --git a/ui/public/assets/schema/dynamic-registration/oidc.json b/ui/public/assets/schema/dynamic-registration/oidc.json new file mode 100644 index 000000000..c746c5d29 --- /dev/null +++ b/ui/public/assets/schema/dynamic-registration/oidc.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "required": ["name"], + "properties": { + "name": { + "title": "label.dynamic-registration-name", + "description": "tooltip.dynamic-registration-name", + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } +} diff --git a/ui/src/app/App.js b/ui/src/app/App.js index 0f6057141..dfaf9bb2c 100644 --- a/ui/src/app/App.js +++ b/ui/src/app/App.js @@ -85,9 +85,7 @@ function App() { - - - + } /> diff --git a/ui/src/app/core/components/Header.js b/ui/src/app/core/components/Header.js index 114b73a8c..8c4398f56 100644 --- a/ui/src/app/core/components/Header.js +++ b/ui/src/app/core/components/Header.js @@ -63,6 +63,10 @@ export function Header () { } + + + + {isAdmin && diff --git a/ui/src/app/dashboard/view/Dashboard.js b/ui/src/app/dashboard/view/Dashboard.js index 4db3f8327..1ea72de09 100644 --- a/ui/src/app/dashboard/view/Dashboard.js +++ b/ui/src/app/dashboard/view/Dashboard.js @@ -85,7 +85,7 @@ export function Dashboard () { } - + Dynamic Registration @@ -111,7 +111,7 @@ export function Dashboard () { - + diff --git a/ui/src/app/dashboard/view/DynamicRegistrationsTab.js b/ui/src/app/dashboard/view/DynamicRegistrationsTab.js index 97b88e3be..5cfae3e25 100644 --- a/ui/src/app/dashboard/view/DynamicRegistrationsTab.js +++ b/ui/src/app/dashboard/view/DynamicRegistrationsTab.js @@ -5,16 +5,17 @@ import { Ordered } from '../component/Ordered'; import { Search } from '../component/Search'; import {DynamicRegistrationList} from '../../dynamic-registration/component/DynamicRegistrationList'; +import { useDynamicRegistrationCollection, useDynamicRegistrationApi } from '../../dynamic-registration/hoc/DynamicRegistrationContext'; const searchProps = ['name']; export function DynamicRegistrationsTab () { - // const dispatcher = useDynamicRegistrationDispatcher(); + const registrations = useDynamicRegistrationCollection(); + const { load } = useDynamicRegistrationApi(); /*eslint-disable react-hooks/exhaustive-deps*/ - // React.useEffect(() => { loadRegistrations() }, []); - const registrations = []; + React.useEffect(() => { load() }, []); return (
diff --git a/ui/src/app/dynamic-registration/DynamicRegistration.js b/ui/src/app/dynamic-registration/DynamicRegistration.js index 95d753d99..db3fab4b4 100644 --- a/ui/src/app/dynamic-registration/DynamicRegistration.js +++ b/ui/src/app/dynamic-registration/DynamicRegistration.js @@ -1,38 +1,31 @@ import React from 'react'; -import { useDynamicRegistrationDispatcher } from './hoc/DynamicRegistrationContext'; -import Translate from '../i18n/components/translate'; -import { Search } from '../dashboard/component/Search'; +import { Switch, Route, useRouteMatch } from 'react-router-dom'; -import {DynamicRegistrationList} from './component/DynamicRegistrationList'; +import { DynamicRegistrationDetail } from './view/DynamicRegistrationDetail'; -const searchProps = ['name']; +import { DynamicRegistrationsApi } from './hoc/DynamicRegistrationContext'; +import { DynamicRegistrationEdit } from './view/DynamicRegistrationEdit'; +import { DynamicRegistrationCreate } from './view/DynamicRegistrationCreate'; export function DynamicRegistration () { - // const dispatcher = useDynamicRegistrationDispatcher(); - - /*eslint-disable react-hooks/exhaustive-deps*/ - // React.useEffect(() => { loadRegistrations() }, []); - const registrations = []; + const { path } = useRouteMatch(); return ( -
-
- <> -
- - Dynamic Registrations - -
-
- - {(searched) => - - } - -
- -
-
+
+ + + + + } /> + + + } /> + + + } /> + + +
) } \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/api.js b/ui/src/app/dynamic-registration/api.js new file mode 100644 index 000000000..0d557f4f0 --- /dev/null +++ b/ui/src/app/dynamic-registration/api.js @@ -0,0 +1,26 @@ +import useFetch from 'use-http'; + +import {API_BASE_PATH, BASE_PATH} from '../App.constant'; + +export function useDynamicRegistration(id, opts = {}, onMount) { + // + return useFetch(`${BASE_PATH}/assets/data/registration.json`, opts, onMount); +} + +export function useDynamicRegistrations(opts = {}, onMount) { + // + return useFetch(`${BASE_PATH}/assets/data/registrations.json`, opts, onMount); +} + +export function useDynamicRegistrationJsonSchema(opts = {}) { + return useFetch(`${BASE_PATH}/assets/schema/dynamic-registration/oidc.json`, opts, []); +} + +export function useDynamicRegistrationUiSchema() { + return {}; +} +export function useDynamicRegistrationValidator() { + return (formData, errors) => { + return errors; + } +} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/component/DynamicRegistrationForm.js b/ui/src/app/dynamic-registration/component/DynamicRegistrationForm.js new file mode 100644 index 000000000..1590d23be --- /dev/null +++ b/ui/src/app/dynamic-registration/component/DynamicRegistrationForm.js @@ -0,0 +1,58 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import Form from '../../form/Form'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSpinner, faSave } from '@fortawesome/free-solid-svg-icons'; +import Translate from '../../i18n/components/translate'; + +import { FormContext, setFormDataAction, setFormErrorAction } from '../../form/FormManager'; +import { useDynamicRegistrationUiSchema, useDynamicRegistrationValidator } from '../api'; + +export function DynamicRegistrationForm ({registration = {}, errors = [], loading = false, schema, onSave, onCancel}) { + + const { dispatch } = React.useContext(FormContext); + const onChange = ({formData, errors}) => { + dispatch(setFormDataAction(formData)); + dispatch(setFormErrorAction(errors)); + }; + + const uiSchema = useDynamicRegistrationUiSchema(); + const validator = useDynamicRegistrationValidator(); + + return (<> +
+
+ + + + +
+
+
+
+
onChange(form)} + validate={validator} + schema={schema} + uiSchema={uiSchema} + liveValidate={true}> + <> +
+
+
+
+ ) +} +/**/ \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js b/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js index f06d7f240..a70c7e3f9 100644 --- a/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js +++ b/ui/src/app/dynamic-registration/component/DynamicRegistrationList.js @@ -1,5 +1,34 @@ import React from 'react'; +import { Link } from 'react-router-dom'; +import Translate from '../../i18n/components/translate'; +import { Scroller } from '../../dashboard/component/Scroller'; -export function DynamicRegistrationList ({entities}) { - return <>
{JSON.stringify(entities, null, 4)}
+export function DynamicRegistrationList ({entities, children}) { + return ( + + + {(limited) => +
+ + + + + + + + {limited.map((reg, idx) => + + + + )} + +
Title
+ {reg.name} +
+
+ } +
+ {children} +
+ ); } \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js b/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js index ff19ae8ef..f922f2247 100644 --- a/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js +++ b/ui/src/app/dynamic-registration/hoc/DynamicRegistrationContext.js @@ -1,5 +1,6 @@ import React from 'react'; +import {useDynamicRegistrations, useDynamicRegistration} from '../api'; const initialState = { registrations: [], @@ -55,6 +56,16 @@ export const deleteRegistration = (payload) => { function reducer(state, action) { switch (action.type) { + case DynamicRegistrationActions.LOAD_REGISTRATIONS: + return { + ...state, + registrations: action.payload + }; + case DynamicRegistrationActions.SELECT_REGISTRATION: + return { + ...state, + selected: action.payload + }; default: return state; } @@ -62,12 +73,74 @@ function reducer(state, action) { /*eslint-disable react-hooks/exhaustive-deps*/ function DynamicRegistrationsApi({ children, initial = {} }) { + const [state, dispatch] = React.useReducer(reducer, initialState); + const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]); + + const loader = useDynamicRegistrations({ + cachePolicy: 'no-cache' + }); + + const selector = useDynamicRegistration({ + cachePolicy: 'no-cache' + }); + + async function load() { + const s = await loader.get(); + if (loader.response.ok) { + dispatch(loadRegistrations(s)); + } + } + + async function select(id) { + const s = await selector.get(); + if (selector.response.ok) { + dispatch(selectRegistration(s)); + } + } + + async function update(id) { + /*const s = await selector.update(); + if (selector.response.ok) { + dispatch(selectRegistration(s)); + }*/ + return Promise.resolve(id); + } - const [contextValue, setContextValue] = React.useState({...initialState}); + async function enable(id) { + /*const s = await selector.update(); + if (selector.response.ok) { + dispatch(selectRegistration(s)); + }*/ + return Promise.resolve(id); + } + + async function create(body) { + /*const s = await selector.update(); + if (selector.response.ok) { + dispatch(selectRegistration(s)); + }*/ + return Promise.resolve(body); + } + + async function remove(id) { + /*const s = await selector.update(); + if (selector.response.ok) { + dispatch(selectRegistration(s)); + }*/ + return Promise.resolve(id); + } return ( - {children} + {children} ); } @@ -82,10 +155,40 @@ function useDynamicRegistrationDispatcher () { return dispatch; } +function useDynamicRegistrationState () { + const { state } = useDynamicRegistrationContext(); + return state; +} + +function useDynamicRegistrationCollection () { + const state = useDynamicRegistrationState(); + return state.registrations; +} + +function useSelectedDynamicRegistration () { + const state = useDynamicRegistrationState(); + return state.selected; +} + +function useDynamicRegistrationApi () { + const {load, select, enable, create, update, remove} = useDynamicRegistrationContext(); + return { + load, + select, + enable, + create, + update, + remove + }; +} + export { DynamicRegistrationsApi, useDynamicRegistrationContext, useDynamicRegistrationDispatcher, + useDynamicRegistrationCollection, + useSelectedDynamicRegistration, + useDynamicRegistrationApi, Provider as MetadataFormProvider, Consumer as MetadataFormConsumer }; \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/view/DynamicRegistrationCreate.js b/ui/src/app/dynamic-registration/view/DynamicRegistrationCreate.js new file mode 100644 index 000000000..8b38b4ad3 --- /dev/null +++ b/ui/src/app/dynamic-registration/view/DynamicRegistrationCreate.js @@ -0,0 +1,82 @@ +import React from 'react'; +import { Prompt, useHistory, useParams } from 'react-router-dom'; + +import { useDynamicRegistrationApi } from '../hoc/DynamicRegistrationContext'; +import Translate from '../../i18n/components/translate'; +import { BASE_PATH } from '../../App.constant'; +import { Schema } from '../../form/Schema'; +import { FormManager } from '../../form/FormManager'; +import { DynamicRegistrationForm } from '../component/DynamicRegistrationForm'; +import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications'; +import { useTranslator } from '../../i18n/hooks'; + +export function DynamicRegistrationCreate () { + + const history = useHistory(); + const translator = useTranslator(); + const notifier = useNotificationDispatcher(); + const { create } = useDynamicRegistrationApi(); + + async function save(reg) { + let toast; + const resp = await create(``, reg); + if (resp.ok) { + gotoDetail({ refresh: true }); + toast = createNotificationAction(`Added group successfully.`, NotificationTypes.SUCCESS); + } else { + toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR); + } + if (toast) { + notifier(toast); + } + }; + + const cancel = () => { + gotoDetail(); + }; + + const gotoDetail = (state = null) => { + setBlocking(false); + history.push(`/dashboard/dynamic-registration`, state); + }; + + const [blocking, setBlocking] = React.useState(false); + const [loading, setLoading] = React.useState(false); + + return ( +
+ + `message.unsaved-editor` + } + /> +
+
+
+
+ New Dynamic Registration +
+
+
+
+ + {(schema) => + + {(data, errors) => + <> + save(data)} + onCancel={() => cancel()} /> + } + } + +
+
+
+ ) +} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js b/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js new file mode 100644 index 000000000..4a0d1d0ef --- /dev/null +++ b/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js @@ -0,0 +1,138 @@ +import React from 'react'; +import { Link, useHistory, useParams } from 'react-router-dom'; + +import { useDynamicRegistrationApi, useSelectedDynamicRegistration } from '../hoc/DynamicRegistrationContext'; +import Translate from '../../i18n/components/translate'; +import FormattedDate from '../../core/components/FormattedDate'; +import Button from 'react-bootstrap/esm/Button'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faEdit, faHistory, faToggleOff, faToggleOn, faTrash } from '@fortawesome/free-solid-svg-icons'; +import Badge from 'react-bootstrap/esm/Badge'; + +export function DynamicRegistrationDetail () { + + const { id } = useParams(); + const history = useHistory(); + + const { select, enable, remove } = useDynamicRegistrationApi(); + + const reselect = React.useCallback(() => select(id), [id, select]); + const detail = useSelectedDynamicRegistration(); + + const redirectOnDelete = () => history.push('/dashboard'); + + const edit = (section) => { + history.push(`/dynamic-registration/${id}/edit`); + } + + /*eslint-disable react-hooks/exhaustive-deps*/ + React.useEffect(() => { reselect() }, [id]); + + return ( +
+
+
+ {detail && + + + +
+ +
+
+
+
+

+ Saved:  + + + +

+

+ By:  + {detail.createdBy } +

+
+
+ + +
+
+ +

+ + Enabled + +

+ +
+
+ + + +
+
+
+

+ + + +

+
+ +
+
+
+
{JSON.stringify(detail, null, 4)}
+
+
+
+ +
+
+ } +
+
+
+ + ) +} \ No newline at end of file diff --git a/ui/src/app/dynamic-registration/view/DynamicRegistrationEdit.js b/ui/src/app/dynamic-registration/view/DynamicRegistrationEdit.js new file mode 100644 index 000000000..e6d33f66f --- /dev/null +++ b/ui/src/app/dynamic-registration/view/DynamicRegistrationEdit.js @@ -0,0 +1,89 @@ +import React from 'react'; +import { Prompt, useHistory, useParams } from 'react-router-dom'; + +import { useDynamicRegistrationApi, useSelectedDynamicRegistration } from '../hoc/DynamicRegistrationContext'; +import Translate from '../../i18n/components/translate'; +import { useDynamicRegistrationJsonSchema } from '../api'; +import Form from '../../form/Form'; +import { BASE_PATH } from '../../App.constant'; +import { Schema } from '../../form/Schema'; +import { FormManager } from '../../form/FormManager'; +import { DynamicRegistrationForm } from '../component/DynamicRegistrationForm'; +import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications'; +import { useTranslator } from '../../i18n/hooks'; + +export function DynamicRegistrationEdit () { + + const { id } = useParams(); + const history = useHistory(); + const translator = useTranslator(); + const notifier = useNotificationDispatcher(); + const { select, create } = useDynamicRegistrationApi(); + + React.useEffect(() => { select(id) }, [id]); + + const detail = useSelectedDynamicRegistration(); + + async function save(reg) { + let toast; + const resp = await create(``, reg); + if (resp.ok) { + gotoDetail({ refresh: true }); + toast = createNotificationAction(`Added group successfully.`, NotificationTypes.SUCCESS); + } else { + toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR); + } + if (toast) { + notifier(toast); + } + }; + + const cancel = () => { + gotoDetail(); + }; + + const gotoDetail = (state = null) => { + setBlocking(false); + history.push(`/dynamic-registration/${id}`, state); + }; + + const [blocking, setBlocking] = React.useState(false); + const [loading, setLoading] = React.useState(false); + + return ( +
+ + `message.unsaved-editor` + } + /> +
+
+
+
+ Edit Dynamic Registration +
+
+
+
+ + {(schema) => + + {(data, errors) => + <> + save(data)} + onCancel={() => cancel()} /> + } + } + +
+
+
+ ) +} \ No newline at end of file diff --git a/ui/src/app/metadata/component/MetadataSection.js b/ui/src/app/metadata/component/MetadataSection.js index f28cd723d..6b9ef1c31 100644 --- a/ui/src/app/metadata/component/MetadataSection.js +++ b/ui/src/app/metadata/component/MetadataSection.js @@ -5,9 +5,6 @@ import Button from 'react-bootstrap/Button'; import Translate from '../../i18n/components/translate'; export function MetadataSection ({ section, index = -1, onEdit, children }) { - - - return ( <>
From 04b0401124106c1b22bf872007a8125ae73e0b95 Mon Sep 17 00:00:00 2001 From: Sean Porth Date: Thu, 27 Oct 2022 16:39:21 -0400 Subject: [PATCH 03/93] installed and configured oidc plugins --- testbed/integration/shibboleth-idp/Dockerfile | 12 +- .../config/shib-idp/conf/credentials.xml | 71 +++++++++ .../config/shib-idp/conf/idp.properties | 2 +- .../config/shib-idp/conf/oidc.properties | 141 ++++++++++++++++++ .../config/shib-idp/conf/relying-party.xml | 6 + .../shibboleth-idp/config/tomcat/context.xml | 1 + .../config/tomcat/rewrite.config | 1 + .../shibboleth-idp/config/tomcat/server.xml | 1 + .../truststore.asc | 32 ++++ .../net.shibboleth.oidc.common/truststore.asc | 32 ++++ 10 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/credentials.xml create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties create mode 100644 testbed/integration/shibboleth-idp/config/tomcat/rewrite.config create mode 100644 testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.idp.plugin.oidc.op/truststore.asc create mode 100644 testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.oidc.common/truststore.asc diff --git a/testbed/integration/shibboleth-idp/Dockerfile b/testbed/integration/shibboleth-idp/Dockerfile index 1a4087074..6cfe13c7f 100644 --- a/testbed/integration/shibboleth-idp/Dockerfile +++ b/testbed/integration/shibboleth-idp/Dockerfile @@ -1,4 +1,4 @@ -FROM i2incommon/shib-idp:4.1.4_20210802 +FROM i2incommon/shib-idp:4.2.1_20220624 # The build args below can be used at build-time to tell the build process where to find your config files. This is for a completely burned-in config. ARG TOMCFG=config/tomcat @@ -11,15 +11,23 @@ ARG SHBEDWAPP=config/shib-idp/edit-webapp ARG SHBMSGS=config/shib-idp/messages ARG SHBMD=config/shib-idp/metadata +#enable OIDC plugins and generate needed keys +ADD ${SHBCREDS} /opt/shibboleth-idp/credentials +RUN /opt/shibboleth-idp/bin/plugin.sh -i https://shibboleth.net/downloads/identity-provider/plugins/oidc-common/2.1.0/oidc-common-dist-2.1.0.tar.gz --noPrompt +RUN /opt/shibboleth-idp/bin/plugin.sh -i https://shibboleth.net/downloads/identity-provider/plugins/oidc-op/3.2.1/idp-plugin-oidc-op-distribution-3.2.1.tar.gz --noPrompt +RUN /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u sig -i defaultRSASign | tail -n +2 > /opt/shibboleth-idp/credentials/idp-signing-rs.jwk +RUN /opt/shibboleth-idp/bin/jwtgen.sh -t EC -c P-256 -u sig -i defaultECSign | tail -n +2 > /opt/shibboleth-idp/credentials/idp-signing-es.jwk +RUN /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u enc -i defaultRSAEnc | tail -n +2 > /opt/shibboleth-idp/credentials/idp-encryption-rsa.jwk + # copy in the needed config files ADD ${TOMCFG} /usr/local/tomcat/conf ADD ${TOMCERT} /opt/certs ADD ${TOMWWWROOT} /usr/local/tomcat/webapps/ROOT ADD ${SHBCFG} /opt/shibboleth-idp/conf -ADD ${SHBCREDS} /opt/shibboleth-idp/credentials #ADD ${SHBVIEWS} /opt/shibboleth-idp/views #ADD ${SHBEDWAPP} /opt/shibboleth-idp/edit-webapp #ADD ${SHBMSGS} /opt/shibboleth-idp/messages ADD ${SHBMD} /opt/shibboleth-idp/metadata + EXPOSE 8080 diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/credentials.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/credentials.xml new file mode 100644 index 000000000..f2d3309b1 --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/credentials.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties index 50af60005..c3c450a11 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties @@ -1,5 +1,5 @@ # Load any additional property resources from a comma-delimited list -idp.additionalProperties=/conf/ldap.properties, /conf/saml-nameid.properties, /conf/services.properties, /conf/authn/duo.properties, /credentials/secrets.properties +idp.additionalProperties=/conf/ldap.properties, /conf/saml-nameid.properties, /conf/services.properties, /conf/authn/duo.properties, /credentials/secrets.properties, /conf/oidc.properties # In most cases (and unless noted in the surrounding comments) the # commented settings in the distributed files document default behavior. diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties new file mode 100644 index 000000000..36da7f76d --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties @@ -0,0 +1,141 @@ +# Set the Open ID Connect Issuer value +idp.oidc.issuer = https://idp.unicon.local + +#Dynamic registration properties +# The validity of registration before a new one is required. +#idp.oidc.dynreg.defaultRegistrationValidity = PT24H +# The validity of client secret registered +#idp.oidc.dynreg.defaultSecretExpiration = P12M +# The default scopes accepted in dynamic registration +#idp.oidc.dynreg.defaultScope = openid profile email address phone offline_access +# The default subject type if not set by client in request. Maybe set to pairwise or public. +#idp.oidc.dynreg.defaultSubjectType = public +# The acceptable client authentication methods when using dynamic registration +#idp.oidc.dynreg.tokenEndpointAuthMethods = client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt +# Regardless of what signing algorithms are configured, allow none for request object signing +#idp.oidc.dynreg.allowNoneForRequestSigning = true +# Bean to determine whether dynamic registration should validate the remote JWK set if it's defined in the request +#idp.oidc.dynreg.validateRemoteJwks = shibboleth.Conditions.TRUE +# Full path to the file containing default metadata policy used for dynamic client registration +#idp.oidc.dynreg.defaultMetadataPolicyFile = +# Bean to determine the default metadata policy used for dynamic client registration +#idp.oidc.dynreg.defaultMetadataPolicy = shibboleth.oidc.dynreg.DefaultMetadataPolicy + +# Storage for storing remote jwk sets. +#idp.oidc.jwk.StorageService = shibboleth.StorageService + +#Authorization/Token endpoint properties +# The acceptable client authentication methods +#idp.oidc.tokenEndpointAuthMethods = client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt + +# Default lifetime of OIDC tokens (issued to the client or against the OP itself) +#idp.oidc.authorizeCode.defaultLifetime = PT5M +#idp.oidc.accessToken.defaultLifetime = PT10M +#idp.oidc.refreshToken.defaultLifetime = PT2H +#idp.oidc.idToken.defaultLifetime = PT1H + +# Lifetime of entries in revocation cache for authorize code +#idp.oidc.revocationCache.authorizeCode.lifetime = PT6H +# Storage for revocation cache. Requires server-side storage +#idp.oidc.revocationCache.StorageService = shibboleth.StorageService + +# Signing keys for id tokens / userinfo response +idp.signing.oidc.rs.key = %{idp.home}/credentials/idp-signing-rs.jwk +idp.signing.oidc.es.key = %{idp.home}/credentials/idp-signing-es.jwk +# Request object decryption key +idp.signing.oidc.rsa.enc.key = %{idp.home}/credentials/idp-encryption-rsa.jwk + +# Set false to preclude issuing unencrypted ID/UserInfo tokens without specific overrides +#idp.oidc.encryptionOptional = true + +#PKCE/AppAuth related properties +#idp.oidc.forcePKCE = false +#idp.oidc.allowPKCEPlain = false + +# Store user consent to authorization code & access/refresh tokens instead of exploiting consent storage +#idp.oidc.encodeConsentInTokens = false + +# shibboleth.ClientInformationResolverService properties +#idp.service.clientinfo.failFast = false +#idp.service.clientinfo.checkInterval = PT0S +#idp.service.clientinfo.resources = shibboleth.ClientInformationResolverResources + +# Special claim handling rules +# "Encoded" attributes are encrypted and embedded into the access token +#idp.oidc.encodedAttributes = +# "Always included" attributes are forced into ID tokens for all response_types +#idp.oidc.alwaysIncludedAttributes = +# "Denied" attributes are omitted from the UserInfo token +#idp.oidc.deniedUserInfoAttributes = + +# The source attribute used in generating the sub claim +idp.oidc.subject.sourceAttribute = uid + +# The digest algorithm used in generating the sub claim +#idp.oidc.subject.algorithm = SHA + +# The salt used in generating the subject +# Do *NOT* share the salt with other people, it's like divulging your private key. +# It is suggested you move this property into credentials/secrets.properties +idp.oidc.subject.salt = this_too_should_be_ch4ng3d + +# Bean to determine whether SAML metadata should be exploited for trusted OIDC RP resolution +#idp.oidc.metadata.saml = shibboleth.Conditions.TRUE + +# Upgrade interval to the remote JWKs +#idp.oidc.jwksuri.fetchInterval = PT30M + +# Bounds on the next file refresh of the OP configuration resource +#idp.oidc.config.minRefreshDelay = PT5M +#idp.oidc.config.maxRefreshDelay = PT4H + +# Bean to configure additional response headers: none is added by default, but e.g. shibboleth.ResponseHeaderFilter +# contains headers further configurable via other properties such as 'idp.hsts', 'idp.frameoptions' and 'idp.csp'. +#idp.oidc.ResponseHeaderFilter = shibboleth.ResponseHeaderFilter + +# Bean used for extracting login_hint from the authentication request. The default function parses login_hint as is. +#idp.oidc.LoginHintLookupStrategy = DefaultRequestLoginHintLookupFunction + +# Bean used for creating SPSessions needed for SLO. By default builds protocol-independent BasicSPSession, as SLO is not yet supported. +#idp.oidc.SPSessionCreationStrategy = DefaultSPSessionCreationStrategy + +# Settings for issue-registration-access-token flow +#idp.oidc.admin.registration.logging = IssueRegistrationAccessToken +#idp.oidc.admin.registration.nonBrowserSupported = true +#idp.oidc.admin.registration.authenticated = false +#idp.oidc.admin.registration.resolveAttributes = false +#idp.oidc.admin.registration.lookup.policy = shibboleth.oidc.admin.DefaultMetadataPolicyLookupStrategy +#idp.oidc.admin.registration.defaultTokenLifetime = P1D +#idp.oidc.admin.registration.accessPolicy = AccessByIPAddress +#idp.oidc.admin.registration.policyLocationPolicy = AccessByAdmin +#idp.oidc.admin.registration.policyIdPolicy = AccessByAdmin +#idp.oidc.admin.registration.clientIdPolicy = AccessByAdmin + +# +# OAuth2 Settings - these typically involve generic OAuth 2.0 use cases +# + +# Supported grant_type values for token requests +#idp.oauth2.grantTypes = authorization_code,refresh_token + +# Default handling of generic OAuth tokens (for use against arbitrary resource servers) +#idp.oauth2.accessToken.defaultLifetime = PT10M +# Set to JWT if desired as a default. +#idp.oauth2.accessToken.type = + +# Set false to preclude issuing unencrypted JWT access tokens without specific overrides +#idp.oauth2.encryptionOptional = true + +# Default scope/audience values if you allow unverified clients without metadata. +#idp.oauth2.defaultAllowedScope = +#idp.oauth2.defaultAllowedAudience = + +# Regular expression matching OAuth login flows to enable. +# For most deployments, the default is sufficient to accomodate a variety of methods +#idp.oauth2.authn.flows = OAuth2Client + +# Set true to enforce refresh token rotation (defaults to false) +#idp.oauth2.enforceRefreshTokenRotation = true + +# Revocation method: set to TOKEN to revoke single tokens (defaults to full chain (value = CHAIN)) +#idp.oauth2.revocationMethod = TOKEN \ No newline at end of file diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml index 478731ac5..84d406b7b 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml @@ -23,6 +23,8 @@ + + @@ -51,6 +53,10 @@ + + + + diff --git a/testbed/integration/shibboleth-idp/config/tomcat/context.xml b/testbed/integration/shibboleth-idp/config/tomcat/context.xml index 98727cb7b..0bba305ef 100644 --- a/testbed/integration/shibboleth-idp/config/tomcat/context.xml +++ b/testbed/integration/shibboleth-idp/config/tomcat/context.xml @@ -20,6 +20,7 @@ + WEB-INF/web.xml ${catalina.base}/conf/web.xml diff --git a/testbed/integration/shibboleth-idp/config/tomcat/rewrite.config b/testbed/integration/shibboleth-idp/config/tomcat/rewrite.config new file mode 100644 index 000000000..804401494 --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/tomcat/rewrite.config @@ -0,0 +1 @@ +RewriteRule ^/.well-known/openid-configuration$ /idp/profile/oidc/configuration [L] \ No newline at end of file diff --git a/testbed/integration/shibboleth-idp/config/tomcat/server.xml b/testbed/integration/shibboleth-idp/config/tomcat/server.xml index f4b875bca..de89b5842 100644 --- a/testbed/integration/shibboleth-idp/config/tomcat/server.xml +++ b/testbed/integration/shibboleth-idp/config/tomcat/server.xml @@ -16,6 +16,7 @@ prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> + diff --git a/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.idp.plugin.oidc.op/truststore.asc b/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.idp.plugin.oidc.op/truststore.asc new file mode 100644 index 000000000..083158dc5 --- /dev/null +++ b/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.idp.plugin.oidc.op/truststore.asc @@ -0,0 +1,32 @@ + + Henri Mikkonen id 9355EBCA + -----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.70 + +mQINBF46zL0BEACUeQllAAViSlyL8uFBCjlCXdH12GpDL9y8fubm+N50ofonIloA +YLbJtETVrqpxfeh+SDiERbEG5W02fbM1y3wdSjef0jzAEP3PoXydv/SdNKvomvBP +U7I9eALgHJI4Nkqzf8ggTrOBHcWbRIRGbVXFRhOE1Z86akmVz3fe3aQzddvzAS7I +YYX0RxbKiNt8iaxUXUo+P1LopD9Zo2I1NTY8u27RuhtxBr5tnHnsuf38mzjG/l6U +RzJ8qhHJr6D4E+MLqRo9ndTREOT/d1TeJUvQddXC59VEL75TrYCEc2v/NZ5m9fD6 +yg0+oqgyrQHmZhPVOqoJiz0lkd3rl7lUqCH9yjREr1H5PUchiuhBKBOogwtirqw3 +NMKH6bs0Bu6qUy5fIJRqjxKVv+6fOEty/xnp0xN7xoBEUPEt1M/V3ewwH1zhOwTo +g4cr4zhTT9RNno3eM0eenEQYapQZ8dFmrNVmhvx9VJlshYGyakrxPwrF3coyC3hh +HjWE9SzmoyGmmbRgvJVt//SqoGpDyaM+d1hPys9tX2N/E1TlwZiD2brWAtjr2K49 +NC9Skizw4qHAbphq4EMGCKzrp9ksnBvwZAY9JjL0JvdjAabqkyRFVh2Mpm5xSxbw +d+Twryh5hXaT/EQXsKMC1WlQnIDREjHpm1UOXTzcsFPa9tEW8XUftPWbQQARAQAB +tCZIZW5yaSBNaWtrb25lbiA8aGVucmkubWlra29uZW5AaWtpLmZpPokCVAQTAQgA +PhYhBG0Y/WNwj8ygebaMzgJmkYOTVevKBQJeOsy9AhsDBQkHhh+ABQsJCAcCBhUK +CQgLAgQWAgMBAh4BAheAAAoJEAJmkYOTVevKwWcP+gLrjnrNxqwEx7/Ly/KdjkGD +0W7aMiQc8acvC9oo74/XXpAD0W1jkK/BXyLH1q/o5Lyjymmm6w7VvEWLSY1Q0+gC +l+hUOqccH572767UrGEeZeJV8+tNhziTU2S7NagK2A0BelHoA3hIhfGmWLJ+ooJe +HZXFCov4ThZOpGzu5d04dEYoOv2jVaWwnrjOBzoKcgws9J6RLX+6gOFhZ3Dh5Rxs +UGhl0ZJuEBQCDT7X9jI4mHsA0Ngo27inb3gxfeCm/ziZhHDV2gZtl777dKVc/sQN +fqGaRGVi1p37La6KKpfIA3KHRjGf4jfg17AQ1Ix+ZgRIpbPXb7fXQHtBElhIbbn/ +VR2CG0Jdchdc4UozelKU6WNsNlcMn3kfTNFosW7+gTiYEGSxZQC9ylSSl1s9oIFM +dvk70u4AgTY6w+27TrTRuEpdARoNZG4NhBTJ8g0BkiX6cHVyc5ir5IOVpmewsxN5 +yLg0ed6OwpcK5V8SwGT60hgkkJp71OeBsnLzyzO3/YoI5GVAIgcwtdzptRUt0iL8 +GUccO3mO6Hm4EfJAZHFWRbxX3ITTfCzw4blbXURlIXkPefprptAYX2+rn/z4iC1F +mJUANl+4WilKuPoAimKGDNi6CvlbckQW2i2i5gsoM3iMxRMsExoZUnoMpfY70Trg +ToF/jwURMQSCsJnZvyQD +=g4uH +-----END PGP PUBLIC KEY BLOCK----- diff --git a/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.oidc.common/truststore.asc b/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.oidc.common/truststore.asc new file mode 100644 index 000000000..083158dc5 --- /dev/null +++ b/testbed/integration/shibboleth-idp/credentials/shib-idp/net.shibboleth.oidc.common/truststore.asc @@ -0,0 +1,32 @@ + + Henri Mikkonen id 9355EBCA + -----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.70 + +mQINBF46zL0BEACUeQllAAViSlyL8uFBCjlCXdH12GpDL9y8fubm+N50ofonIloA +YLbJtETVrqpxfeh+SDiERbEG5W02fbM1y3wdSjef0jzAEP3PoXydv/SdNKvomvBP +U7I9eALgHJI4Nkqzf8ggTrOBHcWbRIRGbVXFRhOE1Z86akmVz3fe3aQzddvzAS7I +YYX0RxbKiNt8iaxUXUo+P1LopD9Zo2I1NTY8u27RuhtxBr5tnHnsuf38mzjG/l6U +RzJ8qhHJr6D4E+MLqRo9ndTREOT/d1TeJUvQddXC59VEL75TrYCEc2v/NZ5m9fD6 +yg0+oqgyrQHmZhPVOqoJiz0lkd3rl7lUqCH9yjREr1H5PUchiuhBKBOogwtirqw3 +NMKH6bs0Bu6qUy5fIJRqjxKVv+6fOEty/xnp0xN7xoBEUPEt1M/V3ewwH1zhOwTo +g4cr4zhTT9RNno3eM0eenEQYapQZ8dFmrNVmhvx9VJlshYGyakrxPwrF3coyC3hh +HjWE9SzmoyGmmbRgvJVt//SqoGpDyaM+d1hPys9tX2N/E1TlwZiD2brWAtjr2K49 +NC9Skizw4qHAbphq4EMGCKzrp9ksnBvwZAY9JjL0JvdjAabqkyRFVh2Mpm5xSxbw +d+Twryh5hXaT/EQXsKMC1WlQnIDREjHpm1UOXTzcsFPa9tEW8XUftPWbQQARAQAB +tCZIZW5yaSBNaWtrb25lbiA8aGVucmkubWlra29uZW5AaWtpLmZpPokCVAQTAQgA +PhYhBG0Y/WNwj8ygebaMzgJmkYOTVevKBQJeOsy9AhsDBQkHhh+ABQsJCAcCBhUK +CQgLAgQWAgMBAh4BAheAAAoJEAJmkYOTVevKwWcP+gLrjnrNxqwEx7/Ly/KdjkGD +0W7aMiQc8acvC9oo74/XXpAD0W1jkK/BXyLH1q/o5Lyjymmm6w7VvEWLSY1Q0+gC +l+hUOqccH572767UrGEeZeJV8+tNhziTU2S7NagK2A0BelHoA3hIhfGmWLJ+ooJe +HZXFCov4ThZOpGzu5d04dEYoOv2jVaWwnrjOBzoKcgws9J6RLX+6gOFhZ3Dh5Rxs +UGhl0ZJuEBQCDT7X9jI4mHsA0Ngo27inb3gxfeCm/ziZhHDV2gZtl777dKVc/sQN +fqGaRGVi1p37La6KKpfIA3KHRjGf4jfg17AQ1Ix+ZgRIpbPXb7fXQHtBElhIbbn/ +VR2CG0Jdchdc4UozelKU6WNsNlcMn3kfTNFosW7+gTiYEGSxZQC9ylSSl1s9oIFM +dvk70u4AgTY6w+27TrTRuEpdARoNZG4NhBTJ8g0BkiX6cHVyc5ir5IOVpmewsxN5 +yLg0ed6OwpcK5V8SwGT60hgkkJp71OeBsnLzyzO3/YoI5GVAIgcwtdzptRUt0iL8 +GUccO3mO6Hm4EfJAZHFWRbxX3ITTfCzw4blbXURlIXkPefprptAYX2+rn/z4iC1F +mJUANl+4WilKuPoAimKGDNi6CvlbckQW2i2i5gsoM3iMxRMsExoZUnoMpfY70Trg +ToF/jwURMQSCsJnZvyQD +=g4uH +-----END PGP PUBLIC KEY BLOCK----- From 4e555f372e76d38a998f7042a3baec84399e74bf Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 28 Oct 2022 07:08:10 -0700 Subject: [PATCH 04/93] updated schema --- ui/public/assets/data/registration.json | 20 ++--- ui/public/assets/data/registrations.json | 25 +++--- .../schema/dynamic-registration/oidc.json | 77 ++++++++++++++++++- 3 files changed, 100 insertions(+), 22 deletions(-) diff --git a/ui/public/assets/data/registration.json b/ui/public/assets/data/registration.json index e7434acd6..c18fb57d6 100644 --- a/ui/public/assets/data/registration.json +++ b/ui/public/assets/data/registration.json @@ -1,18 +1,18 @@ { "resourceId": "foobar", "name": "Foobar", - "redirect_uris": [], - "response_types": [], - "grant_types": "", - "application_type": "", + "redirectUris": [], + "responseTypes": [], + "grantTypes": "", + "applicationType": "", "contacts": "", - "subject_type": "", + "subjectType": "", "jwks": "", - "jwks_uri": "", - "token_endpoint_auth_method": "", - "logo_uri": "", - "policy_uri": "", - "tos_uri": "", + "jwksUri": "", + "tokenEndpointAuthMethod": "", + "logoUri": "", + "policyUri": "", + "tosUri": "", "scope": "", "enabled": true, "modifiedDate": "2022-10-21T11:57:24.391649", diff --git a/ui/public/assets/data/registrations.json b/ui/public/assets/data/registrations.json index 90dd2b1af..1578a9723 100644 --- a/ui/public/assets/data/registrations.json +++ b/ui/public/assets/data/registrations.json @@ -2,18 +2,21 @@ { "resourceId": "foobar", "name": "Foobar", - "redirect_uris": [], - "response_types": [], - "grant_types": "", - "application_type": "", + "redirectUris": [], + "responseTypes": [], + "grantTypes": "", + "applicationType": "", "contacts": "", - "subject_type": "", + "subjectType": "", "jwks": "", - "jwks_uri": "", - "token_endpoint_auth_method": "", - "logo_uri": "", - "policy_uri": "", - "tos_uri": "", - "scope": "" + "jwksUri": "", + "tokenEndpointAuthMethod": "", + "logoUri": "", + "policyUri": "", + "tosUri": "", + "scope": "", + "enabled": true, + "modifiedDate": "2022-10-21T11:57:24.391649", + "createdData": "2022-10-21T11:57:24.391649" } ] diff --git a/ui/public/assets/schema/dynamic-registration/oidc.json b/ui/public/assets/schema/dynamic-registration/oidc.json index c746c5d29..4b6f8fb85 100644 --- a/ui/public/assets/schema/dynamic-registration/oidc.json +++ b/ui/public/assets/schema/dynamic-registration/oidc.json @@ -8,6 +8,81 @@ "type": "string", "minLength": 1, "maxLength": 255 - } + }, + "resourceId": { + "type": "string" + }, + "redirectUris": { + "type": "array", + "items": { + "type": "string" + } + }, + "responseTypes": { + "type": "array", + "items": { + "type": "string" + } + }, + "grantTypes": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "applicationType": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "contacts": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "subjectType": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "jwks": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "jwksUri": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "tokenEndpointAuthMethod": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "logoUri": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "policyUri": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "tosUri": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "scope": { + "title": "label.dynamic-registration-", + "description": "tooltip.dynamic-registration-", + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "modifiedDate": "2022-10-21T11:57:24.391649", + "createdData": "2022-10-21T11:57:24.391649" } } From 698f77a0eb8bbdf193d244c70335a47147859227 Mon Sep 17 00:00:00 2001 From: Sean Porth Date: Fri, 28 Oct 2022 14:52:04 -0400 Subject: [PATCH 05/93] configure oidc --- testbed/integration/shibboleth-idp/Dockerfile | 5 +- .../config/shib-idp/conf/idp.properties | 2 + .../shib-idp/conf/oidc-attribute-filter.xml | 142 +++++++++++++ .../shib-idp/conf/oidc-attribute-resolver.xml | 197 ++++++++++++++++++ .../config/shib-idp/conf/oidc.properties | 2 +- .../config/shib-idp/conf/services.xml | 3 + .../shib-idp/static/openid-configuration.json | 139 ++++++++++++ 7 files changed, 488 insertions(+), 2 deletions(-) create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-filter.xml create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-resolver.xml create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/static/openid-configuration.json diff --git a/testbed/integration/shibboleth-idp/Dockerfile b/testbed/integration/shibboleth-idp/Dockerfile index 6cfe13c7f..e4a2ae236 100644 --- a/testbed/integration/shibboleth-idp/Dockerfile +++ b/testbed/integration/shibboleth-idp/Dockerfile @@ -10,6 +10,8 @@ ARG SHBVIEWS=config/shib-idp/views ARG SHBEDWAPP=config/shib-idp/edit-webapp ARG SHBMSGS=config/shib-idp/messages ARG SHBMD=config/shib-idp/metadata +ARG OIDCREG=config/shib-idp/static +ARG TOMREWRITE=config/tomcat/rewrite.config #enable OIDC plugins and generate needed keys ADD ${SHBCREDS} /opt/shibboleth-idp/credentials @@ -28,6 +30,7 @@ ADD ${SHBCFG} /opt/shibboleth-idp/conf #ADD ${SHBEDWAPP} /opt/shibboleth-idp/edit-webapp #ADD ${SHBMSGS} /opt/shibboleth-idp/messages ADD ${SHBMD} /opt/shibboleth-idp/metadata - +ADD ${OIDCREG} /opt/shibboleth-idp/static +ADD ${TOMREWRITE} /opt/shibboleth-idp/edit-webapp/WEB-INF/rewrite.config EXPOSE 8080 diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties index c3c450a11..a04eb3ff7 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties @@ -224,3 +224,5 @@ idp.ui.fallbackLanguages=en,fr,de # Set false if you want SAML bindings "spelled out" in audit log idp.audit.shortenBindings=true + +idp.loglevel.idp=DEBUG diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-filter.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-filter.xml new file mode 100644 index 000000000..e1c7e4aed --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-filter.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-resolver.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-resolver.xml new file mode 100644 index 000000000..bab9f96ae --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-attribute-resolver.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + member + staff + + + +1 (604) 555-1234;ext=5678 + + + true + + + false + + + Mr.Teppo Matias Testaaja + + + Testaaja + + + Teppo Matias + + + Matias + + + TT + + + https://fi.wikipedia.org/wiki/Tom_Cruise + + + https://pixabay.com/fi/pentu-kissa-kukka-potin-tabby-pentu-2766820/ + + + https://www.facebook.com/officialtomcruise/ + + + male + + + 1969-07-20 + + + America/Los_Angeles + + + en-US + + + 1509450347 + + + 234 Hollywood Blvd. + + + Los Angeles + + + CA + + + 90210 + + + US + + + + diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties index 36da7f76d..50d713a94 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties @@ -77,7 +77,7 @@ idp.oidc.subject.sourceAttribute = uid # The salt used in generating the subject # Do *NOT* share the salt with other people, it's like divulging your private key. # It is suggested you move this property into credentials/secrets.properties -idp.oidc.subject.salt = this_too_should_be_ch4ng3d +idp.oidc.subject.salt = eezien3iteit0gaiciiweayohxahmai6 # Bean to determine whether SAML metadata should be exploited for trusted OIDC RP resolution #idp.oidc.metadata.saml = shibboleth.Conditions.TRUE diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/services.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/services.xml index c38ff2aa3..93d102727 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/services.xml +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/services.xml @@ -26,6 +26,7 @@ %{idp.home}/conf/attribute-resolver.xml + %{idp.home}/conf/oidc-attribute-resolver.xml - WEB-INF/web.xml ${catalina.base}/conf/web.xml diff --git a/testbed/integration/shibboleth-idp/config/tomcat/server.xml b/testbed/integration/shibboleth-idp/config/tomcat/server.xml index de89b5842..2b4b8ebfa 100644 --- a/testbed/integration/shibboleth-idp/config/tomcat/server.xml +++ b/testbed/integration/shibboleth-idp/config/tomcat/server.xml @@ -12,6 +12,7 @@ + From 7d448c47cb6344504066b7368ade5c26b7d88217 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 28 Oct 2022 14:08:02 -0700 Subject: [PATCH 08/93] Updated labels, detail page --- .../main/resources/i18n/messages.properties | 41 +++++++++++- .../schema/dynamic-registration/oidc.json | 52 ++++++++------- .../hoc/DynamicConfigurationDefinition.js | 66 +++++++++++++++++++ .../view/DynamicRegistrationDetail.js | 46 +++++-------- .../component/MetadataConfiguration.js | 6 +- .../app/metadata/component/MetadataSection.js | 2 +- ui/src/app/metadata/hoc/Configuration.js | 2 - 7 files changed, 156 insertions(+), 59 deletions(-) create mode 100644 ui/src/app/dynamic-registration/hoc/DynamicConfigurationDefinition.js diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index a2ecaf585..82223c5a3 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -944,7 +944,44 @@ tooltip.IDTokenLifetime.browser=Lifetime of ID token (browser) tooltip.includeIssuerInResponse=Whether to include issuer -parameter in the responses as specified by RFC 9207. If set to true also consider including authorization_response_iss_parameter_supported to the OP metadata. tooltip.refreshTokenLifetime.oauth=Lifetime of refresh token tooltip.alwaysIncludedAttributes.browser=Specifies IdPAttributes to always include in ID token regardless of response_type -tooltip.encryptionOptional=Whether the absence of encryption details in a client's metadata should fail when issuing an ID token +tooltip.encryptionOptional=Whether the absence of encryption details in a client\u0027s metadata should fail when issuing an ID token tooltip.IDTokenLifetime=Lifetime of ID token issued to client tooltip.deniedUserInfoAttributes=Specifies IdPAttributes to omit from UserInfo token -tooltip.resolveAttributes.oauth=Whether to run the attribute resolution/filtering step \ No newline at end of file +tooltip.resolveAttributes.oauth=Whether to run the attribute resolution/filtering step + +label.dynamic-registration=Dynamic Registration +label.dynamic-registration-configuration=Dynamic Registration +action.dynamic-registrations=Dynamic registrations +action.add-new-dynamic-registration=Add a new dynamic registration +label.dynamic-registration-name=Name + +label.dynamic-registration-name=Name +tooltip.dynamic-registration-name=Name +label.dynamic-registration-redirectUris=Redirect uris +tooltip.dynamic-registration-redirectUris=Redirect uris +label.dynamic-registration-responseTypes=Response types +tooltip.dynamic-registration-responseTypes=Response types +label.dynamic-registration-grantTypes=Grant types +tooltip.dynamic-registration-grantTypes=Grant types +label.dynamic-registration-applicationType=Application type +tooltip.dynamic-registration-applicationType=Application type +label.dynamic-registration-contacts=Contacts +tooltip.dynamic-registration-contacts=Contacts +label.dynamic-registration-subjectType=Subject type +tooltip.dynamic-registration-subjectType=Subject type +label.dynamic-registration-jwks=Jwks +tooltip.dynamic-registration-jwks=Jwks +label.dynamic-registration-jwksUri=Jwks uri +tooltip.dynamic-registration-jwksUri=Jwks uri +label.dynamic-registration-tokenEndpointAuthMethod=Token endpoint auth method +tooltip.dynamic-registration-tokenEndpointAuthMethod=Token endpoint auth method +label.dynamic-registration-logo-uri=Logo uri +tooltip.dynamic-registration-logo-uri=Logo uri +label.dynamic-registration-policy-uri=Policy uri +tooltip.dynamic-registration-policy-uri=Policy uri +label.dynamic-registration-tosuri=To uri +tooltip.dynamic-registration-tosuri=To uri +label.dynamic-registration-scope=Scope +tooltip.dynamic-registration-scope=Scope +label.dynamic-registration-enabled=Enabled +tooltip.dynamic-registration-enabled=Enabled diff --git a/ui/public/assets/schema/dynamic-registration/oidc.json b/ui/public/assets/schema/dynamic-registration/oidc.json index 4b6f8fb85..d9e0ad451 100644 --- a/ui/public/assets/schema/dynamic-registration/oidc.json +++ b/ui/public/assets/schema/dynamic-registration/oidc.json @@ -10,76 +10,84 @@ "maxLength": 255 }, "resourceId": { + "title": "label.dynamic-registration-resourceId", + "description": "tooltip.dynamic-registration-resourceId", "type": "string" }, "redirectUris": { + "title": "label.dynamic-registration-redirectUris", + "description": "tooltip.dynamic-registration-redirectUris", "type": "array", "items": { "type": "string" } }, "responseTypes": { + "title": "label.dynamic-registration-responseTypes", + "description": "tooltip.dynamic-registration-responseTypes", "type": "array", "items": { "type": "string" } }, "grantTypes": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-grantTypes", + "description": "tooltip.dynamic-registration-grantTypes", "type": "string" }, "applicationType": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-applicationType", + "description": "tooltip.dynamic-registration-applicationType", "type": "string" }, "contacts": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-contacts", + "description": "tooltip.dynamic-registration-contacts", "type": "string" }, "subjectType": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-subjectType", + "description": "tooltip.dynamic-registration-subjectType", "type": "string" }, "jwks": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-jwks", + "description": "tooltip.dynamic-registration-jwks", "type": "string" }, "jwksUri": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-jwksUri", + "description": "tooltip.dynamic-registration-jwksUri", "type": "string" }, "tokenEndpointAuthMethod": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-tokenEndpointAuthMethod", + "description": "tooltip.dynamic-registration-tokenEndpointAuthMethod", "type": "string" }, "logoUri": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-logo-uri", + "description": "tooltip.dynamic-registration-logo-uri", "type": "string" }, "policyUri": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-policy-uri", + "description": "tooltip.dynamic-registration-policy-uri", "type": "string" }, "tosUri": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-tosuri", + "description": "tooltip.dynamic-registration-tosuri", "type": "string" }, "scope": { - "title": "label.dynamic-registration-", - "description": "tooltip.dynamic-registration-", + "title": "label.dynamic-registration-scope", + "description": "tooltip.dynamic-registration-scope", "type": "string" }, "enabled": { + "title": "label.dynamic-registration-enabled", + "description": "tooltip.dynamic-registration-enabled", "type": "boolean" }, "modifiedDate": "2022-10-21T11:57:24.391649", diff --git a/ui/src/app/dynamic-registration/hoc/DynamicConfigurationDefinition.js b/ui/src/app/dynamic-registration/hoc/DynamicConfigurationDefinition.js new file mode 100644 index 000000000..9ccf0bd42 --- /dev/null +++ b/ui/src/app/dynamic-registration/hoc/DynamicConfigurationDefinition.js @@ -0,0 +1,66 @@ +import { BASE_PATH } from '../../App.constant'; + +export const DynamicRegistrationDefinition = { + label: 'Dynamic Registration', + type: '@DynamicRegistration', + steps: [ + { + id: 'common', + label: 'label.dynamic-registration', + index: 1, + fields: [ + 'name', + 'resourceId', + 'redirectUris', + 'responseTypes', + 'grantTypes', + 'applicationType', + 'contacts', + 'subjectType', + 'jwks', + 'jwksUri', + 'tokenEndpointAuthMethod', + 'logoUri', + 'policyUri', + 'tosUri', + 'scope' + ] + } + ], + schema: `${BASE_PATH}assets/schema/dynamic-registration/oidc.json`, + + uiSchema: { + layout: { + groups: [ + { + size: 6, + classNames: '', + fields: [ + 'name', + 'resourceId', + 'redirectUris', + 'responseTypes', + 'grantTypes', + 'applicationType', + 'contacts', + 'subjectType', + 'jwks', + 'jwksUri', + 'tokenEndpointAuthMethod', + 'logoUri', + 'policyUri', + 'tosUri', + 'scope' + ] + }, + ] + }, + }, + + parser: (changes) => changes, + formatter: (changes) => changes, + display: (changes) => changes, +} + +export default DynamicRegistrationDefinition; + diff --git a/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js b/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js index 4a0d1d0ef..eb9646bbb 100644 --- a/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js +++ b/ui/src/app/dynamic-registration/view/DynamicRegistrationDetail.js @@ -8,6 +8,12 @@ import Button from 'react-bootstrap/esm/Button'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEdit, faHistory, faToggleOff, faToggleOn, faTrash } from '@fortawesome/free-solid-svg-icons'; import Badge from 'react-bootstrap/esm/Badge'; +import { Configuration } from '../../metadata/hoc/Configuration'; +import { MetadataConfiguration } from '../../metadata/component/MetadataConfiguration'; + +import { Schema } from '../../form/Schema'; + +import definition from '../hoc/DynamicConfigurationDefinition'; export function DynamicRegistrationDetail () { @@ -54,7 +60,7 @@ export function DynamicRegistrationDetail () {
-
+
@@ -97,35 +103,15 @@ export function DynamicRegistrationDetail () {
- - -
-
-
-

- - - -

-
- -
-
-
-
{JSON.stringify(detail, null, 4)}
-
-
-
+ + {(schema) => + + {(config) => + edit()} /> + } + + } +
diff --git a/ui/src/app/metadata/component/MetadataConfiguration.js b/ui/src/app/metadata/component/MetadataConfiguration.js index 79acec8c5..a23080af1 100644 --- a/ui/src/app/metadata/component/MetadataConfiguration.js +++ b/ui/src/app/metadata/component/MetadataConfiguration.js @@ -8,15 +8,17 @@ import { ObjectProperty } from './properties/ObjectProperty'; export function MetadataConfiguration ({ configuration, onEdit }) { - const columns = configuration.dates?.length || 1; + const columns = configuration?.dates?.length || 1; const width = usePropertyWidth(columns); + React.useEffect(() => console.log(configuration), [configuration]); + return ( <> { configuration && configuration.sections.map((section, sidx) => {section?.properties?.length > 0 && - + 1 ? sidx : -1 } onEdit={onEdit}>
Option {configuration.dates.map((d, didx) => diff --git a/ui/src/app/metadata/component/MetadataSection.js b/ui/src/app/metadata/component/MetadataSection.js index 6b9ef1c31..853f9df80 100644 --- a/ui/src/app/metadata/component/MetadataSection.js +++ b/ui/src/app/metadata/component/MetadataSection.js @@ -18,7 +18,7 @@ export function MetadataSection ({ section, index = -1, onEdit, children }) { } - + diff --git a/ui/src/app/metadata/hoc/Configuration.js b/ui/src/app/metadata/hoc/Configuration.js index 06bac7b0b..bcffd91c9 100644 --- a/ui/src/app/metadata/hoc/Configuration.js +++ b/ui/src/app/metadata/hoc/Configuration.js @@ -2,9 +2,7 @@ import React from 'react'; import { useMetadataConfiguration } from '../hooks/configuration'; export function Configuration ({entities, schema, definition, limited, children}) { - const config = useMetadataConfiguration(entities, schema, definition, limited); - return ( <>{children(config)} ); From ca51b8e112e36b4ff4d5b2ff6fbfa611b4efe80d Mon Sep 17 00:00:00 2001 From: Sean Porth Date: Mon, 31 Oct 2022 15:48:17 -0400 Subject: [PATCH 09/93] oidc dynamic registration --- testbed/integration/docker-compose.yml | 4 + testbed/integration/shibboleth-idp/Dockerfile | 3 +- .../config/shib-idp/conf/access-control.xml | 14 ++-- .../config/shib-idp/conf/global.xml | 80 +++++++++++++++++++ .../config/shib-idp/conf/idp.properties | 2 +- .../conf/oidc-clientinfo-resolvers.xml | 39 +++++++++ .../config/shib-idp/conf/oidc.properties | 13 ++- .../config/shib-idp/conf/relying-party.xml | 1 + .../shibboleth-idp/db/oidc_dynreg.sql | 10 +++ 9 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/global.xml create mode 100644 testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-clientinfo-resolvers.xml create mode 100644 testbed/integration/shibboleth-idp/db/oidc_dynreg.sql diff --git a/testbed/integration/docker-compose.yml b/testbed/integration/docker-compose.yml index eb448e56d..d249fc2be 100644 --- a/testbed/integration/docker-compose.yml +++ b/testbed/integration/docker-compose.yml @@ -48,9 +48,11 @@ services: depends_on: - directory - reverse-proxy + - database networks: - reverse-proxy - idp + - backend volumes: - ../directory/certs/ca.crt:/opt/shibboleth-idp/credentials/ldap-server.crt - dynamic_metadata:/opt/shibboleth-idp/metadata/dynamic @@ -86,6 +88,8 @@ services: - backend volumes: - database_data:/var/lib/postgresql/data + - ./shibboleth-idp/db/oidc_dynreg.sql:/docker-entrypoint-initdb.d/oidc_dynreg.sql + networks: reverse-proxy: idp: diff --git a/testbed/integration/shibboleth-idp/Dockerfile b/testbed/integration/shibboleth-idp/Dockerfile index a625c07e8..31684bb89 100644 --- a/testbed/integration/shibboleth-idp/Dockerfile +++ b/testbed/integration/shibboleth-idp/Dockerfile @@ -17,6 +17,7 @@ ARG TOMREWRITE=config/tomcat/rewrite.config ADD ${SHBCREDS} /opt/shibboleth-idp/credentials RUN /opt/shibboleth-idp/bin/plugin.sh -i https://shibboleth.net/downloads/identity-provider/plugins/oidc-common/2.1.0/oidc-common-dist-2.1.0.tar.gz --noPrompt RUN /opt/shibboleth-idp/bin/plugin.sh -i https://shibboleth.net/downloads/identity-provider/plugins/oidc-op/3.2.1/idp-plugin-oidc-op-distribution-3.2.1.tar.gz --noPrompt +RUN /opt/shibboleth-idp/bin/module.sh -e idp.authn.RemoteUserInternal RUN /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u sig -i defaultRSASign | tail -n +2 > /opt/shibboleth-idp/credentials/idp-signing-rs.jwk RUN /opt/shibboleth-idp/bin/jwtgen.sh -t EC -c P-256 -u sig -i defaultECSign | tail -n +2 > /opt/shibboleth-idp/credentials/idp-signing-es.jwk RUN /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u enc -i defaultRSAEnc | tail -n +2 > /opt/shibboleth-idp/credentials/idp-encryption-rsa.jwk @@ -27,7 +28,7 @@ ADD ${TOMCERT} /opt/certs ADD ${TOMWWWROOT} /usr/local/tomcat/webapps/ROOT ADD ${SHBCFG} /opt/shibboleth-idp/conf #ADD ${SHBVIEWS} /opt/shibboleth-idp/views -#ADD ${SHBEDWAPP} /opt/shibboleth-idp/edit-webapp +ADD ${SHBEDWAPP} /opt/shibboleth-idp/edit-webapp #ADD ${SHBMSGS} /opt/shibboleth-idp/messages ADD ${SHBMD} /opt/shibboleth-idp/metadata ADD ${OIDCREG} /opt/shibboleth-idp/static diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/access-control.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/access-control.xml index e8215e441..5a0b0d14b 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/access-control.xml +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/access-control.xml @@ -28,20 +28,18 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties index c328309fb..b356a4574 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/idp.properties @@ -225,4 +225,4 @@ idp.ui.fallbackLanguages=en,fr,de # Set false if you want SAML bindings "spelled out" in audit log idp.audit.shortenBindings=true -#idp.loglevel.idp=DEBUG \ No newline at end of file +#idp.loglevel.idp=DEBUG diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-clientinfo-resolvers.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-clientinfo-resolvers.xml new file mode 100644 index 000000000..35cc7d853 --- /dev/null +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc-clientinfo-resolvers.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties index 50d713a94..09d6ebd60 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/oidc.properties @@ -2,6 +2,8 @@ idp.oidc.issuer = https://idp.unicon.local #Dynamic registration properties +idp.oidc.dynreg.StorageService=shibboleth.JPAStorageService + # The validity of registration before a new one is required. #idp.oidc.dynreg.defaultRegistrationValidity = PT24H # The validity of client secret registered @@ -101,16 +103,19 @@ idp.oidc.subject.salt = eezien3iteit0gaiciiweayohxahmai6 # Settings for issue-registration-access-token flow #idp.oidc.admin.registration.logging = IssueRegistrationAccessToken -#idp.oidc.admin.registration.nonBrowserSupported = true -#idp.oidc.admin.registration.authenticated = false +idp.oidc.admin.registration.nonBrowserSupported = true +idp.oidc.admin.registration.authenticated = true #idp.oidc.admin.registration.resolveAttributes = false #idp.oidc.admin.registration.lookup.policy = shibboleth.oidc.admin.DefaultMetadataPolicyLookupStrategy #idp.oidc.admin.registration.defaultTokenLifetime = P1D -#idp.oidc.admin.registration.accessPolicy = AccessByIPAddress +idp.oidc.admin.registration.accessPolicy = AccessByAdminUser #idp.oidc.admin.registration.policyLocationPolicy = AccessByAdmin -#idp.oidc.admin.registration.policyIdPolicy = AccessByAdmin +idp.oidc.admin.registration.policyIdPolicy = AccessByAdminUser #idp.oidc.admin.registration.clientIdPolicy = AccessByAdmin +idp.oidc.admin.clients.authenticated = true +idp.oidc.admin.clients.accessPolicy = AccessByAdminUser + # # OAuth2 Settings - these typically involve generic OAuth 2.0 use cases # diff --git a/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml b/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml index 84d406b7b..9227a1dfe 100644 --- a/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml +++ b/testbed/integration/shibboleth-idp/config/shib-idp/conf/relying-party.xml @@ -57,6 +57,7 @@ + diff --git a/testbed/integration/shibboleth-idp/db/oidc_dynreg.sql b/testbed/integration/shibboleth-idp/db/oidc_dynreg.sql new file mode 100644 index 000000000..ab60b941e --- /dev/null +++ b/testbed/integration/shibboleth-idp/db/oidc_dynreg.sql @@ -0,0 +1,10 @@ +CREATE DATABASE oidc_dynreg; +\c oidc_dynreg +CREATE TABLE storagerecords ( + context varchar(255) NOT NULL, + id varchar(255) NOT NULL, + expires bigint DEFAULT NULL, + value text NOT NULL, + version bigint NOT NULL, + PRIMARY KEY (context, id) +); From 45bd53706613e7b14050fec872581a66f46e4119 Mon Sep 17 00:00:00 2001 From: Sean Porth Date: Mon, 31 Oct 2022 15:54:46 -0400 Subject: [PATCH 10/93] update smoke-test to match changes from integration for oidc dynreg --- testbed/smoke-test/docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testbed/smoke-test/docker-compose.yml b/testbed/smoke-test/docker-compose.yml index 9e2ac5340..4332bfeed 100644 --- a/testbed/smoke-test/docker-compose.yml +++ b/testbed/smoke-test/docker-compose.yml @@ -45,6 +45,9 @@ services: POSTGRES_PASSWORD: shibui POSTGRES_USER: shibui POSTGRES_DB: shibui + volumes: + - database_data:/var/lib/postgresql/data + - ../integration/shibboleth-idp/db/oidc_dynreg.sql:/docker-entrypoint-initdb.d/oidc_dynreg.sql idp: build: ../integration/shibboleth-idp labels: @@ -56,9 +59,11 @@ services: depends_on: - directory - reverse-proxy + - database networks: - reverse-proxy - idp + - backend volumes: - dynamic_metadata:/opt/shibboleth-idp/metadata/dynamic - dynamic_config:/opt/shibboleth-idp/conf/dynamic From 49bc5120c08f82644ad94e019485bebb19b7a3a1 Mon Sep 17 00:00:00 2001 From: Sean Porth Date: Mon, 31 Oct 2022 16:04:07 -0400 Subject: [PATCH 11/93] update smoke-test to match changes from integration for oidc dynreg --- .../shibboleth-idp/conf/access-control.xml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/testbed/smoke-test/shibboleth-idp/conf/access-control.xml b/testbed/smoke-test/shibboleth-idp/conf/access-control.xml index 053bc22c7..37579c823 100644 --- a/testbed/smoke-test/shibboleth-idp/conf/access-control.xml +++ b/testbed/smoke-test/shibboleth-idp/conf/access-control.xml @@ -28,21 +28,20 @@ - - - - - + + + + + - + - - + - -