diff --git a/apps/admin-ui/cypress/e2e/clients_saml_test.spec.ts b/apps/admin-ui/cypress/e2e/clients_saml_test.spec.ts index 3fa2261e7a..87320dcc40 100644 --- a/apps/admin-ui/cypress/e2e/clients_saml_test.spec.ts +++ b/apps/admin-ui/cypress/e2e/clients_saml_test.spec.ts @@ -5,6 +5,7 @@ import SidebarPage from "../support/pages/admin_console/SidebarPage"; import ModalUtils from "../support/util/ModalUtils"; import adminClient from "../support/util/AdminClient"; import { keycloakBefore } from "../support/util/keycloak_hooks"; +import SettingsTab from "../support/pages/admin_console/manage/clients/client_details/tabs/SettingsTab"; const loginPage = new LoginPage(); const masthead = new Masthead(); @@ -112,4 +113,83 @@ describe("Clients SAML tests", () => { cy.findAllByTestId("certificate").should("have.length", 1); }); }); + + describe("SAML settings tab", () => { + const clientId = "saml-settings"; + const settingsTab = new SettingsTab(); + + before(() => { + adminClient.createClient({ + clientId, + protocol: "saml", + }); + keycloakBefore(); + loginPage.logIn(); + }); + + after(() => { + adminClient.deleteClient(clientId); + }); + + beforeEach(() => { + sidebarPage.goToClients(); + listingPage.searchItem(clientId).goToItemDetails(clientId); + }); + + it("should check SAML capabilities", () => { + cy.get(".pf-c-jump-links__list").contains("SAML capabilities").click(); + + settingsTab.assertNameIdFormatDropdown(); + settingsTab.assertSAMLCapabilitiesSwitches(); + }); + + it("should check signature and encryption", () => { + cy.get(".pf-c-jump-links__list") + .contains("Signature and Encryption") + .click(); + + settingsTab.assertSignatureAlgorithmDropdown(); + settingsTab.assertSignatureKeyNameDropdown(); + settingsTab.assertCanonicalizationDropdown(); + + settingsTab.assertSignatureEncryptionSwitches(); + }); + + it("should check access settings", () => { + cy.get(".pf-c-jump-links__list").contains("Access settings").click(); + + const validUrl = + "http://localhost:8180/realms/master/protocol/" + + clientId + + "/clients/"; + const rootUrlError = + "Client could not be updated: Root URL is not a valid URL"; + const homeUrlError = + "Client could not be updated: Base URL is not a valid URL"; + + cy.get("#kc-root-url").type("Invalid URL"); + settingsTab.clickSaveBtn(); + masthead.checkNotificationMessage(rootUrlError); + cy.get("#kc-root-url").clear(); + + cy.get("#kc-home-url").type("Invalid URL"); + settingsTab.clickSaveBtn(); + masthead.checkNotificationMessage(homeUrlError); + cy.get("#kc-home-url").clear(); + + cy.get("#kc-root-url").type(validUrl); + cy.get("#kc-home-url").type(validUrl); + settingsTab.clickSaveBtn(); + masthead.checkNotificationMessage("Client successfully updated"); + + settingsTab.assertAccessSettings(); + }); + + it("should check login settings", () => { + cy.get(".pf-c-jump-links__list").contains("Login settings").click(); + + settingsTab.assertLoginThemeDropdown(); + settingsTab.assertLoginSettings(); + }); + }); }); diff --git a/apps/admin-ui/cypress/e2e/clients_test.spec.ts b/apps/admin-ui/cypress/e2e/clients_test.spec.ts index 8b83342424..291d1b62f7 100644 --- a/apps/admin-ui/cypress/e2e/clients_test.spec.ts +++ b/apps/admin-ui/cypress/e2e/clients_test.spec.ts @@ -1023,8 +1023,8 @@ describe("Clients test", () => { }); it("Displays the correct tabs", () => { + clientDetailsPage.goToSettingsTab(); clientDetailsPage - .goToSettingsTab() .tabUtils() .checkTabExists(ClientsDetailsTab.Settings, true) .checkTabExists(ClientsDetailsTab.Roles, true) diff --git a/apps/admin-ui/cypress/support/pages/admin_console/manage/clients/client_details/tabs/SettingsTab.ts b/apps/admin-ui/cypress/support/pages/admin_console/manage/clients/client_details/tabs/SettingsTab.ts index 3880cf38d2..e762abce85 100644 --- a/apps/admin-ui/cypress/support/pages/admin_console/manage/clients/client_details/tabs/SettingsTab.ts +++ b/apps/admin-ui/cypress/support/pages/admin_console/manage/clients/client_details/tabs/SettingsTab.ts @@ -1,3 +1,239 @@ -import CommonPage from "../../../../../CommonPage"; +import PageObject from "../../../../components/PageObject"; +import Masthead from "../../../../Masthead"; -export default class SettingsTab extends CommonPage {} +export enum NameIdFormat { + Username = "username", + Email = "email", + Transient = "transient", + Persistent = "persistent", +} + +const masthead = new Masthead(); + +export default class SettingsTab extends PageObject { + private samlNameIdFormat = "#samlNameIdFormat"; + private forceNameIdFormat = "forceNameIdFormat"; + private forcePostBinding = "forcePostBinding"; + private forceArtifactBinding = "forceArtifactBinding"; + private includeAuthnStatement = "includeAuthnStatement"; + private includeOneTimeUseCondition = "includeOneTimeUseCondition"; + private optimizeLookup = "optimizeLookup"; + + private signDocumentsSwitch = "signDocuments"; + private signAssertionsSwitch = "signAssertions"; + private signatureAlgorithm = "#signatureAlgorithm"; + private signatureKeyName = "#signatureKeyName"; + private canonicalization = "#canonicalization"; + + private loginTheme = "#loginTheme"; + private consentSwitch = "#kc-consent-switch"; + private displayClientSwitch = "#kc-display-on-client-switch"; + private consentScreenText = "#kc-consent-screen-text"; + + private saveBtn = "settingsSave"; + private revertBtn = "settingsRevert"; + + private redirectUris = "#redirectUris"; + private postLogoutRedirectUris = "attributes.post.logout.redirect.uris"; + + private idpInitiatedSsoUrlName = "idpInitiatedSsoUrlName"; + private idpInitiatedSsoRelayState = "idpInitiatedSsoRelayState"; + private masterSamlProcessingUrl = "masterSamlProcessingUrl"; + + public clickSaveBtn() { + cy.findByTestId(this.saveBtn).click(); + return this; + } + + public clickRevertBtn() { + cy.findByTestId(this.revertBtn).click(); + return this; + } + + public selectNameIdFormatDropdown(nameId: NameIdFormat) { + cy.get(this.samlNameIdFormat).click(); + cy.findByText(nameId).click(); + return this; + } + + public selectSignatureAlgorithmDropdown(sign: string) { + cy.get(this.signatureAlgorithm).click(); + cy.findByText(sign).click(); + return this; + } + + public selectSignatureKeyNameDropdown(keyName: string) { + cy.get(this.signatureKeyName).click(); + cy.findByText(keyName).click(); + return this; + } + + public selectCanonicalizationDropdown(canon: string) { + cy.get(this.canonicalization).click(); + cy.findByText(canon).click(); + } + + public selectLoginThemeDropdown(theme: string) { + cy.get(this.loginTheme).click(); + cy.findByText(theme).click(); + } + + public clickForceNameIdFormatSwitch() { + cy.findByTestId(this.forceNameIdFormat).parent().click(); + return this; + } + + public clickForcePostBindingSwitch() { + cy.findByTestId(this.forcePostBinding).parent().click(); + return this; + } + + public clickForceArtifactBindingSwitch() { + cy.findByTestId(this.forceArtifactBinding).parent().click(); + return this; + } + + public clickIncludeAuthnStatementSwitch() { + cy.findByTestId(this.includeAuthnStatement).parent().click(); + return this; + } + + public clickIncludeOneTimeUseConditionSwitch() { + cy.findByTestId(this.includeOneTimeUseCondition).parent().click(); + return this; + } + + public clickOptimizeLookupSwitch() { + cy.findByTestId(this.optimizeLookup).parent().click(); + return this; + } + + public clickSignDocumentsSwitch() { + cy.findByTestId(this.signDocumentsSwitch).parent().click(); + return this; + } + + public clickSignAssertionsSwitch() { + cy.findByTestId(this.signAssertionsSwitch).parent().click(); + return this; + } + + public clickConsentSwitch() { + cy.get(this.consentSwitch).parent().click(); + return this; + } + + public clickDisplayClientSwitch() { + cy.get(this.displayClientSwitch).parent().click(); + return this; + } + + public assertNameIdFormatDropdown() { + this.selectNameIdFormatDropdown(NameIdFormat.Email); + this.selectNameIdFormatDropdown(NameIdFormat.Username); + this.selectNameIdFormatDropdown(NameIdFormat.Persistent); + this.selectNameIdFormatDropdown(NameIdFormat.Transient); + return this; + } + + public assertSignatureAlgorithmDropdown() { + this.selectSignatureAlgorithmDropdown("RSA_SHA1"); + this.selectSignatureAlgorithmDropdown("RSA_SHA256"); + this.selectSignatureAlgorithmDropdown("RSA_SHA256_MGF1"); + this.selectSignatureAlgorithmDropdown("RSA_SHA512"); + this.selectSignatureAlgorithmDropdown("RSA_SHA512_MGF1"); + this.selectSignatureAlgorithmDropdown("DSA_SHA1"); + return this; + } + + public assertSignatureKeyNameDropdown() { + this.selectSignatureKeyNameDropdown("KEY_ID"); + this.selectSignatureKeyNameDropdown("CERT_SUBJECT"); + this.selectSignatureKeyNameDropdown("NONE"); + return this; + } + + public assertCanonicalizationDropdown() { + this.selectCanonicalizationDropdown("EXCLUSIVE_WITH_COMMENTS"); + this.selectCanonicalizationDropdown("EXCLUSIVE"); + this.selectCanonicalizationDropdown("INCLUSIVE_WITH_COMMENTS"); + this.selectCanonicalizationDropdown("INCLUSIVE"); + return this; + } + + public assertLoginThemeDropdown() { + this.selectLoginThemeDropdown("base"); + this.selectLoginThemeDropdown("keycloak"); + return this; + } + + public assertSAMLCapabilitiesSwitches() { + this.clickForceNameIdFormatSwitch(); + this.assertSwitchStateOn(cy.findByTestId(this.forceNameIdFormat)); + + this.clickForcePostBindingSwitch(); + this.assertSwitchStateOff(cy.findByTestId(this.forcePostBinding)); + + this.clickForceArtifactBindingSwitch(); + this.assertSwitchStateOn(cy.findByTestId(this.forceArtifactBinding)); + + this.clickIncludeAuthnStatementSwitch(); + this.assertSwitchStateOff(cy.findByTestId(this.includeAuthnStatement)); + + this.clickIncludeOneTimeUseConditionSwitch(); + this.assertSwitchStateOn(cy.findByTestId(this.includeOneTimeUseCondition)); + + this.clickOptimizeLookupSwitch(); + this.assertSwitchStateOn(cy.findByTestId(this.optimizeLookup)); + return this; + } + + public assertSignatureEncryptionSwitches() { + cy.get(this.signatureAlgorithm).should("exist"); + + this.clickSignDocumentsSwitch(); + this.assertSwitchStateOff(cy.findByTestId(this.signDocumentsSwitch)); + cy.get(this.signatureAlgorithm).should("not.exist"); + + this.clickSignAssertionsSwitch(); + this.assertSwitchStateOn(cy.findByTestId(this.signAssertionsSwitch)); + cy.get(this.signatureAlgorithm).should("exist"); + return this; + } + + public assertLoginSettings() { + cy.get(this.displayClientSwitch).should("be.disabled"); + cy.get(this.consentScreenText).should("be.disabled"); + this.clickConsentSwitch(); + cy.get(this.displayClientSwitch).should("not.be.disabled"); + this.clickDisplayClientSwitch(); + cy.get(this.consentScreenText).should("not.be.disabled"); + cy.get(this.consentScreenText).click().type("Consent Screen Text"); + return this; + } + + public selectRedirectUriTextField(number: number, text: string) { + cy.get(this.redirectUris + number) + .click() + .clear() + .type(text); + return this; + } + + public assertAccessSettings() { + const redirectUriError = + "Client could not be updated: A redirect URI is not a valid URI"; + + cy.findByTestId(this.idpInitiatedSsoUrlName).click().type("a"); + cy.findByTestId(this.idpInitiatedSsoRelayState).click().type("b"); + cy.findByTestId(this.masterSamlProcessingUrl).click().type("c"); + + this.selectRedirectUriTextField(0, "Redirect Uri"); + cy.findByText("Add valid redirect URIs").click(); + this.selectRedirectUriTextField(1, "Redirect Uri second field"); + this.clickSaveBtn(); + masthead.checkNotificationMessage(redirectUriError); + + return this; + } +} diff --git a/apps/admin-ui/src/clients/add/AccessSettings.tsx b/apps/admin-ui/src/clients/add/AccessSettings.tsx index 3c474157e0..8b4fb4244c 100644 --- a/apps/admin-ui/src/clients/add/AccessSettings.tsx +++ b/apps/admin-ui/src/clients/add/AccessSettings.tsx @@ -129,6 +129,7 @@ export const AccessSettings = ({ type="text" id="idpInitiatedSsoUrlName" name="attributes.saml_idp_initiated_sso_url_name" + data-testid="idpInitiatedSsoUrlName" ref={register} /> @@ -146,6 +147,7 @@ export const AccessSettings = ({ type="text" id="idpInitiatedSsoRelayState" name="attributes.saml_idp_initiated_sso_relay_state" + data-testid="idpInitiatedSsoRelayState" ref={register} /> @@ -163,6 +165,7 @@ export const AccessSettings = ({ type="text" id="masterSamlProcessingUrl" name="adminUrl" + data-testid="masterSamlProcessingUrl" ref={register} />