Improve authentication handling (#908)
This commit is contained in:
committed by
GitHub
parent
24e674469e
commit
0ebbd71e9a
2
lib/Connection.d.ts
vendored
2
lib/Connection.d.ts
vendored
@ -21,6 +21,7 @@
|
||||
|
||||
import { URL } from 'url';
|
||||
import { inspect, InspectOptions } from 'util';
|
||||
import { ApiKeyAuth, BasicAuth } from './ConnectionPool'
|
||||
import * as http from 'http';
|
||||
import { ConnectionOptions as TlsConnectionOptions } from 'tls';
|
||||
|
||||
@ -34,6 +35,7 @@ interface ConnectionOptions {
|
||||
agent?: AgentOptions | agentFn;
|
||||
status?: string;
|
||||
roles?: any;
|
||||
auth?: BasicAuth | ApiKeyAuth;
|
||||
}
|
||||
|
||||
interface RequestOptions extends http.ClientRequestArgs {
|
||||
|
||||
@ -34,8 +34,7 @@ class Connection {
|
||||
this.url = opts.url
|
||||
this.ssl = opts.ssl || null
|
||||
this.id = opts.id || stripAuth(opts.url.href)
|
||||
this.headers = opts.headers || null
|
||||
this.auth = opts.auth || { username: null, password: null }
|
||||
this.headers = prepareHeaders(opts.headers, opts.auth)
|
||||
this.deadCount = 0
|
||||
this.resurrectTimeout = 0
|
||||
|
||||
@ -181,7 +180,6 @@ class Connection {
|
||||
|
||||
buildRequestObject (params) {
|
||||
const url = this.url
|
||||
const { username, password } = this.auth
|
||||
const request = {
|
||||
protocol: url.protocol,
|
||||
hostname: url.hostname[0] === '['
|
||||
@ -196,9 +194,6 @@ class Connection {
|
||||
// https://github.com/elastic/elasticsearch-js/issues/843
|
||||
port: url.port !== '' ? url.port : undefined,
|
||||
headers: this.headers,
|
||||
auth: username != null && password != null
|
||||
? `${username}:${password}`
|
||||
: undefined,
|
||||
agent: this.agent
|
||||
}
|
||||
|
||||
@ -230,10 +225,15 @@ class Connection {
|
||||
// the logs very hard to read. The user can still
|
||||
// access them with `instance.agent` and `instance.ssl`.
|
||||
[inspect.custom] (depth, options) {
|
||||
const {
|
||||
authorization,
|
||||
...headers
|
||||
} = this.headers
|
||||
|
||||
return {
|
||||
url: stripAuth(this.url.toString()),
|
||||
id: this.id,
|
||||
headers: this.headers,
|
||||
headers,
|
||||
deadCount: this.deadCount,
|
||||
resurrectTimeout: this.resurrectTimeout,
|
||||
_openRequests: this._openRequests,
|
||||
@ -243,10 +243,15 @@ class Connection {
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
const {
|
||||
authorization,
|
||||
...headers
|
||||
} = this.headers
|
||||
|
||||
return {
|
||||
url: stripAuth(this.url.toString()),
|
||||
id: this.id,
|
||||
headers: this.headers,
|
||||
headers,
|
||||
deadCount: this.deadCount,
|
||||
resurrectTimeout: this.resurrectTimeout,
|
||||
_openRequests: this._openRequests,
|
||||
@ -302,4 +307,21 @@ function resolve (host, path) {
|
||||
}
|
||||
}
|
||||
|
||||
function prepareHeaders (headers = {}, auth) {
|
||||
if (auth != null && headers.authorization == null) {
|
||||
if (auth.username && auth.password) {
|
||||
headers.authorization = 'Basic ' + Buffer.from(`${auth.username}:${auth.password}`).toString('base64')
|
||||
}
|
||||
|
||||
if (auth.apiKey) {
|
||||
if (typeof auth.apiKey === 'object') {
|
||||
headers.authorization = 'ApiKey ' + Buffer.from(`${auth.apiKey.id}:${auth.apiKey.api_key}`).toString('base64')
|
||||
} else {
|
||||
headers.authorization = `ApiKey ${auth.apiKey}`
|
||||
}
|
||||
}
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
module.exports = Connection
|
||||
|
||||
16
lib/ConnectionPool.d.ts
vendored
16
lib/ConnectionPool.d.ts
vendored
@ -26,6 +26,7 @@ import { nodeFilterFn, nodeSelectorFn } from './Transport';
|
||||
interface ConnectionPoolOptions {
|
||||
ssl?: SecureContextOptions;
|
||||
agent?: AgentOptions;
|
||||
auth: BasicAuth | ApiKeyAuth;
|
||||
pingTimeout?: number;
|
||||
Connection: typeof Connection;
|
||||
resurrectStrategy?: string;
|
||||
@ -36,6 +37,20 @@ export interface getConnectionOptions {
|
||||
selector?: nodeSelectorFn;
|
||||
}
|
||||
|
||||
export interface ApiKeyAuth {
|
||||
apiKey:
|
||||
| string
|
||||
| {
|
||||
id: string;
|
||||
api_key: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface BasicAuth {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface resurrectOptions {
|
||||
now?: number;
|
||||
requestId: string;
|
||||
@ -66,6 +81,7 @@ export default class ConnectionPool {
|
||||
resurrectTimeout: number;
|
||||
resurrectTimeoutCutoff: number;
|
||||
pingTimeout: number;
|
||||
auth: BasicAuth | ApiKeyAuth;
|
||||
Connection: typeof Connection;
|
||||
resurrectStrategy: number;
|
||||
constructor(opts?: ConnectionPoolOptions);
|
||||
|
||||
@ -30,7 +30,7 @@ class ConnectionPool {
|
||||
this.connections = new Map()
|
||||
this.dead = []
|
||||
this.selector = opts.selector
|
||||
this._auth = null
|
||||
this.auth = opts.auth || null
|
||||
this._ssl = opts.ssl
|
||||
this._agent = opts.agent
|
||||
// the resurrect timeout is 60s
|
||||
@ -217,23 +217,14 @@ class ConnectionPool {
|
||||
if (typeof opts === 'string') {
|
||||
opts = this.urlToHost(opts)
|
||||
}
|
||||
// if a given node has auth data we store it in the connection pool,
|
||||
// so if we add new nodes without auth data (after a sniff for example)
|
||||
// we can add it to them once the connection instance has been created
|
||||
|
||||
if (opts.url.username !== '' && opts.url.password !== '') {
|
||||
this._auth = {
|
||||
opts.auth = {
|
||||
username: decodeURIComponent(opts.url.username),
|
||||
password: decodeURIComponent(opts.url.password)
|
||||
}
|
||||
opts.auth = this._auth
|
||||
}
|
||||
|
||||
if (this._auth != null) {
|
||||
if (opts.auth == null || (opts.auth.username == null && opts.auth.password == null)) {
|
||||
opts.auth = this._auth
|
||||
opts.url.username = this._auth.username
|
||||
opts.url.password = this._auth.password
|
||||
}
|
||||
} else if (this.auth !== null) {
|
||||
opts.auth = this.auth
|
||||
}
|
||||
|
||||
if (opts.ssl == null) opts.ssl = this._ssl
|
||||
|
||||
Reference in New Issue
Block a user