Skip to content

Commit

Permalink
introduce pre-/post-auth request hooks for HttpServer (#36690)
Browse files Browse the repository at this point in the history
* introduce pre-,post-auth stages

* cleanup integration_tests. now contracts available in tests

* auth per route is configurable

* Unify lifecycle results structure

* expose api to store auth state and status via http service

* update tests

* update docs

* use full name, auth should not mutate request

* move basePath functionality under namespace

* regenerate docs

* Revert "move basePath functionality under namespace"

This reverts commit 9599d32.

* Revert "regenerate docs"

This reverts commit 1799d3b.

* regenerate docs

* updated yarn.lock no idea why

* extract AuthStateStorage to a separate entity

* get rid of nested ifs

* describe what is the difference between hooks

* re-wording
  • Loading branch information
mshustov authored May 29, 2019
1 parent 575cdbe commit b0c0165
Show file tree
Hide file tree
Showing 40 changed files with 1,001 additions and 337 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
<b>Signature:</b>

```typescript
export declare type AuthenticationHandler<T> = (request: Request, sessionStorage: SessionStorage<T>, t: AuthToolkit) => Promise<AuthResult>;
export declare type AuthenticationHandler<T> = (request: Readonly<Request>, sessionStorage: SessionStorage<T>, t: AuthToolkit) => AuthResult | Promise<AuthResult>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ Authentication is successful with given credentials, allow request to pass throu
<b>Signature:</b>

```typescript
authenticated: (credentials: any) => AuthResult;
authenticated: (state: object) => AuthResult;
```
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface AuthToolkit

| Property | Type | Description |
| --- | --- | --- |
| [authenticated](./kibana-plugin-server.authtoolkit.authenticated.md) | <code>(credentials: any) =&gt; AuthResult</code> | Authentication is successful with given credentials, allow request to pass through |
| [authenticated](./kibana-plugin-server.authtoolkit.authenticated.md) | <code>(state: object) =&gt; AuthResult</code> | Authentication is successful with given credentials, allow request to pass through |
| [redirected](./kibana-plugin-server.authtoolkit.redirected.md) | <code>(url: string) =&gt; AuthResult</code> | Authentication requires to interrupt request handling and redirect to a configured url |
| [rejected](./kibana-plugin-server.authtoolkit.rejected.md) | <code>(error: Error, options?: {`<p/>` statusCode?: number;`<p/>` }) =&gt; AuthResult</code> | Authentication is unsuccessful, fail the request with specified error. |

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

```typescript
http: {
registerOnPreAuth: HttpServiceSetup['registerOnPreAuth'];
registerAuth: HttpServiceSetup['registerAuth'];
registerOnRequest: HttpServiceSetup['registerOnRequest'];
registerOnPostAuth: HttpServiceSetup['registerOnPostAuth'];
getBasePathFor: HttpServiceSetup['getBasePathFor'];
setBasePathFor: HttpServiceSetup['setBasePathFor'];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ export interface CoreSetup
| Property | Type | Description |
| --- | --- | --- |
| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | <code>{`<p/>` adminClient$: Observable&lt;ClusterClient&gt;;`<p/>` dataClient$: Observable&lt;ClusterClient&gt;;`<p/>` }</code> | |
| [http](./kibana-plugin-server.coresetup.http.md) | <code>{`<p/>` registerAuth: HttpServiceSetup['registerAuth'];`<p/>` registerOnRequest: HttpServiceSetup['registerOnRequest'];`<p/>` getBasePathFor: HttpServiceSetup['getBasePathFor'];`<p/>` setBasePathFor: HttpServiceSetup['setBasePathFor'];`<p/>` }</code> | |
| [http](./kibana-plugin-server.coresetup.http.md) | <code>{`<p/>` registerOnPreAuth: HttpServiceSetup['registerOnPreAuth'];`<p/>` registerAuth: HttpServiceSetup['registerAuth'];`<p/>` registerOnPostAuth: HttpServiceSetup['registerOnPostAuth'];`<p/>` getBasePathFor: HttpServiceSetup['getBasePathFor'];`<p/>` setBasePathFor: HttpServiceSetup['setBasePathFor'];`<p/>` }</code> | |
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export declare class KibanaRequest<Params = unknown, Query = unknown, Body = unk
| [params](./kibana-plugin-server.kibanarequest.params.md) | | <code>Params</code> | |
| [path](./kibana-plugin-server.kibanarequest.path.md) | | <code>string</code> | |
| [query](./kibana-plugin-server.kibanarequest.query.md) | | <code>Query</code> | |
| [url](./kibana-plugin-server.kibanarequest.url.md) | | <code>Url</code> | |

## Methods

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [KibanaRequest](./kibana-plugin-server.kibanarequest.md) &gt; [url](./kibana-plugin-server.kibanarequest.url.md)

## KibanaRequest.url property

<b>Signature:</b>

```typescript
readonly url: Url;
```
6 changes: 4 additions & 2 deletions docs/development/core/server/kibana-plugin-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [Logger](./kibana-plugin-server.logger.md) | Logger exposes all the necessary methods to log any type of information and this is the interface used by the logging consumers including plugins. |
| [LoggerFactory](./kibana-plugin-server.loggerfactory.md) | The single purpose of <code>LoggerFactory</code> interface is to define a way to retrieve a context-based logger instance. |
| [LogMeta](./kibana-plugin-server.logmeta.md) | Contextual metadata |
| [OnRequestToolkit](./kibana-plugin-server.onrequesttoolkit.md) | A tool set defining an outcome of OnRequest interceptor for incoming request. |
| [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md) | A tool set defining an outcome of OnPostAuth interceptor for incoming request. |
| [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. |
| [Plugin](./kibana-plugin-server.plugin.md) | The interface that should be returned by a <code>PluginInitializer</code>. |
| [PluginInitializerContext](./kibana-plugin-server.plugininitializercontext.md) | Context that's available to plugins during initialization stage. |
| [PluginsServiceSetup](./kibana-plugin-server.pluginsservicesetup.md) | |
Expand All @@ -49,7 +50,8 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [ElasticsearchClientConfig](./kibana-plugin-server.elasticsearchclientconfig.md) | |
| [Headers](./kibana-plugin-server.headers.md) | |
| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) | |
| [OnRequestHandler](./kibana-plugin-server.onrequesthandler.md) | |
| [OnPostAuthHandler](./kibana-plugin-server.onpostauthhandler.md) | |
| [OnPreAuthHandler](./kibana-plugin-server.onpreauthhandler.md) | |
| [PluginInitializer](./kibana-plugin-server.plugininitializer.md) | The <code>plugin</code> export at the root of a plugin's <code>server</code> directory should conform to this interface. |
| [PluginName](./kibana-plugin-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

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

## OnPostAuthHandler type


<b>Signature:</b>

```typescript
export declare type OnPostAuthHandler<Params = any, Query = any, Body = any> = (request: KibanaRequest<Params, Query, Body>, t: OnPostAuthToolkit) => OnPostAuthResult | Promise<OnPostAuthResult>;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

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

## OnPostAuthToolkit interface

A tool set defining an outcome of OnPostAuth interceptor for incoming request.

<b>Signature:</b>

```typescript
export interface OnPostAuthToolkit
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [next](./kibana-plugin-server.onpostauthtoolkit.next.md) | <code>() =&gt; OnPostAuthResult</code> | To pass request to the next handler |
| [redirected](./kibana-plugin-server.onpostauthtoolkit.redirected.md) | <code>(url: string) =&gt; OnPostAuthResult</code> | To interrupt request handling and redirect to a configured url |
| [rejected](./kibana-plugin-server.onpostauthtoolkit.rejected.md) | <code>(error: Error, options?: {`<p/>` statusCode?: number;`<p/>` }) =&gt; OnPostAuthResult</code> | Fail the request with specified error. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md) &gt; [next](./kibana-plugin-server.onpostauthtoolkit.next.md)

## OnPostAuthToolkit.next property

To pass request to the next handler

<b>Signature:</b>

```typescript
next: () => OnPostAuthResult;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md) &gt; [redirected](./kibana-plugin-server.onpostauthtoolkit.redirected.md)

## OnPostAuthToolkit.redirected property

To interrupt request handling and redirect to a configured url

<b>Signature:</b>

```typescript
redirected: (url: string) => OnPostAuthResult;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md) &gt; [rejected](./kibana-plugin-server.onpostauthtoolkit.rejected.md)

## OnPostAuthToolkit.rejected property

Fail the request with specified error.

<b>Signature:</b>

```typescript
rejected: (error: Error, options?: {
statusCode?: number;
}) => OnPostAuthResult;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

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

## OnPreAuthHandler type


<b>Signature:</b>

```typescript
export declare type OnPreAuthHandler<Params = any, Query = any, Body = any> = (request: KibanaRequest<Params, Query, Body>, t: OnPreAuthToolkit) => OnPreAuthResult | Promise<OnPreAuthResult>;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

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

## OnPreAuthToolkit interface

A tool set defining an outcome of OnPreAuth interceptor for incoming request.

<b>Signature:</b>

```typescript
export interface OnPreAuthToolkit
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [next](./kibana-plugin-server.onpreauthtoolkit.next.md) | <code>() =&gt; OnPreAuthResult</code> | To pass request to the next handler |
| [redirected](./kibana-plugin-server.onpreauthtoolkit.redirected.md) | <code>(url: string, options?: {`<p/>` forward: boolean;`<p/>` }) =&gt; OnPreAuthResult</code> | To interrupt request handling and redirect to a configured url. If "options.forwarded" = true, request will be forwarded to another url right on the server. |
| [rejected](./kibana-plugin-server.onpreauthtoolkit.rejected.md) | <code>(error: Error, options?: {`<p/>` statusCode?: number;`<p/>` }) =&gt; OnPreAuthResult</code> | Fail the request with specified error. |

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnRequestToolkit](./kibana-plugin-server.onrequesttoolkit.md) &gt; [next](./kibana-plugin-server.onrequesttoolkit.next.md)
[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md) &gt; [next](./kibana-plugin-server.onpreauthtoolkit.next.md)

## OnRequestToolkit.next property
## OnPreAuthToolkit.next property

To pass request to the next handler

<b>Signature:</b>

```typescript
next: () => OnRequestResult;
next: () => OnPreAuthResult;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md) &gt; [redirected](./kibana-plugin-server.onpreauthtoolkit.redirected.md)

