Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NP] Platform exposes API to get authenticated user data #55327

Merged
merged 8 commits into from
Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [CoreSetup](./kibana-plugin-server.coresetup.md) &gt; [getStartServices](./kibana-plugin-server.coresetup.getstartservices.md)

## CoreSetup.getStartServices() method

Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed `start`<!-- -->. This should only be used inside handlers registered during `setup` that will only be executed after `start` lifecycle.

<b>Signature:</b>

```typescript
getStartServices(): Promise<[CoreStart, TPluginsStart]>;
```
<b>Returns:</b>

`Promise<[CoreStart, TPluginsStart]>`

<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [CoreSetup](./kibana-plugin-server.coresetup.md) &gt; [getStartServices](./kibana-plugin-server.coresetup.getstartservices.md)

## CoreSetup.getStartServices() method

Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed `start`<!-- -->. This should only be used inside handlers registered during `setup` that will only be executed after `start` lifecycle.

<b>Signature:</b>

```typescript
getStartServices(): Promise<[CoreStart, TPluginsStart]>;
```
<b>Returns:</b>

`Promise<[CoreStart, TPluginsStart]>`

64 changes: 32 additions & 32 deletions docs/development/core/server/kibana-plugin-server.coresetup.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [CoreSetup](./kibana-plugin-server.coresetup.md)

## CoreSetup interface

Context passed to the plugins `setup` method.

<b>Signature:</b>

```typescript
export interface CoreSetup<TPluginsStart extends object = object>
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [capabilities](./kibana-plugin-server.coresetup.capabilities.md) | <code>CapabilitiesSetup</code> | [CapabilitiesSetup](./kibana-plugin-server.capabilitiessetup.md) |
| [context](./kibana-plugin-server.coresetup.context.md) | <code>ContextSetup</code> | [ContextSetup](./kibana-plugin-server.contextsetup.md) |
| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | <code>ElasticsearchServiceSetup</code> | [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) |
| [http](./kibana-plugin-server.coresetup.http.md) | <code>HttpServiceSetup</code> | [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) |
| [savedObjects](./kibana-plugin-server.coresetup.savedobjects.md) | <code>SavedObjectsServiceSetup</code> | [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) |
| [uiSettings](./kibana-plugin-server.coresetup.uisettings.md) | <code>UiSettingsServiceSetup</code> | [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) |
| [uuid](./kibana-plugin-server.coresetup.uuid.md) | <code>UuidServiceSetup</code> | [UuidServiceSetup](./kibana-plugin-server.uuidservicesetup.md) |

## Methods

| Method | Description |
| --- | --- |
| [getStartServices()](./kibana-plugin-server.coresetup.getstartservices.md) | Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed <code>start</code>. This should only be used inside handlers registered during <code>setup</code> that will only be executed after <code>start</code> lifecycle. |

<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [CoreSetup](./kibana-plugin-server.coresetup.md)

## CoreSetup interface

Context passed to the plugins `setup` method.

<b>Signature:</b>

```typescript
export interface CoreSetup<TPluginsStart extends object = object>
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [capabilities](./kibana-plugin-server.coresetup.capabilities.md) | <code>CapabilitiesSetup</code> | [CapabilitiesSetup](./kibana-plugin-server.capabilitiessetup.md) |
| [context](./kibana-plugin-server.coresetup.context.md) | <code>ContextSetup</code> | [ContextSetup](./kibana-plugin-server.contextsetup.md) |
| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | <code>ElasticsearchServiceSetup</code> | [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) |
| [http](./kibana-plugin-server.coresetup.http.md) | <code>HttpServiceSetup</code> | [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) |
| [savedObjects](./kibana-plugin-server.coresetup.savedobjects.md) | <code>SavedObjectsServiceSetup</code> | [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) |
| [uiSettings](./kibana-plugin-server.coresetup.uisettings.md) | <code>UiSettingsServiceSetup</code> | [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) |
| [uuid](./kibana-plugin-server.coresetup.uuid.md) | <code>UuidServiceSetup</code> | [UuidServiceSetup](./kibana-plugin-server.uuidservicesetup.md) |

## Methods

| Method | Description |
| --- | --- |
| [getStartServices()](./kibana-plugin-server.coresetup.getstartservices.md) | Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed <code>start</code>. This should only be used inside handlers registered during <code>setup</code> that will only be executed after <code>start</code> lifecycle. |

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

## GetAuthState type

Get authentication state for a request. Returned by `auth` interceptor.
Gets authentication state for a request. Returned by `auth` interceptor.

<b>Signature:</b>

