Skip to content

Commit

Permalink
Initial work
Browse files Browse the repository at this point in the history
  • Loading branch information
mikecote committed Mar 20, 2020
1 parent 8a5f23c commit bfaa113
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 23 deletions.
52 changes: 52 additions & 0 deletions x-pack/plugins/security/server/authentication/api_keys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,56 @@ describe('API Keys', () => {
);
});
});

describe('invalidateAsInternalUser()', () => {
it('returns null when security feature is disabled', async () => {
mockLicense.isEnabled.mockReturnValue(false);
const result = await apiKeys.invalidateAsInternalUser({ id: '123' });
expect(result).toBeNull();
expect(mockClusterClient.callAsInternalUser).not.toHaveBeenCalled();
});

it('calls callCluster with proper parameters', async () => {
mockLicense.isEnabled.mockReturnValue(true);
mockClusterClient.callAsInternalUser.mockResolvedValueOnce({
invalidated_api_keys: ['api-key-id-1'],
previously_invalidated_api_keys: [],
error_count: 0,
});
const result = await apiKeys.invalidateAsInternalUser({ id: '123' });
expect(result).toEqual({
invalidated_api_keys: ['api-key-id-1'],
previously_invalidated_api_keys: [],
error_count: 0,
});
expect(mockClusterClient.callAsInternalUser).toHaveBeenCalledWith('shield.invalidateAPIKey', {
body: {
id: '123',
},
});
});

it('Only passes id as a parameter', async () => {
mockLicense.isEnabled.mockReturnValue(true);
mockClusterClient.callAsInternalUser.mockResolvedValueOnce({
invalidated_api_keys: ['api-key-id-1'],
previously_invalidated_api_keys: [],
error_count: 0,
});
const result = await apiKeys.invalidateAsInternalUser({
id: '123',
name: 'abc',
} as any);
expect(result).toEqual({
invalidated_api_keys: ['api-key-id-1'],
previously_invalidated_api_keys: [],
error_count: 0,
});
expect(mockClusterClient.callAsInternalUser).toHaveBeenCalledWith('shield.invalidateAPIKey', {
body: {
id: '123',
},
});
});
});
});
64 changes: 41 additions & 23 deletions x-pack/plugins/security/server/authentication/api_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { IClusterClient, KibanaRequest, Logger } from '../../../../../src/core/server';
import { IClusterClient, KibanaRequest, Logger, IScopedClusterClient } from '../../../../../src/core/server';
import { SecurityLicense } from '../../common/licensing';
import { HTTPAuthorizationHeader } from './http_authentication';
import { BasicHTTPAuthorizationHeaderCredentials } from './http_authentication';
Expand Down Expand Up @@ -197,29 +197,21 @@ export class APIKeys {
request: KibanaRequest,
params: InvalidateAPIKeyParams
): Promise<InvalidateAPIKeyResult | null> {
if (!this.license.isEnabled()) {
return null;
}

this.logger.debug('Trying to invalidate an API key');

// User needs `manage_api_key` privilege to use this API
let result: InvalidateAPIKeyResult;
try {
result = (await this.clusterClient
.asScoped(request)
.callAsCurrentUser('shield.invalidateAPIKey', {
body: {
id: params.id,
},
})) as InvalidateAPIKeyResult;
this.logger.debug('API key was invalidated successfully');
} catch (e) {
this.logger.error(`Failed to invalidate API key: ${e.message}`);
throw e;
}
return await this.callClusterToInvalidate(
params,
this.clusterClient.asScoped(request).callAsCurrentUser
);
}

return result;
/**
* Tries to invalidate an API key by using the internal user.
* @param params The params to invalidate an API key.
*/
async invalidateAsInternalUser(
params: InvalidateAPIKeyParams
): Promise<InvalidateAPIKeyResult | null> {
// Internal user needs `cluster:admin/xpack/security/api_key/invalidate` privilege to use this API
return await this.callClusterToInvalidate(params, this.clusterClient.callAsInternalUser);
}

private getGrantParams(authorizationHeader: HTTPAuthorizationHeader): GrantAPIKeyParams {
Expand All @@ -243,4 +235,30 @@ export class APIKeys {

throw new Error(`Unsupported scheme "${authorizationHeader.scheme}" for granting API Key`);
}

private async callClusterToInvalidate(
params: InvalidateAPIKeyParams,
callCluster: (endpoint: string, params: Record<string, any>) => Promise<any>
): Promise<InvalidateAPIKeyResult | null> {
if (!this.license.isEnabled()) {
return null;
}

this.logger.debug('Trying to invalidate an API key');

let result: InvalidateAPIKeyResult;
try {
result = (await callCluster('shield.invalidateAPIKey', {
body: {
id: params.id,
},
})) as InvalidateAPIKeyResult;
this.logger.debug('API key was invalidated successfully');
} catch (e) {
this.logger.error(`Failed to invalidate API key: ${e.message}`);
throw e;
}

return result;
}
}
22 changes: 22 additions & 0 deletions x-pack/plugins/security/server/authentication/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,4 +392,26 @@ describe('setupAuthentication()', () => {
expect(apiKeysInstance.invalidate).toHaveBeenCalledWith(request, params);
});
});

describe('invalidateAPIKeyAsInternalUser()', () => {
let invalidateAPIKeyAsInternalUser: (
params: InvalidateAPIKeyParams
) => Promise<InvalidateAPIKeyResult | null>;

beforeEach(async () => {
invalidateAPIKeyAsInternalUser = (await setupAuthentication(mockSetupAuthenticationParams)).invalidateAPIKeyAsInternalUser;
});

it('calls invalidateAPIKeyAsInternalUser with given arguments', async () => {
const apiKeysInstance = jest.requireMock('./api_keys').APIKeys.mock.instances[0];
const params = {
id: '123',
};
apiKeysInstance.invalidateAsInternalUser.mockResolvedValueOnce({ success: true });
await expect(invalidateAPIKeyAsInternalUser(params)).resolves.toEqual({
success: true,
});
expect(apiKeysInstance.invalidateAsInternalUser).toHaveBeenCalledWith(params);
});
});
});
2 changes: 2 additions & 0 deletions x-pack/plugins/security/server/authentication/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ export async function setupAuthentication({
grantAPIKeyAsInternalUser: (request: KibanaRequest) => apiKeys.grantAsInternalUser(request),
invalidateAPIKey: (request: KibanaRequest, params: InvalidateAPIKeyParams) =>
apiKeys.invalidate(request, params),
invalidateAPIKeyAsInternalUser: (params: InvalidateAPIKeyParams) =>
apiKeys.invalidateAsInternalUser(params),
isAuthenticated: (request: KibanaRequest) => http.auth.isAuthenticated(request),
};
}

0 comments on commit bfaa113

Please sign in to comment.