## OnPreAuthToolkit.redirected property

To interrupt request handling and redirect to a configured url. If "options.forwarded" = true, request will be forwarded to another url right on the server.

<b>Signature:</b>

```typescript
redirected: (url: string, options?: {
forward: boolean;
}) => OnPreAuthResult;
```
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnRequestToolkit](./kibana-plugin-server.onrequesttoolkit.md) &gt; [rejected](./kibana-plugin-server.onrequesttoolkit.rejected.md)
[Home](./index) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md) &gt; [rejected](./kibana-plugin-server.onpreauthtoolkit.rejected.md)

## OnRequestToolkit.rejected property
## OnPreAuthToolkit.rejected property

Fail the request with specified error.

Expand All @@ -11,5 +11,5 @@ Fail the request with specified error.
```typescript
rejected: (error: Error, options?: {
statusCode?: number;
}) => OnRequestResult;
}) => OnPreAuthResult;
```

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

51 changes: 51 additions & 0 deletions src/core/server/http/auth_state_storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Request } from 'hapi';
import { KibanaRequest } from './router';

export enum AuthStatus {
authenticated = 'authenticated',
unauthenticated = 'unauthenticated',
unknown = 'unknown',
}

const toKey = (request: KibanaRequest | Request) =>
request instanceof KibanaRequest ? request.unstable_getIncomingMessage() : request.raw.req;

export class AuthStateStorage {
private readonly storage = new WeakMap<ReturnType<typeof toKey>, unknown>();
constructor(private readonly canBeAuthenticated: () => boolean) {}
public set = (request: KibanaRequest | Request, state: unknown) => {
this.storage.set(toKey(request), state);
};
public get = (request: KibanaRequest | Request) => {
const key = toKey(request);
const state = this.storage.get(key);
const status: AuthStatus = this.storage.has(key)
? AuthStatus.authenticated
: this.canBeAuthenticated()
? AuthStatus.unauthenticated
: AuthStatus.unknown;

return { status, state };
};
public isAuthenticated = (request: KibanaRequest | Request) => {
return this.get(request).status === AuthStatus.authenticated;
};
}
Loading

0 comments on commit b0c0165

Please sign in to comment.