UNPKG

graphdb-workbench-tests

Version:
1,052 lines (933 loc) 53.1 kB
import {UserAndAccessSteps} from '../../../steps/setup/user-and-access-steps'; import {RepositoriesStubs} from '../../../stubs/repositories/repositories-stubs'; import {RepositorySelectorSteps} from '../../../steps/repository-selector-steps'; import {ModalDialogSteps} from '../../../steps/modal-dialog-steps'; import {ToasterSteps} from '../../../steps/toaster-steps'; import HomeSteps from '../../../steps/home-steps'; import {LoginSteps} from '../../../steps/login-steps'; import {MainMenuSteps} from '../../../steps/main-menu-steps'; import {SecurityStubs} from '../../../stubs/security-stubs.js'; import {RepositorySteps} from '../../../steps/repository-steps.js'; describe('User and Access', () => { const PASSWORD = 'password'; const ROLE_USER = '#roleUser'; const ROLE_REPO_MANAGER = '#roleRepoAdmin'; const ROLE_CUSTOM_ADMIN = '#roleAdmin'; const DEFAULT_ADMIN_PASSWORD = 'root'; context('User and access management', () => { const user = 'user'; let repoName; before(() => { repoName = 'user-access-repo1-' + Date.now(); cy.createRepository({id: repoName}); }); after(() => { cy.loginAsAdmin().then(() => { cy.switchOffSecurity(true); cy.switchOffFreeAccess(false); }); cy.deleteRepository(repoName, true); }); beforeEach(() => { SecurityStubs.spyOnUserGet(); UserAndAccessSteps.visit(); // Users table should be visible UserAndAccessSteps.getUsersTable().should('be.visible'); cy.switchOffSecurity(true); }); afterEach(() => { cy.loginAsAdmin().then(() => { cy.deleteUser(user, true); cy.switchOffSecurity(true); cy.switchOffFreeAccess(false); }); }); context('Initial state', () => { it('Initial state', () => { // Create new user button should be visible UserAndAccessSteps.getCreateNewUserButton().should('be.visible'); // Security should be disabled UserAndAccessSteps.getSecuritySwitchLabel().should('be.visible').and('contain', 'Security is OFF'); UserAndAccessSteps.getSecurityCheckbox().should('not.be.checked'); // Only admin user should be created by default UserAndAccessSteps.getTableRow().should('have.length', 1); UserAndAccessSteps.findUserInTable('admin'); UserAndAccessSteps.getUserType().should('be.visible').and('contain', 'Administrator'); // The admin should have unrestricted rights UserAndAccessSteps.getRepositoryRights().should('be.visible').and('contain', 'Unrestricted'); // And can be edited UserAndAccessSteps.getEditUserButton().should('be.visible').and('not.be.disabled'); // And cannot be deleted UserAndAccessSteps.getDeleteUserButton().should('not.exist'); // Date created should be visible UserAndAccessSteps.getDateCreated().should('be.visible'); }); }); context('User creation', () => { it('Create user', () => { //create a normal read/write user createUser(user, PASSWORD, ROLE_USER, {readWrite: true}); testForUser(user, false); }); it('Create manage user', () => { createUser(user, PASSWORD, ROLE_USER, {manage: true, repoName}); testForUser(user, false); }); it('Create repo-manager', () => { //create a repo-manager createUser(user, PASSWORD, ROLE_REPO_MANAGER); testForUser(user, false); }); it('Create second admin', () => { //create a custom admin createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN); testForUser(user, true); }); it('Create user with custom role', () => { // When I create a read/write user UserAndAccessSteps.clickCreateNewUserButton(); UserAndAccessSteps.typeUsername(user); UserAndAccessSteps.typePassword(PASSWORD); UserAndAccessSteps.typeConfirmPasswordField(PASSWORD); UserAndAccessSteps.selectRoleRadioButton(ROLE_USER); // And add a custom role of 1 letter UserAndAccessSteps.addTextToCustomRoleField('A'); UserAndAccessSteps.toggleWriteAccessAny(); // Then the 'create' button should be disabled UserAndAccessSteps.getConfirmUserCreateButton().should('be.disabled'); // And the field should show an error UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long'); // When I add more text to the custom role tag UserAndAccessSteps.addTextToCustomRoleField('A{enter}'); // Then the 'create' button should be enabled UserAndAccessSteps.getConfirmUserCreateButton().should('be.enabled'); // And the field error should not exist UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible'); // When I type an invalid tag UserAndAccessSteps.addTextToCustomRoleField('B{enter}'); // And the field shows an error UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long'); // When I delete the invalid text UserAndAccessSteps.addTextToCustomRoleField('{backspace}'); // Then the error should not be visible UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible'); // When I create the user with a valid custom role UserAndAccessSteps.toggleWriteAccessAny(); SecurityStubs.spyOnUserCreate(); UserAndAccessSteps.confirmUserCreate(); // Then the user should be created with that custom role cy.wait('@create-user').its('request.body').then((body) => { expect(body).to.deep.eq({ 'password': 'password', 'grantedAuthorities': [ 'ROLE_USER', 'CUSTOM_AA', 'WRITE_REPO_*', 'READ_REPO_*', ], 'appSettings': { 'DEFAULT_VIS_GRAPH_SCHEMA': true, 'DEFAULT_INFERENCE': true, 'DEFAULT_SAMEAS': true, 'IGNORE_SHARED_QUERIES': false, 'EXECUTE_COUNT': true, }, }); }); cy.url().should('include', '/users'); UserAndAccessSteps.findUserInTable(user).should('be.visible'); UserAndAccessSteps.getUserCustomRoles('@user') .should('have.length', 1) .eq(0).and('have.text', 'AA'); // And when I open the edit page for that user, the custom role should be visible in the field without the prefix UserAndAccessSteps.openEditUserPage(user); cy.wait('@get-user'); UserAndAccessSteps.getCustomRoleField().find('.tag-item span') .should('have.length', 1) .eq(0).and('have.text', 'AA'); }); it('Adding a role with a CUSTOM_ prefix shows a warning message', () => { // When I create a user UserAndAccessSteps.clickCreateNewUserButton(); // And I add a custom role tag with prefix CUSTOM_ UserAndAccessSteps.addTextToCustomRoleField('CUSTOM_USER{Enter}'); // There should be a warning text UserAndAccessSteps.getPrefixWarning(0).should('contain', 'Custom roles should be entered without the "CUSTOM_" prefix in Workbench'); }); it('Warn users when setting no password when creating new user admin', () => { UserAndAccessSteps.getUsersTable().should('be.visible'); createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN, {noPassword: true}); UserAndAccessSteps.getUsersTable().should('be.visible'); UserAndAccessSteps.getSplashLoader().should('not.be.visible'); }); // Skipped until image with GDB implementation is available it.skip('should create user with manage repo rights for specific repo', () => { SecurityStubs.spyOnUserCreate(); UserAndAccessSteps.getUsersCatalogContainer().should('be.visible'); createUser(user, PASSWORD, ROLE_USER, {manage: true, repoName: repoName}); // Then the user should be created with that custom role cy.wait('@create-user').its('request.body').then((body) => { expect(body).to.deep.eq({ 'password': 'password', 'grantedAuthorities': [ 'ROLE_USER', `MANAGE_REPO_${repoName}`, `WRITE_REPO_${repoName}`, `READ_REPO_${repoName}`, ], 'appSettings': { 'DEFAULT_VIS_GRAPH_SCHEMA': true, 'DEFAULT_INFERENCE': true, 'DEFAULT_SAMEAS': true, 'IGNORE_SHARED_QUERIES': false, 'EXECUTE_COUNT': true, }, }); }); UserAndAccessSteps.getUsersCatalogContainer().should('be.visible'); assertUserAuthsInCatalog(user, {repo: repoName, read: false, manage: true, graphql: false}); UserAndAccessSteps.openEditUserPage(user); cy.wait('@get-user'); UserAndAccessSteps.getRepositoryRightsList().should('be.visible'); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: false, graphql: true}); }); }); context('Free access', () => { it('should toggle free access after Admin has logged in', () => { // Given I have available repositories to allow Free Access for RepositoriesStubs.stubRepositories(); RepositoriesStubs.stubFreeAccess(); // When I enable security UserAndAccessSteps.toggleSecurity(); // When I log in as an Admin LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD); // Then the page should load UserAndAccessSteps.getSplashLoader().should('not.be.visible'); UserAndAccessSteps.getUsersTable().should('be.visible'); // The Free Access toggle should be OFF UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked'); // When I toggle Free Access ON UserAndAccessSteps.toggleFreeAccess(); // And I allow free access to a repository ModalDialogSteps.getDialog().should('be.visible'); // Then I click OK in the modal ModalDialogSteps.clickOKButton(); // Then the toggle button should be ON UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked'); // And I should see a success message ToasterSteps.verifySuccess('Free access has been enabled.'); ToasterSteps.getToast().should('not.exist'); UserAndAccessSteps.getUsersTable().should('be.visible'); // When I toggle Free Access OFF UserAndAccessSteps.toggleFreeAccess(); // Then I should see a success message ToasterSteps.getToast().should('exist'); ToasterSteps.getToasterMessage().should('contain', 'Free access has been disabled.'); }); }); context('Login / return URL redirects', () => { it('should not add the active repository to the login page URL', () => { cy.presetRepository(repoName); UserAndAccessSteps.visit(); cy.url().should('include', `repositoryId=${repoName}`); UserAndAccessSteps.toggleSecurity(); cy.url() .should('include', '/login') .and('not.include', 'repositoryId='); }); it('should redirect to previous page after logout and then login', () => { UserAndAccessSteps.toggleSecurity(); LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD); MainMenuSteps.clickOnSparqlMenu(); cy.url().should('include', '/sparql'); LoginSteps.logout(); cy.url().should('include', '/login'); LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD); cy.url().should('include', '/sparql'); }); it('should redirect to correct return url when user is authenticated and on login page', () => { UserAndAccessSteps.visit(); UserAndAccessSteps.toggleSecurity(); LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD); UserAndAccessSteps.getUsersTable().should('be.visible'); cy.visit('/login?r=%252Fsparql'); cy.reload(); UserAndAccessSteps.getUrl().should('include', '/sparql'); }); }); }); context('Verify access states', () => { let repoName; before(() => { repoName = 'user-access-repo1-' + Date.now(); cy.createRepository({id: repoName}); cy.switchOffSecurity(true); SecurityStubs.spyOnUserGet(); }); beforeEach(() => { UserAndAccessSteps.visit(); // Users table should be visible UserAndAccessSteps.getUsersTable().should('be.visible'); }); after(() => { cy.loginAsAdmin().then(() => { cy.deleteRepository(repoName, true); cy.switchOffFreeAccess(true); cy.switchOffSecurity(true); }); }); it('initial state', () => { UserAndAccessSteps.clickCreateNewUserButton(); verifyCheckedUserAuth('*', {read: false, write: false, manage: false, graphql: false}); verifyDisabledUserAuth('*', {read: false, write: false, manage: true, graphql: true}); verifyCheckedUserAuth(repoName, {read: false, write: false, manage: false, graphql: false}); verifyDisabledUserAuth(repoName, {read: false, write: false, manage: false, graphql: true}); }); context('for non user roles', () => { it('admin', () => { UserAndAccessSteps.clickCreateNewUserButton(); UserAndAccessSteps.selectRoleRadioButton(ROLE_CUSTOM_ADMIN); verifyCheckedUserAuth('*', {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth('*', {read: true, write: true, manage: true, graphql: true}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: true, graphql: true}); }); it('repository manager', () => { UserAndAccessSteps.clickCreateNewUserButton(); UserAndAccessSteps.selectRoleRadioButton(ROLE_REPO_MANAGER); verifyCheckedUserAuth('*', {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth('*', {read: true, write: true, manage: true, graphql: true}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: true, graphql: true}); }); }); context('for specific repo', () => { it('read', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({read: true, repoName}); verifyCheckedUserAuth(repoName, {read: true, write: false, manage: false, graphql: false}); verifyDisabledUserAuth(repoName, {read: false, write: false, manage: false, graphql: false}); }); it('write', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({readWrite: true, repoName}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: false, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: false, manage: false, graphql: false}); }); it('manage', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({manage: true, repoName}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: true, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: false, graphql: true}); }); it('graphql with read', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({read: true, graphql: true, repoName}); verifyCheckedUserAuth(repoName, {read: true, write: false, manage: false, graphql: true}); verifyDisabledUserAuth(repoName, {read: false, write: false, manage: false, graphql: false}); }); it('graphql with write', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({readWrite: true, graphql: true, repoName}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: false, graphql: true}); verifyDisabledUserAuth(repoName, {read: true, write: false, manage: false, graphql: false}); }); }); context('for any repo', () => { let anyRepo = '*'; it('read', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({read: true, anyRepo}); verifyCheckedUserAuth(anyRepo, {read: true, write: false, manage: false, graphql: false}); verifyDisabledUserAuth(anyRepo, {read: false, write: false, manage: true, graphql: false}); verifyCheckedUserAuth(repoName, {read: true, write: false, manage: false, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: false, manage: false, graphql: false}); }); it('write', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({readWrite: true, anyRepo}); verifyCheckedUserAuth(anyRepo, {read: true, write: true, manage: false, graphql: false}); verifyDisabledUserAuth(anyRepo, {read: true, write: false, manage: true, graphql: false}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: false, graphql: false}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: false, graphql: false}); }); it('graphql with read', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({read: true, graphql: true, anyRepo}); verifyCheckedUserAuth(anyRepo, {read: true, write: false, manage: false, graphql: true}); verifyDisabledUserAuth(anyRepo, {read: false, write: false, manage: true, graphql: false}); verifyCheckedUserAuth(repoName, {read: true, write: false, manage: false, graphql: true}); verifyDisabledUserAuth(repoName, {read: true, write: false, manage: false, graphql: true}); }); it('graphql with write', () => { UserAndAccessSteps.clickCreateNewUserButton(); setRoles({readWrite: true, graphql: true, anyRepo}); verifyCheckedUserAuth(anyRepo, {read: true, write: true, manage: false, graphql: true}); verifyDisabledUserAuth(anyRepo, {read: true, write: false, manage: true, graphql: false}); verifyCheckedUserAuth(repoName, {read: true, write: true, manage: false, graphql: true}); verifyDisabledUserAuth(repoName, {read: true, write: true, manage: false, graphql: true}); }); }); }); context('GraphQL access', () => { let repositoryId1; let repositoryId2; let repositoryId3; const graphqlUser = 'graphqlUser'; beforeEach(() => { RepositoriesStubs.spyGetRepositories(); repositoryId1 = 'user-access-repo1-' + Date.now(); repositoryId2 = 'user-access-repo2-' + Date.now(); repositoryId3 = 'user-access-repo3-' + Date.now(); cy.createRepository({id: repositoryId1}); cy.createRepository({id: repositoryId2}); cy.createRepository({id: repositoryId3}); cy.presetRepository(repositoryId1); UserAndAccessSteps.visit(); // Users table should be visible UserAndAccessSteps.getUsersTable().should('be.visible'); SecurityStubs.spyOnUserGet(); }); afterEach(() => { cy.loginAsAdmin().then(() => { cy.deleteRepository(repositoryId1, true); cy.deleteRepository(repositoryId2, true); cy.deleteRepository(repositoryId3, true); cy.deleteUser(graphqlUser, true); cy.switchOffFreeAccess(true); cy.switchOffSecurity(true); }); }); context('GraphQL checkbox behavior', () => { it('Create user with GraphQL-only access', () => { cy.wait('@getRepositories'); createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2}); }); // Fails for unknown reason only in CI it('Can create user with different auth combinations', () => { cy.wait('@getRepositories'); cy.wait('@getRepositories'); UserAndAccessSteps.getUsersCatalogContainer().should('be.visible'); // WHEN I create a user with read + GraphQL for repository #2 createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2}); // THEN the user should have read + GraphQL on that repo assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId2, read: true, graphql: true}); // WHEN I open the edit page for that user UserAndAccessSteps.openEditUserPage(graphqlUser); cy.wait('@get-user'); // THEN for repository #1, the GraphQL checkbox should be disabled initially UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {disabled: true}); // WHEN I enable "read" for repository #1 setUserAuths({repo: repositoryId1, read: true}); // THEN GraphQL for repository #1 should become enabled UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {disabled: false}); // WHEN I enable GraphQL with read setUserAuths({repo: repositoryId1, graphql: true}); // THEN GraphQL should be checked and enabled UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {checked: true, disabled: false}); // THEN for repository #3, GraphQL should be disabled initially UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId3, {disabled: true}); // WHEN I enable "write" for repository #3 setUserAuths({repo: repositoryId3, write: true}); // THEN GraphQL for repository #3 should become enabled UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId3, {disabled: false}); // And I expect "read" to be checked and disabled UserAndAccessSteps.validateReadAccessForRepo(repositoryId3, {checked: true, disabled: true}); // I enable GraphQL for repository #3 setUserAuths({repo: repositoryId3, graphql: true}); // THEN GraphQL should be checked and enabled UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {checked: true, disabled: false}); // When I remove "read" for repository #2 UserAndAccessSteps.toggleReadAccessForRepo(repositoryId2); // THEN I expect "graphql" to be unchecked and disabled for repository #2 UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId2, {checked: false, disabled: true}); // WHEN I confirm the user edit UserAndAccessSteps.confirmUserEdit(); // THEN verify the final rights: // - repo #1 has no read/write/graphql // - repo #2 has read + graphql // - repo #3 has write + graphql (and read was auto-checked but disabled) assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId1, read: true, write: false, graphql: true}); assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId2, read: false, write: false, graphql: false}); assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId3, read: false, write: true, graphql: true}); }); }); context('Menu navigation based on permissions', () => { it('Should have access to 5 pages when have graphql only rights', () => { cy.wait('@getRepositories'); cy.wait('@getRepositories'); // WHEN I create a user with read + GraphQL for repository #2 createUser(graphqlUser, PASSWORD, ROLE_USER, {readWrite: true, graphql: true, repoName: repositoryId1}); //enable security UserAndAccessSteps.toggleSecurity(); //login new user LoginSteps.loginWithUser(graphqlUser, PASSWORD); cy.wait('@getRepositories'); cy.wait('@getRepositories'); MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => { navigateMenuPath(path, expectedUrl, expectedTitle); if (checks) { runChecks(checks); } navigateMenuPath(['Import'], '/import', 'Import'); }); }); it('Should not have access endpoints management when have read graphql only rights', () => { cy.wait('@getRepositories'); cy.wait('@getRepositories'); // WHEN I create a user with read + GraphQL for repository #2 createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId1}); //enable security UserAndAccessSteps.toggleSecurity(); //login new user LoginSteps.loginWithUser(graphqlUser, PASSWORD); cy.wait('@getRepositories'); cy.wait('@getRepositories'); // RepositorySelectorSteps.selectRepository(repositoryId1); GRAPHQL_READ_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => { navigateMenuPath(path, expectedUrl, expectedTitle); if (checks) { runChecks(checks); } navigateMenuPath(['Import'], '/import', 'Import'); }); }); it('Should have all access to endpoints management when have REPO_MANAGER role', () => { cy.wait('@getRepositories'); cy.wait('@getRepositories'); createUser(graphqlUser, PASSWORD, ROLE_REPO_MANAGER); //enable security UserAndAccessSteps.toggleSecurity(); HomeSteps.visitAndWaitLoader(); //login new user LoginSteps.loginWithUser(graphqlUser, PASSWORD); cy.wait('@getRepositories'); cy.wait('@getRepositories'); GRAPHQL_REPO_MANAGER_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => { navigateMenuPath(path, expectedUrl, expectedTitle); if (checks) { runChecks(checks); } navigateMenuPath(['Import'], '/import', 'Import'); }); }); it('Can have Free Access and GraphQL working together', () => { cy.wait('@getRepositories'); cy.wait('@getRepositories'); //enable security UserAndAccessSteps.toggleSecurity(); //login with the admin LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD); cy.wait('@getRepositories'); cy.wait('@getRepositories'); // The Free Access toggle should be OFF UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked'); // When I toggle Free Access ON UserAndAccessSteps.toggleFreeAccess(); // Then I set repo auths UserAndAccessSteps.clickFreeReadAccessRepo(repositoryId1); UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId2); UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId3); UserAndAccessSteps.clickFreeGraphqlAccessRepo(repositoryId3); // Then I click OK in the modal ModalDialogSteps.clickOKButton(); // Then the toggle button should be ON UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked'); // And I should see a success message ToasterSteps.verifySuccess('Free access has been enabled.'); UserAndAccessSteps.getUsersTable().should('be.visible'); // Then I logout LoginSteps.logout(); HomeSteps.visit(); // I change the repository to this with GraphQL only rights RepositorySelectorSteps.selectRepository(repositoryId3); // Then I should have GraphQL only rights FREE_ACCESS_MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => { navigateMenuPath(path, expectedUrl, expectedTitle); if (checks) { runChecks(checks); } navigateMenuPath(['Import'], '/import', 'Import'); }); }); }); }); context('User with manage permission', () => { let withoutPermissionRepositoryId; let readRepositoryId; let writeRepositoryId; let graphQLOnlyRepositoryId; let manageRepositoryId; const manageUser = 'manageUser'; beforeEach(() => { RepositoriesStubs.spyGetRepositories(); readRepositoryId = 'readRepositoryId-' + Date.now(); writeRepositoryId = 'writeRepositoryId-' + Date.now(); graphQLOnlyRepositoryId = 'graphQLOnlyRepositoryId-' + Date.now(); manageRepositoryId = 'manageRepositoryId-' + Date.now(); withoutPermissionRepositoryId = 'withoutPermissionRepositoryId-' + Date.now(); cy.createRepository({id: readRepositoryId}); cy.createRepository({id: writeRepositoryId}); cy.createRepository({id: graphQLOnlyRepositoryId}); cy.createRepository({id: manageRepositoryId}); cy.createRepository({id: withoutPermissionRepositoryId}); UserAndAccessSteps.visit(); // Users table should be visible UserAndAccessSteps.getUsersTable().should('be.visible'); SecurityStubs.spyOnUserGet(); }); afterEach(() => { cy.loginAsAdmin().then(() => { cy.deleteRepository(readRepositoryId, true); cy.deleteRepository(writeRepositoryId, true); cy.deleteRepository(graphQLOnlyRepositoryId, true); cy.deleteRepository(manageRepositoryId, true); cy.deleteRepository(withoutPermissionRepositoryId, true); cy.deleteUser(manageUser, true); cy.switchOffFreeAccess(true); cy.switchOffSecurity(true); }); }); it('should list all repositories for which a user with manage permission has at least read permission', () => { // Given there are five repositories. // And there is a user with permissions for four of them: // 1. Manage permission for one repository. createUser(manageUser, PASSWORD, ROLE_USER, {manage: true, repoName: manageRepositoryId}); // 2. Read permission for one repository. UserAndAccessSteps.openEditUserPage(manageUser); cy.wait('@get-user'); setUserAuths({repo: readRepositoryId, read: true}); // 3. Write permission for one repository. setUserAuths({repo: writeRepositoryId, write: true}); // 4. GraphQL-only permission for one repository. setUserAuths({repo: graphQLOnlyRepositoryId, write: true, graphql: true}); UserAndAccessSteps.confirmUserEdit(); // When I log in as a user with repository management permission. UserAndAccessSteps.toggleSecurity(); LoginSteps.loginWithUser(manageUser, PASSWORD); // And navigate to the repository list view. RepositorySteps.visit(false); // Then I should see all repositories for which the user has at least read permission. RepositorySteps.getRepositories().should('have.length', 4); // And I should see the actions allowed for the repository the user can manage. RepositorySteps.getCopyRepositoryButton(manageRepositoryId).should('be.visible'); RepositorySteps.getEditRepositoryButton(manageRepositoryId).should('be.visible'); RepositorySteps.getDownloadRepositoryConfigurationButton(manageRepositoryId).should('be.visible'); RepositorySteps.getRestartRepositoryButton(manageRepositoryId).should('be.visible'); // And the delete button should not be available because users with manage permission // are not allowed to delete repositories. RepositorySteps.getDeleteRepositoryButton(manageRepositoryId).should('not.exist'); // And the "Set as default repository" button should not be available because users // with manage permission are not allowed to set the default repository. RepositorySteps.getSetDefaultRepositoryButton(manageRepositoryId).should('not.exist'); // And should see the copy action for all repositories. RepositorySteps.getCopyRepositoryButton(writeRepositoryId).should('be.visible'); RepositorySteps.getCopyRepositoryButton(readRepositoryId).should('be.visible'); RepositorySteps.getCopyRepositoryButton(graphQLOnlyRepositoryId).should('be.visible'); // And no repository management actions should be available for the other repositories. RepositorySteps.getEditRepositoryButton(readRepositoryId).should('not.exist'); RepositorySteps.getDownloadRepositoryConfigurationButton(readRepositoryId).should('not.exist'); RepositorySteps.getRestartRepositoryButton(readRepositoryId).should('not.exist'); RepositorySteps.getDeleteRepositoryButton(readRepositoryId).should('not.exist'); RepositorySteps.getSetDefaultRepositoryButton(readRepositoryId).should('not.exist'); RepositorySteps.getEditRepositoryButton(writeRepositoryId).should('not.exist'); RepositorySteps.getDownloadRepositoryConfigurationButton(writeRepositoryId).should('not.exist'); RepositorySteps.getRestartRepositoryButton(writeRepositoryId).should('not.exist'); RepositorySteps.getDeleteRepositoryButton(writeRepositoryId).should('not.exist'); RepositorySteps.getSetDefaultRepositoryButton(writeRepositoryId).should('not.exist'); RepositorySteps.getEditRepositoryButton(graphQLOnlyRepositoryId).should('not.exist'); RepositorySteps.getDownloadRepositoryConfigurationButton(graphQLOnlyRepositoryId).should('not.exist'); RepositorySteps.getRestartRepositoryButton(graphQLOnlyRepositoryId).should('not.exist'); RepositorySteps.getDeleteRepositoryButton(graphQLOnlyRepositoryId).should('not.exist'); RepositorySteps.getSetDefaultRepositoryButton(graphQLOnlyRepositoryId).should('not.exist'); // And the "Create", "Create from file", and "Attach remote repository" page buttons // should not be available to a user with manage permission. RepositorySteps.getPageButtons().should('not.exist'); // When I select a repository for which I have GraphQL-only permission. RepositorySelectorSteps.selectRepository(graphQLOnlyRepositoryId); // Then I should still see all repositories for which the user has at least read permission. RepositorySteps.getRepositories().should('have.length', 4); }); }); function createUser(username, password, role, opts = {}) { UserAndAccessSteps.clickCreateNewUserButton(); cy.url().should('include', '/user/create'); UserAndAccessSteps.getUsernameField().should('be.visible').and('be.enabled').and('not.be.disabled'); UserAndAccessSteps.typeUsername(username); UserAndAccessSteps.typePassword(password); UserAndAccessSteps.typeConfirmPasswordField(password); UserAndAccessSteps.selectRoleRadioButton(role); UserAndAccessSteps.getRoleRadioButton(role).should('be.checked'); if (role === '#roleUser') { setRoles(opts); } if (role === ROLE_CUSTOM_ADMIN && opts.noPassword) { UserAndAccessSteps.getNoPasswordCheckbox().check() .then(() => { UserAndAccessSteps.getNoPasswordCheckbox() .should('be.checked'); }); UserAndAccessSteps.getConfirmUserCreateButton().click() .then(() => { UserAndAccessSteps.getDialogText().contains('If the password is unset and security is enabled, this administrator will not be ' + 'able to log into GraphDB through the workbench. Are you sure that you want to continue?'); UserAndAccessSteps.confirmInDialog(); }); } else { UserAndAccessSteps.confirmUserCreate(); } UserAndAccessSteps.getSplashLoader().should('not.be.visible'); UserAndAccessSteps.getUsersTable().should('contain', username); } function setRoles(opts = {}) { const {read = false, readWrite = false, graphql = false, manage = false, repoName = '*'} = opts; setUserAuths({repo: repoName, read, write: readWrite, graphql, manage}); } function testForUser(name, isAdmin) { //enable security UserAndAccessSteps.toggleSecurity(); LoginSteps.visitLoginPageWithReturnUrl('/users'); //login new user LoginSteps.loginWithUser(name, PASSWORD); //verify permissions UserAndAccessSteps.getUrl().should('include', '/users'); if (isAdmin) { UserAndAccessSteps.getUsersTable().should('be.visible'); } else { UserAndAccessSteps.getPermissionError().should('contain', 'You have no permission to access this functionality with your current credentials.'); } } function assertUserAuthsInCatalog(username, {repo, read = false, write = false, manage = false, graphql = false} = {}) { UserAndAccessSteps.findUserRowAlias(username, 'userRow'); if (!read && !write && !manage) { return UserAndAccessSteps.getRepoLine('@userRow', repo).should('not.exist'); } UserAndAccessSteps.findRepoLineAlias('@userRow', repo, 'repoLine'); if (read) { UserAndAccessSteps.findReadIconAlias('@repoLine').should('be.visible'); } else { UserAndAccessSteps.findReadIconAlias('@repoLine').should('not.exist'); } if (write) { UserAndAccessSteps.findWriteIconAlias('@repoLine').should('be.visible'); } else { UserAndAccessSteps.findWriteIconAlias('@repoLine').should('not.exist'); } if (manage) { UserAndAccessSteps.findManageIconAlias('@repoLine').should('be.visible'); } else { UserAndAccessSteps.findManageIconAlias('@repoLine').should('not.exist'); } if (graphql) { UserAndAccessSteps.findGraphqlIconAlias('@repoLine').should('exist'); } else { UserAndAccessSteps.findGraphqlIconAlias('@repoLine').should('not.exist'); } } function setUserAuths({repo, read = false, write = false, graphql = false, manage = false} = {}) { if (read === true) { UserAndAccessSteps.toggleReadAccessForRepo(repo); UserAndAccessSteps.validateReadAccessForRepo(repo, {checked: read}); } if (write === true) { UserAndAccessSteps.toggleWriteAccessForRepo(repo); UserAndAccessSteps.validateWriteAccessForRepo(repo, {checked: write}); } if (graphql === true) { UserAndAccessSteps.toggleGraphqlAccessForRepo(repo); UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {checked: graphql}); } if (manage === true) { UserAndAccessSteps.toggleManageRepoForRepo(repo); UserAndAccessSteps.validateManageAccessForRepo(repo, {checked: manage}); } } function verifyCheckedUserAuth(repo, {read = false, write = false, graphql = false, manage = false} = {}) { UserAndAccessSteps.validateReadAccessForRepo(repo, {checked: read}); UserAndAccessSteps.validateWriteAccessForRepo(repo, {checked: write}); UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {checked: graphql}); UserAndAccessSteps.validateManageAccessForRepo(repo, {checked: manage}); } function verifyDisabledUserAuth(repo, {read = false, write = false, graphql = false, manage = false} = {}) { UserAndAccessSteps.validateReadAccessForRepo(repo, {disabled: read}); UserAndAccessSteps.validateWriteAccessForRepo(repo, {disabled: write}); UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {disabled: graphql}); UserAndAccessSteps.validateManageAccessForRepo(repo, {disabled: manage}); } function navigateMenuPath(pathArray, expectedUrl, expectedTitle) { pathArray.forEach((label, index) => { if (index === 0) { MainMenuSteps.clickOnMenu(label); if (pathArray.length > 1) { MainMenuSteps.getSubmenuFor(label).scrollIntoView().should('be.visible'); } } else { MainMenuSteps.clickOnSubMenu(label); } if (index === pathArray.length - 1) { // wait for the page label on the last navigation step to be visible before moving on const title = expectedTitle ? expectedTitle : label; cy.get('h1').should('be.visible').should('contain', title); } }); if (expectedUrl) { cy.url().should('include', expectedUrl); } } function runChecks(checks = {}) { Object.entries(checks).forEach(([selector, assertions]) => { // eslint-disable-next-line cypress/no-assigning-return-values let chain = cy.get(selector); // assertions is an array, e.g. ["exist", ["contain.text", "Hello"], "be.visible"] assertions.forEach((assertion, index) => { if (index === 0) { // First assertion = .should(...) if (Array.isArray(assertion)) { // e.g. ["contain.text", "Hello"] chain = chain.should(...assertion); } else { // e.g. "exist" chain = chain.should(assertion); } } else { // Subsequent assertions = .and(...) if (Array.isArray(assertion)) { chain = chain.and(...assertion); } else { chain = chain.and(assertion); } } }); }); } const noAuthChecks = { '.no-authority-panel .alert-warning': [ 'be.visible', ['contains.text', 'Some functionalities are not available because'], ['contains.text', 'you do not have the required repository permissions.'], ], }; const hasAuthChecks = { '.no-authority-panel .alert-warning': [ 'not.exist', ], }; const MENU_ITEMS_WITHOUT_GRAPHQL = [ // 1) Import { path: ['Import'], expectedUrl: '/import', checks: noAuthChecks, }, // 2) Explore { path: ['Explore', 'Graphs overview'], expectedUrl: '/graphs', checks: noAuthChecks, }, { path: ['Explore', 'Class hierarchy'], expectedUrl: '/hierarchy', checks: noAuthChecks, }, { path: ['Explore', 'Class relationships'], expectedUrl: '/relationships', checks: noAuthChecks, }, { path: ['Explore', 'Visual graph'], expectedUrl: '/graphs-visualizations', checks: noAuthChecks, }, { path: ['Explore', 'Similarity'], expectedTitle: 'Similarity indexes', expectedUrl: '/similarity', checks: noAuthChecks, }, // 3) SPARQL { path: ['SPARQL'], expectedTitle: 'SPARQL Query & Update', expectedUrl: '/sparql', checks: noAuthChecks, }, // 4) GraphQL // 5) Monitor { path: ['Monitor', 'Queries and Updates'], expectedUrl: '/monitor/queries', expectedTitle: 'Query and Update monitoring', checks: noAuthChecks, }, // 6) Setup { path: ['Setup', 'My Settings'], expectedUrl: '/settings', expectedTitle: 'Settings', checks: hasAuthChecks, }, { path: ['Setup', 'Connectors'], expectedUrl: '/connectors', expectedTitle: 'Connector management', checks: noAuthChecks, }, { path: ['Setup', 'Cluster'], expectedUrl: '/cluster', expectedTitle: 'Cluster management', checks: hasAuthChecks, }, { path: ['Setup', 'Plugins'], expectedUrl: '/plugins', checks: noAuthChecks, }, { path: ['Setup', 'Namespaces'], expectedUrl: '/namespaces', checks: noAuthChecks, }, { path: ['Setup', 'Autocomplete'], expectedUrl: '/autocomplete', expectedTitle: 'Autocomplete index', checks: noAuthChecks, }, { path: ['Setup', 'RDF Rank'], expectedUrl: '/rdfrank', checks: noAuthChecks, }, { path: ['Setup', 'JDBC'], expectedUrl: '/jdbc', expectedTitle: 'JDBC configuration', checks: noAuthChecks, }, { path: ['Setup', 'SPARQL Templates'], expectedUrl: '/sparql-templates', checks: noAuthChecks, }, // 7) Lab { path: ['Lab', 'Talk to Your Graph'], expectedUrl: '/ttyg', checks: noAuthChecks, }, // 8) Help { path: ['Help', 'REST API'], expectedUrl: '/webapi', expectedTitle: 'REST API documentation', checks: hasAuthChecks, }, ]; const GRAPHQL_READ_MENU_ITEMS = [ { path: ['GraphQL', 'GraphQL Playground'],