Skip to content

Commit

Permalink
Merge branch 'feature-make-it-ingest' into feature/fleet/agent-enroll…
Browse files Browse the repository at this point in the history
…ment
  • Loading branch information
jen-huang authored Oct 16, 2019
2 parents fcd56d3 + fb77f20 commit 5caa385
Show file tree
Hide file tree
Showing 17 changed files with 272 additions and 29 deletions.
24 changes: 24 additions & 0 deletions x-pack/legacy/plugins/fleet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,30 @@ export function fleet(kibana: any) {
attributesToEncrypt: new Set(['token']),
attributesToExcludeFromAAD: new Set(['enrollment_rules']),
});
server.plugins.xpack_main.registerFeature({
id: 'fleet',
name: 'Fleet',
app: ['fleet', 'kibana'],
excludeFromBasePrivileges: true,
privileges: {
all: {
savedObject: {
all: ['agents', 'events', 'tokens'],
read: [],
},
ui: ['read', 'write'],
api: ['fleet-read', 'fleet-all'],
},
read: {
savedObject: {
all: [],
read: ['agents', 'events', 'tokens'],
},
ui: ['read'],
api: ['fleet-read'],
},
},
});
initServerWithKibana(server);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface FrameworkAdapter {
// Instance vars
info: FrameworkInfo;
version: string;
capabilities: { read: boolean; write: boolean };
currentUser: FrameworkUser;
// Methods
waitUntilFrameworkReady(): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { isLeft } from 'fp-ts/lib/Either';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { UIRoutes } from 'ui/routes';
import { capabilities } from 'ui/capabilities';
import { BufferedKibanaServiceCall, KibanaAdapterServiceRefs, KibanaUIConfig } from '../../types';
import {
FrameworkAdapter,
Expand All @@ -36,6 +37,10 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
public get currentUser() {
return this.shieldUser!;
}
public get capabilities(): Readonly<{ read: boolean; write: boolean }> {
return capabilities.get().fleet as { read: boolean; write: boolean };
}

private xpackInfo: FrameworkInfo | null = null;
private adapterService: KibanaAdapterServiceProvider;
private shieldUser: FrameworkUser | null = null;
Expand Down
4 changes: 4 additions & 0 deletions x-pack/legacy/plugins/fleet/public/lib/framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export class FrameworkLib {
return this.adapter.currentUser;
}

public get capabilities(): { read: boolean; write: boolean } {
return this.adapter.capabilities;
}

public get info() {
return this.adapter.info;
}
Expand Down
34 changes: 20 additions & 14 deletions x-pack/legacy/plugins/fleet/public/pages/agent_list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@ export const AgentListPage: React.SFC<RouterProps> = ({ libs }) => {
</h2>
}
actions={
<EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
<FormattedMessage
id="xpack.fleet.agentList.addButton"
defaultMessage="Install new agent"
/>
</EuiButton>
libs.framework.capabilities.write ? (
<EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
<FormattedMessage
id="xpack.fleet.agentList.addButton"
defaultMessage="Install new agent"
/>
</EuiButton>
) : (
null
)
}
/>
);
Expand Down Expand Up @@ -191,14 +195,16 @@ export const AgentListPage: React.SFC<RouterProps> = ({ libs }) => {
<EuiFlexItem grow={4}>
<SearchBar libs={libs} value={search} onChange={setSearch} fieldPrefix="agents" />
</EuiFlexItem>
<EuiFlexItem>
<EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
<FormattedMessage
id="xpack.fleet.agentList.addButton"
defaultMessage="Install new agent"
/>
</EuiButton>
</EuiFlexItem>
{libs.framework.capabilities.write && (
<EuiFlexItem>
<EuiButton fill iconType="plusInCircle" onClick={() => setIsEnrollmentFlyoutOpen(true)}>
<FormattedMessage
id="xpack.fleet.agentList.addButton"
defaultMessage="Install new agent"
/>
</EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup>

<EuiSpacer size="m" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const NoAccessPage = injectI18n(({ intl }) => (
<FormattedMessage
id="xpack.fleet.noAccess.accessDeniedDescription"
defaultMessage="You are not authorized to access Elastic Fleet. To use Elastic Fleet,
you need the privileges granted by the {elasticFleetRole} role."
you need a user role that contains read or all permissions for this application."
values={{ elasticFleetRole: '`elastic_admin`' }}
/>
</p>
Expand Down
10 changes: 10 additions & 0 deletions x-pack/legacy/plugins/fleet/public/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ export class AppRoutes extends Component<RouterProps, RouterState> {
/>
)}

{!this.props.libs.framework.capabilities.read && (
<Route
render={props =>
!props.location.pathname.includes('/error') ? (
<Redirect to="/error/no_access" />
) : null
}
/>
)}

{/* Ensure security is eanabled for elastic and kibana */}
{/* TODO: Disabled for now as we don't have this info set up on backend yet */}
{/* {!get(this.props.libs.framework.info, 'security.enabled', true) && (
Expand Down
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { AgentAction } from '../../../common/types/domain_data';
export const createAgentsAddActionRoute = (libs: FleetServerLib) => ({
method: 'POST',
path: '/api/fleet/agents/{agentId}/actions',
config: {
options: {
tags: ['access:fleet-all'],
validate: {
payload: Joi.object(),
},
Expand Down
4 changes: 3 additions & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import { FleetServerLib } from '../../libs/types';

export const createDeleteAgentsRoute = (libs: FleetServerLib) => ({
method: 'DELETE',
config: {},
path: '/api/fleet/agents/{id}',
options: {
tags: ['access:fleet-all'],
},
handler: async (
request: FrameworkRequest<{ params: { id: string } }>,
h: FrameworkResponseToolkit
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/enroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Agent } from '../../../common/types/domain_data';
export const createEnrollAgentsRoute = (libs: FleetServerLib) => ({
method: 'POST',
path: '/api/fleet/agents/enroll',
config: {
options: {
auth: false,
validate: {
headers: Joi.object({
Expand Down
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { AgentEvent } from '../../../common/types/domain_data';
export const createGETAgentEventsRoute = (libs: FleetServerLib) => ({
method: 'GET',
path: '/api/fleet/agents/{agentId}/events',
config: {
options: {
tags: ['access:fleet-read'],
validate: {
query: Joi.object({
kuery: Joi.string()
Expand Down
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { Agent } from '../../../common/types/domain_data';
export const createGETAgentsRoute = (libs: FleetServerLib) => ({
method: 'GET',
path: '/api/fleet/agents/{agentId}',
config: {
options: {
tags: ['access:fleet-read'],
validate: {},
},
handler: async (
Expand Down
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/fleet/server/routes/agents/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { DEFAULT_AGENTS_PAGE_SIZE } from '../../../common/constants';
export const createListAgentsRoute = (libs: FleetServerLib) => ({
method: 'GET',
path: '/api/fleet/agents',
config: {
options: {
tags: ['access:fleet-read'],
validate: {
query: {
page: Joi.number().default(1),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export default function({ getService }: FtrProviderContext) {
expect(featureIds.sort()).to.eql(
[
'discover',
'fleet',
'visualize',
'dashboard',
'dev_tools',
Expand Down
63 changes: 61 additions & 2 deletions x-pack/test/api_integration/apis/fleet/agent_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,55 @@
import expect from '@kbn/expect';

import { FtrProviderContext } from '../../ftr_provider_context';
import { SecurityService } from '../../../common/services';

export default function({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');

const supertest = getService('supertestWithoutAuth');
const security: SecurityService = getService('security');
const users: { [rollName: string]: { username: string; password: string; permissions?: any } } = {
fleet_user: {
permissions: {
feature: {
fleet: ['read'],
},
spaces: ['*'],
},
username: 'fleet_user',
password: 'changeme',
},
fleet_admin: {
permissions: {
feature: {
fleet: ['all'],
},
spaces: ['*'],
},
username: 'fleet_admin',
password: 'changeme',
},
};
describe('fleet_agent_actions', () => {
before(async () => {
for (const roleName in users) {
if (users.hasOwnProperty(roleName)) {
const user = users[roleName];

if (user.permissions) {
await security.role.create(roleName, {
kibana: [user.permissions],
});
}

// Import a repository first
await security.user.create(user.username, {
password: user.password,
roles: [roleName],
full_name: user.username,
});
}
}

await esArchiver.loadIfNeeded('fleet/agents');
});
after(async () => {
Expand All @@ -23,6 +65,8 @@ export default function({ getService }: FtrProviderContext) {
it('should return a 404 if the agent do not exists', async () => {
await supertest
.post(`/api/fleet/agents/i-do-not-exist/actions`)
.auth(users.fleet_admin.username, users.fleet_admin.password)

.send({
type: 'PAUSE',
})
Expand All @@ -33,6 +77,8 @@ export default function({ getService }: FtrProviderContext) {
it('should return a 400 if the action is not invalid', async () => {
await supertest
.post(`/api/fleet/agents/agent1/actions`)
.auth(users.fleet_admin.username, users.fleet_admin.password)

.send({
type: 'INVALID_ACTION',
})
Expand All @@ -43,6 +89,8 @@ export default function({ getService }: FtrProviderContext) {
it('should return a 200 if the action is not invalid', async () => {
const { body: apiResponse } = await supertest
.post(`/api/fleet/agents/agent1/actions`)
.auth(users.fleet_admin.username, users.fleet_admin.password)

.send({
type: 'PAUSE',
})
Expand All @@ -52,6 +100,17 @@ export default function({ getService }: FtrProviderContext) {
expect(apiResponse.item).to.have.keys(['id', 'type', 'created_at']);
});

it('should return a 404 if called by a user without permissions', async () => {
await supertest
.post(`/api/fleet/agents/agent1/actions`)
.auth(users.fleet_user.username, users.fleet_user.password)
.send({
type: 'PAUSE',
})
.set('kbn-xsrf', 'xx')
.expect(404);
});

// it('should return a 200 after deleting an agent', async () => {
// const { body: apiResponse } = await supertest
// .delete(`/api/fleet/agents/agent1`)
Expand Down
Loading

0 comments on commit 5caa385

Please sign in to comment.