Browse Source

chore: get everything up 2 date

master
simon 2 years ago
parent
commit
842b93634e
  1. 11
      __tests__/auth/google-ldap.test.ts
  2. 2
      __tests__/auth/imap.test.ts
  3. 11
      __tests__/auth/ldap.test.ts
  4. 2
      __tests__/auth/smtp.test.ts
  5. 12
      config.js
  6. 2642
      package-lock.json
  7. 28
      package.json
  8. 4
      src/app.ts
  9. 3
      src/auth.ts
  10. 18
      src/auth/GoogleLDAPAuth.ts
  11. 6
      src/auth/IMAPAuth.ts
  12. 8
      src/auth/LDAPAuth.ts
  13. 4
      src/auth/SMTPAuth.ts
  14. 2
      src/auth/StaticAuth.ts
  15. 4
      src/helpers.ts
  16. 2
      src/radius/PacketHandler.ts
  17. 4
      src/radius/RadiusService.ts
  18. 8
      src/radius/handler/EAPPacketHandler.ts
  19. 6
      src/radius/handler/UserPasswordPacketHandler.ts
  20. 6
      src/radius/handler/eap/EAPHelper.ts
  21. 4
      src/radius/handler/eap/eapMethods/EAP-GTC.ts
  22. 38
      src/radius/handler/eap/eapMethods/EAP-TTLS.ts
  23. 8
      src/tls/crypt.ts
  24. 2
      src/types/PacketHandler.ts

11
__tests__/auth/google-ldap.test.ts

