fix: session resumptions + google ldap auth

This commit is contained in:
Simon Tretter 2020-08-05 12:44:39 +02:00 committed by GitHub
parent ab1ab1b130
commit 66fbcf4ca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 526 additions and 787 deletions

View File

@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [1.1.6](https://github.com/simllll/node-radius-server/compare/v1.1.5...v1.1.6) (2020-08-05)
### Bug Fixes
* **google-auth:** search base must include ou ([a3ab393](https://github.com/simllll/node-radius-server/commit/a3ab393379be7f1b8b2f82347bbc4300b8db409d))
### [1.1.5](https://github.com/simllll/node-radius-server/compare/v1.1.4...v1.1.5) (2020-06-26) ### [1.1.5](https://github.com/simllll/node-radius-server/compare/v1.1.4...v1.1.5) (2020-06-26)

1235
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "radius-server", "name": "radius-server",
"description": "radius server for google LDAP and TTLS", "description": "radius server for google LDAP and TTLS",
"version": "1.1.5", "version": "1.1.6",
"engines": { "engines": {
"node": ">13.10.1" "node": ">13.10.1"
}, },
@ -30,30 +30,30 @@
"preferGlobal": true, "preferGlobal": true,
"main": "dist/app.js", "main": "dist/app.js",
"dependencies": { "dependencies": {
"@hokify/node-ts-cache": "^5.1.7", "@hokify/node-ts-cache": "^5.2.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"imap-simple": "^5.0.0", "imap-simple": "^5.0.0",
"ldapauth-fork": "^4.3.3", "ldapauth-fork": "^4.3.3",
"ldapjs": "^2.0.0", "ldapjs": "^2.1.1",
"native-duplexpair": "^1.0.0", "native-duplexpair": "^1.0.0",
"node-cache": "^5.1.1", "node-cache": "^5.1.2",
"radius": "~1.1.4", "radius": "~1.1.4",
"smtp-client": "^0.3.1", "smtp-client": "^0.3.2",
"yargs": "~15.3.1" "yargs": "~15.4.1"
}, },
"license": "GPLv3", "license": "GPLv3",
"devDependencies": { "devDependencies": {
"ts-node": "^8.10.2", "ts-node": "^8.10.2",
"standard-version": "^8.0.0", "standard-version": "^8.0.2",
"@hokify/eslint-config": "^0.4.25", "@hokify/eslint-config": "^0.4.42",
"@types/chai": "^4.2.11", "@types/chai": "^4.2.12",
"@types/ldapjs": "^1.0.8", "@types/ldapjs": "^1.0.9",
"@types/mocha": "^7.0.2", "@types/mocha": "^8.0.1",
"@types/radius": "0.0.28", "@types/radius": "0.0.28",
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^7.3.1", "eslint": "^7.6.0",
"mocha": "^8.0.1", "mocha": "^8.1.1",
"prettier": "^2.0.5", "prettier": "^2.0.5",
"typescript": "^3.9.5" "typescript": "^3.9.7"
} }
} }

View File

@ -14,6 +14,7 @@ interface IGoogleLDAPAuthOptions {
/** base DN /** base DN
* e.g. 'dc=hokify,dc=com', */ * e.g. 'dc=hokify,dc=com', */
base: string; base: string;
searchBase?: string; // default ou=users,{{base}}
tls: { tls: {
keyFile: string; keyFile: string;
certFile: string; certFile: string;
@ -35,8 +36,11 @@ export class GoogleLDAPAuth implements IAuthentication {
private config: ClientOptions; private config: ClientOptions;
searchBase: string;
constructor(config: IGoogleLDAPAuthOptions) { constructor(config: IGoogleLDAPAuthOptions) {
this.base = config.base; this.base = config.base;
this.searchBase = config.searchBase || `ou=users,${this.base}`;
const tlsOptions = { const tlsOptions = {
key: fs.readFileSync(config.tls.keyFile), key: fs.readFileSync(config.tls.keyFile),
@ -50,7 +54,9 @@ export class GoogleLDAPAuth implements IAuthentication {
tlsOptions, tlsOptions,
}; };
this.fetchDNs(); this.fetchDNs().catch((err) => {
console.error('fatal error google ldap auth, cannot fetch DNs', err);
});
} }
private async fetchDNs() { private async fetchDNs() {
@ -63,7 +69,7 @@ export class GoogleLDAPAuth implements IAuthentication {
}); });
ldapDNClient.search( ldapDNClient.search(
this.base, this.searchBase,
{ {
scope: 'sub', scope: 'sub',
}, },
@ -86,8 +92,8 @@ export class GoogleLDAPAuth implements IAuthentication {
}); });
res.on('error', function (ldapErr) { res.on('error', function (ldapErr) {
console.error(`error: ${ldapErr.message}`); console.error(`error: ${JSON.stringify(ldapErr)}`);
reject(); reject(ldapErr);
}); });
res.on('end', (result) => { res.on('end', (result) => {
@ -132,6 +138,7 @@ export class GoogleLDAPAuth implements IAuthentication {
if (!dnsFetched && !forceFetching) { if (!dnsFetched && !forceFetching) {
return this.authenticate(username, password, count, true); return this.authenticate(username, password, count, true);
} }
// console.log('this.allValidDNsCache', this.allValidDNsCache);
console.error(`invalid username, not found in DN: ${username}`); // , this.allValidDNsCache); console.error(`invalid username, not found in DN: ${username}`); // , this.allValidDNsCache);
return false; return false;
} }

View File

@ -34,8 +34,11 @@ export class EAPPacketHandler implements IPacketHandler {
// EAP MESSAGE // EAP MESSAGE
let msg = packet.attributes['EAP-Message'] as Buffer; let msg = packet.attributes['EAP-Message'] as Buffer;
if (Array.isArray(msg)) { if (Array.isArray(msg) && !(packet.attributes['EAP-Message'] instanceof Buffer)) {
msg = Buffer.concat(msg); // log('multiple EAP Messages received, concat', msg.length);
const allMsgs = msg as Buffer[];
msg = Buffer.concat(allMsgs);
// log('final EAP Message', msg);
} }
try { try {

View File

@ -3,7 +3,7 @@
/* eslint-disable no-bitwise */ /* eslint-disable no-bitwise */
import * as tls from 'tls'; import * as tls from 'tls';
import * as NodeCache from 'node-cache'; import * as NodeCache from 'node-cache';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
import { attr_id_to_name, attr_name_to_id } from 'radius'; import { attr_id_to_name, attr_name_to_id } from 'radius';
import debug from 'debug'; import debug from 'debug';
@ -219,12 +219,13 @@ export class EAPTTLS implements IEAPMethod {
if (decodedFlags.lengthIncluded) { if (decodedFlags.lengthIncluded) {
msglength = msg.slice(6, 10).readUInt32BE(0); // .readDoubleLE(0); // .toString('hex'); msglength = msg.slice(6, 10).readUInt32BE(0); // .readDoubleLE(0); // .toString('hex');
} }
const data = msg.slice(decodedFlags.lengthIncluded ? 10 : 6, msg.length); const data = msg.slice(decodedFlags.lengthIncluded ? 10 : 6).slice(0, msglength);
log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', { log('>>>>>>>>>>>> REQUEST FROM CLIENT: EAP TTLS', {
flags: `00000000${flags.toString(2)}`.substr(-8), flags: `00000000${flags.toString(2)}`.substr(-8),
decodedFlags, decodedFlags,
identifier, identifier,
msglengthBuffer: msg.length,
msglength, msglength,
data, data,
// dataStr: data.toString() // dataStr: data.toString()
@ -388,15 +389,24 @@ export class EAPTTLS implements IEAPMethod {
}; };
const responseHandler = (encryptedResponseData: Buffer) => { const responseHandler = (encryptedResponseData: Buffer) => {
log('complete');
// send back... // send back...
sendResponsePromise.resolve( sendResponsePromise.resolve(
this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData) this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData)
); );
}; };
const checkExistingSession = (isSessionReused) => {
if (isSessionReused) {
log('secured, session reused, accept auth!');
sendResponsePromise.resolve(this.authResponse(identifier, true, connection.tls, packet));
}
};
// register event listeners // register event listeners
connection.events.on('incoming', incomingMessageHandler); connection.events.on('incoming', incomingMessageHandler);
connection.events.on('response', responseHandler); connection.events.on('response', responseHandler);
connection.events.on('secured', checkExistingSession);
// emit data to tls server // emit data to tls server
connection.events.emit('decrypt', data); connection.events.emit('decrypt', data);
@ -405,6 +415,9 @@ export class EAPTTLS implements IEAPMethod {
// cleanup // cleanup
connection.events.off('incoming', incomingMessageHandler); connection.events.off('incoming', incomingMessageHandler);
connection.events.off('response', responseHandler); connection.events.off('response', responseHandler);
connection.events.off('secured', checkExistingSession);
// connection.events.off('secured');
// send response // send response
return responseData; // this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData); return responseData; // this.buildEAPTTLSResponse(identifier, 21, 0x00, stateID, encryptedResponseData);
@ -473,7 +486,7 @@ export class EAPTTLS implements IEAPMethod {
let vendorId; let vendorId;
let data; let data;
if (flags & 0b010000000) { if (decodedFlags.V) {
// V flag set // V flag set
vendorId = currentBuffer.slice(8, 12).readUInt32BE(0); vendorId = currentBuffer.slice(8, 12).readUInt32BE(0);
data = currentBuffer.slice(12, length); data = currentBuffer.slice(12, length);

View File

@ -5,6 +5,7 @@ import * as crypto from 'crypto';
import * as DuplexPair from 'native-duplexpair'; import * as DuplexPair from 'native-duplexpair';
import debug from 'debug'; import debug from 'debug';
import * as NodeCache from 'node-cache'; import * as NodeCache from 'node-cache';
// import * as constants from 'constants';
import * as config from '../../config'; import * as config from '../../config';
const log = debug('radius:tls'); const log = debug('radius:tls');
@ -96,6 +97,7 @@ export function startTLSServer(): ITLSServer {
}); });
log('*********** new TLS connection established / secured ********'); log('*********** new TLS connection established / secured ********');
emitter.emit('secured', cleartext.isSessionReused());
}); });
cleartext.on('error', (err?: Error) => { cleartext.on('error', (err?: Error) => {