diff --git a/backend/build.gradle b/backend/build.gradle index 71ab2c763..83d2c8dd8 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -331,6 +331,12 @@ task generateSources { processLine(it['@className'].toString(), 'src/main/templates/AlgorithmBuilderTemplate.java') } } + + new XmlSlurper().parse(file('src/main/resources/jpa-signature-config.xml')).with { builders -> + builders.ObjectProviders.ObjectProvider.BuilderClass.each { + processLine(it['@className'].toString(), 'src/main/templates/SignatureBuilderTemplate.java') + } + } } } diff --git a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy index 363f1a06f..beb593a70 100644 --- a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy +++ b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy @@ -157,6 +157,7 @@ class SeleniumSIDETest extends Specification { 'SHIBUI-1674: Verify metadata source tooltips' | '/SHIBUI-1674-1.side' 'SHIBUI-1674: Verify metadata provider tooltips' | '/SHIBUI-1674-2.side' 'SHIBUI-1674: Verify advanced menu tooltips' | '/SHIBUI-1674-3.side' + 'SHIBUI-2268: Verify Algorithm Filter' | '/SHIBUI-2268.side' 'SHIBUI-2269: Verify XML generation of external filters' | '/SHIBUI-2269.side' } } diff --git a/backend/src/integration/resources/SHIBUI-2268.side b/backend/src/integration/resources/SHIBUI-2268.side new file mode 100644 index 000000000..a9533b8c8 --- /dev/null +++ b/backend/src/integration/resources/SHIBUI-2268.side @@ -0,0 +1,995 @@ +{ + "id": "1b31a551-eb09-4bd4-8db9-694bf1539a46", + "version": "2.0", + "name": "SHIBUI-2268", + "url": "http://localhost:10101", + "tests": [{ + "id": "841ade0e-83bd-4a4b-94f2-de6bd5c536b2", + "name": "SHIBUI-2268", + "commands": [{ + "id": "d6b23986-6d14-4b10-be7b-a7e6f576e3b2", + "comment": "", + "command": "open", + "target": "/login", + "targets": [], + "value": "" + }, { + "id": "f77ecd77-01c2-4463-944e-1a69600f5297", + "comment": "", + "command": "type", + "target": "name=username", + "targets": [ + ["name=username", "name"], + ["css=tr:nth-child(1) input", "css:finder"], + ["xpath=//input[@name='username']", "xpath:attributes"], + ["xpath=//input", "xpath:position"] + ], + "value": "admin" + }, { + "id": "c9bf0a22-faa9-494c-b2ed-6c9653248551", + "comment": "", + "command": "type", + "target": "name=password", + "targets": [ + ["name=password", "name"], + ["css=tr:nth-child(2) input", "css:finder"], + ["xpath=//input[@name='password']", "xpath:attributes"], + ["xpath=//tr[2]/td[2]/input", "xpath:position"] + ], + "value": "adminpass" + }, { + "id": "7ab1d854-3582-4101-bd19-f94b8f438090", + "comment": "", + "command": "sendKeys", + "target": "name=password", + "targets": [ + ["name=password", "name"], + ["css=tr:nth-child(2) input", "css:finder"], + ["xpath=//input[@name='password']", "xpath:attributes"], + ["xpath=//tr[2]/td[2]/input", "xpath:position"] + ], + "value": "${KEY_ENTER}" + }, { + "id": "4059cae7-b9f9-49d0-a213-343bcaba66d1", + "comment": "", + "command": "waitForElementVisible", + "target": "id=metadata-nav-dropdown-toggle", + "targets": [], + "value": "30000" + }, { + "id": "f03af8d5-5875-4a2c-b93a-c3ddcbd4b16a", + "comment": "", + "command": "open", + "target": "/api/heheheheheheheWipeout", + "targets": [], + "value": "" + }, { + "id": "081f495b-4d84-4758-824c-1e85b6311e7f", + "comment": "", + "command": "assertText", + "target": "css=body", + "targets": [], + "value": "yes, you did it" + }, { + "id": "9e912dd5-6ace-45be-bafd-2d1655906575", + "comment": "", + "command": "open", + "target": "/", + "targets": [], + "value": "" + }, { + "id": "ad3811ad-f95b-4cca-a5d9-63a10063a652", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-toggle", + "targets": [ + ["id=metadata-nav-dropdown-toggle", "id"], + ["css=#metadata-nav-dropdown-toggle", "css:finder"], + ["xpath=//button[@id='metadata-nav-dropdown-toggle']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/button", "xpath:idRelative"], + ["xpath=//div[2]/button", "xpath:position"], + ["xpath=//button[contains(.,'Add New')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "c47bd884-187f-4702-9a9d-0155cf2c61a0", + "comment": "", + "command": "click", + "target": "id=metadata-nav-dropdown-provider", + "targets": [ + ["id=metadata-nav-dropdown-provider", "id"], + ["linkText=Add a new metadata provider", "linkText"], + ["css=#metadata-nav-dropdown-provider", "css:finder"], + ["xpath=//a[contains(text(),'Add a new metadata provider')]", "xpath:link"], + ["xpath=//a[@id='metadata-nav-dropdown-provider']", "xpath:attributes"], + ["xpath=//div[@id='metadata-nav-dropdown']/div/a[2]", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/new')]", "xpath:href"], + ["xpath=//a[2]", "xpath:position"], + ["xpath=//a[contains(.,'Add a new metadata provider')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "14908519-6a02-48db-b35c-c31895bbc693", + "comment": "", + "command": "type", + "target": "name=name", + "targets": [ + ["name=name", "name"], + ["css=.form-control", "css:finder"], + ["xpath=//input[@name='name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/div/form/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "FBHMR" + }, { + "id": "60f88cda-2d8a-4921-b712-9bfde45ae64d", + "comment": "", + "command": "select", + "target": "name=type", + "targets": [], + "value": "label=FileBackedHttpMetadataResolver" + }, { + "id": "8f939d91-fb81-4cb6-a37e-3d6bbca9c2e7", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/nav/ul/li[2]/button/span", "xpath:idRelative"], + ["xpath=//li[2]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'2. Common Attributes')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "a17b7150-4228-4301-a996-18eb930b553d", + "comment": "", + "command": "type", + "target": "id=root_xmlId", + "targets": [ + ["id=root_xmlId", "id"], + ["css=#root_xmlId", "css:finder"], + ["xpath=//input[@id='root_xmlId']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[2]/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "1" + }, { + "id": "8fd7f246-f96f-40eb-b899-7dfda17b3113", + "comment": "", + "command": "type", + "target": "id=root_metadataURL", + "targets": [ + ["id=root_metadataURL", "id"], + ["css=#root_metadataURL", "css:finder"], + ["xpath=//input[@id='root_metadataURL']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[2]/div[2]/div/div/input", "xpath:idRelative"], + ["xpath=//div[2]/div/div/input", "xpath:position"] + ], + "value": "https://idp.unicon.net/idp/shibboleth" + }, { + "id": "a056da7c-811f-47b5-894f-fd110aac9ec5", + "comment": "", + "command": "type", + "target": "id=root_backingFile", + "targets": [ + ["id=root_backingFile", "id"], + ["css=#root_backingFile", "css:finder"], + ["xpath=//input[@id='root_backingFile']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[2]/div[4]/div/div/input", "xpath:idRelative"], + ["xpath=//div[4]/div/div/input", "xpath:position"] + ], + "value": "%{idp.home}/foo" + }, { + "id": "57bf7cfe-5677-4a44-ae97-afa123b56d17", + "comment": "", + "command": "click", + "target": "id=option-selector-root_backupFileInitNextRefreshDelay", + "targets": [ + ["id=option-selector-root_backupFileInitNextRefreshDelay", "id"], + ["css=#option-selector-root_backupFileInitNextRefreshDelay", "css:finder"], + ["xpath=//input[@id='option-selector-root_backupFileInitNextRefreshDelay']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[2]/div[5]/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//div[5]/div/div/div/div/input", "xpath:position"] + ], + "value": "" + }, { + "id": "2941c513-6f49-4681-af06-4e8cdb9916d2", + "comment": "", + "command": "click", + "target": "id=option-selector-items-root_backupFileInitNextRefreshDelay-item-2", + "targets": [ + ["id=option-selector-items-root_backupFileInitNextRefreshDelay-item-2", "id"], + ["linkText=PT30S", "linkText"], + ["css=#option-selector-items-root_backupFileInitNextRefreshDelay-item-2", "css:finder"], + ["xpath=//a[@id='option-selector-items-root_backupFileInitNextRefreshDelay-item-2']", "xpath:attributes"], + ["xpath=//div[@id='option-selector-items-root_backupFileInitNextRefreshDelay']/a[3]", "xpath:idRelative"], + ["xpath=(//a[contains(@href, '#')])[3]", "xpath:href"], + ["xpath=//a[3]", "xpath:position"], + ["xpath=//a[contains(.,'PT30S')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "bef48138-60ec-44e5-b9f9-72ad9280edfb", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'3. Reloading Attributes')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2c6543c6-b4c6-42a8-8960-92955125635f", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'4. Metadata Filter Plugins')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "f309e7b3-5379-45c3-9dc2-93c9a98f4d48", + "comment": "", + "command": "click", + "target": "css=.next", + "targets": [ + ["css=.label:nth-child(1)", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div/nav/ul/li[3]/button/span", "xpath:idRelative"], + ["xpath=//li[3]/button/span", "xpath:position"], + ["xpath=//span[contains(.,'5. Finished!')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "a844a1e3-61c3-4b09-9923-0dd29b1ae090", + "comment": "", + "command": "click", + "target": "css=.save", + "targets": [], + "value": "" + }, { + "id": "f49a10af-88be-447f-84a5-a47126158a72", + "comment": "", + "command": "click", + "target": "linkText=FBHMR", + "targets": [ + ["linkText=FBHMR", "linkText"], + ["css=.align-middle > a", "css:finder"], + ["xpath=//a[contains(text(),'FBHMR')]", "xpath:link"], + ["xpath=//div[@id='root']/div/main/div/section/div/div[2]/div/div/div/table/tbody/tr/td[2]/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/b5adf5e8-a494-49c8-ae1b-5e9cb2e4acc4/configuration/options')]", "xpath:href"], + ["xpath=//td[2]/a", "xpath:position"], + ["xpath=//a[contains(.,'FBHMR')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "1cb419ae-3b96-486e-bb7d-326d6116b7f7", + "comment": "", + "command": "click", + "target": "css=.btn-link:nth-child(2)", + "targets": [ + ["css=.btn-link:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='navigation']/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Filters')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "88556432-8cdb-4cd3-a933-28db3b7b1c8f", + "comment": "", + "command": "click", + "target": "linkText=Add Filter", + "targets": [ + ["linkText=Add Filter", "linkText"], + ["css=#filters .btn", "css:finder"], + ["xpath=//div[@id='filters']/div/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/b5adf5e8-a494-49c8-ae1b-5e9cb2e4acc4/filter/new')]", "xpath:href"], + ["xpath=//div[3]/div/div/a", "xpath:position"], + ["xpath=//a[contains(.,' Add Filter')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "60f8b3ce-19af-4369-9246-a81cf6b3728d", + "comment": "", + "command": "select", + "target": "name=type", + "targets": [], + "value": "label=Algorithm" + }, { + "id": "54495332-08c2-4e37-8898-99346632de5b", + "comment": "", + "command": "waitForElementEditable", + "target": "id=root_name", + "targets": [], + "value": "30000" + }, { + "id": "dbf26501-319b-4a0e-9b94-a2b47a8a863c", + "comment": "", + "command": "type", + "target": "id=root_name", + "targets": [ + ["id=root_name", "id"], + ["css=#root_name", "css:finder"], + ["xpath=//input[@id='root_name']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//input", "xpath:position"] + ], + "value": "Algorithm Test" + }, { + "id": "b89fdf2c-c5cc-468d-a88f-56fd752235df", + "comment": "", + "command": "type", + "target": "css=.rbt-input-main", + "targets": [ + ["css=.rbt-input-main", "css:finder"], + ["xpath=//input[@value='foo']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[3]/div/div/div/fieldset/div/div/div[2]/div/div/div/div/input", "xpath:idRelative"], + ["xpath=//div[2]/div/div/div/div/input", "xpath:position"] + ], + "value": "foo" + }, { + "id": "450646dd-2c5f-4b55-ae70-0971f75cf1da", + "comment": "", + "command": "click", + "target": "css=.btn-success", + "targets": [ + ["css=.btn-success", "css:finder"], + ["xpath=(//button[@type='button'])[19]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[3]/div/div/div/fieldset/div/div/div[2]/div/div[2]/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div[2]/button", "xpath:position"], + ["xpath=//button[contains(.,'Add Entity ID  ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "3d3041ca-b6e4-45fd-8394-1f129e3ec160", + "comment": "", + "command": "click", + "target": "css=.nav-link:nth-child(2)", + "targets": [ + ["css=.nav-link:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[10]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div/nav/button[2]", "xpath:idRelative"], + ["xpath=//nav/button[2]", "xpath:position"], + ["xpath=//button[contains(.,'Options')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "f69c47c5-cea9-4a01-9388-6e03279db488", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "0e591beb-3feb-4a0f-9746-0d77487ab083", + "comment": "", + "command": "click", + "target": "id=root_algorithms_0", + "targets": [ + ["id=root_algorithms_0", "id"], + ["css=#root_algorithms_0", "css:finder"], + ["xpath=//select[@id='root_algorithms_0']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "cf2b807b-4c0a-4a23-aeda-3b7865de2b96", + "comment": "", + "command": "select", + "target": "id=root_algorithms_0", + "targets": [], + "value": "label=GCM (256) - http://www.w3.org/2009/xmlenc11#aes256-gcm" + }, { + "id": "fe50f455-a2c5-492a-900c-41b2c4a4373b", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "e5789dd9-8e03-4eda-be7d-32d495b8d4a5", + "comment": "", + "command": "click", + "target": "id=root_algorithms_1", + "targets": [ + ["id=root_algorithms_1", "id"], + ["css=#root_algorithms_1", "css:finder"], + ["xpath=//select[@id='root_algorithms_1']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[2]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[2]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "0fb47623-654b-4dd1-8b03-d273cba16502", + "comment": "", + "command": "select", + "target": "id=root_algorithms_1", + "targets": [], + "value": "label=GCM (192) - http://www.w3.org/2009/xmlenc11#aes192-gcm" + }, { + "id": "579e8683-e6a9-4630-92ae-8d61885d355f", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "27c7a598-679e-450a-a71a-ecdc258ad45c", + "comment": "", + "command": "click", + "target": "id=root_algorithms_2", + "targets": [ + ["id=root_algorithms_2", "id"], + ["css=#root_algorithms_2", "css:finder"], + ["xpath=//select[@id='root_algorithms_2']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[3]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[3]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "7498fe45-5fda-49c1-bca7-2f4954346fae", + "comment": "", + "command": "select", + "target": "id=root_algorithms_2", + "targets": [], + "value": "label=GCM (128) - http://www.w3.org/2009/xmlenc11#aes128-gcm" + }, { + "id": "d777d547-3614-4a3c-99c6-dcffffea4400", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "e1145572-f207-415e-8908-500bf348e750", + "comment": "", + "command": "click", + "target": "id=root_algorithms_3", + "targets": [ + ["id=root_algorithms_3", "id"], + ["css=#root_algorithms_3", "css:finder"], + ["xpath=//select[@id='root_algorithms_3']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[4]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[4]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "d4bb89e3-f855-4ca3-9ea3-941e93219a29", + "comment": "", + "command": "select", + "target": "id=root_algorithms_3", + "targets": [], + "value": "label=CBC (256) - http://www.w3.org/2001/04/xmlenc#aes256-cbc" + }, { + "id": "b8b5241d-0712-469c-aaec-bbaf0db9ec39", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "f4b10a72-9ef4-465f-9c3c-39a8e555a748", + "comment": "", + "command": "click", + "target": "id=root_algorithms_4", + "targets": [ + ["id=root_algorithms_4", "id"], + ["css=#root_algorithms_4", "css:finder"], + ["xpath=//select[@id='root_algorithms_4']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[5]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[5]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "03ed33bd-f797-4608-83bd-ff328054cd94", + "comment": "", + "command": "select", + "target": "id=root_algorithms_4", + "targets": [], + "value": "label=CBC (192) - http://www.w3.org/2001/04/xmlenc#aes192-cbc" + }, { + "id": "209015c5-5aef-448b-b297-6c1269f3c6e3", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2085d727-c9fc-42cd-a233-4fad48a20e78", + "comment": "", + "command": "click", + "target": "id=root_algorithms_5", + "targets": [ + ["id=root_algorithms_5", "id"], + ["css=#root_algorithms_5", "css:finder"], + ["xpath=//select[@id='root_algorithms_5']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[6]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[6]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "537feda7-72d7-4fd6-b680-c733f3577a54", + "comment": "", + "command": "select", + "target": "id=root_algorithms_5", + "targets": [], + "value": "label=CBC (128) - http://www.w3.org/2001/04/xmlenc#aes128-cbc" + }, { + "id": "ad4084f8-cb8c-46e1-b949-c55ae8d6498c", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "cfbf52c7-4303-40d1-bf43-4bd4abb23785", + "comment": "", + "command": "click", + "target": "id=root_algorithms_6", + "targets": [ + ["id=root_algorithms_6", "id"], + ["css=#root_algorithms_6", "css:finder"], + ["xpath=//select[@id='root_algorithms_6']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[7]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "8053bff4-b13f-48c6-9c50-ce94a2c12789", + "comment": "", + "command": "select", + "target": "id=root_algorithms_6", + "targets": [], + "value": "label=CBC (TRIPLEDES) - http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + }, { + "id": "6ba09b16-4bc5-4609-87fe-4f481e9dbe60", + "comment": "", + "command": "click", + "target": "css=.array-add-button", + "targets": [ + ["css=.array-add-button", "css:finder"], + ["xpath=(//button[@type='button'])[11]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div/button", "xpath:idRelative"], + ["xpath=//div[7]/div/div/div/div/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add ')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "1aab279c-5db0-4cee-8049-1d3dd7705210", + "comment": "", + "command": "click", + "target": "id=root_algorithms_7", + "targets": [ + ["id=root_algorithms_7", "id"], + ["css=#root_algorithms_7", "css:finder"], + ["xpath=//select[@id='root_algorithms_7']", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[8]/div/div/div/div/div/select", "xpath:idRelative"], + ["xpath=//div[8]/div/div/div/div/div/select", "xpath:position"] + ], + "value": "" + }, { + "id": "6041d01a-8271-4768-8df7-7503de2e4999", + "comment": "", + "command": "select", + "target": "id=root_algorithms_7", + "targets": [], + "value": "label=CBC (192) - http://www.w3.org/2001/04/xmlenc#aes192-cbc" + }, { + "id": "ccc82782-8d9c-4a5c-bde3-180bce9e0267", + "comment": "", + "command": "assertText", + "target": "css=.border-0 > .m-0", + "targets": [ + ["css=.border-0 > .m-0", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[7]/div/div/div/div/div/div[2]/div[8]/div/div/div/div/div/ul/li/small", "xpath:idRelative"], + ["xpath=//small", "xpath:position"], + ["xpath=//small[contains(.,'Each algorithm may only be used once.')]", "xpath:innerText"] + ], + "value": "Each algorithm may only be used once." + }, { + "id": "dffd83ae-108a-4cf1-87bf-3de8e4ecb2a1", + "comment": "", + "command": "click", + "target": "css=.mt-2:nth-child(8) path", + "targets": [ + ["css=.mt-2:nth-child(8) path", "css:finder"] + ], + "value": "" + }, { + "id": "0d6e43e3-88b7-4e90-b4bf-88bc662cc43f", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[7]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div/div[2]/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "089770b5-dcc0-4857-966b-a9b855e8a3da", + "comment": "", + "command": "waitForElementVisible", + "target": "css=div:nth-child(2) > div:nth-child(1) > .d-flex > .text-truncate", + "targets": [ + ["css=div:nth-child(2) > div:nth-child(1) > .d-flex > .text-truncate", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div/div/section/div/div[2]/div[2]/div/div/span[2]", "xpath:idRelative"], + ["xpath=//div/span[2]", "xpath:position"] + ], + "value": "30000" + }, { + "id": "fe9a428a-7940-46b2-8433-1630e62bf4c5", + "comment": "", + "command": "assertText", + "target": "css=div:nth-child(2) > div:nth-child(1) > .d-flex > .text-truncate", + "targets": [], + "value": "FBHMR" + }, { + "id": "0bba7bb6-ced5-482b-bd5a-5cd23f498c0d", + "comment": "", + "command": "click", + "target": "css=div:nth-child(1) > .btn:nth-child(2)", + "targets": [ + ["css=div:nth-child(1) > .btn:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='navigation']/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Filters')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "2bd19215-f9e2-4acc-a224-575998285a28", + "comment": "", + "command": "waitForElementVisible", + "target": "css=.mx-4", + "targets": [], + "value": "30000" + }, { + "id": "96fc373a-b871-4307-adeb-fdab78d464a0", + "comment": "", + "command": "click", + "target": "css=.mx-4", + "targets": [ + ["css=.mx-4", "css:finder"], + ["xpath=(//button[@type='button'])[13]", "xpath:attributes"], + ["xpath=//div[@id='filters']/ul/li/div/button", "xpath:idRelative"], + ["xpath=//li/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Algorithm Test')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "fced2579-7ff3-40f6-893f-8208370e8b2c", + "comment": "", + "command": "assertText", + "target": "css=div:nth-child(2) > .mb-4 .p-2 > div > div:nth-child(1) .d-block:nth-child(2)", + "targets": [ + ["css=div:nth-child(2) > .mb-4 .p-2 > div > div:nth-child(1) .d-block:nth-child(2)", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section/div/div[2]/div[2]/div/div/span[2]", "xpath:idRelative"], + ["xpath=//div[2]/section/div/div[2]/div[2]/div/div/span[2]", "xpath:position"], + ["xpath=//span[contains(.,'Algorithm Test')]", "xpath:innerText"] + ], + "value": "Algorithm Test" + }, { + "id": "900af1be-bb32-4052-9290-b8b4a73f0717", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(1) > .list-unstyled > .d-flex:nth-child(1) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(1) > .list-unstyled > .d-flex:nth-child(1) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li/span", "xpath:idRelative"], + ["xpath=//div[2]/div/ul/li/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2009/xmlenc11#aes256-gcm')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2009/xmlenc11#aes256-gcm" + }, { + "id": "3d622935-40af-4807-8843-1d71605ef480", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(2) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(2) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[2]/span", "xpath:idRelative"], + ["xpath=//ul/li[2]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2009/xmlenc11#aes192-gcm')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2009/xmlenc11#aes192-gcm" + }, { + "id": "12dfe6bb-acb1-4f9f-acb0-00e244ca3ac3", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(3) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(3) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[3]/span", "xpath:idRelative"], + ["xpath=//li[3]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2009/xmlenc11#aes128-gcm')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2009/xmlenc11#aes128-gcm" + }, { + "id": "47bf69fa-e126-4c06-b9ae-504d09a0d37b", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(4) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(4) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[4]/span", "xpath:idRelative"], + ["xpath=//li[4]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2001/04/xmlenc#aes256-cbc')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2001/04/xmlenc#aes256-cbc" + }, { + "id": "223043f1-e31c-4019-b68f-d654f3fea9b0", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(5) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(5) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[5]/span", "xpath:idRelative"], + ["xpath=//li[5]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2001/04/xmlenc#aes192-cbc')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2001/04/xmlenc#aes192-cbc" + }, { + "id": "2ecdc8fe-d63d-48e8-bcdf-eb675cd8912f", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(6) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(6) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[6]/span", "xpath:idRelative"], + ["xpath=//li[6]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2001/04/xmlenc#aes128-cbc')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2001/04/xmlenc#aes128-cbc" + }, { + "id": "8c87d87e-6b09-456e-806b-1d69dc9b2cc8", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(7) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(7) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[7]/span", "xpath:idRelative"], + ["xpath=//li[7]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2001/04/xmlenc#tripledes-cbc')]", "xpath:innerText"] + ], + "value": "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + }, { + "id": "79f7ca40-090b-485f-a220-9e43728f4bc1", + "comment": "", + "command": "assertText", + "target": "css=.d-flex:nth-child(1) > .p-2", + "targets": [ + ["css=.d-flex:nth-child(1) > .p-2", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/span", "xpath:idRelative"], + ["xpath=//section[2]/div/div[2]/div[2]/div/span", "xpath:position"] + ], + "value": "Algorithm" + }, { + "id": "8e4fb6e0-618b-46f2-934b-8bf474615815", + "comment": "", + "command": "assertText", + "target": "css=div:nth-child(4) > div:nth-child(1) > .d-flex > .text-truncate", + "targets": [ + ["css=div:nth-child(4) > div:nth-child(1) > .d-flex > .text-truncate", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section/div/div[2]/div[2]/div[3]/div/div/span[2]", "xpath:idRelative"], + ["xpath=//div[2]/div[3]/div/div/span[2]", "xpath:position"], + ["xpath=//span[contains(.,'Entity ID')]", "xpath:innerText"] + ], + "value": "Entity ID" + }, { + "id": "3d1b105b-9dec-40f4-802e-b5a3ddcbc2fc", + "comment": "", + "command": "click", + "target": "linkText=Edit", + "targets": [ + ["linkText=Edit", "linkText"], + ["css=.d-flex:nth-child(1) > .btn:nth-child(1)", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/div/div/a", "xpath:idRelative"], + ["xpath=//a[contains(@href, '/metadata/provider/66d0dbbb-4049-4584-8a6f-17707dc2a8d1/filter/62ffb91c-9af1-466b-83ac-307f21c0cebd/edit/common')]", "xpath:href"], + ["xpath=//div[2]/div/div/a", "xpath:position"], + ["xpath=//a[contains(.,' Edit')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "bfd501c9-e06c-4dd5-ad25-60b21fca1eb1", + "comment": "", + "command": "click", + "target": "css=.nav-link:nth-child(2)", + "targets": [ + ["css=.nav-link:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[9]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div[2]/div/nav/button[2]", "xpath:idRelative"], + ["xpath=//nav/button[2]", "xpath:position"], + ["xpath=//button[contains(.,'Options')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "493533af-c18e-46f6-b7df-82f7c3aa548e", + "comment": "", + "command": "click", + "target": "css=.mt-2:nth-child(7) path", + "targets": [ + ["css=.mt-2:nth-child(7) path", "css:finder"] + ], + "value": "" + }, { + "id": "cfc916c7-80a6-4cdc-b2c0-2425b168bcc4", + "comment": "", + "command": "click", + "target": "css=.btn-info", + "targets": [ + ["css=.btn-info", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div[2]/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Save')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "269c4acd-2e59-4f76-816c-9a7f06b4ce87", + "comment": "", + "command": "waitForElementVisible", + "target": "css=div:nth-child(2) > div:nth-child(1) > .d-flex > .text-truncate", + "targets": [ + ["css=div:nth-child(2) > div:nth-child(1) > .d-flex > .text-truncate", "css:finder"], + ["xpath=//div[@id='root']/div/main/div/section/div/div/section/div/div[2]/div[2]/div/div/span[2]", "xpath:idRelative"], + ["xpath=//div/span[2]", "xpath:position"] + ], + "value": "30000" + }, { + "id": "40fb10d5-231f-4d1a-8891-c4f48ea2c1b6", + "comment": "", + "command": "click", + "target": "css=div:nth-child(1) > .btn:nth-child(2)", + "targets": [ + ["css=div:nth-child(1) > .btn:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[6]", "xpath:attributes"], + ["xpath=//div[@id='navigation']/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Filters')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "e26e03eb-f01c-433c-aa19-683f1887c472", + "comment": "", + "command": "click", + "target": "css=.mx-4", + "targets": [ + ["css=.mx-4", "css:finder"], + ["xpath=(//button[@type='button'])[13]", "xpath:attributes"], + ["xpath=//div[@id='filters']/ul/li/div/button", "xpath:idRelative"], + ["xpath=//li/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Algorithm Test')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "10fbd6c4-804a-4bcc-866b-7bf221ffa266", + "comment": "", + "command": "assertElementNotPresent", + "target": "css=.d-flex:nth-child(7) > .d-block", + "targets": [ + ["css=.d-flex:nth-child(7) > .d-block", "css:finder"], + ["xpath=//div[@id='filters']/ul/li/div[2]/section[2]/div/div[2]/div[2]/div/ul/li[7]/span", "xpath:idRelative"], + ["xpath=//li[7]/span", "xpath:position"], + ["xpath=//span[contains(.,'http://www.w3.org/2001/04/xmlenc#tripledes-cbc')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "6af1cc94-05df-47db-8672-d078928260ed", + "comment": "", + "command": "click", + "target": "css=.justify-content-end .btn:nth-child(2)", + "targets": [ + ["css=.justify-content-end .btn:nth-child(2)", "css:finder"], + ["xpath=(//button[@type='button'])[14]", "xpath:attributes"], + ["xpath=//div[@id='filters']/ul/li/div[2]/div/div/button", "xpath:idRelative"], + ["xpath=//div[2]/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,' Delete')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "b44418d1-ed8c-4199-92a6-4b130bfe2cb2", + "comment": "", + "command": "click", + "target": "css=.btn-danger", + "targets": [ + ["css=.btn-danger", "css:finder"], + ["xpath=(//button[@type='button'])[18]", "xpath:attributes"], + ["xpath=//div[4]/div/div/div[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "6cd2789b-4ec1-4153-8d4e-fb896a1b0e5e", + "comment": "", + "command": "click", + "target": "css=.align-items-end", + "targets": [ + ["css=.align-items-end", "css:finder"], + ["xpath=//div[@id='root']/div/footer/div/div[2]/div", "xpath:idRelative"], + ["xpath=//footer/div/div[2]/div", "xpath:position"] + ], + "value": "" + }, { + "id": "b9432398-233d-4872-8b56-9aa8fd48ca85", + "comment": "", + "command": "assertText", + "target": "css=.alert", + "targets": [], + "value": "No FiltersNo filters have been added to this Metadata Provider" + }, { + "id": "3543733a-3e14-4f07-9aaa-e29a26fe36b1", + "comment": "", + "command": "open", + "target": "/api/heheheheheheheWipeout", + "targets": [], + "value": "" + }, { + "id": "da1edae7-e865-404e-971c-37bdb13c2845", + "comment": "", + "command": "assertText", + "target": "css=body", + "targets": [], + "value": "yes, you did it" + }] + }], + "suites": [{ + "id": "d2caeac4-7520-4e3c-96b1-840610b6983c", + "name": "Default Suite", + "persistSession": false, + "parallel": false, + "timeout": 300, + "tests": ["841ade0e-83bd-4a4b-94f2-de6bd5c536b2"] + }], + "urls": ["http://localhost:10101/"], + "plugins": [] +} \ No newline at end of file diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AlgorithmFilterUiDefinitionController.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AlgorithmFilterUiDefinitionController.groovy new file mode 100644 index 000000000..9a7005fa7 --- /dev/null +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/AlgorithmFilterUiDefinitionController.groovy @@ -0,0 +1,57 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller + +import com.fasterxml.jackson.databind.ObjectMapper +import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation +import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry +import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService +import groovy.util.logging.Slf4j +import io.swagger.v3.oas.annotations.tags.Tag +import io.swagger.v3.oas.annotations.tags.Tags +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +import javax.annotation.PostConstruct + +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.algorithmFilterSchema +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR + +/** + * Controller implementing REST resource responsible for exposing structure definition for algorithm format filter user + * interface in terms of JSON schema. + */ +@RestController +@RequestMapping('/api/ui/AlgorithmFilter') +@Slf4j +@Tags(value = [@Tag(name = "ui")]) +class AlgorithmFilterUiDefinitionController { + + @Autowired + JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry + + JsonSchemaResourceLocation jsonSchemaLocation + + @Autowired + ObjectMapper jacksonObjectMapper + + @Autowired + JsonSchemaBuilderService jsonSchemaBuilderService + + @GetMapping + ResponseEntity getUiDefinitionJsonSchema() { + try { + def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map) + return ResponseEntity.ok(parsedJson) + } catch (Exception e) { + log.error(e.getMessage(), e) + return ResponseEntity.status(INTERNAL_SERVER_ERROR).body([jsonParseError : e.getMessage(), sourceUiSchemaDefinitionFile: this.jsonSchemaLocation.url]) + } + } + + @PostConstruct + void init() { + this.jsonSchemaLocation = algorithmFilterSchema(this.jsonSchemaResourceLocationRegistry) + } +} \ No newline at end of file diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy index 170a45fa8..bb86a1915 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy @@ -2,6 +2,8 @@ package edu.internet2.tier.shibboleth.admin.ui.service import com.google.common.base.Predicate import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.EncryptionMethod +import edu.internet2.tier.shibboleth.admin.ui.domain.EncryptionMethodBuilder import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget @@ -9,6 +11,8 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityRoleWhiteList import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.AlgorithmFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.AlgorithmFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.filters.opensaml.OpenSamlNameIdFormatFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ExternalMetadataResolver @@ -89,6 +93,69 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } + void constructXmlNodeForFilter(AlgorithmFilter filter, def markupBuilderDelegate) { + if (!filter.isFilterEnabled()) { + return + } + markupBuilderDelegate.MetadataFilter( + 'xsi:type': 'Algorithm', + 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation': 'urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd urn:oasis:names:tc:SAML:metadata:algsupport https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-algsupport-v1.0.xsd http://www.w3.org/2000/09/xmldsig# https://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd http://www.w3.org/2009/xmlenc11# https://www.w3.org/TR/xmlenc-core1/xenc-schema-11.xsd', + 'xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata', + 'xmlns': 'urn:mace:shibboleth:2.0:metadata', + 'xmlns:security': 'urn:mace:shibboleth:2.0:security', + 'xmlns:saml2': 'urn:oasis:names:tc:SAML:2.0:assertion', + 'xmlns:xenc11': 'http://www.w3.org/2009/xmlenc11#', + 'xmlns:alg': 'urn:oasis:names:tc:SAML:metadata:algsupport', + 'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#' + ) { + for (String algValue : filter.getAlgorithms()) { + EncryptionMethod method = new EncryptionMethodBuilder().buildObject(); + method.setAlgorithm(algValue) + mkp.yieldUnescaped(openSamlObjects.marshalToXmlString(method, false)) + } + switch (filter.algorithmFilterTarget.algorithmFilterTargetType) { + case AlgorithmFilterTarget.AlgorithmFilterTargetType.ENTITY: + filter.algorithmFilterTarget.value.each { + Entity(it) + } + break + case AlgorithmFilterTarget.AlgorithmFilterTargetType.CONDITION_REF: + ConditionRef(xmlObject.getValue()) + break + case AlgorithmFilterTarget.AlgorithmFilterTargetType.CONDITION_SCRIPT: + ConditionScript() { + Script() { + def script = filter.getAlgorithmFilterTarget().value[0] + mkp.yieldUnescaped("\n\n") + } + } + break + default: + // do nothing, we'd have exploded elsewhere previously. + break + } +// filter.unknownXMLObjects.each { xmlObject -> +// { +// if (xmlObject instanceof Entity) { +// Entity(xmlObject.getValue()) +// } else if (xmlObject instanceof ConditionRef) { +// ConditionRef(xmlObject.getValue()) +// } else if (xmlObject instanceof ConditionScript) { +// ConditionScript() { +// Script() { +// def script = xmlObject.getValue() +// mkp.yieldUnescaped("\n\n") +// } +// } +// } else { +// mkp.yieldUnescaped(openSamlObjects.marshalToXmlString(xmlObject, false)) +// } +// } +// } + } + } + void constructXmlNodeForFilter(EntityAttributesFilter filter, def markupBuilderDelegate) { if (!filter.isFilterEnabled()) { return } markupBuilderDelegate.MetadataFilter('xsi:type': 'EntityAttributes') { @@ -103,10 +170,8 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { Entity(it) } break - case EntityAttributesFilterTarget - .EntityAttributesFilterTargetType.CONDITION_SCRIPT: - case EntityAttributesFilterTarget - .EntityAttributesFilterTargetType.REGEX: + case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.CONDITION_SCRIPT: + case EntityAttributesFilterTarget.EntityAttributesFilterTargetType.REGEX: ConditionScript() { Script() { def script @@ -485,6 +550,48 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { } } + @Override + Document generateSingleMetadataConfiguration(edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr) { + if (mr instanceof ExternalMetadataResolver) { + return generateExternalMetadataFilterConfiguration(); + } + new StringWriter().withCloseable { writer -> + def xml = new MarkupBuilder(writer) + xml.omitEmptyAttributes = true + xml.omitNullAttributes = true + + xml.MetadataProvider(id: 'ShibbolethIdPUIGeneratedMetadata', + xmlns: 'urn:mace:shibboleth:2.0:metadata', + 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:type': 'ChainingMetadataProvider', + 'xsi:schemaLocation': 'urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd urn:mace:shibboleth:2.0:resource http://shibboleth.net/schema/idp/shibboleth-resource.xsd urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd' + ) { + // We do not currently marshall the internal incommon chaining resolver (with BaseMetadataResolver type) + // We do not want to include the custom type: ExternalMetadataResolver + if ((mr.type != 'BaseMetadataResolver') && (mr.type != 'ExternalMetadataResolver') && (mr.enabled)) { + constructXmlNodeForResolver(mr, delegate) { + //TODO: enhance + def didNamespaceProtectionFilter = !(shibUIConfiguration.protectedAttributeNamespaces && shibUIConfiguration.protectedAttributeNamespaces.size() > 0) + def doNamespaceProtectionFilter = { def filter -> + if (mr.type in ['FileBackedMetadataResolver', 'DynamicHttpMetadataResolver'] && (filter == null || filter instanceof EntityAttributesFilter) && !didNamespaceProtectionFilter) { + constructXmlNodeForEntityAttributeNamespaceProtection(delegate) + didNamespaceProtectionFilter = true + } + } + mr.metadataFilters.each { edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter filter -> + if (filter.isFilterEnabled()) { + doNamespaceProtectionFilter() + constructXmlNodeForFilter(filter, delegate) + } + } + doNamespaceProtectionFilter() + } + } + } + return DOMBuilder.newInstance().parseText(writer.toString()) + } + } + @Override Document generateExternalMetadataFilterConfiguration() { // TODO: this can probably be a better writer diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java index 34c5c1eaf..23fbaaa30 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java @@ -2,23 +2,22 @@ import com.fasterxml.jackson.databind.ObjectMapper; import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry; -import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService; import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService; import lombok.Setter; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.*; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.JsonSchemaLocationBuilder; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ALGORITHM_FILTER; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.DYNAMIC_HTTP_METADATA_RESOLVER; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.EXTERNAL_METADATA_RESOLVER; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.FILESYSTEM_METADATA_RESOLVER; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.LOCAL_DYNAMIC_METADATA_RESOLVER; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.DYNAMIC_HTTP_METADATA_RESOLVER; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.NAME_ID_FORMAT_FILTER; /** @@ -58,8 +57,16 @@ public class JsonSchemaComponentsConfiguration { @Setter private String nameIdFormatFilterUiSchemaLocation = "classpath:nameid-filter.schema.json"; + //Configured via @ConfigurationProperties (using setter method) with 'shibui.external-metadata-resolver-ui-schema-location' property and + // default value set here if that property is not explicitly set in application.properties + @Setter private String externalMetadataResolverUiSchemaLocation = "classpath:external.schema.json"; + //Configured via @ConfigurationProperties (using setter method) with 'shibui.algorithm-filter-ui-schema-location' property and + // default value set here if that property is not explicitly set in application.properties + @Setter + private String algorithmFilterUiSchemaLocation = "classpath:algorithm-filter.schema.json"; + @Bean public JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(ResourceLoader resourceLoader, ObjectMapper jacksonMapper) { return JsonSchemaResourceLocationRegistry.inMemory() @@ -104,6 +111,12 @@ public JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(Res .resourceLoader(resourceLoader) .jacksonMapper(jacksonMapper) .detectMalformedJson(true) + .build()) + .register(ALGORITHM_FILTER, JsonSchemaLocationBuilder.with() + .jsonSchemaLocation(algorithmFilterUiSchemaLocation) + .resourceLoader(resourceLoader) + .jacksonMapper(jacksonMapper) + .detectMalformedJson(true) .build()); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java index 6a11f07a2..1b030ad74 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java @@ -35,6 +35,7 @@ import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; @@ -102,6 +103,22 @@ public ResponseEntity getXml() throws IOException, TransformerException { } } + @GetMapping(value = "/MetadataResolvers/{resourceId}", produces = "application/xml") + @Transactional(readOnly = true) + public ResponseEntity getOneXml(@PathVariable String resourceId) throws TransformerException { + MetadataResolver resolver = resolverRepository.findByResourceId(resourceId); + if (resolver == null) { + return ResponseEntity.notFound().build(); + } + StringWriter writer = new StringWriter(); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + transformer.transform(new DOMSource(metadataResolverService.generateSingleMetadataConfiguration(resolver)), new StreamResult(writer)); + return ResponseEntity.ok(writer.toString()); + } + @GetMapping(value = "/MetadataResolvers/External", produces = "application/xml") @Transactional(readOnly = true) public ResponseEntity getExternalXml() throws IOException, TransformerException { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAlgorithmIdentifierType.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAlgorithmIdentifierType.java new file mode 100644 index 000000000..3a3eeef77 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAlgorithmIdentifierType.java @@ -0,0 +1,36 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractXMLObject; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.Audited; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.xmlsec.encryption.AlgorithmIdentifierType; + +import javax.annotation.Nullable; +import javax.persistence.Entity; + +@Entity +@Audited +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +public abstract class AbstractAlgorithmIdentifierType extends AbstractXMLObject implements AlgorithmIdentifierType { + private String algorithm; + + @Nullable + @Override + public XMLObject getParameters() { + // implement? + return null; + } + + @Override + public void setParameters(@Nullable final XMLObject newParameters) { + // do nothing? + } + +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AlgorithmDigestMethod.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AlgorithmDigestMethod.java new file mode 100644 index 000000000..509f9613d --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AlgorithmDigestMethod.java @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import lombok.EqualsAndHashCode; + +import javax.annotation.Nullable; +import javax.persistence.Entity; + +@Entity(name = "DigestMethod") // for backwards compatibility instead of dealing with renaming the table +@EqualsAndHashCode(callSuper = true) +public class AlgorithmDigestMethod extends AbstractElementExtensibleXMLObject implements org.opensaml.saml.ext.saml2alg.DigestMethod { + private String algorithm; + + public AlgorithmDigestMethod() {} + + public AlgorithmDigestMethod(String algorithm) { + this.algorithm = algorithm; + } + + @Nullable + @Override + public String getAlgorithm() { + return this.algorithm; + } + + @Override + public void setAlgorithm(@Nullable String value) { + this.algorithm = value; + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/EncryptionMethod.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/EncryptionMethod.java index 06a47da63..16a122883 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/EncryptionMethod.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/EncryptionMethod.java @@ -2,12 +2,14 @@ import lombok.EqualsAndHashCode; import org.hibernate.envers.Audited; +import org.opensaml.core.xml.XMLObject; import org.opensaml.xmlsec.encryption.KeySize; import org.opensaml.xmlsec.encryption.OAEPparams; import javax.annotation.Nullable; import javax.persistence.Embedded; import javax.persistence.Entity; +import java.util.List; @Entity @EqualsAndHashCode(callSuper = true) @@ -16,12 +18,9 @@ public class EncryptionMethod extends AbstractElementExtensibleXMLObject impleme private String algorithm; - @Embedded - private KeySize keySize; - - @Embedded - private OAEPparams oaePparams; + @Embedded private KeySize keySize; + @Embedded private OAEPparams oaePparams; @Nullable @Override @@ -55,4 +54,9 @@ public org.opensaml.xmlsec.encryption.OAEPparams getOAEPparams() { public void setOAEPparams(@Nullable org.opensaml.xmlsec.encryption.OAEPparams oaePparams) { this.oaePparams = oaePparams; } -} + + @Override + public List getOrderedChildren() { + return this.getUnknownXMLObjects(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MGF.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MGF.java new file mode 100644 index 000000000..e145231af --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MGF.java @@ -0,0 +1,24 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.Audited; +import org.opensaml.xmlsec.encryption.support.EncryptionConstants; + +import javax.persistence.Entity; + +@Entity +@Audited +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +public class MGF extends AbstractAlgorithmIdentifierType { + public MGF() { + setElementLocalName("MGF"); + setNamespaceURI(EncryptionConstants.XMLENC11_NS); + setNamespacePrefix(EncryptionConstants.XMLENC11_PREFIX); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/OtherSource.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/OtherSource.java new file mode 100644 index 000000000..0fbd26a16 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/OtherSource.java @@ -0,0 +1,26 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.Audited; +import org.opensaml.xmlsec.encryption.support.EncryptionConstants; + +import javax.persistence.Entity; + +@Entity +@Audited +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +public class OtherSource extends AbstractAlgorithmIdentifierType { + public OtherSource() { + { + setElementLocalName("OtherSource"); + setNamespaceURI(EncryptionConstants.XMLENC11_NS); + setNamespacePrefix(EncryptionConstants.XMLENC11_PREFIX); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/PRF.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/PRF.java new file mode 100644 index 000000000..876c11561 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/PRF.java @@ -0,0 +1,24 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.Audited; +import org.opensaml.xmlsec.encryption.support.EncryptionConstants; + +import javax.persistence.Entity; + +@Entity +@Audited +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +public class PRF extends AbstractAlgorithmIdentifierType { + public PRF() { + setElementLocalName("PRF"); + setNamespaceURI(EncryptionConstants.XMLENC11_NS); + setNamespacePrefix(EncryptionConstants.XMLENC11_PREFIX); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/SignatureDigestMethod.java similarity index 66% rename from backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java rename to backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/SignatureDigestMethod.java index 199947f88..519df1faf 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/SignatureDigestMethod.java @@ -1,18 +1,19 @@ package edu.internet2.tier.shibboleth.admin.ui.domain; import lombok.EqualsAndHashCode; +import org.opensaml.xmlsec.signature.DigestMethod; import javax.annotation.Nullable; import javax.persistence.Entity; @Entity @EqualsAndHashCode(callSuper = true) -public class DigestMethod extends AbstractElementExtensibleXMLObject implements org.opensaml.saml.ext.saml2alg.DigestMethod { +public class SignatureDigestMethod extends AbstractElementExtensibleXMLObject implements DigestMethod { private String algorithm; - public DigestMethod() {} + public SignatureDigestMethod() {} - public DigestMethod(String algorithm) { + public SignatureDigestMethod(String algorithm) { this.algorithm = algorithm; } @@ -26,4 +27,4 @@ public String getAlgorithm() { public void setAlgorithm(@Nullable String value) { this.algorithm = value; } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AbstractFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AbstractFilterTarget.java new file mode 100644 index 000000000..a26c06e88 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AbstractFilterTarget.java @@ -0,0 +1,39 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import lombok.EqualsAndHashCode; + +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.FetchType; +import javax.persistence.MappedSuperclass; +import javax.persistence.OrderColumn; +import java.util.ArrayList; +import java.util.List; + +@MappedSuperclass +@EqualsAndHashCode(callSuper = true) +public abstract class AbstractFilterTarget extends AbstractAuditable implements IFilterTarget { + @ElementCollection(fetch = FetchType.EAGER) + @OrderColumn + @Column(length = 760, name="target_value") + protected List value; + + @Override + public List getValue() { + return value == null ? new ArrayList<>() : value; + } + + @Override + public void setSingleValue(String value) { + List values = new ArrayList<>(); + values.add(value); + this.value = values; + } + + @Override + public void setValue(List value) { + this.value = value; + } + +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilter.java new file mode 100644 index 000000000..062ffa8c6 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilter.java @@ -0,0 +1,48 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.Audited; + +import javax.persistence.CascadeType; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.OneToOne; +import javax.persistence.OrderColumn; +import java.util.List; + +@Entity +@Audited +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = true) +public class AlgorithmFilter extends MetadataFilter implements ITargetable { + @OneToOne(cascade = CascadeType.ALL) private AlgorithmFilterTarget algorithmFilterTarget; + + @ElementCollection + @OrderColumn + private List algorithms; + + public AlgorithmFilter() { + type = "Algorithm"; + } + + @Override + public IFilterTarget getTarget() { + return algorithmFilterTarget; + } + + private AlgorithmFilter updateConcreteFilterTypeData(AlgorithmFilter filterToBeUpdated) { + filterToBeUpdated.setAlgorithms(getAlgorithms()); + filterToBeUpdated.setAlgorithmFilterTarget(getAlgorithmFilterTarget()); + return filterToBeUpdated; + } + + @Override + public MetadataFilter updateConcreteFilterTypeData(MetadataFilter filterToBeUpdated) { + return updateConcreteFilterTypeData((AlgorithmFilter) filterToBeUpdated); + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilterTarget.java new file mode 100644 index 000000000..8a80dba6a --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/AlgorithmFilterTarget.java @@ -0,0 +1,36 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.filters; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.AbstractFilterTarget; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.envers.AuditOverride; +import org.hibernate.envers.Audited; + +import javax.persistence.Entity; + +@Entity +@EqualsAndHashCode(callSuper = true) +@ToString +@Audited +@AuditOverride(forClass = AbstractAuditable.class) +@JsonIgnoreProperties({"handler", "hibernateLazyInitializer"}) +public class AlgorithmFilterTarget extends AbstractFilterTarget { + @Getter + @Setter + private AlgorithmFilterTargetType algorithmFilterTargetType; + + @Override + @JsonIgnore + public String getTargetTypeValue() { + return algorithmFilterTargetType == null ? "NONE" : algorithmFilterTargetType.name(); + } + + public enum AlgorithmFilterTargetType { + ENTITY, CONDITION_SCRIPT, CONDITION_REF + } +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java index e2ed028a0..b2ffb6b0d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTarget.java @@ -4,31 +4,21 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; import lombok.EqualsAndHashCode; +import lombok.ToString; import org.hibernate.envers.AuditOverride; import org.hibernate.envers.Audited; -import javax.persistence.Column; -import javax.persistence.ElementCollection; import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.OrderColumn; -import java.util.ArrayList; -import java.util.List; @Entity @EqualsAndHashCode(callSuper = true) +@ToString @Audited @AuditOverride(forClass = AbstractAuditable.class) @JsonIgnoreProperties({"handler", "hibernateLazyInitializer"}) -public class EntityAttributesFilterTarget extends AbstractAuditable implements IFilterTarget { - +public class EntityAttributesFilterTarget extends AbstractFilterTarget { private EntityAttributesFilterTargetType entityAttributesFilterTargetType; - @ElementCollection (fetch = FetchType.EAGER) - @OrderColumn - @Column(length = 760, name="target_value") - private List value; - public EntityAttributesFilterTargetType getEntityAttributesFilterTargetType() { return entityAttributesFilterTargetType; } @@ -39,33 +29,10 @@ public String getTargetTypeValue() { return entityAttributesFilterTargetType == null ? "NONE" : entityAttributesFilterTargetType.name(); } - @Override - public List getValue() { - return value == null ? new ArrayList<>() : value; - } - public void setEntityAttributesFilterTargetType(EntityAttributesFilterTargetType entityAttributesFilterTarget) { this.entityAttributesFilterTargetType = entityAttributesFilterTarget; } - public void setSingleValue(String value) { - List values = new ArrayList<>(); - values.add(value); - this.value = values; - } - - public void setValue(List value) { - this.value = value; - } - - @Override - public String toString() { - return "EntityAttributesFilterTarget{" + - "entityAttributesFilterTargetType=" + entityAttributesFilterTargetType + - ", value=" + value + - '}'; - } - public enum EntityAttributesFilterTargetType { ENTITY, CONDITION_SCRIPT, CONDITION_REF, REGEX } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java index 548c97356..29612b15d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java @@ -36,7 +36,8 @@ @JsonSubTypes.Type(value=EntityAttributesFilter.class, name="EntityAttributes"), @JsonSubTypes.Type(value=SignatureValidationFilter.class, name="SignatureValidation"), @JsonSubTypes.Type(value=RequiredValidUntilFilter.class, name="RequiredValidUntil"), - @JsonSubTypes.Type(value=NameIdFormatFilter.class, name="NameIDFormat")}) + @JsonSubTypes.Type(value=NameIdFormatFilter.class, name="NameIDFormat"), + @JsonSubTypes.Type(value=AlgorithmFilter.class, name="Algorithm")}) @Audited @AuditOverride(forClass = AbstractAuditable.class) public abstract class MetadataFilter extends AbstractAuditable implements IConcreteMetadataFilterType, IActivatable { @@ -50,7 +51,7 @@ public abstract class MetadataFilter extends AbstractAuditable implements IConcr @JsonProperty("@type") @Transient - String type; + protected String type; @Transient private transient Integer version; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java index 3a5bfe9da..c5441a053 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/NameIdFormatFilterTarget.java @@ -8,29 +8,18 @@ import org.hibernate.envers.AuditOverride; import org.hibernate.envers.Audited; -import javax.persistence.Column; -import javax.persistence.ElementCollection; import javax.persistence.Entity; -import javax.persistence.OrderColumn; -import javax.persistence.Transient; -import java.util.ArrayList; -import java.util.List; @Entity @EqualsAndHashCode(callSuper = true) @ToString @Audited @AuditOverride(forClass = AbstractAuditable.class) -@JsonIgnoreProperties({"handler", "hibernateLazyInitializer"}) -public class NameIdFormatFilterTarget extends AbstractAuditable implements IFilterTarget { +@JsonIgnoreProperties({ "handler", "hibernateLazyInitializer" }) +public class NameIdFormatFilterTarget extends AbstractFilterTarget { private NameIdFormatFilterTargetType nameIdFormatFilterTargetType; - @ElementCollection - @OrderColumn - @Column(name="target_value") - private List value; - public NameIdFormatFilterTargetType getNameIdFormatFilterTargetType() { return nameIdFormatFilterTargetType; } @@ -41,24 +30,10 @@ public String getTargetTypeValue() { return nameIdFormatFilterTargetType.name(); } - public List getValue() { - return value; - } - public void setNameIdFormatFilterTargetType(NameIdFormatFilterTargetType nameIdFormatFilterTargetType) { this.nameIdFormatFilterTargetType = nameIdFormatFilterTargetType; } - public void setSingleValue(String value) { - List values = new ArrayList<>(); - values.add(value); - this.value = values; - } - - public void setValue(List value) { - this.value = value; - } - public enum NameIdFormatFilterTargetType { ENTITY, CONDITION_SCRIPT, REGEX } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java index b44e4e7ce..bdb781d9a 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java @@ -1,11 +1,12 @@ package edu.internet2.tier.shibboleth.admin.ui.jsonschema; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ALGORITHM_FILTER; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.DYNAMIC_HTTP_METADATA_RESOLVER; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.EXTERNAL_METADATA_RESOLVER; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.FILESYSTEM_METADATA_RESOLVER; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.LOCAL_DYNAMIC_METADATA_RESOLVER; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.DYNAMIC_HTTP_METADATA_RESOLVER; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.NAME_ID_FORMAT_FILTER; /** @@ -105,4 +106,16 @@ public static JsonSchemaResourceLocation nameIdFormatFilterSchema(JsonSchemaReso .lookup(NAME_ID_FORMAT_FILTER) .orElseThrow(() -> new IllegalStateException("JSON schema resource location for name id format filter is not registered.")); } + + /** + * Searches algorithm filter JSON schema resource location object in the given location registry. + * + * @param resourceLocationRegistry + * @return algorithm filter JSON schema resource location object + * @throws IllegalStateException if schema is not found in the given registry + */ + public static JsonSchemaResourceLocation algorithmFilterSchema(JsonSchemaResourceLocationRegistry resourceLocationRegistry) { + return resourceLocationRegistry.lookup(ALGORITHM_FILTER) + .orElseThrow(() -> new IllegalStateException("JSON schema resource location for algorithm filter is not registered.")); + } } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java index 1b9054cd3..02e3da1d8 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java @@ -99,6 +99,7 @@ public enum SchemaType { // filter types ENTITY_ATTRIBUTES_FILTERS("EntityAttributesFilters"), NAME_ID_FORMAT_FILTER("NameIdFormatFilter"), + ALGORITHM_FILTER("AlgorithmFilter"), // resolver types FILE_BACKED_HTTP_METADATA_RESOLVER("FileBackedHttpMetadataResolver"), diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/OpenSamlObjects.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/OpenSamlObjects.java index 8a25b0855..bd149c9ff 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/OpenSamlObjects.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/OpenSamlObjects.java @@ -88,11 +88,11 @@ public void init() throws ComponentInitializationException { this.unmarshallerFactory = registry.getUnmarshallerFactory(); } - public String marshalToXmlString(XMLObject ed, boolean includeXMLDeclaration) throws MarshallingException { - Marshaller marshaller = this.marshallerFactory.getMarshaller(ed); - ed.releaseDOM(); - ed.releaseChildrenDOM(true); - String entityDescriptorXmlString = null; + public String marshalToXmlString(XMLObject xmlObject, boolean includeXMLDeclaration) throws MarshallingException { + Marshaller marshaller = this.marshallerFactory.getMarshaller(xmlObject); + xmlObject.releaseDOM(); + xmlObject.releaseChildrenDOM(true); + String resultString = null; if (marshaller != null) { try (StringWriter writer = new StringWriter()) { Transformer transformer = TransformerFactory.newInstance().newTransformer(); @@ -101,22 +101,22 @@ public String marshalToXmlString(XMLObject ed, boolean includeXMLDeclaration) th if (!includeXMLDeclaration) { transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } - transformer.transform(new DOMSource(marshaller.marshall(ed)), new StreamResult(writer)); - entityDescriptorXmlString = writer.toString(); + transformer.transform(new DOMSource(marshaller.marshall(xmlObject)), new StreamResult(writer)); + resultString = writer.toString(); } catch (TransformerException | IOException e) { logger.error(e.getMessage(), e); } } - if (entityDescriptorXmlString == null) { + if (resultString == null) { //Figure out the best way to deal with this case - throw new RuntimeException("Unable to marshal EntityDescriptor"); + throw new RuntimeException("Unable to marshal xmlObject"); } - return entityDescriptorXmlString; + return resultString; } - public String marshalToXmlString(XMLObject ed) throws MarshallingException { - return this.marshalToXmlString(ed, true); + public String marshalToXmlString(XMLObject xmlObject) throws MarshallingException { + return this.marshalToXmlString(xmlObject, true); } public EntityDescriptor unmarshalFromXml(byte[] entityDescriptorXml) throws Exception { @@ -152,4 +152,4 @@ public T buildDefaultInstanceOfType(Class type) { throw new RuntimeException("there was a problem building an instance", e); } } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializer.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializer.java index 25000ae67..24757d560 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializer.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializer.java @@ -8,17 +8,17 @@ public class JPAXMLObjectProviderInitializer extends AbstractXMLObjectProviderIn protected String[] getConfigResources() { return new String[]{ "/jpa-default-config.xml", - "/jpa-saml2-metadata-config.xml", - "/jpa-saml2-metadata-attr-config.xml", + "/encryption-config.xml", "/jpa-saml2-assertion-config.xml", - "/jpa-schema-config.xml", - "/jpa-saml2-metadata-ui-config.xml", - "/jpa-signature-config.xml", "/jpa-saml2-metadata-algorithm-config.xml", - "/encryption-config.xml", + "/jpa-saml2-metadata-attr-config.xml", + "/jpa-saml2-metadata-config.xml", "/jpa-saml2-metadata-reqinit-config.xml", + "/jpa-saml2-metadata-ui-config.xml", + "/jpa-schema-config.xml", + "/jpa-signature-config.xml", "/saml2-protocol-config.xml", "/modified-saml2-assertion-config.xml" }; } -} +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java index d851cd021..6c921509e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverService.java @@ -14,6 +14,8 @@ public interface MetadataResolverService { public Document generateConfiguration(); + public Document generateSingleMetadataConfiguration(MetadataResolver mr); + public void reloadFilters(String metadataResolverName); public MetadataResolver updateMetadataResolverEnabledStatus(MetadataResolver existingResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException; diff --git a/backend/src/main/resources/algorithm-filter.schema.json b/backend/src/main/resources/algorithm-filter.schema.json new file mode 100644 index 000000000..552d92ec2 --- /dev/null +++ b/backend/src/main/resources/algorithm-filter.schema.json @@ -0,0 +1,82 @@ +{ + "type": "object", + "required": ["name"], + "properties": { + "name": { + "title": "label.filter-name", + "description": "tooltip.filter-name", + "type": "string" + }, + "filterEnabled": { + "title": "label.enable-filter", + "description": "tooltip.enable-filter", + "type": "boolean", + "default": false + }, + "algorithmFilterTarget": { + "title": "label.search-criteria", + "description": "tooltip.search-criteria", + "type": "object", + "properties": { + "algorithmFilterTargetType": { + "title": "label.filter-target-type", + "type": "string", + "default": "ENTITY", + "enum": ["ENTITY", "CONDITION_REF", "CONDITION_SCRIPT"], + "enumNames": ["value.entity-id", "value.reference", "value.script"] + }, + "value": { + "title": "label.filter-target-value", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string" + } + } + }, + "required": ["value", "algorithmFilterTargetType"] + }, + "@type": { + "type": "string", + "default": "Algorithm" + }, + "version": { + "type": "integer" + }, + "resourceId": { + "type": "string" + }, + "algorithms": { + "$ref": "#/definitions/AlgorithmList" + } + }, + "definitions": { + "AlgorithmList": { + "title": "label.algorithm", + "description": "tooltip.algorithm", + "type": "array", + "items": { + "type": "string", + "enum": [ + "http://www.w3.org/2009/xmlenc11#aes256-gcm", + "http://www.w3.org/2009/xmlenc11#aes192-gcm", + "http://www.w3.org/2009/xmlenc11#aes128-gcm", + "http://www.w3.org/2001/04/xmlenc#aes256-cbc", + "http://www.w3.org/2001/04/xmlenc#aes192-cbc", + "http://www.w3.org/2001/04/xmlenc#aes128-cbc", + "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + ], + "enumNames": [ + "value.algorithm-gcm-256", + "value.algorithm-gcm-192", + "value.algorithm-gcm-128", + "value.algorithm-cbc-256", + "value.algorithm-cbc-192", + "value.algorithm-cbc-128", + "value.algorithm-cbc-tripledes" + ] + } + } + } +} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 31e5eeb5a..5861402ae 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -163,15 +163,4 @@ custom: helpText: tooltip.ignore-request-signatures attributeName: http://shibboleth.net/ns/profiles/ignoreRequestSignatures attributeFriendlyName: ignoreRequestSignatures -# shibprops: -# - category: main # required -# configFile: random.properties # required -# defaultValue: foo -# description: whatever -# idpVersion: 4.1 # required -# module: some random module -# moduleVersion: 1 -# note: this is an example for the application.yml file -# propertyName: example.property.name # required -# propertyType: SELECTION_LIST # required as one of: BOOLEAN, DURATION, INTEGER, SELECTION_LIST, SPRING_BEAN_ID, STRING -# selectionItems: dddd,eeee # required if propertyType is SELECTION_LIST - comma seperated values \ No newline at end of file + diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 38213cef2..ddfa6947f 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -94,6 +94,7 @@ value.false=false value.regex=Regex value.script=Script value.entity-id=Entity ID +value.reference=Condition Ref value.support=Support value.technical=Technical @@ -606,6 +607,7 @@ message.wizard-status=Step { index } of { length } message.entity-id-min-unique=You must add at least one entity id target and they must each be unique. message.required-for-scripts=Required for Scripts message.required-for-regex=Required for Regex +message.required-for-condition-ref=Required for Condition Ref message.file-doesnt-exist=The requested file to be processed does not exist on the server. message.database-constraint=There was a database constraint problem processing the request. Check the request to ensure that fields that must be unique are truly unique. @@ -755,4 +757,18 @@ tooltip.role-description=A description of the purpose of the role. tooltip.contact-information=Add a contact to organization information. Contacts provide information about how to contact the organization responsible for standing up the entity. label.external-description=Description -tooltip.external-description=A brief description of the purpose of this filter. \ No newline at end of file + +tooltip.external-description=A brief description of the purpose of this filter. + +label.algorithm=Algorithm +tooltip.algorithm=Block encryption algorithms are designed for encrypting and decrypting data in fixed size, multiple octet blocks. +tooltip.search-criteria-by=The value used to search against, such as a regex pattern or entityID to match against. + +value.algorithm-gcm-256=GCM (256) - http://www.w3.org/2009/xmlenc11#aes256-gcm +value.algorithm-gcm-192=GCM (192) - http://www.w3.org/2009/xmlenc11#aes192-gcm +value.algorithm-gcm-128=GCM (128) - http://www.w3.org/2009/xmlenc11#aes128-gcm +value.algorithm-cbc-256=CBC (256) - http://www.w3.org/2001/04/xmlenc#aes256-cbc +value.algorithm-cbc-192=CBC (192) - http://www.w3.org/2001/04/xmlenc#aes192-cbc +value.algorithm-cbc-128=CBC (128) - http://www.w3.org/2001/04/xmlenc#aes128-cbc +value.algorithm-cbc-tripledes=CBC (TRIPLEDES) - http://www.w3.org/2001/04/xmlenc#tripledes-cbc +message.algorithms-unique=Each algorithm may only be used once. diff --git a/backend/src/main/resources/jpa-encryption-config.xml b/backend/src/main/resources/jpa-encryption-config.xml new file mode 100644 index 000000000..05adde279 --- /dev/null +++ b/backend/src/main/resources/jpa-encryption-config.xml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/jpa-saml2-metadata-algorithm-config.xml b/backend/src/main/resources/jpa-saml2-metadata-algorithm-config.xml index f6432a71a..c37c788c1 100644 --- a/backend/src/main/resources/jpa-saml2-metadata-algorithm-config.xml +++ b/backend/src/main/resources/jpa-saml2-metadata-algorithm-config.xml @@ -6,13 +6,13 @@ - + - + @@ -31,4 +31,4 @@ - + \ No newline at end of file diff --git a/backend/src/main/templates/SignatureBuilderTemplate.java b/backend/src/main/templates/SignatureBuilderTemplate.java new file mode 100644 index 000000000..d8ba87cb1 --- /dev/null +++ b/backend/src/main/templates/SignatureBuilderTemplate.java @@ -0,0 +1,22 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain; + +import edu.internet2.tier.shibboleth.admin.ui.opensaml.xml.AbstractXMLObjectBuilder; +import org.opensaml.xmlsec.signature.support.SignatureConstants; + +public class {{TOKEN}}Builder extends AbstractXMLObjectBuilder<{{TOKEN}}> { + public {{TOKEN}}Builder() { + } + + public {{TOKEN}} buildObject() { + return buildObject(SignatureConstants.XMLSIG_NS, {{TOKEN}}.DEFAULT_ELEMENT_LOCAL_NAME, + SignatureConstants.XMLSIG_PREFIX); + } + + public {{TOKEN}} buildObject(final String namespaceURI, final String localName, final String namespacePrefix) { + {{TOKEN}} o = new {{TOKEN}}(); + o.setNamespaceURI(namespaceURI); + o.setElementLocalName(localName); + o.setNamespacePrefix(namespacePrefix); + return o; + } +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index b9789201f..14f5d9a16 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -13,6 +13,7 @@ import org.springframework.test.context.ActiveProfiles import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.* +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ALGORITHM_FILTER import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.DYNAMIC_HTTP_METADATA_RESOLVER import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.FILESYSTEM_METADATA_RESOLVER @@ -87,6 +88,12 @@ class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Speci .jacksonMapper(jacksonMapper) .detectMalformedJson(false) .build()) + .register(ALGORITHM_FILTER, JsonSchemaLocationBuilder.with() + .jsonSchemaLocation('classpath:algorithm-filter.schema.json') + .resourceLoader(resourceLoader) + .jacksonMapper(jacksonMapper) + .detectMalformedJson(false) + .build()) } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy index 82bee21b2..2820533e9 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy @@ -90,6 +90,11 @@ class MetadataFiltersControllerTests extends AbstractBaseDataJpaTest { return null } + @Override + Document generateSingleMetadataConfiguration(MetadataResolver mr) { + return null + } + @Override MetadataResolver updateMetadataResolverEnabledStatus(MetadataResolver existingResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException { // This won't get called diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializerForTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializerForTest.groovy new file mode 100644 index 000000000..f84afdcc5 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/opensaml/config/JPAXMLObjectProviderInitializerForTest.groovy @@ -0,0 +1,12 @@ +package edu.internet2.tier.shibboleth.admin.ui.opensaml.config + +import org.opensaml.core.xml.config.AbstractXMLObjectProviderInitializer + +class JPAXMLObjectProviderInitializerForTest extends AbstractXMLObjectProviderInitializer { + @Override + protected String[] getConfigResources() { + return new String[]{ + "/jpa-saml2-metadata-config.xml", "jpa-saml2-metadata-algorithm-config.xml", "jpa-encryption-config.xml", "jpa-signature-config.xml" + } + } +} \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy index 9905dbcea..f5f37da1f 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy @@ -1,16 +1,17 @@ package edu.internet2.tier.shibboleth.admin.ui.service -import com.google.common.collect.Lists import edu.internet2.tier.shibboleth.admin.ui.AbstractBaseDataJpaTest import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration -import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute -import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeValue +import edu.internet2.tier.shibboleth.admin.ui.domain.AlgorithmDigestMethod +import edu.internet2.tier.shibboleth.admin.ui.domain.EncryptionMethod +import edu.internet2.tier.shibboleth.admin.ui.domain.SignatureDigestMethod import edu.internet2.tier.shibboleth.admin.ui.domain.XSString import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.AlgorithmFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ClasspathMetadataResource import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ExternalMetadataResolver @@ -21,6 +22,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.SvnMetadataResour import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.TemplateScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import edu.internet2.tier.shibboleth.admin.ui.opensaml.config.JPAXMLObjectProviderInitializerForTest import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility @@ -29,9 +31,11 @@ import groovy.xml.MarkupBuilder import net.shibboleth.ext.spring.resource.ResourceHelper import net.shibboleth.utilities.java.support.resolver.CriteriaSet import org.opensaml.core.criterion.EntityIdCriterion +import org.opensaml.saml.common.xml.SAMLConstants import org.opensaml.saml.metadata.resolver.MetadataResolver import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver +import org.opensaml.xmlsec.signature.support.SignatureConstants import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean @@ -48,7 +52,7 @@ import java.time.Instant import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedXmlIsTheSameAsExpectedXml -@ContextConfiguration(classes=[ JPAMRSIConfig, PlaceholderResolverComponentsConfiguration ]) +@ContextConfiguration(classes=[ JPAMRSIConfig, PlaceholderResolverComponentsConfiguration, JPAXMLObjectProviderInitializerForTest ]) class JPAMetadataResolverServiceImplTests extends AbstractBaseDataJpaTest { @Autowired @@ -184,6 +188,47 @@ class JPAMetadataResolverServiceImplTests extends AbstractBaseDataJpaTest { !diff.hasDifferences() } + def 'test generating AlgorithmFilter shibui-2268 entities'() { + given: + def filter = TestObjectGenerator.algorithmFilter() + ArrayList algs = new ArrayList<>() + algs.add("http://www.w3.org/2001/04/xmlenc#aes128-cbc") + filter.setAlgorithms(algs) + + AlgorithmFilterTarget target = new AlgorithmFilterTarget() + target.setAlgorithmFilterTargetType(AlgorithmFilterTarget.AlgorithmFilterTargetType.ENTITY) + ArrayList entities = new ArrayList<>() + entities.add("https://broken.example.org/sp") + entities.add("https://also-broken.example.org/sp") + target.setValue(entities) + filter.setAlgorithmFilterTarget(target) + + when: + genXmlSnippet(markupBuilder) { JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForFilter(filter, it) } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/2268-entity.xml', domBuilder.parseText(writer.toString())) + } + + def 'test generating AlgorithmFilter shibui-2268 script'() { + given: + def filter = TestObjectGenerator.algorithmFilter() + ArrayList algs = new ArrayList<>() + algs.add("http://www.w3.org/2001/04/xmlenc#aes128-cbc") + filter.setAlgorithms(algs) + + AlgorithmFilterTarget target = new AlgorithmFilterTarget() + target.setAlgorithmFilterTargetType(AlgorithmFilterTarget.AlgorithmFilterTargetType.CONDITION_SCRIPT) + target.setSingleValue("\"use strict\";\nfalse;") + filter.setAlgorithmFilterTarget(target) + + when: + genXmlSnippet(markupBuilder) { JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForFilter(filter, it) } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/2268-script.xml', domBuilder.parseText(writer.toString())) + } + def 'test generating EntityAttributesFilter xml snippet with condition script'() { given: def filter = testObjectGenerator.entityAttributesFilterWithConditionScript() @@ -506,6 +551,34 @@ class JPAMetadataResolverServiceImplTests extends AbstractBaseDataJpaTest { !DiffBuilder.compare(Input.fromStream(this.class.getResourceAsStream('/metadata/984-3-expected.xml'))).withTest(Input.fromString(openSamlObjects.marshalToXmlString(ed))).ignoreComments().ignoreWhitespace().build().hasDifferences() } + private EncryptionMethod getEncryptionMethod(String algorithm){ + EncryptionMethod encryptionMethod = new EncryptionMethod() + encryptionMethod.setElementLocalName(EncryptionMethod.DEFAULT_ELEMENT_LOCAL_NAME) + encryptionMethod.setNamespacePrefix(SAMLConstants.SAML20MD_PREFIX) + encryptionMethod.setNamespaceURI(SAMLConstants.SAML20MD_NS) + encryptionMethod.setSchemaLocation(SAMLConstants.SAML20MD_SCHEMA_LOCATION) + encryptionMethod.setAlgorithm(algorithm) + return encryptionMethod + } + + private AlgorithmDigestMethod getDigestMethod(String algorithm) { + AlgorithmDigestMethod dm = new AlgorithmDigestMethod() + dm.setNamespaceURI(SAMLConstants.SAML20ALG_NS) + dm.setElementLocalName(AlgorithmDigestMethod.DEFAULT_ELEMENT_LOCAL_NAME) + dm.setNamespacePrefix(SAMLConstants.SAML20ALG_PREFIX) + dm.setAlgorithm(algorithm) + return dm + } + + private SignatureDigestMethod getSignatureDigestMethod(String algorithm) { + SignatureDigestMethod dm = new SignatureDigestMethod() + dm.setNamespaceURI(SignatureConstants.XMLSIG_NS) + dm.setElementLocalName(SignatureDigestMethod.DEFAULT_ELEMENT_LOCAL_NAME) + dm.setNamespacePrefix(SignatureConstants.XMLSIG_PREFIX) + dm.setAlgorithm(algorithm) + return dm + } + static genXmlSnippet(MarkupBuilder xml, Closure xmlNodeGenerator) { xml.MetadataProvider('id': 'ShibbolethMetadata', 'xmlns': 'urn:mace:shibboleth:2.0:metadata', diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy index 7b2865462..972120ab4 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy @@ -17,6 +17,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.SignatureValidationFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.AlgorithmFilter import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterTargetRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ClasspathMetadataResource @@ -182,6 +183,14 @@ class TestObjectGenerator { randomFilter } + static AlgorithmFilter algorithmFilter() { + return new AlgorithmFilter().with { + it.name = "Algorithm" + it.enabled = true; + it + } + } + SignatureValidationFilter signatureValidationFilter() { new SignatureValidationFilter().with { it.name = 'SignatureValidation' diff --git a/backend/src/test/resources/META-INF/services/org.opensaml.core.config.Initializer b/backend/src/test/resources/META-INF/services/org.opensaml.core.config.Initializer new file mode 100644 index 000000000..c7c2e7cb3 --- /dev/null +++ b/backend/src/test/resources/META-INF/services/org.opensaml.core.config.Initializer @@ -0,0 +1 @@ +edu.internet2.tier.shibboleth.admin.ui.opensaml.config.JPAXMLObjectProviderInitializerForTest \ No newline at end of file diff --git a/backend/src/test/resources/conf/2268-entity.xml b/backend/src/test/resources/conf/2268-entity.xml new file mode 100644 index 000000000..daf8c5fac --- /dev/null +++ b/backend/src/test/resources/conf/2268-entity.xml @@ -0,0 +1,22 @@ + + + + + + + https://broken.example.org/sp + https://also-broken.example.org/sp + + + \ No newline at end of file diff --git a/backend/src/test/resources/conf/2268-script.xml b/backend/src/test/resources/conf/2268-script.xml new file mode 100644 index 000000000..3283e883c --- /dev/null +++ b/backend/src/test/resources/conf/2268-script.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/test/resources/jpa-encryption-config.xml b/backend/src/test/resources/jpa-encryption-config.xml new file mode 100644 index 000000000..05adde279 --- /dev/null +++ b/backend/src/test/resources/jpa-encryption-config.xml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/test/resources/jpa-saml2-metadata-algorithm-config.xml b/backend/src/test/resources/jpa-saml2-metadata-algorithm-config.xml new file mode 100644 index 000000000..c37c788c1 --- /dev/null +++ b/backend/src/test/resources/jpa-saml2-metadata-algorithm-config.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/test/resources/jpa-saml2-metadata-config.xml b/backend/src/test/resources/jpa-saml2-metadata-config.xml new file mode 100644 index 000000000..b008809ce --- /dev/null +++ b/backend/src/test/resources/jpa-saml2-metadata-config.xml @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/test/resources/jpa-saml2-metadata-ds-config.xml b/backend/src/test/resources/jpa-saml2-metadata-ds-config.xml new file mode 100644 index 000000000..3a0eed8f0 --- /dev/null +++ b/backend/src/test/resources/jpa-saml2-metadata-ds-config.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/test/resources/jpa-signature-config.xml b/backend/src/test/resources/jpa-signature-config.xml new file mode 100644 index 000000000..9a8da32e8 --- /dev/null +++ b/backend/src/test/resources/jpa-signature-config.xml @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7efe1ae08..1594d2baa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ name=shibui group=edu.internet2.tier.shibboleth.admin.ui -version=1.12.0-SNAPSHOT +version=1.13.0-SNAPSHOT ### library versions ### commonsCollections4Version=4.4 diff --git a/ui/public/assets/schema/filter/algorithm.schema.json b/ui/public/assets/schema/filter/algorithm.schema.json new file mode 100644 index 000000000..a7abba111 --- /dev/null +++ b/ui/public/assets/schema/filter/algorithm.schema.json @@ -0,0 +1,86 @@ +{ + "type": "object", + "required": ["name"], + "properties": { + "name": { + "title": "label.filter-name", + "description": "tooltip.filter-name", + "type": "string" + }, + "filterEnabled": { + "title": "label.enable-filter", + "description": "tooltip.enable-filter", + "type": "boolean", + "default": false + }, + "algorithmFilterTarget": { + "title": "label.search-criteria", + "description": "tooltip.search-criteria", + "type": "object", + "properties": { + "algorithmFilterTargetType": { + "title": "label.filter-target-type", + "type": "string", + "default": "ENTITY", + "enum": ["ENTITY", "CONDITION_REF", "CONDITION_SCRIPT"], + "enumNames": [ + "value.entity-id", + "value.reference", + "value.script" + ] + }, + "value": { + "title": "label.filter-target-value", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string" + } + } + }, + "required": ["value", "algorithmFilterTargetType"] + }, + "@type": { + "type": "string", + "default": "Algorithm" + }, + "version": { + "type": "integer" + }, + "resourceId": { + "type": "string" + }, + "algorithms": { + "$ref": "#/definitions/AlgorithmList" + } + }, + "definitions": { + "AlgorithmList": { + "title": "label.algorithm", + "description": "tooltip.algorithm", + "type": "array", + "items": { + "type": "string", + "enum": [ + "http://www.w3.org/2009/xmlenc11#aes256-gcm", + "http://www.w3.org/2009/xmlenc11#aes192-gcm", + "http://www.w3.org/2009/xmlenc11#aes128-gcm", + "http://www.w3.org/2001/04/xmlenc#aes256-cbc", + "http://www.w3.org/2001/04/xmlenc#aes192-cbc", + "http://www.w3.org/2001/04/xmlenc#aes128-cbc", + "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + ], + "enumNames": [ + "value.algorithm-gcm-256", + "value.algorithm-gcm-192", + "value.algorithm-gcm-128", + "value.algorithm-cbc-256", + "value.algorithm-cbc-192", + "value.algorithm-cbc-128", + "value.algorithm-cbc-tripledes" + ] + } + } + } +} diff --git a/ui/src/app/core/components/ProtectRoute.test.js b/ui/src/app/core/components/ProtectRoute.test.js index 0edd7662e..477707774 100644 --- a/ui/src/app/core/components/ProtectRoute.test.js +++ b/ui/src/app/core/components/ProtectRoute.test.js @@ -6,7 +6,8 @@ import { ProtectRoute } from './ProtectRoute'; const mockIsAdmin = jest.fn(); jest.mock('../user/UserContext', () => ({ - useIsAdmin: () => mockIsAdmin() + useIsAdmin: () => mockIsAdmin(), + useCurrentUser: () => ({role: 'ROLE_ADMIN'}), })); const renderWithRouter = (ui, { route = '/' } = {}) => { diff --git a/ui/src/app/form/component/fields/FilterTargetField.js b/ui/src/app/form/component/fields/FilterTargetField.js index afb4f7828..d42738059 100644 --- a/ui/src/app/form/component/fields/FilterTargetField.js +++ b/ui/src/app/form/component/fields/FilterTargetField.js @@ -128,7 +128,8 @@ const FilterTargetField = ({ }; const selectType = (option) => { - setSelectedTarget([]); + const t = option.value === 'REGEX' || option.value === 'CONDITION_REF' ? [''] : []; + setSelectedTarget(t); setSelectedType(option); }; @@ -170,7 +171,7 @@ const FilterTargetField = ({ - +
@@ -240,7 +241,6 @@ const FilterTargetField = ({ {errorSchema?.value?.__errors ? {errors} - : Required for Regex @@ -249,14 +249,33 @@ const FilterTargetField = ({ } } - + {targetType === 'CONDITION_REF' && + <> + handleTextChange(value) } /> + {errorSchema?.value?.__errors ? + + {errors} + : + + Required for Condition Ref +   + + } + + }
{targetType === 'ENTITY' &&
@@ -305,7 +324,4 @@ const FilterTargetField = ({ ); }; -/* -*/ - export default FilterTargetField; \ No newline at end of file diff --git a/ui/src/app/form/component/widgets/SelectWidget.js b/ui/src/app/form/component/widgets/SelectWidget.js index 2bf62bb2d..57f18b532 100644 --- a/ui/src/app/form/component/widgets/SelectWidget.js +++ b/ui/src/app/form/component/widgets/SelectWidget.js @@ -61,6 +61,7 @@ const SelectWidget = ({ onFocus, placeholder, rawErrors = [], + uiSchema, }) => { const { enumOptions, enumDisabled } = options; @@ -120,6 +121,9 @@ const SelectWidget = ({ onChange={(event) => { const newValue = getValue(event, multiple); onChange(processValue(schema, newValue)); + if (uiSchema.checkOnChange) { + setTouched(true); + } }}> {!multiple && schema.default === undefined && ( diff --git a/ui/src/app/metadata/Filter.js b/ui/src/app/metadata/Filter.js index 4c1bc707c..58b867040 100644 --- a/ui/src/app/metadata/Filter.js +++ b/ui/src/app/metadata/Filter.js @@ -11,6 +11,8 @@ export function Filter() { const { path, url } = useRouteMatch(); + console.log(path, url) + return ( diff --git a/ui/src/app/metadata/component/properties/PropertyValue.js b/ui/src/app/metadata/component/properties/PropertyValue.js index 8e5beb226..ef2e89e59 100644 --- a/ui/src/app/metadata/component/properties/PropertyValue.js +++ b/ui/src/app/metadata/component/properties/PropertyValue.js @@ -14,7 +14,7 @@ export function PropertyValue ({ name, value, columns, className }) { { name && value !== null && value !== undefined ? - {value.toString()} + {value.toString()} )}> { + const base = BaseFilterDefinition.validator(data, current, group, 'algorithmFilterTarget', 'algorithmFilterTargetType'); + + return (formData, errors) => { + const errorList = base(formData, errors); + const { algorithms = [] } = formData; + + const dupes = algorithms.filter((item, index) => index !== algorithms.indexOf(item)); + + if (dupes.length) { + algorithms.forEach((value, index) => { + if (dupes.indexOf(value) > -1) { + errors.algorithms[index].addError('message.algorithms-unique'); + } + }); + } + + return errorList; + } + }, + formatter: (changes) => ({ + ...changes, + '@type': AlgorithmFilterWizard.type + }) +}; + +export const AlgorithmFilterEditor = { + ...AlgorithmFilterWizard, + steps: [ + { + id: 'common', + label: 'label.target', + index: 1, + fields: [ + 'name', + '@type', + 'resourceId', + 'algorithmFilterTarget', + 'filterEnabled' + ] + }, + { + id: 'options', + label: 'label.options', + index: 2, + initialValues: [], + fields: [ + 'algorithms' + ] + } + ] +}; \ No newline at end of file diff --git a/ui/src/app/metadata/domain/filter/definition/BaseFilterDefinition.js b/ui/src/app/metadata/domain/filter/definition/BaseFilterDefinition.js index daed4cadc..1f8191cdc 100644 --- a/ui/src/app/metadata/domain/filter/definition/BaseFilterDefinition.js +++ b/ui/src/app/metadata/domain/filter/definition/BaseFilterDefinition.js @@ -29,6 +29,13 @@ export const BaseFilterDefinition = { errors[targetProp].value.addError('message.required-for-scripts'); } } + + if (formData[targetProp][typeProp] === 'CONDITION_REF') { + const { [targetProp]: { value } } = formData; + if (!value[0]) { + errors[targetProp].value.addError('message.required-for-condition-ref'); + } + } } return errors; diff --git a/ui/src/app/metadata/domain/filter/index.js b/ui/src/app/metadata/domain/filter/index.js index 9f5326ba9..fe4af7fd1 100644 --- a/ui/src/app/metadata/domain/filter/index.js +++ b/ui/src/app/metadata/domain/filter/index.js @@ -1,14 +1,17 @@ import { EntityAttributesFilterEditor } from './definition/EntityAttributesFilterDefinition'; import { NameIDFilterEditor } from './definition/NameIdFilterDefinition'; +import { AlgorithmFilterEditor } from './definition/AlgorithmFilterDefinition'; export const MetadataFilterWizardTypes = { EntityAttributes: EntityAttributesFilterEditor, - NameIDFormat: NameIDFilterEditor + NameIDFormat: NameIDFilterEditor, + Algorithm: AlgorithmFilterEditor, }; export const MetadataFilterEditorTypes = [ EntityAttributesFilterEditor, - NameIDFilterEditor + NameIDFilterEditor, + AlgorithmFilterEditor, ]; export const MetadataFilterTypes = [