diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties
index 1c103c695..749267367 100644
--- a/backend/src/main/resources/i18n/messages.properties
+++ b/backend/src/main/resources/i18n/messages.properties
@@ -66,6 +66,10 @@ action.custom-entity-attributes=Custom Entity Attributes
 action.enable=Enable
 action.disable=Disable
 
+action.add-new-role=Add new role
+action.roles=Roles
+action.source-role=Role
+
 value.enabled=Enabled
 value.disabled=Disabled
 value.current=Current
@@ -483,6 +487,16 @@ label.by=By
 label.source=Metadata Source
 label.provider=Metadata Provider
 
+label.roles-management=Role Management
+label.new-role=New Role
+label.role-name=Role Name
+label.role-description=Role Description
+label.role=Role
+
+message.delete-role-title=Delete Role?
+
+message.delete-role-body=You are requesting to delete a role. If you complete this process the role will be removed. This cannot be undone. Do you wish to continue?
+
 message.delete-user-title=Delete User?
 message.delete-user-body=You are requesting to delete a user. If you complete this process the user will be removed. This cannot be undone. Do you wish to continue?
 
@@ -669,4 +683,7 @@ tooltip.match=A regular expression against which the entityID is evaluated.
 tooltip.remove-existing-formats=Whether to remove any existing formats from a role if any are added by the filter (unmodified roles will be untouched regardless of this setting)
 tooltip.nameid-formats-format=Format
 tooltip.nameid-formats-value=Value
