diff --git a/x-pack/plugins/cloud/public/plugin.test.ts b/x-pack/plugins/cloud/public/plugin.test.ts index f7d71e7e1219a..2215fbd64fe98 100644 --- a/x-pack/plugins/cloud/public/plugin.test.ts +++ b/x-pack/plugins/cloud/public/plugin.test.ts @@ -434,7 +434,7 @@ describe('Cloud Plugin', () => { const securityStart = securityMock.createStart(); securityStart.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ - roles: ['superuser'], + elastic_cloud_user: true, }) ); @@ -446,14 +446,15 @@ describe('Cloud Plugin', () => { expect(securityStart.authc.getCurrentUser).not.toHaveBeenCalled(); }); - it('registers a custom nav link for superusers', async () => { + it('registers a custom nav link for cloud users', async () => { const { plugin } = startPlugin(); const coreStart = coreMock.createStart(); const securityStart = securityMock.createStart(); + securityStart.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ - roles: ['superuser'], + elastic_cloud_user: true, }) ); plugin.start(coreStart, { security: securityStart }); @@ -494,14 +495,14 @@ describe('Cloud Plugin', () => { `); }); - it('does not register a custom nav link for non-superusers', async () => { + it('does not register a custom nav link for non-cloud users', async () => { const { plugin } = startPlugin(); const coreStart = coreMock.createStart(); const securityStart = securityMock.createStart(); securityStart.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ - roles: ['not-a-superuser'], + elastic_cloud_user: false, }) ); plugin.start(coreStart, { security: securityStart }); @@ -511,14 +512,14 @@ describe('Cloud Plugin', () => { expect(coreStart.chrome.setCustomNavLink).not.toHaveBeenCalled(); }); - it('registers user profile links for superusers', async () => { + it('registers user profile links for cloud users', async () => { const { plugin } = startPlugin(); const coreStart = coreMock.createStart(); const securityStart = securityMock.createStart(); securityStart.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ - roles: ['superuser'], + elastic_cloud_user: true, }) ); plugin.start(coreStart, { security: securityStart }); @@ -532,7 +533,7 @@ describe('Cloud Plugin', () => { Object { "href": "https://cloud.elastic.co/profile/alice", "iconType": "user", - "label": "Profile", + "label": "Edit profile", "order": 100, "setAsProfile": true, }, @@ -564,7 +565,7 @@ describe('Cloud Plugin', () => { Object { "href": "https://cloud.elastic.co/profile/alice", "iconType": "user", - "label": "Profile", + "label": "Edit profile", "order": 100, "setAsProfile": true, }, @@ -579,14 +580,14 @@ describe('Cloud Plugin', () => { `); }); - it('does not register profile links for non-superusers', async () => { + it('does not register profile links for non-cloud users', async () => { const { plugin } = startPlugin(); const coreStart = coreMock.createStart(); const securityStart = securityMock.createStart(); securityStart.authc.getCurrentUser.mockResolvedValue( securityMock.createMockAuthenticatedUser({ - roles: ['not-a-superuser'], + elastic_cloud_user: false, }) ); plugin.start(coreStart, { security: securityStart }); diff --git a/x-pack/plugins/cloud/public/plugin.tsx b/x-pack/plugins/cloud/public/plugin.tsx index 10c7b7165528e..195e359436e28 100644 --- a/x-pack/plugins/cloud/public/plugin.tsx +++ b/x-pack/plugins/cloud/public/plugin.tsx @@ -212,10 +212,12 @@ export class CloudPlugin implements Plugin { } // Security plugin is disabled if (!security) return true; - // Otherwise check roles. If user is not defined due to an unexpected error, then fail *open*. + + // Otherwise check if user is a cloud user. + // If user is not defined due to an unexpected error, then fail *open*. // Cloud admin console will always perform the actual authorization checks. const user = await security.authc.getCurrentUser().catch(() => null); - return user?.roles.includes('superuser') ?? true; + return user?.elastic_cloud_user ?? true; } /** diff --git a/x-pack/plugins/cloud/public/user_menu_links.ts b/x-pack/plugins/cloud/public/user_menu_links.ts index 55c41831cc18c..e29736e215e0d 100644 --- a/x-pack/plugins/cloud/public/user_menu_links.ts +++ b/x-pack/plugins/cloud/public/user_menu_links.ts @@ -17,7 +17,7 @@ export const createUserMenuLinks = (config: CloudConfigType): UserMenuLink[] => if (baseUrl && profileUrl) { userMenuLinks.push({ label: i18n.translate('xpack.cloud.userMenuLinks.profileLinkText', { - defaultMessage: 'Profile', + defaultMessage: 'Edit profile', }), iconType: 'user', href: getFullCloudUrl(baseUrl, profileUrl), diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx index c0c90c6421ab2..fdaeeed66fb63 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx @@ -6,6 +6,7 @@ */ import { act, renderHook } from '@testing-library/react-hooks'; +import { mount } from 'enzyme'; import type { FunctionComponent } from 'react'; import React from 'react'; @@ -14,10 +15,11 @@ import { coreMock, scopedHistoryMock, themeServiceMock } from '@kbn/core/public/ import { UserProfileAPIClient } from '..'; import type { UserData } from '../../../common'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import { UserAvatar } from '../../components'; import { UserAPIClient } from '../../management'; import { securityMock } from '../../mocks'; import { Providers } from '../account_management_app'; -import { useUserProfileForm } from './user_profile'; +import { UserProfile, useUserProfileForm } from './user_profile'; const user = mockAuthenticatedUser(); const coreStart = coreMock.createStart(); @@ -181,4 +183,52 @@ describe('useUserProfileForm', () => { expect(result.current.initialValues.user.full_name).toEqual('Another Name'); }); + + describe('User Avatar Form', () => { + it('should display if the User is not a cloud user', () => { + const data: UserData = {}; + + const nonCloudUser = mockAuthenticatedUser({ elastic_cloud_user: false }); + + const testWrapper = mount( + + + + ); + + expect(testWrapper.exists(UserAvatar)).toBeTruthy(); + }); + + it('should not display if the User is a cloud user', () => { + const data: UserData = {}; + + const cloudUser = mockAuthenticatedUser({ elastic_cloud_user: true }); + + const testWrapper = mount( + + + + ); + + expect(testWrapper.exists(UserAvatar)).toBeFalsy(); + }); + }); }); diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx index cc42f10da39b9..bc95fae5b1c68 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx @@ -439,6 +439,8 @@ export const UserProfile: FunctionComponent = ({ user, data }) const canChangeDetails = canUserChangeDetails(user, services.application.capabilities); + const isCloudUser = user.elastic_cloud_user; + const rightSideItems = [ { title: ( @@ -559,7 +561,7 @@ export const UserProfile: FunctionComponent = ({ user, data }) >
- + {isCloudUser ? null : } setShowChangePasswordForm(true)} diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx index 7b44fb0893362..298f71d01dd88 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx @@ -173,10 +173,10 @@ describe('SecurityNavControl', () => { expect(wrapper.prop('isOpen')).toEqual(false); }); - it('should render additional user menu links registered by other plugins', async () => { + it('should render additional user menu links registered by other plugins and should render the default Edit Profile link as the first link when no custom profile link is provided', async () => { const wrapper = shallow( { "items": Array [ Object { "data-test-subj": "profileLink", - "href": "", + "href": "edit-profile-link", "icon": , "name": , "onClick": [Function], }, @@ -258,10 +254,10 @@ describe('SecurityNavControl', () => { `); }); - it('should render custom profile link registered by other plugins', async () => { + it('should render custom profile link registered by other plugins and not render default Edit Profile link', async () => { const wrapper = shallow( { />, "name": "link3", }, - Object { - "data-test-subj": "profileLink", - "href": "", - "icon": , - "name": , - "onClick": [Function], - }, Object { "data-test-subj": "logoutLink", "href": "", diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx index 2f462aaba4bc6..74d29fbb9f87b 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx @@ -79,7 +79,6 @@ export const SecurityNavControl: FunctionComponent = ({ ); - const isAnonymous = currentUser.value ? isUserAnonymous(currentUser.value) : false; const items: EuiContextMenuPanelItemDescriptor[] = []; if (userMenuLinks.length) { const userMenuLinkMenuItems = userMenuLinks @@ -93,17 +92,18 @@ export const SecurityNavControl: FunctionComponent = ({ items.push(...userMenuLinkMenuItems); } - if (!isAnonymous) { - const hasCustomProfileLinks = userMenuLinks.some(({ setAsProfile }) => setAsProfile === true); + const isAnonymous = currentUser.value ? isUserAnonymous(currentUser.value) : false; + const hasCustomProfileLinks = userMenuLinks.some(({ setAsProfile }) => setAsProfile === true); + + if (!isAnonymous && !hasCustomProfileLinks) { const profileMenuItem: EuiContextMenuPanelItemDescriptor = { name: ( ), - icon: , + icon: , href: editProfileUrl, onClick: () => { setIsPopoverOpen(false); @@ -112,11 +112,7 @@ export const SecurityNavControl: FunctionComponent = ({ }; // Set this as the first link if there is no user-defined profile link - if (!hasCustomProfileLinks) { - items.unshift(profileMenuItem); - } else { - items.push(profileMenuItem); - } + items.unshift(profileMenuItem); } items.push({ diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ddc14eb55173e..e9f20b6333da4 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -24135,7 +24135,6 @@ "xpack.security.management.users.usersTitle": "Utilisateurs", "xpack.security.management.usersTitle": "Utilisateurs", "xpack.security.navControlComponent.accountMenuAriaLabel": "Menu Compte", - "xpack.security.navControlComponent.editProfileLinkText": "{profileOverridden, select, true{Préférences} other{Profil}}", "xpack.security.navControlComponent.loginLinkText": "Connexion", "xpack.security.navControlComponent.logoutLinkText": "Déconnexion", "xpack.security.overwrittenSession.continueAsUserText": "Continuer en tant que {username}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0caf8c69cd81f..2f88cbf583584 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -24120,7 +24120,6 @@ "xpack.security.management.users.usersTitle": "ユーザー", "xpack.security.management.usersTitle": "ユーザー", "xpack.security.navControlComponent.accountMenuAriaLabel": "アカウントメニュー", - "xpack.security.navControlComponent.editProfileLinkText": "{profileOverridden, select, true{設定} other{プロファイル}}", "xpack.security.navControlComponent.loginLinkText": "ログイン", "xpack.security.navControlComponent.logoutLinkText": "ログアウト", "xpack.security.overwrittenSession.continueAsUserText": "{username} として続行", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 921ca2a48b925..073efb7030708 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -24146,7 +24146,6 @@ "xpack.security.management.users.usersTitle": "用户", "xpack.security.management.usersTitle": "用户", "xpack.security.navControlComponent.accountMenuAriaLabel": "帐户菜单", - "xpack.security.navControlComponent.editProfileLinkText": "{profileOverridden, select, true{首选项} other{配置文件}}", "xpack.security.navControlComponent.loginLinkText": "登录", "xpack.security.navControlComponent.logoutLinkText": "注销", "xpack.security.overwrittenSession.continueAsUserText": "作为 {username} 继续",