```typescript
export declare type GetAuthState = (request: KibanaRequest | LegacyRequest) => {
export declare type GetAuthState = <T = unknown>(request: KibanaRequest | LegacyRequest) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just expose this on RequestHandlerContext?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can expose auth.isAuthenticated when optional authentication implemented. Not sure we need to provide auth.get until then or can be exposed later upon request.

status: AuthStatus;
state: unknown;
state: T;
};
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) &gt; [auth](./kibana-plugin-server.httpservicesetup.auth.md)

## HttpServiceSetup.auth property

<b>Signature:</b>

```typescript
auth: {
get: GetAuthState;
isAuthenticated: IsAuthenticated;
};
```
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ async (context, request, response) => {

| Property | Type | Description |
| --- | --- | --- |
| [auth](./kibana-plugin-server.httpservicesetup.auth.md) | <code>{</code><br/><code> get: GetAuthState;</code><br/><code> isAuthenticated: IsAuthenticated;</code><br/><code> }</code> | |
| [basePath](./kibana-plugin-server.httpservicesetup.basepath.md) | <code>IBasePath</code> | Access or manipulate the Kibana base path See [IBasePath](./kibana-plugin-server.ibasepath.md)<!-- -->. |
| [createCookieSessionStorageFactory](./kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md) | <code>&lt;T&gt;(cookieOptions: SessionStorageCookieOptions&lt;T&gt;) =&gt; Promise&lt;SessionStorageFactory&lt;T&gt;&gt;</code> | Creates cookie based session storage factory [SessionStorageFactory](./kibana-plugin-server.sessionstoragefactory.md) |
| [createRouter](./kibana-plugin-server.httpservicesetup.createrouter.md) | <code>() =&gt; IRouter</code> | Provides ability to declare a handler function for a particular path and HTTP request method. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## IsAuthenticated type

Return authentication status for a request.
Returns authentication status for a request.

<b>Signature:</b>

Expand Down
4 changes: 2 additions & 2 deletions docs/development/core/server/kibana-plugin-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [ConfigPath](./kibana-plugin-server.configpath.md) | |
| [ElasticsearchClientConfig](./kibana-plugin-server.elasticsearchclientconfig.md) | |
| [GetAuthHeaders](./kibana-plugin-server.getauthheaders.md) | Get headers to authenticate a user against Elasticsearch. |
| [GetAuthState](./kibana-plugin-server.getauthstate.md) | Get authentication state for a request. Returned by <code>auth</code> interceptor. |
| [GetAuthState](./kibana-plugin-server.getauthstate.md) | Gets authentication state for a request. Returned by <code>auth</code> interceptor. |
| [HandlerContextType](./kibana-plugin-server.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-server.handlerfunction.md) to represent the type of the context. |
| [HandlerFunction](./kibana-plugin-server.handlerfunction.md) | A function that accepts a context object and an optional number of additional arguments. Used for the generic types in [IContextContainer](./kibana-plugin-server.icontextcontainer.md) |
| [HandlerParameters](./kibana-plugin-server.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-server.handlerfunction.md)<!-- -->, excluding the [HandlerContextType](./kibana-plugin-server.handlercontexttype.md)<!-- -->. |
Expand All @@ -181,7 +181,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [IClusterClient](./kibana-plugin-server.iclusterclient.md) | Represents an Elasticsearch cluster API client created by the platform. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via <code>asScoped(...)</code>).<!-- -->See [ClusterClient](./kibana-plugin-server.clusterclient.md)<!-- -->. |
| [IContextProvider](./kibana-plugin-server.icontextprovider.md) | A function that returns a context value for a specific key of given context type. |
| [ICustomClusterClient](./kibana-plugin-server.icustomclusterclient.md) | Represents an Elasticsearch cluster API client created by a plugin. It allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via <code>asScoped(...)</code>).<!-- -->See [ClusterClient](./kibana-plugin-server.clusterclient.md)<!-- -->. |
| [IsAuthenticated](./kibana-plugin-server.isauthenticated.md) | Return authentication status for a request. |
| [IsAuthenticated](./kibana-plugin-server.isauthenticated.md) | Returns authentication status for a request. |
| [ISavedObjectsRepository](./kibana-plugin-server.isavedobjectsrepository.md) | See [SavedObjectsRepository](./kibana-plugin-server.savedobjectsrepository.md) |
| [IScopedClusterClient](./kibana-plugin-server.iscopedclusterclient.md) | Serves the same purpose as "normal" <code>ClusterClient</code> but exposes additional <code>callAsCurrentUser</code> method that doesn't use credentials of the Kibana internal user (as <code>callAsInternalUser</code> does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API.<!-- -->See [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md)<!-- -->. |
| [KibanaRequestRouteOptions](./kibana-plugin-server.kibanarequestrouteoptions.md) | Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. |
Expand Down
4 changes: 2 additions & 2 deletions src/core/server/elasticsearch/elasticsearch_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class ElasticsearchService implements CoreService<InternalElasticsearchSe
const coreClients = {
config,
adminClient: this.createClusterClient('admin', config),
dataClient: this.createClusterClient('data', config, deps.http.auth.getAuthHeaders),
dataClient: this.createClusterClient('data', config, deps.http.getAuthHeaders),
};

subscriber.next(coreClients);
Expand Down Expand Up @@ -157,7 +157,7 @@ export class ElasticsearchService implements CoreService<InternalElasticsearchSe

createClient: (type: string, clientConfig: Partial<ElasticsearchClientConfig> = {}) => {
const finalConfig = merge({}, config, clientConfig);
return this.createClusterClient(type, finalConfig, deps.http.auth.getAuthHeaders);
return this.createClusterClient(type, finalConfig, deps.http.getAuthHeaders);
},
};
}
Expand Down
12 changes: 6 additions & 6 deletions src/core/server/http/auth_state_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ export enum AuthStatus {
}

/**
* Get authentication state for a request. Returned by `auth` interceptor.
* Gets authentication state for a request. Returned by `auth` interceptor.
* @param request {@link KibanaRequest} - an incoming request.
* @public
*/
export type GetAuthState = (
export type GetAuthState = <T = unknown>(
request: KibanaRequest | LegacyRequest
) => { status: AuthStatus; state: unknown };
) => { status: AuthStatus; state: T };

/**
* Return authentication status for a request.
* Returns authentication status for a request.
* @param request {@link KibanaRequest} - an incoming request.
* @public
*/
Expand All @@ -60,9 +60,9 @@ export class AuthStateStorage {
public set = (request: KibanaRequest | LegacyRequest, state: unknown) => {
this.storage.set(ensureRawRequest(request), state);
};
public get: GetAuthState = request => {
public get = <T = unknown>(request: KibanaRequest | LegacyRequest) => {
const key = ensureRawRequest(request);
const state = this.storage.get(key);
const state = this.storage.get(key) as T;
const status: AuthStatus = this.storage.has(key)
? AuthStatus.authenticated
: this.canBeAuthenticated()
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/http/http_server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ describe('setup contract', () => {

const router = new Router('', logger, enhanceWithContext);
router.get({ path: '/', validate: false }, (context, req, res) =>
res.ok({ body: auth.get(req) })
res.ok({ body: auth.get<{ id: string }>(req) })
);
registerRouter(router);
await server.start();
Expand Down
6 changes: 3 additions & 3 deletions src/core/server/http/http_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
SessionStorageCookieOptions,
createCookieSessionStorageFactory,
} from './cookie_session_storage';
import { AuthStateStorage, GetAuthState, IsAuthenticated } from './auth_state_storage';
import { IsAuthenticated, AuthStateStorage, GetAuthState } from './auth_state_storage';
import { AuthHeadersStorage, GetAuthHeaders } from './auth_headers_storage';
import { BasePath } from './base_path_service';
import { HttpServiceSetup } from './types';
Expand All @@ -53,10 +53,10 @@ export interface HttpServerSetup {
registerOnPostAuth: HttpServiceSetup['registerOnPostAuth'];
registerOnPreResponse: HttpServiceSetup['registerOnPreResponse'];
isTlsEnabled: HttpServiceSetup['isTlsEnabled'];
getAuthHeaders: GetAuthHeaders;
auth: {
get: GetAuthState;
isAuthenticated: IsAuthenticated;
getAuthHeaders: GetAuthHeaders;
};
}

Expand Down Expand Up @@ -120,8 +120,8 @@ export class HttpServer {
auth: {
get: this.authState.get,
isAuthenticated: this.authState.isAuthenticated,
getAuthHeaders: this.authRequestHeaders.get,
},
getAuthHeaders: this.authRequestHeaders.get,
isTlsEnabled: config.ssl.enabled,
// Return server instance with the connection options so that we can properly
// bridge core and the "legacy" Kibana internally. Once this bridge isn't
Expand Down
21 changes: 16 additions & 5 deletions src/core/server/http/http_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import { mockRouter } from './router/router.mock';
import { configMock } from '../config/config.mock';
import { InternalHttpServiceSetup } from './types';
import { HttpService } from './http_service';
import { AuthStatus } from './auth_state_storage';
import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';
import { AuthToolkit } from './lifecycle/auth';
import { sessionStorageMock } from './cookie_session_storage.mocks';
import { OnPostAuthToolkit } from './lifecycle/on_post_auth';
import { OnPreResponseToolkit } from './lifecycle/on_pre_response';

type BasePathMocked = jest.Mocked<InternalHttpServiceSetup['basePath']>;
type AuthMocked = jest.Mocked<InternalHttpServiceSetup['auth']>;
export type HttpServiceSetupMock = jest.Mocked<InternalHttpServiceSetup> & {
basePath: BasePathMocked;
};
Expand All @@ -42,6 +44,16 @@ const createBasePathMock = (serverBasePath = '/mock-server-basepath'): BasePathM
remove: jest.fn(),
});

const createAuthMock = () => {
const mock: AuthMocked = {
get: jest.fn(),
isAuthenticated: jest.fn(),
};
mock.get.mockReturnValue({ status: AuthStatus.authenticated, state: {} });
mock.isAuthenticated.mockReturnValue(true);
return mock;
};

const createSetupContractMock = () => {
const setupContract: HttpServiceSetupMock = {
// we can mock other hapi server methods when we need it
Expand All @@ -62,17 +74,15 @@ const createSetupContractMock = () => {
createRouter: jest.fn().mockImplementation(() => mockRouter.create({})),
basePath: createBasePathMock(),
csp: CspConfig.DEFAULT,
auth: {
get: jest.fn(),
isAuthenticated: jest.fn(),
getAuthHeaders: jest.fn(),
},
auth: createAuthMock(),
getAuthHeaders: jest.fn(),
isTlsEnabled: false,
};
setupContract.createCookieSessionStorageFactory.mockResolvedValue(
sessionStorageMock.createFactory()
);
setupContract.createRouter.mockImplementation(() => mockRouter.create());
setupContract.getAuthHeaders.mockReturnValue({ authorization: 'authorization-header' });
return setupContract;
};

Expand Down Expand Up @@ -107,6 +117,7 @@ const createOnPreResponseToolkitMock = (): jest.Mocked<OnPreResponseToolkit> =>
export const httpServiceMock = {
create: createHttpServiceMock,
createBasePath: createBasePathMock,
createAuth: createAuthMock,
createSetupContract: createSetupContractMock,
createOnPreAuthToolkit: createOnPreAuthToolkitMock,
createOnPostAuthToolkit: createOnPostAuthToolkitMock,
Expand Down
16 changes: 16 additions & 0 deletions src/core/server/http/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
import { IContextProvider, IContextContainer } from '../context';
import { ICspConfig } from '../csp';
import { GetAuthState, IsAuthenticated } from './auth_state_storage';
import { GetAuthHeaders } from './auth_headers_storage';
import { RequestHandler, IRouter } from './router';
import { HttpServerSetup } from './http_server';
import { SessionStorageCookieOptions } from './cookie_session_storage';
Expand Down Expand Up @@ -183,6 +185,19 @@ export interface HttpServiceSetup {
*/
basePath: IBasePath;

auth: {
/**
* Gets authentication state for a request. Returned by `auth` interceptor.
* {@link GetAuthState}
*/
get: GetAuthState;
/**
* Returns authentication status for a request.
* {@link IsAuthenticated}
*/
isAuthenticated: IsAuthenticated;
};

/**
* The CSP config used for Kibana.
*/
Expand Down Expand Up @@ -245,6 +260,7 @@ export interface InternalHttpServiceSetup
auth: HttpServerSetup['auth'];
server: HttpServerSetup['server'];
createRouter: (path: string, plugin?: PluginOpaqueId) => IRouter;
getAuthHeaders: GetAuthHeaders;
registerRouteHandlerContext: <T extends keyof RequestHandlerContext>(
pluginOpaqueId: PluginOpaqueId,
contextName: T,
Expand Down
4 changes: 4 additions & 0 deletions src/core/server/legacy/legacy_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@ export class LegacyService implements CoreService {
registerOnPostAuth: setupDeps.core.http.registerOnPostAuth,
registerOnPreResponse: setupDeps.core.http.registerOnPreResponse,
basePath: setupDeps.core.http.basePath,
auth: {
get: setupDeps.core.http.auth.get,
isAuthenticated: setupDeps.core.http.auth.isAuthenticated,
},
csp: setupDeps.core.http.csp,
isTlsEnabled: setupDeps.core.http.isTlsEnabled,
},
Expand Down
4 changes: 4 additions & 0 deletions src/core/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ function createCoreSetupMock() {
isTlsEnabled: httpService.isTlsEnabled,
createRouter: jest.fn(),
registerRouteHandlerContext: jest.fn(),
auth: {
get: httpService.auth.get,
isAuthenticated: httpService.auth.isAuthenticated,
},
};
httpMock.createRouter.mockImplementation(() => httpService.createRouter(''));

Expand Down
Loading