-tooltip.nameid-formats-type=Type
\ No newline at end of file
+tooltip.nameid-formats-type=Type
+
+tooltip.role-name=Role Name
+tooltip.role-description=Role Description
\ No newline at end of file
diff --git a/ui/public/assets/schema/roles/role.json b/ui/public/assets/schema/roles/role.json
new file mode 100644
index 000000000..8145fae88
--- /dev/null
+++ b/ui/public/assets/schema/roles/role.json
@@ -0,0 +1,15 @@
+{
+    "type": "object",
+    "required": [
+        "name"
+    ],
+    "properties": {
+        "name": {
+            "title": "label.role-name",
+            "description": "tooltip.role-name",
+            "type": "string",
+            "minLength": 1,
+            "maxLength": 255
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/App.js b/ui/src/app/App.js
index 5d0c4e1e4..c65324bb9 100644
--- a/ui/src/app/App.js
+++ b/ui/src/app/App.js
@@ -26,6 +26,7 @@ import { NewProvider } from './metadata/new/NewProvider';
 import { Filter } from './metadata/Filter';
 import { Contention } from './metadata/contention/ContentionContext';
 import { SessionModal } from './core/user/SessionModal';
+import { Roles } from './admin/Roles';
 import Button from 'react-bootstrap/Button';
 
 
@@ -79,6 +80,7 @@ function App() {
                                                      
                                                      
                                                      
+                                                     
                                                     
                                                          
                                                      
diff --git a/ui/src/app/admin/Roles.js b/ui/src/app/admin/Roles.js
new file mode 100644
index 000000000..08daed90d
--- /dev/null
+++ b/ui/src/app/admin/Roles.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom';
+import { RolesProvider } from './hoc/RolesProvider';
+import { NewRole } from './container/NewRole';
+import { EditRole } from './container/EditRole';
+import { RoleList } from './container/RoleList';
+
+export function Roles() {
+
+    let { path } = useRouteMatch();
+
+    return (
+        <>
+            
+                
+                    
+                        {(roles, onDelete) =>
+                             
+                        }
+                     
+                } />
+                
+                     
+                } />
+                
+                     
+                } />
+                 
+                
+        >
+    );
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/component/RoleForm.js b/ui/src/app/admin/component/RoleForm.js
new file mode 100644
index 000000000..074cb5b09
--- /dev/null
+++ b/ui/src/app/admin/component/RoleForm.js
@@ -0,0 +1,68 @@
+import React from 'react';
+import Button from 'react-bootstrap/Button';
+import Form from '@rjsf/bootstrap-4';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faSpinner, faSave } from '@fortawesome/free-solid-svg-icons';
+import Translate from '../../i18n/components/translate';
+
+import { useRoleUiSchema } from '../hooks';
+import { fields, widgets } from '../../form/component';
+import { templates } from '../../form/component';
+import { FormContext, setFormDataAction, setFormErrorAction } from '../../form/FormManager';
+
+function ErrorListTemplate() {
+    return (<>>);
+}
+
+export function RoleForm({ role = {}, errors = [], loading = false, schema, onSave, onCancel }) {
+
+    const { dispatch } = React.useContext(FormContext);
+    const onChange = ({ formData, errors }) => {
+        dispatch(setFormDataAction(formData));
+        dispatch(setFormErrorAction(errors));
+    };
+
+    const uiSchema = useRoleUiSchema();
+
+    return (<>
+        
+            
+                
+                     onSave(role)}
+                        disabled={errors.length > 0 || loading}
+                        aria-label="Save changes to the metadata source. You will return to the dashboard">
+                          
+                        Save 
+                     
+                     onCancel()} aria-label="Cancel changes, go back to dashboard">
+                        Cancel 
+                     
+                 
+            
+            
+            
+        
 
+    >)
+}
+/**/
\ No newline at end of file
diff --git a/ui/src/app/admin/container/EditRole.js b/ui/src/app/admin/container/EditRole.js
new file mode 100644
index 000000000..cc8d802ed
--- /dev/null
+++ b/ui/src/app/admin/container/EditRole.js
@@ -0,0 +1,91 @@
+import React from 'react';
+
+import { Prompt, useHistory } from 'react-router';
+import { useParams } from 'react-router-dom';
+import Translate from '../../i18n/components/translate';
+import { useRoles } from '../hooks';
+import { Schema } from '../../form/Schema';
+import { FormManager } from '../../form/FormManager';
+
+import { RoleForm } from '../component/RoleForm';
+import { RoleProvider } from '../hoc/RoleProvider';
+import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications';
+import { useTranslator } from '../../i18n/hooks';
+
+export function EditRole() {
+
+    const { id } = useParams();
+
+    const notifier = useNotificationDispatcher();
+    const translator = useTranslator();
+
+    const history = useHistory();
+
+    const { put, response, loading } = useRoles();
+
+    const [blocking, setBlocking] = React.useState(false);
+
+    async function save(role) {
+        let toast;
+        const resp = await put(``, role);
+        if (response.ok) {
+            gotoDetail({ refresh: true });
+            toast = createNotificationAction(`Updated role 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(`/roles`, state);
+    };
+
+    return (
+        
+            
+                    `message.unsaved-editor`
+                }
+            />
+            
+                
+                
+                    
+                        {(role) =>
+                            
+                                {(schema) =>
+                                    <>{role &&
+                                        
+                                            {(data, errors) =>
+                                                 save(data)}
+                                                    onCancel={() => cancel()} />}
+                                          
+                                    }>}
+                             
+                        }
+                     
+                
+             
+          
+    );
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/container/MetadataActions.js b/ui/src/app/admin/container/MetadataActions.js
index 80f43d56a..4500354f4 100644
--- a/ui/src/app/admin/container/MetadataActions.js
+++ b/ui/src/app/admin/container/MetadataActions.js
@@ -1,5 +1,5 @@
 import React from 'react';
-import { DeleteConfirmation } from '../../metadata/component/DeleteConfirmation';
+import { DeleteConfirmation } from '../../core/components/DeleteConfirmation';
 import { useMetadataEntity } from '../../metadata/hooks/api';
 
 import { NotificationContext, createNotificationAction } from '../../notifications/hoc/Notifications';
diff --git a/ui/src/app/admin/container/NewRole.js b/ui/src/app/admin/container/NewRole.js
new file mode 100644
index 000000000..6d1abfc56
--- /dev/null
+++ b/ui/src/app/admin/container/NewRole.js
@@ -0,0 +1,79 @@
+import React from 'react';
+
+import { Prompt, useHistory } from 'react-router';
+import Translate from '../../i18n/components/translate';
+import { useRoles } from '../hooks';
+import { Schema } from '../../form/Schema';
+import { FormManager } from '../../form/FormManager';
+import { RoleForm } from '../component/RoleForm';
+
+import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications';
+import { useTranslator } from '../../i18n/hooks';
+
+export function NewRole() {
+    const history = useHistory();
+    const notifier = useNotificationDispatcher();
+    const translator = useTranslator();
+
+    const { post, response, loading } = useRoles({});
+
+    const [blocking, setBlocking] = React.useState(false);
+
+    async function save(role) {
+        let toast;
+        const resp = await post(``, role);
+        if (response.ok) {
+            gotoDetail({ refresh: true });
+            toast = createNotificationAction(`Added role 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(`/roles`, state);
+    };
+
+    return (
+        
+            
+                    `message.unsaved-editor`
+                }
+            />
+            
+                
+                
+                    
+                        {(schema) =>
+                            
+                                {(data, errors) =>
+                                     save(data)}
+                                        onCancel={() => cancel()} />}
+                              }
+                     
+                
+             
+          
+    );
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/container/RoleList.js b/ui/src/app/admin/container/RoleList.js
new file mode 100644
index 000000000..e48851f90
--- /dev/null
+++ b/ui/src/app/admin/container/RoleList.js
@@ -0,0 +1,78 @@
+import React from 'react';
+import { faEdit, faPlusCircle, faTrash } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import Button from 'react-bootstrap/Button';
+import { Link } from 'react-router-dom';
+
+import { Translate } from '../../i18n/components/translate';
+
+import { DeleteConfirmation } from '../../core/components/DeleteConfirmation';
+
+export function RoleList({ roles, onDelete }) {
+
+    const remove = (id) => {
+        onDelete(id);
+    }
+
+    return (
+        
+            {(block) =>
+                
+                    
+                        
+                            
+                                
+                                    Roles Management 
+                                 
+                            
+                            
+                                
+                                     
+                                           
+                                        Add new role 
+                                    
+                                
+                                
+                                    
+                                        
+                                            
+                                                
+                                                    Role Name 
+                                                 
+                                                Actions  
+                                             
+                                         
+                                        
+                                            {(roles?.length > 0) ? roles.map((role, i) =>
+                                                
+                                                    {role.name} 
+                                                    
+                                                         
+                                                             
+                                                            
+                                                                Edit 
+                                                             
+                                                        
+                                                         block(() => remove(role.resourceId))}>
+                                                             
+                                                            
+                                                                Delete 
+                                                             
+                                                         
+                                                     
+                                                 
+                                            ) : 
+                                                No roles defined. 
+                                             }
+                                         
+                                    
+                                
+                            
+                        
 
+                     
+                
 
+            }
+         
+    );
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/hoc/RoleProvider.js b/ui/src/app/admin/hoc/RoleProvider.js
new file mode 100644
index 000000000..091ac1bd6
--- /dev/null
+++ b/ui/src/app/admin/hoc/RoleProvider.js
@@ -0,0 +1,20 @@
+import React from 'react';
+import { useRole } from '../hooks';
+
+export function RoleProvider({ id, children }) {
+
+    const [role, setRole] = React.useState({id: 'foo'});
+    const { get, response } = useRole(id);
+
+    async function loadRole() {
+        const role = await get(``);
+        if (response.ok) {
+            setRole(role);
+        }
+    }
+
+    /*eslint-disable react-hooks/exhaustive-deps*/
+    React.useEffect(() => { loadRole() }, []);
+
+    return (<>{children(role)}>);
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/hoc/RoleProvider.test.js b/ui/src/app/admin/hoc/RoleProvider.test.js
new file mode 100644
index 000000000..9c063a41a
--- /dev/null
+++ b/ui/src/app/admin/hoc/RoleProvider.test.js
@@ -0,0 +1,35 @@
+import { render, screen } from "@testing-library/react";
+import { act } from 'react-dom/test-utils';
+import React from 'react';
+import {RoleProvider} from './RoleProvider';
+
+import {useRole} from '../hooks';
+
+jest.mock('../hooks');
+
+describe('RoleProvider component', () => {
+
+    beforeEach(() => {
+        useRole.mockImplementation(() => {
+            return {
+                get: jest.fn().mockResolvedValue({ id: 'foo' }),
+                response: {
+                    ok: false,
+                    status: 200
+                }
+            };
+        });
+    })
+
+    test('should provide the role context', async () => {
+        act(() => {
+            render(
+            {(role) => {role?.id}
}
+             );
+        });
+
+        expect(useRole).toHaveBeenCalled();
+        expect(screen.getByText('foo')).toBeInTheDocument();
+    });
+
+})
\ No newline at end of file
diff --git a/ui/src/app/admin/hoc/RolesProvider.js b/ui/src/app/admin/hoc/RolesProvider.js
new file mode 100644
index 000000000..e87d96539
--- /dev/null
+++ b/ui/src/app/admin/hoc/RolesProvider.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import { useRoles } from '../hooks';
+import { createNotificationAction, NotificationTypes, useNotificationDispatcher } from '../../notifications/hoc/Notifications';
+import { useTranslator } from '../../i18n/hooks';
+
+export function RolesProvider({ children, cache = 'no-cache' }) {
+
+    const [roles, setRoles] = React.useState([]);
+
+    const notifier = useNotificationDispatcher();
+    const translator = useTranslator();
+
+    const { get, del, response, loading } = useRoles({
+        cachePolicy: cache
+    });
+
+    async function loadRoles() {
+        const list = await get(``);
+        if (response.ok) {
+            setRoles(list);
+        }
+    }
+
+    async function removeRole(id) {
+        let toast;
+        const resp = await del(`/${id}`);
+        if (response.ok) {
+            loadRoles();
+            toast = createNotificationAction(`Deleted role successfully.`, NotificationTypes.SUCCESS);
+        } else {
+            toast = createNotificationAction(`${resp.errorCode} - ${translator(resp.errorMessage)}`, NotificationTypes.ERROR);
+        }
+        if (toast) {
+            notifier(toast);
+        }
+    }
+
+    /*eslint-disable react-hooks/exhaustive-deps*/
+    React.useEffect(() => { loadRoles() }, []);
+
+    return (<>{children(roles, removeRole, loading)}>);
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/hoc/RolesProvider.test.js b/ui/src/app/admin/hoc/RolesProvider.test.js
new file mode 100644
index 000000000..11c01481e
--- /dev/null
+++ b/ui/src/app/admin/hoc/RolesProvider.test.js
@@ -0,0 +1,43 @@
+import { render, screen } from "@testing-library/react";
+import { act } from 'react-dom/test-utils';
+import React from 'react';
+import { RolesProvider } from './RolesProvider';
+
+import { useRoles } from '../hooks';
+import { useNotificationDispatcher } from "../../notifications/hoc/Notifications";
+
+jest.mock('../hooks');
+
+jest.mock('../../notifications/hoc/Notifications');
+
+describe('RolesProvider component', () => {
+
+    beforeEach(() => {
+
+        useNotificationDispatcher.mockImplementation(() => {
+            return {};
+        });
+
+        useRoles.mockImplementation(() => {
+            return {
+                get: jest.fn().mockResolvedValue([]),
+                response: {
+                    ok: false,
+                    status: 200
+                }
+            };
+        });
+    })
+
+    test('should provide the roles context', async () => {
+        act(() => {
+            render(
+                {(roles) => {roles.length}
}
+             );
+        });
+
+        expect(useRoles).toHaveBeenCalled();
+        expect(screen.getByText('0')).toBeInTheDocument();
+    });
+
+})
\ No newline at end of file
diff --git a/ui/src/app/admin/hooks.js b/ui/src/app/admin/hooks.js
new file mode 100644
index 000000000..30e840dc8
--- /dev/null
+++ b/ui/src/app/admin/hooks.js
@@ -0,0 +1,16 @@
+import useFetch from 'use-http';
+import API_BASE_PATH from '../App.constant';
+
+export function useRoles(opts = { cachePolicy: 'no-cache' }) {
+    return useFetch(`${API_BASE_PATH}/admin/roles`, opts);
+}
+
+export function useRole(id) {
+    return useFetch(`${API_BASE_PATH}/admin/roles/${id}`, {
+        cachePolicy: 'no-cache'
+    });
+}
+
+export function useRoleUiSchema() {
+    return {};
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/hooks.test.js b/ui/src/app/admin/hooks.test.js
new file mode 100644
index 000000000..d739c9aa1
--- /dev/null
+++ b/ui/src/app/admin/hooks.test.js
@@ -0,0 +1,55 @@
+import {
+    useRoles,
+    useRole,
+} from './hooks';
+
+import useFetch from 'use-http';
+import API_BASE_PATH from '../App.constant';
+
+jest.mock('use-http');
+
+describe('api hooks', () => {
+
+    let mockPut;
+    let mockGet;
+
+    beforeEach(() => {
+
+        mockPut = jest.fn().mockResolvedValue({ response: { ok: true } });
+        mockGet = jest.fn().mockResolvedValue({ response: { ok: true } });
+
+        useFetch.mockImplementation(() => {
+            return {
+                request: {
+                    ok: true
+                },
+                put: mockPut,
+                get: mockGet,
+                error: null,
+                response: {
+                    status: 409
+                }
+            };
+        });
+    })
+
+    describe('useRoles', () => {
+        it('should call useFetch', () => {
+            const opts = {};
+            const roles = useRoles(opts);
+
+            expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/admin/roles`, opts)
+        });
+    });
+
+    describe('useRole', () => {
+        it('should call useFetch', () => {
+            const opts = {
+                cachePolicy: 'no-cache'
+            };
+            const role = useRole('foo');
+
+            expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/admin/roles/foo`, opts)
+        });
+    });
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/component/DeleteConfirmation.js b/ui/src/app/core/components/DeleteConfirmation.js
similarity index 93%
rename from ui/src/app/metadata/component/DeleteConfirmation.js
rename to ui/src/app/core/components/DeleteConfirmation.js
index a0f2f8c09..ac699063e 100644
--- a/ui/src/app/metadata/component/DeleteConfirmation.js
+++ b/ui/src/app/core/components/DeleteConfirmation.js
@@ -37,7 +37,7 @@ export function DeleteConfirmation({ children, body, title }) {
                 
                      
                     
-                        You are deleting an entity. This cannot be undone. Continue? 
+                        You are deleting an entity. This cannot be undone. Continue? 
                     
                  
                 
diff --git a/ui/src/app/metadata/component/DeleteConfirmation.test.js b/ui/src/app/core/components/DeleteConfirmation.test.js
similarity index 97%
rename from ui/src/app/metadata/component/DeleteConfirmation.test.js
rename to ui/src/app/core/components/DeleteConfirmation.test.js
index 8aa4a57ee..76abf8dd6 100644
--- a/ui/src/app/metadata/component/DeleteConfirmation.test.js
+++ b/ui/src/app/core/components/DeleteConfirmation.test.js
@@ -28,7 +28,7 @@ test('Delete confirmation', () => {
             
                 {(block) =>  block(() => noop())}> }
              ,
-        container);
+            container);
     });
 
     const initiator = container.querySelector('button');
diff --git a/ui/src/app/core/components/Header.js b/ui/src/app/core/components/Header.js
index 54d0c402c..b464dffe6 100644
--- a/ui/src/app/core/components/Header.js
+++ b/ui/src/app/core/components/Header.js
@@ -6,7 +6,7 @@ import Navbar from 'react-bootstrap/Navbar';
 import Dropdown from 'react-bootstrap/Dropdown';
 
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes } from '@fortawesome/free-solid-svg-icons';
+import { faTh, faSignOutAlt, faPlusCircle, faCube, faCubes, faUserTag } from '@fortawesome/free-solid-svg-icons';
 
 import Translate from '../../i18n/components/translate';
 import { useTranslator } from '../../i18n/hooks';
@@ -41,6 +41,10 @@ export function Header () {
                                  
                                  
                             
+                            
+                                 
+                                 
+                             
                         
                     
                     }
diff --git a/ui/src/app/core/components/UserConfirmation.test.js b/ui/src/app/core/components/UserConfirmation.test.js
index 9c2835d9b..58f73c3b8 100644
--- a/ui/src/app/core/components/UserConfirmation.test.js
+++ b/ui/src/app/core/components/UserConfirmation.test.js
@@ -1,5 +1,5 @@
 import React from 'react';
-import { act, render, fireEvent, waitFor, screen } from '@testing-library/react';
+import { render, fireEvent, screen } from '@testing-library/react';
 import { UserConfirmation, ConfirmWindow } from './UserConfirmation';
 
 jest.mock('../../i18n/hooks', () => ({
diff --git a/ui/src/app/form/FormManager.js b/ui/src/app/form/FormManager.js
new file mode 100644
index 000000000..41b39d520
--- /dev/null
+++ b/ui/src/app/form/FormManager.js
@@ -0,0 +1,105 @@
+import React from 'react';
+
+const initialState = {
+    data: {},
+    errors: []
+};
+
+const FormContext = React.createContext();
+
+const { Provider, Consumer } = FormContext;
+
+export const FormActions = {
+    SET_FORM_ERROR: 'set form error',
+    SET_FORM_DATA: 'set form data'
+};
+
+export const setFormDataAction = (payload) => {
+    return {
+        type: FormActions.SET_FORM_DATA,
+        payload
+    }
+}
+
+export const setFormErrorAction = (errors) => {
+    return {
+        type: FormActions.SET_FORM_ERROR,
+        payload: errors
+    }
+}
+
+function reducer(state, action) {
+    switch (action.type) {
+
+        case FormActions.SET_FORM_ERROR:
+            return {
+                ...state,
+                errors: action.payload
+            };
+        case FormActions.SET_FORM_DATA:
+            return {
+                ...state,
+                data: action.payload
+            };
+        default:
+            return state;
+    }
+}
+
+/*eslint-disable react-hooks/exhaustive-deps*/
+function FormManager({ children, initial = {} }) {
+
+    const data = {
+        ...initial
+    };
+
+    const [state, dispatch] = React.useReducer(reducer, {
+        ...initialState,
+        data
+    });
+    const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]);
+
+    return (
+        
+            {children(state.data, state.errors)} 
+         
+    );
+}
+
+function useFormErrors() {
+    const { state } = React.useContext(FormContext);
+    const { errors } = state;
+
+    return errors;
+}
+
+function useFormContext() {
+    return React.useContext(FormContext);
+}
+
+function useFormDispatcher() {
+    const { dispatch } = useFormContext();
+    return dispatch;
+}
+
+function useFormState() {
+    const { state } = useFormContext();
+    return state;
+}
+
+function useFormData() {
+    const { data } = useFormContext();
+    return data;
+}
+
+export {
+    useFormErrors,
+    useFormContext,
+    useFormDispatcher,
+    useFormState,
+    useFormData,
+    FormManager,
+    FormContext,
+    Provider as FormProvider,
+    Consumer as FormConsumer
+};
\ No newline at end of file
diff --git a/ui/src/app/form/Schema.js b/ui/src/app/form/Schema.js
new file mode 100644
index 000000000..92aefe325
--- /dev/null
+++ b/ui/src/app/form/Schema.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import useFetch from 'use-http';
+
+export function Schema({ path, children }) {
+
+    const [schema, setSchema] = React.useState({});
+
+
+    const { get, response } = useFetch(path, {
+        cachePolicy: 'no-cache'
+    });
+
+    async function loadSchema() {
+        const list = await get(``);
+        if (response.ok) {
+            setSchema(list);
+        }
+    }
+
+    /*eslint-disable react-hooks/exhaustive-deps*/
+    React.useEffect(() => { loadSchema() }, []);
+
+    return (<>{children(schema)}>);
+}
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/filter/component/MetadataFilters.js b/ui/src/app/metadata/domain/filter/component/MetadataFilters.js
index d38c97013..26c63f131 100644
--- a/ui/src/app/metadata/domain/filter/component/MetadataFilters.js
+++ b/ui/src/app/metadata/domain/filter/component/MetadataFilters.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { useMetadataFilters } from '../../../hooks/api';
-import { DeleteConfirmation } from '../../../component/DeleteConfirmation';
+import { DeleteConfirmation } from '../../../../core/components/DeleteConfirmation';
 import { NotificationContext, createNotificationAction } from '../../../../notifications/hoc/Notifications';
 
 export const MetadataFiltersContext = React.createContext();
diff --git a/ui/src/app/metadata/hooks/schema.js b/ui/src/app/metadata/hooks/schema.js
index ecde47f05..5083559b1 100644
--- a/ui/src/app/metadata/hooks/schema.js
+++ b/ui/src/app/metadata/hooks/schema.js
@@ -1,5 +1,4 @@
 import React from 'react';
-import { useIsAdmin } from '../../core/user/UserContext';
 
 export const fillInRootProperties = (keys, ui) => keys.reduce((sch, key, idx) => {
     if (!sch.hasOwnProperty(key)) {
@@ -31,21 +30,7 @@ export function useUiSchema(definition, schema, current, locked = true) {
         }
     ), [mapped, step.locked, locked]);
 
-    const isAdmin = useIsAdmin();
-
-    const hideEnableFromNonAdmins = React.useMemo(() => {
-        if (!isAdmin) {
-            return {
-                ...isLocked,
-                serviceEnabled: {
-                    'ui:widget': 'hidden'
-                }
-            };
-        }
-        return isLocked;
-    }, [isAdmin, isLocked]);
-
-    return { uiSchema: hideEnableFromNonAdmins, step};
+    return { uiSchema: isLocked, step};
 }
 
 
diff --git a/ui/src/app/metadata/view/MetadataAttributeList.js b/ui/src/app/metadata/view/MetadataAttributeList.js
index f585f805f..69e6754f6 100644
--- a/ui/src/app/metadata/view/MetadataAttributeList.js
+++ b/ui/src/app/metadata/view/MetadataAttributeList.js
@@ -8,7 +8,7 @@ import { Link } from 'react-router-dom';
 import { Translate } from '../../i18n/components/translate';
 import { useTranslator } from '../../i18n/hooks';
 
-import { DeleteConfirmation } from '../component/DeleteConfirmation';
+import { DeleteConfirmation } from '../../core/components/DeleteConfirmation';
 
 export function MetadataAttributeList ({entities, onDelete}) {
 
diff --git a/ui/src/testing/sourceSchema.js b/ui/src/testing/sourceSchema.js
index 93262c5f4..c723fd548 100644
--- a/ui/src/testing/sourceSchema.js
+++ b/ui/src/testing/sourceSchema.js
@@ -1,3 +1,3 @@
-const SCHEMA = { "type": "object", "required": ["serviceProviderName", "entityId"], "properties": { "serviceProviderName": { "title": "label.service-provider-name", "description": "tooltip.service-provider-name", "type": "string", "minLength": 1, "maxLength": 255 }, "entityId": { "title": "label.entity-id", "description": "tooltip.entity-id", "type": "string", "minLength": 1, "maxLength": 255 }, "serviceEnabled": { "title": "label.enable-this-service", "description": "tooltip.enable-this-service-upon-saving", "type": "boolean", "default": false }, "organization": { "$ref": "#/definitions/Organization" }, "contacts": { "title": "label.contact-information", "description": "tooltip.contact-information", "type": "array", "items": { "$ref": "#/definitions/Contact" } }, "mdui": { "$ref": "#/definitions/MDUI" }, "securityInfo": { "type": "object", "widget": { "id": "fieldset" }, "dependencies": { "authenticationRequestsSigned": { "oneOf": [{ "properties": { "authenticationRequestsSigned": { "enum": [true] }, "x509Certificates": { "minItems": 1 } } }, { "properties": { "authenticationRequestsSigned": { "enum": [false] }, "x509Certificates": { "minItems": 0 } } }] } }, "properties": { "x509CertificateAvailable": { "type": "boolean", "default": true }, "authenticationRequestsSigned": { "title": "label.authentication-requests-signed", "description": "tooltip.authentication-requests-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "wantAssertionsSigned": { "title": "label.want-assertions-signed", "description": "tooltip.want-assertions-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "x509Certificates": { "title": "label.x509-certificates", "type": "array", "items": { "$ref": "#/definitions/Certificate" } } } }, "assertionConsumerServices": { "title": "label.assertion-consumer-service-endpoints", "description": "", "type": "array", "items": { "$ref": "#/definitions/AssertionConsumerService" } }, "serviceProviderSsoDescriptor": { "type": "object", "properties": { "protocolSupportEnum": { "title": "label.protocol-support-enumeration", "description": "tooltip.protocol-support-enumeration", "type": "string", "widget": { "id": "select" }, "oneOf": [{ "enum": ["SAML 2"], "description": "SAML 2" }, { "enum": ["SAML 1.1"], "description": "SAML 1.1" }] }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" } }, "dependencies": { "nameIdFormats": ["protocolSupportEnum"] } }, "logoutEndpoints": { "title": "label.logout-endpoints", "description": "tooltip.logout-endpoints", "type": "array", "items": { "$ref": "#/definitions/LogoutEndpoint" } }, "relyingPartyOverrides": { "type": "object", "properties": { "signAssertion": { "title": "label.sign-the-assertion", "description": "tooltip.sign-assertion", "type": "boolean", "default": false }, "dontSignResponse": { "title": "label.dont-sign-the-response", "description": "tooltip.dont-sign-response", "type": "boolean", "default": false }, "turnOffEncryption": { "title": "label.turn-off-encryption-of-response", "description": "tooltip.turn-off-encryption", "type": "boolean", "default": false }, "useSha": { "title": "label.use-sha1-signing-algorithm", "description": "tooltip.usa-sha-algorithm", "type": "boolean", "default": false }, "ignoreAuthenticationMethod": { "title": "label.ignore-any-sp-requested-authentication-method", "description": "tooltip.ignore-auth-method", "type": "boolean", "default": false }, "omitNotBefore": { "title": "label.omit-not-before-condition", "description": "tooltip.omit-not-before-condition", "type": "boolean", "default": false }, "responderId": { "title": "label.responder-id", "description": "tooltip.responder-id", "type": "string", "default": "" }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" }, "authenticationMethods": { "$ref": "#/definitions/authenticationMethods" }, "forceAuthn": { "title": "label.force-authn", "description": "tooltip.force-authn", "type": "boolean", "default": false } } }, "attributeRelease": { "type": "array", "title": "label.attribute-release", "description": "Attribute release table - select the attributes you want to release (default unchecked)", "items": { "type": "string", "enum": ["eduPersonPrincipalName", "uid", "mail", "surname", "givenName", "eduPersonAffiliation", "eduPersonScopedAffiliation", "eduPersonPrimaryAffiliation", "eduPersonEntitlement", "eduPersonAssurance", "eduPersonUniqueId", "employeeNumber"] }, "uniqueItems": true } }, "definitions": { "Contact": { "type": "object", "required": ["name", "type", "emailAddress"], "properties": { "name": { "title": "label.contact-name", "description": "tooltip.contact-name", "type": "string", "minLength": 1, "maxLength": 255 }, "type": { "title": "label.contact-type", "description": "tooltip.contact-type", "type": "string", "widget": "select", "minLength": 1, "oneOf": [{ "enum": ["support"], "description": "value.support" }, { "enum": ["technical"], "description": "value.technical" }, { "enum": ["administrative"], "description": "value.administrative" }, { "enum": ["other"], "description": "value.other" }] }, "emailAddress": { "title": "label.contact-email-address", "description": "tooltip.contact-email", "type": "string", "pattern": "^(mailto:)?(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", "minLength": 1, "maxLength": 255 } } }, "Certificate": { "type": "object", "required": ["type", "value"], "properties": { "name": { "title": "label.certificate-name-display-only", "description": "tooltip.certificate-name", "type": "string", "maxLength": 255 }, "type": { "title": "label.certificate-type", "type": "string", "widget": { "id": "radio", "class": "form-check-inline" }, "oneOf": [{ "enum": ["signing"], "description": "value.signing" }, { "enum": ["encryption"], "description": "value.encryption" }, { "enum": ["both"], "description": "value.both" }] }, "value": { "title": "label.certificate", "description": "tooltip.certificate", "type": "string", "widget": "textarea", "minLength": 1 } } }, "AssertionConsumerService": { "type": "object", "required": ["locationUrl", "binding"], "properties": { "locationUrl": { "title": "label.assertion-consumer-service-location", "description": "tooltip.assertion-consumer-service-location", "type": "string", "widget": { "id": "string", "help": "message.valid-url" }, "minLength": 1, "maxLength": 255 }, "binding": { "title": "label.assertion-consumer-service-location-binding", "description": "tooltip.assertion-consumer-service-location-binding", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:PAOS"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:PAOS" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:browser-post"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:browser-post" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" }] }, "makeDefault": { "title": "label.mark-as-default", "description": "tooltip.mark-as-default", "type": "boolean" } } }, "LogoutEndpoint": { "description": "tooltip.new-endpoint", "type": "object", "fieldsets": [{ "fields": ["url", "bindingType"] }], "required": ["url", "bindingType"], "properties": { "url": { "title": "label.url", "description": "tooltip.url", "type": "string", "minLength": 1, "maxLength": 255 }, "bindingType": { "title": "label.binding-type", "description": "tooltip.binding-type", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:SOAP"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }] } } }, "MDUI": { "type": "object", "widget": { "id": "fieldset" }, "fieldsets": [{ "type": "group", "fields": ["displayName", "informationUrl", "description"] }, { "type": "group", "fields": ["privacyStatementUrl", "logoUrl", "logoWidth", "logoHeight"] }], "properties": { "displayName": { "title": "label.display-name", "description": "tooltip.mdui-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "informationUrl": { "title": "label.information-url", "description": "tooltip.mdui-information-url", "type": "string", "minLength": 1, "maxLength": 255 }, "privacyStatementUrl": { "title": "label.privacy-statement-url", "description": "tooltip.mdui-privacy-statement-url", "type": "string", "minLength": 1, "maxLength": 255 }, "description": { "title": "label.description", "description": "tooltip.mdui-description", "type": "string", "widget": { "id": "textarea" }, "minLength": 1, "maxLength": 255 }, "logoUrl": { "title": "label.logo-url", "description": "tooltip.mdui-logo-url", "type": "string", "minLength": 1, "maxLength": 255 }, "logoHeight": { "title": "label.logo-height", "description": "tooltip.mdui-logo-height", "minimum": 0, "type": "integer" }, "logoWidth": { "title": "label.logo-width", "description": "tooltip.mdui-logo-width", "minimum": 0, "type": "integer" } } }, "Organization": { "type": "object", "properties": { "name": { "title": "label.organization-name", "description": "tooltip.organization-name", "type": "string", "minLength": 1, "maxLength": 255 }, "displayName": { "title": "label.organization-display-name", "description": "tooltip.organization-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "url": { "title": "label.organization-url", "description": "tooltip.organization-url", "type": "string", "minLength": 1, "maxLength": 255 } }, "dependencies": { "name": { "required": ["displayName", "url"] }, "displayName": { "required": ["name", "url"] }, "url": { "required": ["name", "displayName"] } } }, "nameIdFormats": { "title": "label.nameid-format-to-send", "description": "tooltip.nameid-format", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] } }, "authenticationMethods": { "title": "label.authentication-methods-to-use", "description": "tooltip.authentication-methods-to-use", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["https://refeds.org/profile/mfa", "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken", "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"] } } } };
+const SCHEMA = { "type": "object", "required": ["serviceProviderName", "entityId"], "properties": { "serviceProviderName": { "title": "label.service-provider-name", "description": "tooltip.service-provider-name", "type": "string", "minLength": 1, "maxLength": 255 }, "entityId": { "title": "label.entity-id", "description": "tooltip.entity-id", "type": "string", "minLength": 1, "maxLength": 255 }, "organization": { "$ref": "#/definitions/Organization" }, "contacts": { "title": "label.contact-information", "description": "tooltip.contact-information", "type": "array", "items": { "$ref": "#/definitions/Contact" } }, "mdui": { "$ref": "#/definitions/MDUI" }, "securityInfo": { "type": "object", "widget": { "id": "fieldset" }, "dependencies": { "authenticationRequestsSigned": { "oneOf": [{ "properties": { "authenticationRequestsSigned": { "enum": [true] }, "x509Certificates": { "minItems": 1 } } }, { "properties": { "authenticationRequestsSigned": { "enum": [false] }, "x509Certificates": { "minItems": 0 } } }] } }, "properties": { "x509CertificateAvailable": { "type": "boolean", "default": true }, "authenticationRequestsSigned": { "title": "label.authentication-requests-signed", "description": "tooltip.authentication-requests-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "wantAssertionsSigned": { "title": "label.want-assertions-signed", "description": "tooltip.want-assertions-signed", "type": "boolean", "enumNames": ["value.true", "value.false"] }, "x509Certificates": { "title": "label.x509-certificates", "type": "array", "items": { "$ref": "#/definitions/Certificate" } } } }, "assertionConsumerServices": { "title": "label.assertion-consumer-service-endpoints", "description": "", "type": "array", "items": { "$ref": "#/definitions/AssertionConsumerService" } }, "serviceProviderSsoDescriptor": { "type": "object", "properties": { "protocolSupportEnum": { "title": "label.protocol-support-enumeration", "description": "tooltip.protocol-support-enumeration", "type": "string", "widget": { "id": "select" }, "oneOf": [{ "enum": ["SAML 2"], "description": "SAML 2" }, { "enum": ["SAML 1.1"], "description": "SAML 1.1" }] }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" } }, "dependencies": { "nameIdFormats": ["protocolSupportEnum"] } }, "logoutEndpoints": { "title": "label.logout-endpoints", "description": "tooltip.logout-endpoints", "type": "array", "items": { "$ref": "#/definitions/LogoutEndpoint" } }, "relyingPartyOverrides": { "type": "object", "properties": { "signAssertion": { "title": "label.sign-the-assertion", "description": "tooltip.sign-assertion", "type": "boolean", "default": false }, "dontSignResponse": { "title": "label.dont-sign-the-response", "description": "tooltip.dont-sign-response", "type": "boolean", "default": false }, "turnOffEncryption": { "title": "label.turn-off-encryption-of-response", "description": "tooltip.turn-off-encryption", "type": "boolean", "default": false }, "useSha": { "title": "label.use-sha1-signing-algorithm", "description": "tooltip.usa-sha-algorithm", "type": "boolean", "default": false }, "ignoreAuthenticationMethod": { "title": "label.ignore-any-sp-requested-authentication-method", "description": "tooltip.ignore-auth-method", "type": "boolean", "default": false }, "omitNotBefore": { "title": "label.omit-not-before-condition", "description": "tooltip.omit-not-before-condition", "type": "boolean", "default": false }, "responderId": { "title": "label.responder-id", "description": "tooltip.responder-id", "type": "string", "default": "" }, "nameIdFormats": { "$ref": "#/definitions/nameIdFormats" }, "authenticationMethods": { "$ref": "#/definitions/authenticationMethods" }, "forceAuthn": { "title": "label.force-authn", "description": "tooltip.force-authn", "type": "boolean", "default": false } } }, "attributeRelease": { "type": "array", "title": "label.attribute-release", "description": "Attribute release table - select the attributes you want to release (default unchecked)", "items": { "type": "string", "enum": ["eduPersonPrincipalName", "uid", "mail", "surname", "givenName", "eduPersonAffiliation", "eduPersonScopedAffiliation", "eduPersonPrimaryAffiliation", "eduPersonEntitlement", "eduPersonAssurance", "eduPersonUniqueId", "employeeNumber"] }, "uniqueItems": true } }, "definitions": { "Contact": { "type": "object", "required": ["name", "type", "emailAddress"], "properties": { "name": { "title": "label.contact-name", "description": "tooltip.contact-name", "type": "string", "minLength": 1, "maxLength": 255 }, "type": { "title": "label.contact-type", "description": "tooltip.contact-type", "type": "string", "widget": "select", "minLength": 1, "oneOf": [{ "enum": ["support"], "description": "value.support" }, { "enum": ["technical"], "description": "value.technical" }, { "enum": ["administrative"], "description": "value.administrative" }, { "enum": ["other"], "description": "value.other" }] }, "emailAddress": { "title": "label.contact-email-address", "description": "tooltip.contact-email", "type": "string", "pattern": "^(mailto:)?(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$", "minLength": 1, "maxLength": 255 } } }, "Certificate": { "type": "object", "required": ["type", "value"], "properties": { "name": { "title": "label.certificate-name-display-only", "description": "tooltip.certificate-name", "type": "string", "maxLength": 255 }, "type": { "title": "label.certificate-type", "type": "string", "widget": { "id": "radio", "class": "form-check-inline" }, "oneOf": [{ "enum": ["signing"], "description": "value.signing" }, { "enum": ["encryption"], "description": "value.encryption" }, { "enum": ["both"], "description": "value.both" }] }, "value": { "title": "label.certificate", "description": "tooltip.certificate", "type": "string", "widget": "textarea", "minLength": 1 } } }, "AssertionConsumerService": { "type": "object", "required": ["locationUrl", "binding"], "properties": { "locationUrl": { "title": "label.assertion-consumer-service-location", "description": "tooltip.assertion-consumer-service-location", "type": "string", "widget": { "id": "string", "help": "message.valid-url" }, "minLength": 1, "maxLength": 255 }, "binding": { "title": "label.assertion-consumer-service-location-binding", "description": "tooltip.assertion-consumer-service-location-binding", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:PAOS"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:PAOS" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:browser-post"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:browser-post" }, { "enum": ["urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"], "description": "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" }] }, "makeDefault": { "title": "label.mark-as-default", "description": "tooltip.mark-as-default", "type": "boolean" } } }, "LogoutEndpoint": { "description": "tooltip.new-endpoint", "type": "object", "fieldsets": [{ "fields": ["url", "bindingType"] }], "required": ["url", "bindingType"], "properties": { "url": { "title": "label.url", "description": "tooltip.url", "type": "string", "minLength": 1, "maxLength": 255 }, "bindingType": { "title": "label.binding-type", "description": "tooltip.binding-type", "type": "string", "widget": "select", "oneOf": [{ "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:SOAP"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" }, { "enum": ["urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"], "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" }] } } }, "MDUI": { "type": "object", "widget": { "id": "fieldset" }, "fieldsets": [{ "type": "group", "fields": ["displayName", "informationUrl", "description"] }, { "type": "group", "fields": ["privacyStatementUrl", "logoUrl", "logoWidth", "logoHeight"] }], "properties": { "displayName": { "title": "label.display-name", "description": "tooltip.mdui-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "informationUrl": { "title": "label.information-url", "description": "tooltip.mdui-information-url", "type": "string", "minLength": 1, "maxLength": 255 }, "privacyStatementUrl": { "title": "label.privacy-statement-url", "description": "tooltip.mdui-privacy-statement-url", "type": "string", "minLength": 1, "maxLength": 255 }, "description": { "title": "label.description", "description": "tooltip.mdui-description", "type": "string", "widget": { "id": "textarea" }, "minLength": 1, "maxLength": 255 }, "logoUrl": { "title": "label.logo-url", "description": "tooltip.mdui-logo-url", "type": "string", "minLength": 1, "maxLength": 255 }, "logoHeight": { "title": "label.logo-height", "description": "tooltip.mdui-logo-height", "minimum": 0, "type": "integer" }, "logoWidth": { "title": "label.logo-width", "description": "tooltip.mdui-logo-width", "minimum": 0, "type": "integer" } } }, "Organization": { "type": "object", "properties": { "name": { "title": "label.organization-name", "description": "tooltip.organization-name", "type": "string", "minLength": 1, "maxLength": 255 }, "displayName": { "title": "label.organization-display-name", "description": "tooltip.organization-display-name", "type": "string", "minLength": 1, "maxLength": 255 }, "url": { "title": "label.organization-url", "description": "tooltip.organization-url", "type": "string", "minLength": 1, "maxLength": 255 } }, "dependencies": { "name": { "required": ["displayName", "url"] }, "displayName": { "required": ["name", "url"] }, "url": { "required": ["name", "displayName"] } } }, "nameIdFormats": { "title": "label.nameid-format-to-send", "description": "tooltip.nameid-format", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] } }, "authenticationMethods": { "title": "label.authentication-methods-to-use", "description": "tooltip.authentication-methods-to-use", "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1, "maxLength": 255, "examples": ["https://refeds.org/profile/mfa", "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken", "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"] } } } };
 
 export default SCHEMA;
\ No newline at end of file
diff --git a/ui/src/testing/uiSchema.js b/ui/src/testing/uiSchema.js
index eb557bcf2..c1af6f4fa 100644
--- a/ui/src/testing/uiSchema.js
+++ b/ui/src/testing/uiSchema.js
@@ -11,7 +11,6 @@ const schema = {
                 "fields": [
                     "serviceProviderName",
                     "entityId",
-                    "serviceEnabled",
                     "organization"
                 ]
             },
@@ -208,7 +207,6 @@ const schema = {
     },
     "serviceProviderName": {},
     "entityId": {},
-    "serviceEnabled": {},
     "organization": {},
     "ui:disabled": false
 };