-
Notifications
You must be signed in to change notification settings - Fork 543
/
Copy pathexec_auth.ts
114 lines (106 loc) · 3.45 KB
/
exec_auth.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import child_process = require('child_process');
import https = require('https');
import request = require('request');
import { Authenticator } from './auth';
import { User } from './config_types';
export interface CredentialStatus {
readonly token: string;
readonly clientCertificateData: string;
readonly clientKeyData: string;
readonly expirationTimestamp: string;
}
export interface Credential {
readonly status: CredentialStatus;
}
export class ExecAuth implements Authenticator {
private readonly tokenCache: { [key: string]: Credential | null } = {};
private execFn: (
cmd: string,
args: string[],
opts: child_process.SpawnOptions,
) => child_process.SpawnSyncReturns<Buffer> = child_process.spawnSync;
public isAuthProvider(user: User): boolean {
if (!user) {
return false;
}
if (user.exec) {
return true;
}
if (!user.authProvider) {
return false;
}
return (
user.authProvider.name === 'exec' || !!(user.authProvider.config && user.authProvider.config.exec)
);
}
public async applyAuthentication(
user: User,
opts: request.Options | https.RequestOptions,
): Promise<void> {
const credential = this.getCredential(user);
if (!credential) {
return;
}
if (credential.status.clientCertificateData) {
opts.cert = credential.status.clientCertificateData;
}
if (credential.status.clientKeyData) {
opts.key = credential.status.clientKeyData;
}
const token = this.getToken(credential);
if (token) {
if (!opts.headers) {
opts.headers = [];
}
opts.headers!.Authorization = `Bearer ${token}`;
}
}
private getToken(credential: Credential): string | null {
if (!credential) {
return null;
}
if (credential.status.token) {
return credential.status.token;
}
return null;
}
private getCredential(user: User): Credential | null {
// TODO: Add a unit test for token caching.
const cachedToken = this.tokenCache[user.name];
if (cachedToken) {
const date = Date.parse(cachedToken.status.expirationTimestamp);
if (date > Date.now()) {
return cachedToken;
}
this.tokenCache[user.name] = null;
}
let exec: any = null;
if (user.authProvider && user.authProvider.config) {
exec = user.authProvider.config.exec;
}
if (user.exec) {
exec = user.exec;
}
if (!exec) {
return null;
}
if (!exec.command) {
throw new Error('No command was specified for exec authProvider!');
}
let opts = {};
if (exec.env) {
const env = {
...process.env,
};
exec.env.forEach((elt: { name: string | number; value?: string }) => (env[elt.name] = elt.value));
opts = { ...opts, env };
}
const result = this.execFn(exec.command, exec.args, opts);
if (result.status === 0) {
const obj = JSON.parse(result.stdout.toString('utf8')) as Credential;
this.tokenCache[user.name] = obj;
return obj;
}
throw new Error(result.stderr.toString('utf8'));
}
}