keycloak-scim/cypress/integration/clients_test.spec.ts
Jenny bbc0bcf8b2
Add new capability configs and tests (#2164)
* add checkbox fields, more tests

unskip test

fix beforeEach

add front channel logout configs

set default to true

set default to true

fix console warning and conditionally render url field

show frontchannel settings under logout settings if OIDC client

PR feedback from Jon

* fix clients test

* resolve console warning

* addCapabilityConfigs
2022-03-02 16:59:37 -05:00

595 lines
18 KiB
TypeScript

import LoginPage from "../support/pages/LoginPage";
import Masthead from "../support/pages/admin_console/Masthead";
import ListingPage, {
Filter,
FilterAssignedType,
} from "../support/pages/admin_console/ListingPage";
import SidebarPage from "../support/pages/admin_console/SidebarPage";
import CreateClientPage from "../support/pages/admin_console/manage/clients/CreateClientPage";
import ModalUtils from "../support/util/ModalUtils";
import AdvancedTab from "../support/pages/admin_console/manage/clients/AdvancedTab";
import adminClient from "../support/util/AdminClient";
import InitialAccessTokenTab from "../support/pages/admin_console/manage/clients/InitialAccessTokenTab";
import {
keycloakBefore,
keycloakBeforeEach,
} from "../support/util/keycloak_hooks";
import RoleMappingTab from "../support/pages/admin_console/manage/RoleMappingTab";
import KeysTab from "../support/pages/admin_console/manage/clients/KeysTab";
import ClientScopesTab from "../support/pages/admin_console/manage/clients/ClientScopesTab";
let itemId = "client_crud";
const loginPage = new LoginPage();
const masthead = new Masthead();
const sidebarPage = new SidebarPage();
const listingPage = new ListingPage();
const createClientPage = new CreateClientPage();
const modalUtils = new ModalUtils();
describe("Clients test", () => {
describe("Client details - Client scopes subtab", () => {
const clientScopesTab = new ClientScopesTab();
const clientId = "client-scopes-subtab-test";
const clientScopeName = "client-scope-test";
const clientScopeNameDefaultType = "client-scope-test-default-type";
const clientScopeNameOptionalType = "client-scope-test-optional-type";
const clientScope = {
name: clientScopeName,
description: "",
protocol: "openid-connect",
attributes: {
"include.in.token.scope": "true",
"display.on.consent.screen": "true",
"gui.order": "1",
"consent.screen.text": "",
},
};
const msgScopeMappingRemoved = "Scope mapping successfully removed";
before(async () => {
adminClient.createClient({
clientId,
protocol: "openid-connect",
publicClient: false,
});
for (let i = 0; i < 5; i++) {
clientScope.name = clientScopeName + i;
await adminClient.createClientScope(clientScope);
await adminClient.addDefaultClientScopeInClient(
clientScopeName + i,
clientId
);
}
clientScope.name = clientScopeNameDefaultType;
await adminClient.createClientScope(clientScope);
clientScope.name = clientScopeNameOptionalType;
await adminClient.createClientScope(clientScope);
});
beforeEach(() => {
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClients();
cy.intercept("/auth/admin/realms/master/clients/*").as("fetchClient");
listingPage.searchItem(clientId).goToItemDetails(clientId);
cy.wait("@fetchClient");
clientScopesTab.goToClientScopesTab();
});
after(async () => {
adminClient.deleteClient(clientId);
for (let i = 0; i < 5; i++) {
await adminClient.deleteClientScope(clientScopeName + i);
}
await adminClient.deleteClientScope(clientScopeNameDefaultType);
await adminClient.deleteClientScope(clientScopeNameOptionalType);
});
it("should list client scopes", () => {
listingPage.itemsGreaterThan(1).itemExist(clientScopeName + 0);
});
it("should search existing client scope by name", () => {
listingPage
.searchItem(clientScopeName + 0, false)
.itemExist(clientScopeName + 0)
.itemsEqualTo(2);
});
it("should search non-existent client scope by name", () => {
const itemName = "non-existent-item";
listingPage.searchItem(itemName, false).checkTableExists(false);
});
it("should search existing client scope by assigned type", () => {
listingPage
.selectFilter(Filter.AssignedType)
.selectSecondaryFilterAssignedType(FilterAssignedType.Default)
.itemExist(FilterAssignedType.Default)
.itemExist(FilterAssignedType.Optional, false)
.selectSecondaryFilterAssignedType(FilterAssignedType.Optional)
.itemExist(FilterAssignedType.Default, false)
.itemExist(FilterAssignedType.Optional)
.selectSecondaryFilterAssignedType(FilterAssignedType.AllTypes)
.itemExist(FilterAssignedType.Default)
.itemExist(FilterAssignedType.Optional);
});
/*it("should empty search", () => {
});*/
const newItemsWithExpectedAssignedTypes = [
[clientScopeNameOptionalType, FilterAssignedType.Optional],
[clientScopeNameDefaultType, FilterAssignedType.Default],
];
newItemsWithExpectedAssignedTypes.forEach(($type) => {
const [itemName, assignedType] = $type;
it(`should add client scope ${itemName} with ${assignedType} assigned type`, () => {
listingPage.clickPrimaryButton();
modalUtils.checkModalTitle("Add client scopes to " + clientId);
listingPage.clickItemCheckbox(itemName);
modalUtils.confirmModalWithItem(assignedType);
masthead.checkNotificationMessage("Scope mapping successfully updated");
listingPage
.searchItem(itemName, false)
.itemExist(itemName)
.itemExist(assignedType);
});
});
const expectedItemAssignedTypes = [
FilterAssignedType.Optional,
FilterAssignedType.Default,
];
expectedItemAssignedTypes.forEach(($assignedType) => {
const itemName = clientScopeName + 0;
it(`should change item ${itemName} AssignedType to ${$assignedType} from search bar`, () => {
listingPage
.searchItem(itemName, false)
.clickItemCheckbox(itemName)
.changeTypeToOfSelectedItems($assignedType);
masthead.checkNotificationMessage("Scope mapping updated");
listingPage.searchItem(itemName, false).itemExist($assignedType);
});
});
it("should show items on next page are more than 11", () => {
listingPage.showNextPageTableItems().itemsGreaterThan(1);
});
it("should remove client scope from item bar", () => {
const itemName = clientScopeName + 0;
listingPage.searchItem(itemName, false).removeItem(itemName);
masthead.checkNotificationMessage(msgScopeMappingRemoved);
listingPage.searchItem(itemName, false).checkTableExists(false);
});
/*it("should remove client scope from search bar", () => {
//covered by next test
});*/
// TODO: https://github.com/keycloak/keycloak-admin-ui/issues/1854
it("should remove multiple client scopes from search bar", () => {
const itemName1 = clientScopeName + 1;
const itemName2 = clientScopeName + 2;
listingPage
.clickSearchBarActionButton()
.checkDropdownItemIsDisabled("Remove")
.searchItem(clientScopeName, false)
.clickItemCheckbox(itemName1)
.clickItemCheckbox(itemName2)
.clickSearchBarActionButton()
.clickSearchBarActionItem("Remove");
masthead.checkNotificationMessage(msgScopeMappingRemoved);
listingPage
.searchItem(clientScopeName, false)
.itemExist(itemName1, false)
.itemExist(itemName2, false)
.clickSearchBarActionButton();
//.checkDropdownItemIsDisabled("Remove");
});
//TODO: https://github.com/keycloak/keycloak-admin-ui/issues/1874
/* it("should show initial items after filtering", () => {
listingPage
.selectFilter(Filter.AssignedType)
.selectFilterAssignedType(FilterAssignedType.Optional)
.selectFilter(Filter.Name)
.itemExist(FilterAssignedType.Default)
.itemExist(FilterAssignedType.Optional);
});*/
});
describe("Client creation", () => {
before(() => {
keycloakBefore();
loginPage.logIn();
});
beforeEach(() => {
keycloakBeforeEach();
sidebarPage.goToClients();
});
it("Should cancel creating client", () => {
listingPage.goToCreateItem();
createClientPage.continue().checkClientIdRequiredMessage();
createClientPage
.fillClientData("")
.selectClientType("openid-connect")
.cancel();
cy.url().should("not.include", "/add-client");
});
it("Should navigate to previous using 'back' button", () => {
listingPage.goToCreateItem();
createClientPage.continue().checkClientIdRequiredMessage();
createClientPage
.fillClientData("test_client")
.selectClientType("openid-connect")
.continue()
.back()
.checkGeneralSettingsStepActive();
});
it("Should fail creating client", () => {
listingPage.goToCreateItem();
createClientPage.continue().checkClientIdRequiredMessage();
createClientPage
.fillClientData("")
.selectClientType("openid-connect")
.continue()
.checkClientIdRequiredMessage();
createClientPage.fillClientData("account").continue().save();
// The error should inform about duplicated name/id
masthead.checkNotificationMessage(
"Could not create client: 'Client account already exists'"
);
});
it("Client CRUD test", () => {
itemId += "_" + (Math.random() + 1).toString(36).substring(7);
// Create
listingPage.itemExist(itemId, false).goToCreateItem();
createClientPage
.selectClientType("openid-connect")
.fillClientData(itemId)
.continue()
.switchClientAuthentication()
.clickDirectAccess()
.clickImplicitFlow()
.clickOAuthDeviceAuthorizationGrant()
.clickOidcCibaGrant()
.clickServiceAccountRoles()
.clickStandardFlow()
.save();
masthead.checkNotificationMessage("Client created successfully");
sidebarPage.goToClients();
listingPage.searchItem("John Doe", false).checkEmptyList();
listingPage.searchItem("").itemExist("account");
listingPage.searchItem(itemId).itemExist(itemId);
// Delete
listingPage.deleteItem(itemId);
sidebarPage.waitForPageLoad();
modalUtils.checkModalTitle(`Delete ${itemId} ?`).confirmModal();
masthead.checkNotificationMessage("The client has been deleted");
listingPage.itemExist(itemId, false);
});
it("Initial access token", () => {
const initialAccessTokenTab = new InitialAccessTokenTab();
initialAccessTokenTab
.goToInitialAccessTokenTab()
.shouldBeEmpty()
.goToCreateFromEmptyList()
.fillNewTokenData(1, 3)
.save();
modalUtils.checkModalTitle("Initial access token details").closeModal();
masthead.checkNotificationMessage(
"New initial access token has been created"
);
initialAccessTokenTab.shouldNotBeEmpty();
listingPage
.searchItem("John Doe", false)
.checkEmptyList()
.searchItem("", false);
initialAccessTokenTab.getFirstId((id) => {
listingPage
.checkRowColumnValue(id, 4, "3")
.checkRowColumnValue(id, 5, "3")
.itemExist(id);
});
listingPage.goToCreateItem();
initialAccessTokenTab.fillNewTokenData(1, 3).save();
modalUtils.closeModal();
initialAccessTokenTab.getFirstId((id) => {
listingPage.deleteItem(id);
sidebarPage.waitForPageLoad();
modalUtils
.checkModalTitle("Delete initial access token?")
.confirmModal();
});
masthead.checkNotificationMessage(
"Initial access token deleted successfully"
);
initialAccessTokenTab.shouldNotBeEmpty();
initialAccessTokenTab.getFirstId((id) => {
listingPage.deleteItem(id);
sidebarPage.waitForPageLoad();
modalUtils.confirmModal();
});
initialAccessTokenTab.shouldBeEmpty();
});
});
describe("Advanced tab test", () => {
const advancedTab = new AdvancedTab();
let client: string;
before(() => {
keycloakBefore();
loginPage.logIn();
});
beforeEach(() => {
keycloakBeforeEach();
sidebarPage.goToClients();
client = "client_" + (Math.random() + 1).toString(36).substring(7);
listingPage.goToCreateItem();
createClientPage
.selectClientType("openid-connect")
.fillClientData(client)
.continue()
.save();
advancedTab.goToAdvancedTab();
});
afterEach(() => {
adminClient.deleteClient(client);
});
it("Clustering", () => {
advancedTab.expandClusterNode();
advancedTab.registerNodeManually().fillHost("localhost").saveHost();
advancedTab.checkTestClusterAvailability(true);
});
it("Fine grain OpenID connect configuration", () => {
const algorithm = "ES384";
advancedTab
.selectAccessTokenSignatureAlgorithm(algorithm)
.saveFineGrain();
advancedTab
.selectAccessTokenSignatureAlgorithm("HS384")
.revertFineGrain();
advancedTab.checkAccessTokenSignatureAlgorithm(algorithm);
});
});
describe("Service account tab test", () => {
const serviceAccountTab = new RoleMappingTab();
const serviceAccountName = "service-account-client";
before(() => {
keycloakBefore();
loginPage.logIn();
adminClient.createClient({
protocol: "openid-connect",
clientId: serviceAccountName,
publicClient: false,
authorizationServicesEnabled: true,
serviceAccountsEnabled: true,
standardFlowEnabled: true,
});
});
beforeEach(() => {
keycloakBeforeEach();
sidebarPage.goToClients();
});
after(() => {
adminClient.deleteClient(serviceAccountName);
});
it("List", () => {
listingPage
.searchItem(serviceAccountName)
.goToItemDetails(serviceAccountName);
serviceAccountTab
.goToServiceAccountTab()
.checkRoles(["manage-account", "offline_access", "uma_authorization"]);
});
it("Assign", () => {
listingPage.goToItemDetails(serviceAccountName);
serviceAccountTab
.goToServiceAccountTab()
.assignRole(false)
.selectRow("create-realm")
.assign();
masthead.checkNotificationMessage("Role mapping updated");
serviceAccountTab.selectRow("create-realm").unAssign();
sidebarPage.waitForPageLoad();
modalUtils.checkModalTitle("Remove mapping?").confirmModal();
masthead.checkNotificationMessage("Scope mapping successfully removed");
});
});
describe("Mapping tab", () => {
const clientScopeTab = new ClientScopesTab();
const mappingClient = "mapping-client";
beforeEach(() => {
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClients();
listingPage.searchItem(mappingClient).goToItemDetails(mappingClient);
});
before(() => {
adminClient.createClient({
protocol: "openid-connect",
clientId: mappingClient,
publicClient: false,
});
});
after(() => {
adminClient.deleteClient(mappingClient);
});
it("Add mapping to openid client", () => {
clientScopeTab.goToClientScopesTab().clickDedicatedScope(mappingClient);
cy.findByTestId("mappersTab").click();
cy.findByText("Add predefined mapper").click();
cy.get("table input").first().click();
cy.findByTestId("confirm").click();
masthead.checkNotificationMessage("Mapping successfully created");
});
});
describe("Keys tab test", () => {
const keysName = "keys-client";
before(() => {
keycloakBefore();
loginPage.logIn();
adminClient.createClient({
protocol: "openid-connect",
clientId: keysName,
publicClient: false,
});
});
beforeEach(() => {
keycloakBeforeEach();
sidebarPage.goToClients();
listingPage.searchItem(keysName).goToItemDetails(keysName);
});
after(() => {
adminClient.deleteClient(keysName);
});
it("Change use JWKS Url", () => {
const keysTab = new KeysTab();
keysTab.goToTab().checkSaveDisabled();
keysTab.toggleUseJwksUrl().checkSaveDisabled(false);
});
it("Generate new keys", () => {
const keysTab = new KeysTab();
keysTab.goToTab().clickGenerate();
keysTab.fillGenerateModal("keyname", "123", "1234").clickConfirm();
masthead.checkNotificationMessage(
"New key pair and certificate generated successfully"
);
});
});
describe("Realm client", () => {
const clientName = "master-realm";
before(() => {
keycloakBefore();
loginPage.logIn();
sidebarPage.goToClients();
listingPage.searchItem(clientName).goToItemDetails(clientName);
});
beforeEach(() => {
keycloakBeforeEach();
});
it("Displays the correct tabs", () => {
cy.findByTestId("client-tabs")
.findByTestId("clientSettingsTab")
.should("exist");
cy.findByTestId("client-tabs").findByTestId("rolesTab").should("exist");
cy.findByTestId("client-tabs")
.findByTestId("advancedTab")
.should("exist");
cy.findByTestId("client-tabs").find("li").should("have.length", 3);
});
it("Hides the delete action", () => {
cy.findByTestId("action-dropdown").click();
cy.findByTestId("delete-client").should("not.exist");
});
});
describe("Bearer only", () => {
const clientId = "bearer-only";
before(() => {
keycloakBefore();
loginPage.logIn();
adminClient.createClient({
clientId,
protocol: "openid-connect",
publicClient: false,
bearerOnly: true,
});
sidebarPage.goToClients();
cy.intercept("/auth/admin/realms/master/clients/*").as("fetchClient");
listingPage.searchItem(clientId).goToItemDetails(clientId);
cy.wait("@fetchClient");
});
after(() => {
adminClient.deleteClient(clientId);
});
beforeEach(() => {
keycloakBeforeEach();
});
it("Shows an explainer text for bearer only clients", () => {
cy.findByTestId("bearer-only-explainer-label").trigger("mouseenter");
cy.findByTestId("bearer-only-explainer-tooltip").should("exist");
});
it("Hides the capability config section", () => {
cy.findByTestId("capability-config-form").should("not.exist");
cy.findByTestId("jump-link-capability-config").should("not.exist");
});
});
});