Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion x-pack/plugins/security/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@

export const GLOBAL_RESOURCE = '*';
export const IGNORED_TYPES = ['space'];
export const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native'];
export const APPLICATION_PREFIX = 'kibana-';
export const RESERVED_PRIVILEGES_APPLICATION_WILDCARD = 'kibana-*';
62 changes: 62 additions & 0 deletions x-pack/plugins/security/common/model/user.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { canUserChangePassword, getUserDisplayName, User } from './user';

describe('#getUserDisplayName', () => {
it(`uses the full name when available`, () => {
expect(
getUserDisplayName({
full_name: 'my full name',
username: 'foo',
} as User)
).toEqual('my full name');
});

it(`uses the username when full name is not available`, () => {
expect(
getUserDisplayName({
username: 'foo',
} as User)
).toEqual('foo');
});
});

describe('#canUserChangePassword', () => {
['reserved', 'native'].forEach(realm => {
it(`returns true for users in the ${realm} realm`, () => {
expect(
canUserChangePassword({
username: 'foo',
authentication_realm: {
name: 'the realm name',
type: realm,
},
} as User)
).toEqual(true);
});
});

it(`returns true when no realm is provided`, () => {
expect(
canUserChangePassword({
username: 'foo',
} as User)
).toEqual(true);
});

it(`returns false for all other realms`, () => {
expect(
canUserChangePassword({
username: 'foo',
authentication_realm: {
name: 'the realm name',
type: 'does not matter',
},
} as User)
).toEqual(false);
});
});
37 changes: 37 additions & 0 deletions x-pack/plugins/security/common/model/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export interface User {
username: string;
email: string;
full_name: string;
roles: string[];
enabled: boolean;
authentication_realm?: {
name: string;
type: string;
};
lookup_realm?: {
name: string;
type: string;
};
}

const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native'];

export function getUserDisplayName(user: User): string {
return user.full_name || user.username;
}

export function canUserChangePassword(user: User): boolean {
const { authentication_realm: authenticationRealm } = user;

if (!authenticationRealm) {
return true;
}

return REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE.includes(authenticationRealm.type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('../../../lib/api', () => {
return {
UserAPIClient: {
changePassword: jest.fn(),
},
};
});
import { EuiFieldText } from '@elastic/eui';
import { ReactWrapper } from 'enzyme';
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { User } from '../../../../common/model/user';
import { UserAPIClient } from '../../../lib/api';
import { ChangePasswordForm } from './change_password_form';

function getCurrentPasswordField(wrapper: ReactWrapper<any>) {
return wrapper.find(EuiFieldText).filter('[data-test-subj="currentPassword"]');
}

function getNewPasswordField(wrapper: ReactWrapper<any>) {
return wrapper.find(EuiFieldText).filter('[data-test-subj="newPassword"]');
}

function getConfirmPasswordField(wrapper: ReactWrapper<any>) {
return wrapper.find(EuiFieldText).filter('[data-test-subj="confirmNewPassword"]');
}

describe('<ChangePasswordForm>', () => {
describe('for the current user', () => {
it('shows fields for current and new passwords', () => {
const user: User = {
username: 'user',
full_name: 'john smith',
email: 'john@smith.com',
enabled: true,
roles: [],
};

const wrapper = mountWithIntl(
<ChangePasswordForm user={user} isUserChangingOwnPassword={true} />
);

expect(getCurrentPasswordField(wrapper)).toHaveLength(1);
expect(getNewPasswordField(wrapper)).toHaveLength(1);
expect(getConfirmPasswordField(wrapper)).toHaveLength(1);
});

it('allows a password to be changed', () => {
const user: User = {
username: 'user',
full_name: 'john smith',
email: 'john@smith.com',
enabled: true,
roles: [],
};

const callback = jest.fn();

const wrapper = mountWithIntl(
<ChangePasswordForm
user={user}
isUserChangingOwnPassword={true}
onChangePassword={callback}
/>
);

const currentPassword = getCurrentPasswordField(wrapper);
currentPassword.props().onChange!({ target: { value: 'myCurrentPassword' } } as any);

const newPassword = getNewPasswordField(wrapper);
newPassword.props().onChange!({ target: { value: 'myNewPassword' } } as any);

const confirmPassword = getConfirmPasswordField(wrapper);
confirmPassword.props().onChange!({ target: { value: 'myNewPassword' } } as any);

wrapper.find('button[data-test-subj="changePasswordButton"]').simulate('click');

expect(UserAPIClient.changePassword).toHaveBeenCalledTimes(1);
expect(UserAPIClient.changePassword).toHaveBeenCalledWith(
'user',
'myNewPassword',
'myCurrentPassword'
);
});
});

describe('for another user', () => {
it('shows fields for new password only', () => {
const user: User = {
username: 'user',
full_name: 'john smith',
email: 'john@smith.com',
enabled: true,
roles: [],
};

const wrapper = mountWithIntl(
<ChangePasswordForm user={user} isUserChangingOwnPassword={false} />
);

expect(getCurrentPasswordField(wrapper)).toHaveLength(0);
expect(getNewPasswordField(wrapper)).toHaveLength(1);
expect(getConfirmPasswordField(wrapper)).toHaveLength(1);
});
});
});
Loading