diff --git a/node-client/src/config.ts b/node-client/src/config.ts index 3862407b33..7bb10a6caa 100644 --- a/node-client/src/config.ts +++ b/node-client/src/config.ts @@ -1,6 +1,7 @@ import fs = require('fs'); import os = require('os'); import path = require('path'); +import https = require('https'); import base64 = require('base-64'); import jsonpath = require('jsonpath'); @@ -80,7 +81,7 @@ export class KubeConfig { return this.getCluster(this.getCurrentContextObject()['cluster']); } - public getCluster(name: string) { + public getCluster(name: string): Cluster { return KubeConfig.findObject(this.clusters, name, 'cluster'); } @@ -88,7 +89,7 @@ export class KubeConfig { return this.getUser(this.getCurrentContextObject()['user']); } - public getUser(name: string) { + public getUser(name: string): User { return KubeConfig.findObject(this.users, name, 'user'); } @@ -106,22 +107,25 @@ export class KubeConfig { return null; } - public applyToRequest(opts: request.Options) { - let cluster = this.getCurrentCluster(); - let user = this.getCurrentUser(); + private applyHTTPSOptions(opts: request.Options | https.RequestOptions) { + const cluster = this.getCurrentCluster(); + const user = this.getCurrentUser(); - if (cluster.skipTLSVerify) { - opts.strictSSL = false - } opts.ca = this.bufferFromFileOrString(cluster.caFile, cluster.caData); opts.cert = this.bufferFromFileOrString(user.certFile, user.certData); opts.key = this.bufferFromFileOrString(user.keyFile, user.keyData); + } + + private applyAuthorizationHeader(opts: request.Options | https.RequestOptions) { + const user = this.getCurrentUser(); let token = null; + if (user.authProvider && user.authProvider.config) { - let config = user.authProvider.config; + const config = user.authProvider.config; // This should probably be extracted as auth-provider specific plugins... token = 'Bearer ' + config['access-token']; - let expiry = config['expiry']; + const expiry = config['expiry']; + if (expiry) { let expiration = Date.parse(expiry); if (expiration < Date.now()) { @@ -131,7 +135,7 @@ export class KubeConfig { cmd = cmd + ' ' + config['cmd-args']; } // TODO: Cache to file? - let result = shelljs.exec(cmd, { silent: true }); + const result = shelljs.exec(cmd, { silent: true }); if (result['code'] != 0) { throw new Error('Failed to refresh token: ' + result); } @@ -148,13 +152,43 @@ export class KubeConfig { } } } + } + if (user.token) { token = 'Bearer ' + user.token; } + if (token) { opts.headers['Authorization'] = token; } + } + + private applyOptions(opts: request.Options | https.RequestOptions) { + this.applyHTTPSOptions(opts); + this.applyAuthorizationHeader(opts); + } + + public applytoHTTPSOptions(opts: https.RequestOptions) { + const user = this.getCurrentUser(); + + this.applyOptions(opts); + + if (user.username) { + opts.auth = `${user.username}:${user.password}`; + } + } + + public applyToRequest(opts: request.Options) { + const cluster = this.getCurrentCluster(); + const user = this.getCurrentUser(); + + this.applyOptions(opts); + + if (cluster.skipTLSVerify) { + opts.strictSSL = false + } + if (user.username) { opts.auth = { username: user.username, diff --git a/node-client/src/config_test.ts b/node-client/src/config_test.ts index f5e7bae776..08da7f5405 100644 --- a/node-client/src/config_test.ts +++ b/node-client/src/config_test.ts @@ -1,7 +1,11 @@ -import { KubeConfig, Config } from './config'; -import { expect } from 'chai'; import 'mocha'; +import { expect } from 'chai'; +import * as https from 'https'; +import * as base64 from 'base-64'; + +import { KubeConfig, Config } from './config'; + const kcFileName = "testdata/kubeconfig.yaml"; describe("Config", () => { @@ -51,10 +55,10 @@ describe("KubeConfig", () => { let cluster1 = kc.clusters[0]; let cluster2 = kc.clusters[1]; expect(cluster1.name).to.equal("cluster1"); - expect(cluster1.caData).to.equal("CADATA"); + expect(cluster1.caData).to.equal("Q0FEQVRB"); expect(cluster1.server).to.equal("http://example.com"); expect(cluster2.name).to.equal("cluster2"); - expect(cluster2.caData).to.equal("CADATA2"); + expect(cluster2.caData).to.equal("Q0FEQVRBMg=="); expect(cluster2.server).to.equal("http://example2.com"); // check users @@ -62,11 +66,11 @@ describe("KubeConfig", () => { let user1 = kc.users[0]; let user2 = kc.users[1]; expect(user1.name).to.equal("user1"); - expect(user1.certData).to.equal("USER_CADATA"); - expect(user1.keyData).to.equal("USER_CKDATA"); + expect(user1.certData).to.equal("VVNFUl9DQURBVEE="); + expect(user1.keyData).to.equal("VVNFUl9DS0RBVEE="); expect(user2.name).to.equal("user2"); - expect(user2.certData).to.equal("USER2_CADATA"); - expect(user2.keyData).to.equal("USER2_CKDATA"); + expect(user2.certData).to.equal("VVNFUjJfQ0FEQVRB"); + expect(user2.keyData).to.equal("VVNFUjJfQ0tEQVRB"); // check contexts expect(kc.contexts.length).to.equal(2); @@ -87,4 +91,20 @@ describe("KubeConfig", () => { // expect(kc.loadFromFile("missing.yaml")).to.throw(); }); }); + + describe("applyHTTPSOptions", () => { + it("should apply cert configs", () => { + const kc = new KubeConfig(); + kc.loadFromFile(kcFileName); + + const opts: https.RequestOptions = {}; + kc.applytoHTTPSOptions(opts); + + expect(opts).to.deep.equal({ + ca: new Buffer('CADATA2', 'utf-8'), + cert: new Buffer('USER2_CADATA', 'utf-8'), + key: new Buffer('USER2_CKDATA', 'utf-8'), + }); + }); + }); }); diff --git a/node-client/src/config_types.ts b/node-client/src/config_types.ts index e5beef24ac..847f8f169e 100644 --- a/node-client/src/config_types.ts +++ b/node-client/src/config_types.ts @@ -37,7 +37,7 @@ export interface User { readonly certFile: string readonly keyData: string readonly keyFile: string - readonly authProvider: Object + readonly authProvider: any readonly token: string readonly username: string readonly password: string diff --git a/node-client/src/web-socket-handler.ts b/node-client/src/web-socket-handler.ts index 896fd561cd..b94f4a5934 100644 --- a/node-client/src/web-socket-handler.ts +++ b/node-client/src/web-socket-handler.ts @@ -1,4 +1,5 @@ import stream = require('stream'); +import https = require('https'); import ws = require('websocket'); import { KubeConfig } from './config'; @@ -32,7 +33,10 @@ export class WebSocketHandler { const target = server.startsWith('https://') ? server.substr(8) : server.substr(7); const uri = `wss://${target}${path}`; - const client = new ws.client(); + const opts : https.RequestOptions = {}; + this.config.applytoHTTPsOptions(opts) + + const client = new ws.client({ tlsOptions: opts } ); return new Promise((resolve, reject) => { client.on('connect', (connection) => { diff --git a/node-client/testdata/kubeconfig.yaml b/node-client/testdata/kubeconfig.yaml index da4e03e348..d2a901a89f 100644 --- a/node-client/testdata/kubeconfig.yaml +++ b/node-client/testdata/kubeconfig.yaml @@ -1,18 +1,18 @@ apiVersion: v1 clusters: - cluster: - certificate-authority-data: CADATA + certificate-authority-data: Q0FEQVRB server: http://example.com name: cluster1 - cluster: - certificate-authority-data: CADATA2 + certificate-authority-data: Q0FEQVRBMg== server: http://example2.com name: cluster2 contexts: - context: cluster: cluster1 - user: user1 + user: user1 name: context1 - context: cluster: cluster2 @@ -23,11 +23,11 @@ current-context: context2 kind: Config preferences: {} users: -- name: user1 +- name: user1 user: - client-certificate-data: USER_CADATA - client-key-data: USER_CKDATA + client-certificate-data: VVNFUl9DQURBVEE= + client-key-data: VVNFUl9DS0RBVEE= - name: user2 user: - client-certificate-data: USER2_CADATA - client-key-data: USER2_CKDATA + client-certificate-data: VVNFUjJfQ0FEQVRB + client-key-data: VVNFUjJfQ0tEQVRB \ No newline at end of file