@ -1,17 +1,16 @@
import 'mocha';
import { expect } from 'chai';
import * as fs from 'fs';
import { GoogleLDAPAuth } from '../../src/auth/GoogleLDAPAuth';
describe('test google ldap auth', function() {
describe('test google ldap auth', function () {
this.timeout(10000);
it('authenticate against ldap server', async () => {
const auth = new GoogleLDAPAuth({
base: 'dc=hokify,dc=com',
tlsOptions: {
key: fs.readFileSync('./ldap.gsuite.key'),
cert: fs.readFileSync('./ldap.gsuite.crt')
}
tls: {
keyFile: './ldap.gsuite.key',
certFile: './ldap.gsuite.crt',
},
});
const result = await auth.authenticate('username', 'password');

2
__tests__/auth/imap.test.ts

@ -8,7 +8,7 @@ describe('test imap auth', () => {
host: 'imap.gmail.com',
port: 993,
useSecureTransport: true,
validHosts: ['gmail.com']
validHosts: ['gmail.com'],
});
const result = await auth.authenticate('username', 'password');

11
__tests__/auth/ldap.test.ts

@ -1,19 +1,20 @@
import 'mocha';
import { expect } from 'chai';
import * as fs from 'fs';
import { LDAPAuth } from '../../src/auth/LDAPAuth';
describe('test ldap auth', function() {
describe('test ldap auth', function () {
this.timeout(10000);
it('authenticate against ldap server', async () => {
const auth = new LDAPAuth({
url: 'ldaps://ldap.google.com:636',
base: 'dc=hokify,dc=com',
tls: {
keyFile: './ldap.gsuite.key',
certFile: './ldap.gsuite.crt',
},
tlsOptions: {
servername: 'ldap.google.com',
key: fs.readFileSync('./ldap.gsuite.key'),
cert: fs.readFileSync('./ldap.gsuite.crt')
}
},
});
const result = await auth.authenticate('username', 'password');

2
__tests__/auth/smtp.test.ts

@ -8,7 +8,7 @@ describe('test smtp auth', () => {
host: 'smtp.gmail.com',
port: 465,
useSecureTransport: true,
validHosts: ['gmail.com']
validHosts: ['gmail.com'],
});
const result = await auth.authenticate('username', 'password');

12
config.js

@ -14,9 +14,9 @@ module.exports = {
key: [
{
pem: fs.readFileSync(path.join(SSL_CERT_DIRECTORY, '/server.key')),
passphrase: 'whatever2020'
}
]
passphrase: 'whatever2020',
},
],
},
// GoogleLDAPAuth (optimized for google auth)
@ -26,9 +26,9 @@ module.exports = {
// get your keys from http://admin.google.com/ -> Apps -> LDAP -> Client
tls: {
keyFile: 'ldap.gsuite.key',
certFile: 'ldap.gsuite.crt'
}
}
certFile: 'ldap.gsuite.crt',
},
},
/** LDAP AUTH
authentication: 'LDAPAuth',

2642
package-lock.json

File diff suppressed because it is too large

28
package.json

@ -30,30 +30,30 @@
"preferGlobal": true,
"main": "dist/app.js",
"dependencies": {
"@hokify/node-ts-cache": "^4.0.1",
"@hokify/node-ts-cache": "^5.1.4",
"debug": "^4.1.1",
"imap-simple": "^4.3.0",
"ldapauth-fork": "^4.3.2",
"imap-simple": "^5.0.0",
"ldapauth-fork": "^4.3.3",
"ldapjs": "^1.0.2",
"native-duplexpair": "^1.0.0",
"node-cache": "^5.1.0",
"radius": "~1.1.4",
"smtp-client": "^0.3.1",
"yargs": "~15.1.0"
"yargs": "~15.3.1"
},
"license": "GPLv3",
"devDependencies": {
"ts-node": "^8.6.2",
"standard-version": "^7.1.0",
"@hokify/eslint-config": "^0.2.7",
"@types/chai": "^4.2.9",
"@types/ldapjs": "^1.0.5",
"@types/mocha": "^7.0.1",
"ts-node": "^8.10.1",
"standard-version": "^8.0.0",
"@hokify/eslint-config": "^0.4.11",
"@types/chai": "^4.2.11",
"@types/ldapjs": "^1.0.7",
"@types/mocha": "^7.0.2",
"@types/radius": "0.0.28",
"chai": "^4.2.0",
"eslint": "^6.8.0",
"mocha": "^7.1.0",
"prettier": "^1.19.1",
"typescript": "^3.8.3"
"eslint": "^7.0.0",
"mocha": "^7.1.2",
"prettier": "^2.0.5",
"typescript": "^3.9.2"
}
}

4
src/app.ts

@ -12,7 +12,7 @@ const testSocket = startTLSServer();
if (typeof (testSocket.tls as any).exportKeyingMaterial !== 'function') {
console.error(`UNSUPPORTED NODE VERSION (${process.version}) FOUND!!`);
console.log('run "sudo npx n nightly" to get nightly build of node js.');
console.log('min version supported is node js 14. run "sudo npx n 14"');
process.exit(-1);
}
@ -23,7 +23,7 @@ const { argv } = yargs
port: config.port || 1812,
s: config.secret || 'testing123',
authentication: config.authentication,
authenticationOptions: config.authenticationOptions
authenticationOptions: config.authenticationOptions,
})
.describe('port', 'RADIUS server listener port')
.alias('s', 'secret')

3
src/auth.ts

@ -1,6 +1,8 @@
import * as NodeCache from 'node-cache';
import { Cache, ExpirationStrategy, MemoryStorage } from '@hokify/node-ts-cache';
import { IAuthentication } from './types/Authentication';
const cacheStrategy = new ExpirationStrategy(new MemoryStorage());
/**
* this is just a simple abstraction to provide
* an application layer for caching credentials
@ -10,6 +12,7 @@ export class Authentication implements IAuthentication {
constructor(private authenticator: IAuthentication) {}
@Cache(cacheStrategy, { ttl: 60000 })
async authenticate(username: string, password: string): Promise<boolean> {
const cacheKey = `usr:${username}|pwd:${password}`;
const fromCache = this.cache.get(cacheKey) as undefined | boolean;

18
src/auth/GoogleLDAPAuth.ts

@ -42,12 +42,12 @@ export class GoogleLDAPAuth implements IAuthentication {
key: fs.readFileSync(config.tls.keyFile),
cert: fs.readFileSync(config.tls.certFile),
servername: 'ldap.google.com',
...config.tlsOptions
...config.tlsOptions,
};
this.config = {
url: 'ldaps://ldap.google.com:636',
tlsOptions
tlsOptions,
};
this.fetchDNs();
@ -57,7 +57,7 @@ export class GoogleLDAPAuth implements IAuthentication {
const dns: { [key: string]: string } = {};
await new Promise((resolve, reject) => {
const ldapDNClient = createClient(this.config).on('error', error => {
const ldapDNClient = createClient(this.config).on('error', (error) => {
console.error('Error in ldap', error);
reject(error);
});
@ -65,7 +65,7 @@ export class GoogleLDAPAuth implements IAuthentication {
ldapDNClient.search(
this.base,
{
scope: 'sub'
scope: 'sub',
},
(err, res) => {
if (err) {
@ -73,24 +73,24 @@ export class GoogleLDAPAuth implements IAuthentication {
return;
}
res.on('searchEntry', function(entry) {
res.on('searchEntry', function (entry) {
// log('entry: ' + JSON.stringify(entry.object));
usernameFields.forEach(field => {
usernameFields.forEach((field) => {
const index = entry.object[field] as string;
dns[index] = entry.object.dn;
});
});
res.on('searchReference', function(referral) {
res.on('searchReference', function (referral) {
log(`referral: ${referral.uris.join()}`);
});
res.on('error', function(ldapErr) {
res.on('error', function (ldapErr) {
console.error(`error: ${ldapErr.message}`);
reject();
});
res.on('end', result => {
res.on('end', (result) => {
log(`ldap status: ${result?.status}`);
// replace with new dns

6
src/auth/IMAPAuth.ts

@ -48,9 +48,9 @@ export class IMAPAuth implements IAuthentication {
user: username,
password,
tlsOptions: {
servername: this.host // SNI (needs to be set for gmail)
}
}
servername: this.host, // SNI (needs to be set for gmail)
},
},
});
success = true;

8
src/auth/LDAPAuth.ts

@ -33,7 +33,7 @@ export class LDAPAuth implements IAuthentication {
const tlsOptions = {
key: fs.readFileSync(config.tls.keyFile),
cert: fs.readFileSync(config.tls.certFile),
...config.tlsOptions
...config.tlsOptions,
};
this.ldap = new LdapAuth({
@ -41,16 +41,16 @@ export class LDAPAuth implements IAuthentication {
searchBase: config.base,
tlsOptions,
searchFilter: config.searchFilter || '(uid={{username}})',
reconnect: true
reconnect: true,
});
this.ldap.on('error', function(err) {
this.ldap.on('error', function (err) {
console.error('LdapAuth: ', err);
});
}
async authenticate(username: string, password: string) {
const authResult: boolean = await new Promise((resolve, reject) => {
this.ldap.authenticate(username, password, function(err, user) {
this.ldap.authenticate(username, password, function (err, user) {
if (err) {
resolve(false);
console.error('ldap error', err);

4
src/auth/SMTPAuth.ts

@ -47,8 +47,8 @@ export class SMTPAuth implements IAuthentication {
port: this.port,
secure: this.useSecureTransport,
tlsOptions: {
servername: this.host // SNI (needs to be set for gmail)
}
servername: this.host, // SNI (needs to be set for gmail)
},
});
let success = false;

2
src/auth/StaticAuth.ts

@ -16,7 +16,7 @@ export class StaticAuth implements IAuthentication {
async authenticate(username: string, password: string) {
return !!this.validCredentials.find(
credential => credential.username === username && credential.password === password
(credential) => credential.username === username && credential.password === password
);
}
}

4
src/helpers.ts

@ -30,7 +30,7 @@ export const newDeferredPromise = (): IDeferredPromise => {
return {
promise: P,
resolve: fResolve,
reject: fReject
reject: fReject,
};
}
@ -38,4 +38,4 @@ export const newDeferredPromise = (): IDeferredPromise => {
};
export const delay = (timeout: number) =>
new Promise(resolve => setTimeout(() => resolve(), timeout));
new Promise((resolve) => setTimeout(() => resolve(), timeout));

2
src/radius/PacketHandler.ts

@ -14,7 +14,7 @@ export class PacketHandler implements IPacketHandler {
new EAPPacketHandler([
new EAPTTLS(authentication, this),
new EAPGTC(authentication),
new EAPMD5(authentication)
new EAPMD5(authentication),
])
);
this.packetHandlers.push(new UserPasswordPacketHandler(authentication));

4
src/radius/RadiusService.ts

@ -34,11 +34,11 @@ export class RadiusService {
packet,
code: response.code,
secret: this.secret,
attributes: response.attributes
attributes: response.attributes,
}),
// if message is accept or reject, we conside this as final message
// this means we do not expect a reponse from the client again (acknowledgement for package)
expectAcknowledgment: response.code === PacketResponseCode.AccessChallenge
expectAcknowledgment: response.code === PacketResponseCode.AccessChallenge,
};
}
}

8
src/radius/handler/EAPPacketHandler.ts

@ -27,7 +27,7 @@ export class EAPPacketHandler implements IPacketHandler {
if (!this.eapConnectionStates.get(stateID)) {
this.eapConnectionStates.set(stateID, {
validMethods: this.eapMethods.filter(eap => eap.getEAPType() !== handlingType) // on init all registered eap methods are valid, we kick them out in case we get a NAK response
validMethods: this.eapMethods.filter((eap) => eap.getEAPType() !== handlingType), // on init all registered eap methods are valid, we kick them out in case we get a NAK response
});
}
@ -78,7 +78,7 @@ export class EAPPacketHandler implements IPacketHandler {
supportedEAPMethods.push(supportedMethod);
}
currentState.validMethods = currentState.validMethods.filter(method => {
currentState.validMethods = currentState.validMethods.filter((method) => {
return supportedEAPMethods.includes(method.getEAPType()); // kick it out?
});
// save
@ -93,7 +93,7 @@ export class EAPPacketHandler implements IPacketHandler {
// continue with responding a NAK and add rest of supported methods
// eslint-disable-next-line no-fallthrough
default: {
const eapMethod = this.eapMethods.find(method => {
const eapMethod = this.eapMethods.find((method) => {
return type === method.getEAPType();
});
@ -108,7 +108,7 @@ export class EAPPacketHandler implements IPacketHandler {
}
// we do not support this auth type, ask for something we support
const serverSupportedMethods = currentState.validMethods.map(method =>
const serverSupportedMethods = currentState.validMethods.map((method) =>
method.getEAPType()
);

6
src/radius/handler/UserPasswordPacketHandler.ts

@ -4,7 +4,7 @@ import {
IPacket,
IPacketHandler,
IPacketHandlerResult,
PacketResponseCode
PacketResponseCode,
} from '../../types/PacketHandler';
const log = debug('radius:user-pwd');
@ -32,13 +32,13 @@ export class UserPasswordPacketHandler implements IPacketHandler {
// success
return {
code: PacketResponseCode.AccessAccept,
attributes: [['User-Name', username]]
attributes: [['User-Name', username]],
};
}
// Failed
return {
code: PacketResponseCode.AccessReject
code: PacketResponseCode.AccessReject,
};
}
}

6
src/radius/handler/eap/EAPHelper.ts

@ -15,7 +15,7 @@ export function buildEAP(identifier: number, msgType: number, data?: Buffer) {
identifier,
0, // length (1/2)
0, // length (2/2)
msgType // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
msgType, // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
]);
const resBuffer = data ? Buffer.concat([buffer, data]) : buffer;
@ -38,7 +38,7 @@ export function buildEAPResponse(
): IPacketHandlerResult {
return {
code: PacketResponseCode.AccessChallenge,
attributes: [['EAP-Message', buildEAP(identifier, msgType, data)]]
attributes: [['EAP-Message', buildEAP(identifier, msgType, data)]],
};
}
@ -74,6 +74,6 @@ export function decodeEAPHeader(msg: Buffer) {
identifier,
length,
type,
data
data,
};
}

4
src/radius/handler/eap/eapMethods/EAP-GTC.ts

@ -15,7 +15,7 @@ export class EAPGTC implements IEAPMethod {
}
extractValue(msg: Buffer) {
let tillBinary0 = msg.findIndex(v => v === 0) || msg.length;
let tillBinary0 = msg.findIndex((v) => v === 0) || msg.length;
if (tillBinary0 < 0) {
tillBinary0 = msg.length - 1;
}
@ -52,7 +52,7 @@ export class EAPGTC implements IEAPMethod {
return {
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
attributes: (success && [['User-Name', username]]) || undefined
attributes: (success && [['User-Name', username]]) || undefined,
};
}
}

38
src/radius/handler/eap/eapMethods/EAP-TTLS.ts

@ -14,7 +14,7 @@ import {
IPacketAttributes,
IPacketHandler,
IPacketHandlerResult,
PacketResponseCode
PacketResponseCode,
} from '../../../../types/PacketHandler';
import { MAX_RADIUS_ATTRIBUTE_SIZE, newDeferredPromise } from '../../../../helpers';
import { IEAPMethod } from '../../../../types/EAPMethod';
@ -108,7 +108,7 @@ export class EAPTTLS implements IEAPMethod {
0, // length (1/2)
0, // length (2/2)
msgType, // 1 = identity, 21 = EAP-TTLS, 2 = notificaiton, 4 = md5-challenge, 3 = NAK
flags // flags: 000000 (L include lenghts, M .. more to come)
flags, // flags: 000000 (L include lenghts, M .. more to come)
]);
// append length
@ -132,7 +132,7 @@ export class EAPTTLS implements IEAPMethod {
dataLength: (data && data.byteLength) || 0,
msgType: msgType.toString(10),
flags: `00000000${flags.toString(2)}`.substr(-8),
data
data,
});
if (dataToQueue) {
@ -161,7 +161,7 @@ export class EAPTTLS implements IEAPMethod {
if (resBuffer.length > 0) {
attributes.push([
'EAP-Message',
resBuffer.slice(sentDataSize, sentDataSize + MAX_RADIUS_ATTRIBUTE_SIZE)
resBuffer.slice(sentDataSize, sentDataSize + MAX_RADIUS_ATTRIBUTE_SIZE),
]);
sentDataSize += MAX_RADIUS_ATTRIBUTE_SIZE;
}
@ -169,7 +169,7 @@ export class EAPTTLS implements IEAPMethod {
return {
code: PacketResponseCode.AccessChallenge,
attributes
attributes,
};
}
@ -212,7 +212,7 @@ export class EAPTTLS implements IEAPMethod {
// R
// reserved: flags & 0b00011000,
// V
version: flags & 0b00000111
version: flags & 0b00000111,
};
let msglength;
@ -226,14 +226,14 @@ export class EAPTTLS implements IEAPMethod {
decodedFlags,
identifier,
msglength,
data
data,
// dataStr: data.toString()
});
return {
decodedFlags,
msglength,
data
data,
};
}
@ -247,7 +247,7 @@ export class EAPTTLS implements IEAPMethod {
success ? 3 : 4, // 3.. success, 4... failure
identifier + 1,
0, // length (1/2)
4 // length (2/2)
4, // length (2/2)
]);
const attributes: any[] = [];
@ -268,13 +268,13 @@ export class EAPTTLS implements IEAPMethod {
attributes.push([
'Vendor-Specific',
311,
[[16, encodeTunnelPW(keyingMaterial.slice(64), packet.authenticator, secret)]]
[[16, encodeTunnelPW(keyingMaterial.slice(64), packet.authenticator, secret)]],
]); // MS-MPPE-Send-Key
attributes.push([
'Vendor-Specific',
311,
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), packet.authenticator, secret)]]
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), packet.authenticator, secret)]],
]); // MS-MPPE-Recv-Key
} else {
console.error(
@ -284,7 +284,7 @@ export class EAPTTLS implements IEAPMethod {
return {
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
attributes
attributes,
};
}
@ -338,7 +338,7 @@ export class EAPTTLS implements IEAPMethod {
// build attributes for packet handler
const attributes: IPacketAttributes = {};
AVPs.forEach(avp => {
AVPs.forEach((avp) => {
attributes[attr_id_to_name(avp.type)] = avp.data;
});
@ -347,7 +347,7 @@ export class EAPTTLS implements IEAPMethod {
// handle incoming package via inner tunnel
const result = await this.innerTunnel.handlePacket(
{
attributes
attributes,
},
this.getEAPType()
);
@ -367,15 +367,15 @@ export class EAPTTLS implements IEAPMethod {
...packet,
attributes: {
...packet.attributes,
...this.transformAttributesArrayToMap(result.attributes)
}
...this.transformAttributesArrayToMap(result.attributes),
},
}
)
);
return;
}
const eapMessage = result.attributes?.find(attr => attr[0] === 'EAP-Message');
const eapMessage = result.attributes?.find((attr) => attr[0] === 'EAP-Message');
if (!eapMessage) {
throw new Error('no eap message found');
}
@ -456,7 +456,7 @@ export class EAPTTLS implements IEAPMethod {
// L
V: !!(flags & 0b10000000),
// M
M: !!(flags & 0b01000000)
M: !!(flags & 0b01000000),
};
// const length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
@ -478,7 +478,7 @@ export class EAPTTLS implements IEAPMethod {
decodedFlags,
length,
vendorId,
data
data,
});
// ensure length is a multiple of 4 octect

8
src/tls/crypt.ts

@ -11,7 +11,7 @@ const log = debug('radius:tls');
// https://nodejs.org/api/tls.html
const tlsOptions: tls.SecureContextOptions = {
...config.certificate
...config.certificate,
};
log('tlsOptions', tlsOptions);
const secureContext = createSecureContext(tlsOptions);
@ -33,7 +33,7 @@ export function startTLSServer(): ITLSServer {
// enableTrace: true,
rejectUnauthorized: false,
// handshakeTimeout: 10,
requestCert: false
requestCert: false,
});
const encrypted = duplexpair.socket2;
@ -90,7 +90,7 @@ export function startTLSServer(): ITLSServer {
emitter.emit('end');
});
cleartext.on('keylog', line => {
cleartext.on('keylog', (line) => {
log('############ KEYLOG #############', line);
// cleartext.getTicketKeys()
});
@ -109,7 +109,7 @@ export function startTLSServer(): ITLSServer {
return {
events: emitter,
tls: cleartext
tls: cleartext,
};
}

2
src/types/PacketHandler.ts

@ -1,7 +1,7 @@
export enum PacketResponseCode {
AccessChallenge = 'Access-Challenge',
AccessAccept = 'Access-Accept',
AccessReject = 'Access-Reject'
AccessReject = 'Access-Reject',
}
export interface IPacketHandlerResult {

Loading…
Cancel
Save