Skip to content

Commit

Permalink
Add support for deprecated roles
Browse files Browse the repository at this point in the history
  • Loading branch information
legrego committed Feb 11, 2020
1 parent 733f602 commit 58a25fa
Show file tree
Hide file tree
Showing 54 changed files with 1,120 additions and 292 deletions.
3 changes: 2 additions & 1 deletion docs/management/advanced-options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ cluster alert notifications from Monitoring.
=== Dashboard settings

[horizontal]
`xpackDashboardMode:roles`:: The roles that belong to <<xpack-dashboard-only-mode, dashboard only mode>>.
`xpackDashboardMode:roles`:: **Deprecated. Use <<kibana-feature-privileges,feature privileges>> instead.**
The roles that belong to <<xpack-dashboard-only-mode, dashboard only mode>>.

[float]
[[kibana-discover-settings]]
Expand Down
1 change: 1 addition & 0 deletions src/core/public/doc_links/doc_links_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export class DocLinksService {
},
management: {
kibanaSearchSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/advanced-options.html#kibana-search-settings`,
dashboardSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/advanced-options.html#kibana-dashboard-settings`,
},
},
});
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions x-pack/legacy/plugins/dashboard_mode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ export function dashboardMode(kibana) {
),
value: ['kibana_dashboard_only_user'],
category: ['dashboard'],
deprecation: {
message: i18n.translate(
'xpack.dashboardMode.uiSettings.dashboardsOnlyRolesDeprecation',
{
defaultMessage: 'This setting is deprecated and will be removed in Kibana 8.0.',
}
),
docLinksKey: 'dashboardSettings',
},
},
},
app: {
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/security/common/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ export {
RoleIndexPrivilege,
RoleKibanaPrivilege,
copyRole,
isReadOnlyRole,
isReservedRole,
isRoleDeprecated,
isRoleReadOnly,
isRoleReserved,
isRoleEnabled,
prepareRoleClone,
getExtendedRoleDeprecationNotice,
} from './role';
export { KibanaPrivileges } from './kibana_privileges';
export {
Expand Down
72 changes: 62 additions & 10 deletions x-pack/plugins/security/common/model/role.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Role, isReadOnlyRole, isReservedRole, isRoleEnabled, copyRole, prepareRoleClone } from '.';
import {
Role,
isRoleEnabled,
isRoleReserved,
isRoleDeprecated,
isRoleReadOnly,
copyRole,
prepareRoleClone,
getExtendedRoleDeprecationNotice,
} from '../../common/model';

describe('role', () => {
describe('isRoleEnabled', () => {
Expand Down Expand Up @@ -32,14 +41,14 @@ describe('role', () => {
});
});

describe('isReservedRole', () => {
describe('isRoleReserved', () => {
test('should return false if role is explicitly not reserved', () => {
const testRole = {
metadata: {
_reserved: false,
},
};
expect(isReservedRole(testRole)).toBe(false);
expect(isRoleReserved(testRole)).toBe(false);
});

test('should return true if role is explicitly reserved', () => {
Expand All @@ -48,30 +57,73 @@ describe('role', () => {
_reserved: true,
},
};
expect(isReservedRole(testRole)).toBe(true);
expect(isRoleReserved(testRole)).toBe(true);
});

test('should return false if role is NOT explicitly reserved or not reserved', () => {
const testRole = {};
expect(isReservedRole(testRole)).toBe(false);
expect(isRoleReserved(testRole)).toBe(false);
});
});

describe('isReadOnlyRole', () => {
describe('isRoleDeprecated', () => {
test('should return false if role is explicitly not deprecated', () => {
const testRole = {
metadata: {
_deprecated: false,
},
};
expect(isRoleDeprecated(testRole)).toBe(false);
});

test('should return true if role is explicitly deprecated', () => {
const testRole = {
metadata: {
_deprecated: true,
},
};
expect(isRoleDeprecated(testRole)).toBe(true);
});

test('should return false if role is NOT explicitly deprecated or not deprecated', () => {
const testRole = {};
expect(isRoleDeprecated(testRole)).toBe(false);
});
});

describe('getExtendedRoleDeprecationNotice', () => {
test('advises not to use the deprecated role', () => {
const testRole = {};
expect(getExtendedRoleDeprecationNotice(testRole)).toMatchInlineSnapshot(
`"This role is deprecated and should no longer be assigned. "`
);
});

test('includes the deprecation reason when provided', () => {
const testRole = {
metadata: { _deprecated_reason: "We just don't like this role anymore" },
};
expect(getExtendedRoleDeprecationNotice(testRole)).toMatchInlineSnapshot(
`"This role is deprecated and should no longer be assigned. We just don't like this role anymore"`
);
});
});

describe('isRoleReadOnly', () => {
test('returns true for reserved roles', () => {
const testRole = {
metadata: {
_reserved: true,
},
};
expect(isReadOnlyRole(testRole)).toBe(true);
expect(isRoleReadOnly(testRole)).toBe(true);
});

test('returns true for roles with transform errors', () => {
const testRole = {
_transform_error: ['kibana'],
};
expect(isReadOnlyRole(testRole)).toBe(true);
expect(isRoleReadOnly(testRole)).toBe(true);
});

test('returns false for disabled roles', () => {
Expand All @@ -80,12 +132,12 @@ describe('role', () => {
enabled: false,
},
};
expect(isReadOnlyRole(testRole)).toBe(false);
expect(isRoleReadOnly(testRole)).toBe(false);
});

test('returns false for all other roles', () => {
const testRole = {};
expect(isReadOnlyRole(testRole)).toBe(false);
expect(isRoleReadOnly(testRole)).toBe(false);
});
});

Expand Down
39 changes: 36 additions & 3 deletions x-pack/plugins/security/common/model/role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { cloneDeep } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FeaturesPrivileges } from './features_privileges';

export interface RoleIndexPrivilege {
Expand Down Expand Up @@ -57,17 +58,49 @@ export function isRoleEnabled(role: Partial<Role>) {
*
* @param role Role as returned by roles API
*/
export function isReservedRole(role: Partial<Role>) {
export function isRoleReserved(role: Partial<Role>) {
return (role.metadata?._reserved as boolean) ?? false;
}

/**
* Returns whether given role is deprecated or not.
*
* @param {role} the Role as returned by roles API
*/
export function isRoleDeprecated(role: Partial<Role>) {
return role.metadata?._deprecated ?? false;
}

/**
* Returns the reason this role is deprecated.
*
* @param role the Role as returned by roles API
*/
export function getRoleDeprecatedReason(role: Partial<Role>) {
return role.metadata?._deprecated_reason ?? '';
}

/**
* Returns the extended deprecation notice for the provided role.
*
* @param role the Role as returned by roles API
*/
export function getExtendedRoleDeprecationNotice(role: Partial<Role>) {
return i18n.translate('xpack.security.common.extendedRoleDeprecationNotice', {
defaultMessage: `This role is deprecated and should no longer be assigned. {reason}`,
values: {
reason: getRoleDeprecatedReason(role),
},
});
}

/**
* Returns whether given role is editable through the UI or not.
*
* @param role the Role as returned by roles API
*/
export function isReadOnlyRole(role: Partial<Role>): boolean {
return isReservedRole(role) || (role._transform_error?.length ?? 0) > 0;
export function isRoleReadOnly(role: Partial<Role>): boolean {
return isRoleReserved(role) || (role._transform_error?.length ?? 0) > 0;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('<AccountManagementPage>', () => {
<AccountManagementPage
authc={getSecuritySetupMock({ currentUser: user }).authc}
notifications={coreMock.createStart().notifications}
apiClient={userAPIClientMock.create()}
userAPIClient={userAPIClientMock.create()}
/>
);

Expand All @@ -70,7 +70,7 @@ describe('<AccountManagementPage>', () => {
<AccountManagementPage
authc={getSecuritySetupMock({ currentUser: user }).authc}
notifications={coreMock.createStart().notifications}
apiClient={userAPIClientMock.create()}
userAPIClient={userAPIClientMock.create()}
/>
);

Expand All @@ -88,7 +88,7 @@ describe('<AccountManagementPage>', () => {
<AccountManagementPage
authc={getSecuritySetupMock({ currentUser: user }).authc}
notifications={coreMock.createStart().notifications}
apiClient={userAPIClientMock.create()}
userAPIClient={userAPIClientMock.create()}
/>
);

Expand All @@ -106,7 +106,7 @@ describe('<AccountManagementPage>', () => {
<AccountManagementPage
authc={getSecuritySetupMock({ currentUser: user }).authc}
notifications={coreMock.createStart().notifications}
apiClient={userAPIClientMock.create()}
userAPIClient={userAPIClientMock.create()}
/>
);

Expand All @@ -125,7 +125,7 @@ describe('<AccountManagementPage>', () => {
<AccountManagementPage
authc={getSecuritySetupMock({ currentUser: user }).authc}
notifications={coreMock.createStart().notifications}
apiClient={userAPIClientMock.create()}
userAPIClient={userAPIClientMock.create()}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import { PersonalInfo } from './personal_info';

interface Props {
authc: AuthenticationServiceSetup;
apiClient: PublicMethodsOf<UserAPIClient>;
userAPIClient: PublicMethodsOf<UserAPIClient>;
notifications: NotificationsStart;
}

export const AccountManagementPage = ({ apiClient, authc, notifications }: Props) => {
export const AccountManagementPage = ({ userAPIClient, authc, notifications }: Props) => {
const [currentUser, setCurrentUser] = useState<AuthenticatedUser | null>(null);
useEffect(() => {
authc.getCurrentUser().then(setCurrentUser);
Expand All @@ -40,7 +40,11 @@ export const AccountManagementPage = ({ apiClient, authc, notifications }: Props

<PersonalInfo user={currentUser} />

<ChangePassword user={currentUser} apiClient={apiClient} notifications={notifications} />
<ChangePassword
user={currentUser}
userAPIClient={userAPIClient}
notifications={notifications}
/>
</EuiPanel>
</EuiPageBody>
</EuiPage>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ChangePasswordForm } from '../../management/users/components/change_pas

interface Props {
user: AuthenticatedUser;
apiClient: PublicMethodsOf<UserAPIClient>;
userAPIClient: PublicMethodsOf<UserAPIClient>;
notifications: NotificationsSetup;
}

Expand Down Expand Up @@ -48,7 +48,7 @@ export class ChangePassword extends Component<Props, {}> {
<ChangePasswordForm
user={this.props.user}
isUserChangingOwnPassword={true}
apiClient={this.props.apiClient}
userAPIClient={this.props.userAPIClient}
notifications={this.props.notifications}
/>
</EuiDescribedFormGroup>
Expand Down
Loading

0 comments on commit 58a25fa

Please sign in to comment.