-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathKerberosTcpAuthentication.ts
113 lines (93 loc) · 4.02 KB
/
KerberosTcpAuthentication.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
import IAuthentication from "../contracts/IAuthentication";
import ITransport from "../contracts/ITransport";
import { AuthOptions } from '../types/AuthOptions';
import { SaslPackageFactory, StatusCode } from "./helpers/SaslPackageFactory";
import { IKerberosAuthProcess } from "../contracts/IKerberosAuthProcess";
import { IKerberosClient } from "../contracts/IKerberosClient";
import AuthenticationError from "../../errors/AuthenticationError";
export default class KerberosTcpAuthentication implements IAuthentication {
static AUTH_MECH = 'GSSAPI';
private username: string;
private password: string;
private authProcess: IKerberosAuthProcess;
constructor(options: AuthOptions, authProcess: IKerberosAuthProcess) {
this.username = options?.username || 'anonymous';
this.password = options?.password !== undefined ? options.password : 'anonymous';
this.authProcess = authProcess;
}
authenticate(transport: ITransport): Promise<ITransport> {
return new Promise((resolve, reject) => {
this.authProcess.init(
{
password: this.password,
username: this.username,
},
(error: Error, client: IKerberosClient) => {
if (error) {
return reject(error);
}
const onError = (err: Error) => {
transport.end();
reject(err);
};
const onSuccess = () => {
transport.removeListener('connect', onConnect);
transport.removeListener('data', onData);
resolve(transport);
};
const onConnect = () => {
this.onConnect(transport).catch(onError);
};
const onData = (data: Buffer) => {
const status = data[0];
if (status === StatusCode.OK) {
this.nextTransition(transport, data).catch(onError);
} else if (status === StatusCode.COMPLETE) {
onSuccess();
} else {
const message = data.slice(5).toString();
onError(new AuthenticationError('Authentication error: ' + message));
}
};
transport.connect();
transport.addListener('connect', onConnect);
transport.addListener('data', onData);
transport.addListener('error', onError);
}
);
});
}
private onConnect(transport: ITransport): Promise<void> {
return new Promise((resolve, reject) => {
transport.write(SaslPackageFactory.create(
StatusCode.START,
Buffer.from(KerberosTcpAuthentication.AUTH_MECH)
));
this.authProcess.transition('', (err: Error, token: string) => {
if (err) {
return reject(err);
}
transport.write(SaslPackageFactory.create(
StatusCode.OK,
Buffer.from(token || '', 'base64')
));
resolve();
});
});
}
private nextTransition(transport: ITransport, data: Buffer): Promise<void> {
return new Promise((resolve, reject) => {
const payload = data.slice(5).toString('base64');
this.authProcess.transition(payload, (err: Error, response: string) => {
if (err) {
return reject(err);
}
transport.write(SaslPackageFactory.create(
StatusCode.OK,
Buffer.from(response || '', 'base64')
));
resolve();
});
});
}
}