chore: get everything up 2 date
This commit is contained in:
parent
174f8b6fc1
commit
842b93634e
@ -1,17 +1,16 @@
|
|||||||
import 'mocha';
|
import 'mocha';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as fs from 'fs';
|
|
||||||
import { GoogleLDAPAuth } from '../../src/auth/GoogleLDAPAuth';
|
import { GoogleLDAPAuth } from '../../src/auth/GoogleLDAPAuth';
|
||||||
|
|
||||||
describe('test google ldap auth', function() {
|
describe('test google ldap auth', function () {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
it('authenticate against ldap server', async () => {
|
it('authenticate against ldap server', async () => {
|
||||||
const auth = new GoogleLDAPAuth({
|
const auth = new GoogleLDAPAuth({
|
||||||
base: 'dc=hokify,dc=com',
|
base: 'dc=hokify,dc=com',
|
||||||
tlsOptions: {
|
tls: {
|
||||||
key: fs.readFileSync('./ldap.gsuite.key'),
|
keyFile: './ldap.gsuite.key',
|
||||||
cert: fs.readFileSync('./ldap.gsuite.crt')
|
certFile: './ldap.gsuite.crt',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await auth.authenticate('username', 'password');
|
const result = await auth.authenticate('username', 'password');
|
||||||
|
@ -8,7 +8,7 @@ describe('test imap auth', () => {
|
|||||||
host: 'imap.gmail.com',
|
host: 'imap.gmail.com',
|
||||||
port: 993,
|
port: 993,
|
||||||
useSecureTransport: true,
|
useSecureTransport: true,
|
||||||
validHosts: ['gmail.com']
|
validHosts: ['gmail.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await auth.authenticate('username', 'password');
|
const result = await auth.authenticate('username', 'password');
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import 'mocha';
|
import 'mocha';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import * as fs from 'fs';
|
|
||||||
import { LDAPAuth } from '../../src/auth/LDAPAuth';
|
import { LDAPAuth } from '../../src/auth/LDAPAuth';
|
||||||
|
|
||||||
describe('test ldap auth', function() {
|
describe('test ldap auth', function () {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
it('authenticate against ldap server', async () => {
|
it('authenticate against ldap server', async () => {
|
||||||
const auth = new LDAPAuth({
|
const auth = new LDAPAuth({
|
||||||
url: 'ldaps://ldap.google.com:636',
|
url: 'ldaps://ldap.google.com:636',
|
||||||
base: 'dc=hokify,dc=com',
|
base: 'dc=hokify,dc=com',
|
||||||
|
tls: {
|
||||||
|
keyFile: './ldap.gsuite.key',
|
||||||
|
certFile: './ldap.gsuite.crt',
|
||||||
|
},
|
||||||
tlsOptions: {
|
tlsOptions: {
|
||||||
servername: 'ldap.google.com',
|
servername: 'ldap.google.com',
|
||||||
key: fs.readFileSync('./ldap.gsuite.key'),
|
},
|
||||||
cert: fs.readFileSync('./ldap.gsuite.crt')
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await auth.authenticate('username', 'password');
|
const result = await auth.authenticate('username', 'password');
|
||||||
|
@ -8,7 +8,7 @@ describe('test smtp auth', () => {
|
|||||||
host: 'smtp.gmail.com',
|
host: 'smtp.gmail.com',
|
||||||
port: 465,
|
port: 465,
|
||||||
useSecureTransport: true,
|
useSecureTransport: true,
|
||||||
validHosts: ['gmail.com']
|
validHosts: ['gmail.com'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await auth.authenticate('username', 'password');
|
const result = await auth.authenticate('username', 'password');
|
||||||
|
12
config.js
12
config.js
@ -14,9 +14,9 @@ module.exports = {
|
|||||||
key: [
|
key: [
|
||||||
{
|
{
|
||||||
pem: fs.readFileSync(path.join(SSL_CERT_DIRECTORY, '/server.key')),
|
pem: fs.readFileSync(path.join(SSL_CERT_DIRECTORY, '/server.key')),
|
||||||
passphrase: 'whatever2020'
|
passphrase: 'whatever2020',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// GoogleLDAPAuth (optimized for google auth)
|
// GoogleLDAPAuth (optimized for google auth)
|
||||||
@ -26,9 +26,9 @@ module.exports = {
|
|||||||
// get your keys from http://admin.google.com/ -> Apps -> LDAP -> Client
|
// get your keys from http://admin.google.com/ -> Apps -> LDAP -> Client
|
||||||
tls: {
|
tls: {
|
||||||
keyFile: 'ldap.gsuite.key',
|
keyFile: 'ldap.gsuite.key',
|
||||||
certFile: 'ldap.gsuite.crt'
|
certFile: 'ldap.gsuite.crt',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
|
||||||
/** LDAP AUTH
|
/** LDAP AUTH
|
||||||
authentication: 'LDAPAuth',
|
authentication: 'LDAPAuth',
|
||||||
|
2300
package-lock.json
generated
2300
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -30,30 +30,30 @@
|
|||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"main": "dist/app.js",
|
"main": "dist/app.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hokify/node-ts-cache": "^4.0.1",
|
"@hokify/node-ts-cache": "^5.1.4",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"imap-simple": "^4.3.0",
|
"imap-simple": "^5.0.0",
|
||||||
"ldapauth-fork": "^4.3.2",
|
"ldapauth-fork": "^4.3.3",
|
||||||
"ldapjs": "^1.0.2",
|
"ldapjs": "^1.0.2",
|
||||||
"native-duplexpair": "^1.0.0",
|
"native-duplexpair": "^1.0.0",
|
||||||
"node-cache": "^5.1.0",
|
"node-cache": "^5.1.0",
|
||||||
"radius": "~1.1.4",
|
"radius": "~1.1.4",
|
||||||
"smtp-client": "^0.3.1",
|
"smtp-client": "^0.3.1",
|
||||||
"yargs": "~15.1.0"
|
"yargs": "~15.3.1"
|
||||||
},
|
},
|
||||||
"license": "GPLv3",
|
"license": "GPLv3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^8.10.1",
|
||||||
"standard-version": "^7.1.0",
|
"standard-version": "^8.0.0",
|
||||||
"@hokify/eslint-config": "^0.2.7",
|
"@hokify/eslint-config": "^0.4.11",
|
||||||
"@types/chai": "^4.2.9",
|
"@types/chai": "^4.2.11",
|
||||||
"@types/ldapjs": "^1.0.5",
|
"@types/ldapjs": "^1.0.7",
|
||||||
"@types/mocha": "^7.0.1",
|
"@types/mocha": "^7.0.2",
|
||||||
"@types/radius": "0.0.28",
|
"@types/radius": "0.0.28",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.0.0",
|
||||||
"mocha": "^7.1.0",
|
"mocha": "^7.1.2",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^2.0.5",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.9.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ const testSocket = startTLSServer();
|
|||||||
if (typeof (testSocket.tls as any).exportKeyingMaterial !== 'function') {
|
if (typeof (testSocket.tls as any).exportKeyingMaterial !== 'function') {
|
||||||
console.error(`UNSUPPORTED NODE VERSION (${process.version}) FOUND!!`);
|
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);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ const { argv } = yargs
|
|||||||
port: config.port || 1812,
|
port: config.port || 1812,
|
||||||
s: config.secret || 'testing123',
|
s: config.secret || 'testing123',
|
||||||
authentication: config.authentication,
|
authentication: config.authentication,
|
||||||
authenticationOptions: config.authenticationOptions
|
authenticationOptions: config.authenticationOptions,
|
||||||
})
|
})
|
||||||
.describe('port', 'RADIUS server listener port')
|
.describe('port', 'RADIUS server listener port')
|
||||||
.alias('s', 'secret')
|
.alias('s', 'secret')
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as NodeCache from 'node-cache';
|
import * as NodeCache from 'node-cache';
|
||||||
|
import { Cache, ExpirationStrategy, MemoryStorage } from '@hokify/node-ts-cache';
|
||||||
import { IAuthentication } from './types/Authentication';
|
import { IAuthentication } from './types/Authentication';
|
||||||
|
|
||||||
|
const cacheStrategy = new ExpirationStrategy(new MemoryStorage());
|
||||||
/**
|
/**
|
||||||
* this is just a simple abstraction to provide
|
* this is just a simple abstraction to provide
|
||||||
* an application layer for caching credentials
|
* an application layer for caching credentials
|
||||||
@ -10,6 +12,7 @@ export class Authentication implements IAuthentication {
|
|||||||
|
|
||||||
constructor(private authenticator: IAuthentication) {}
|
constructor(private authenticator: IAuthentication) {}
|
||||||
|
|
||||||
|
@Cache(cacheStrategy, { ttl: 60000 })
|
||||||
async authenticate(username: string, password: string): Promise<boolean> {
|
async authenticate(username: string, password: string): Promise<boolean> {
|
||||||
const cacheKey = `usr:${username}|pwd:${password}`;
|
const cacheKey = `usr:${username}|pwd:${password}`;
|
||||||
const fromCache = this.cache.get(cacheKey) as undefined | boolean;
|
const fromCache = this.cache.get(cacheKey) as undefined | boolean;
|
||||||
|
@ -42,12 +42,12 @@ export class GoogleLDAPAuth implements IAuthentication {
|
|||||||
key: fs.readFileSync(config.tls.keyFile),
|
key: fs.readFileSync(config.tls.keyFile),
|
||||||
cert: fs.readFileSync(config.tls.certFile),
|
cert: fs.readFileSync(config.tls.certFile),
|
||||||
servername: 'ldap.google.com',
|
servername: 'ldap.google.com',
|
||||||
...config.tlsOptions
|
...config.tlsOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.config = {
|
this.config = {
|
||||||
url: 'ldaps://ldap.google.com:636',
|
url: 'ldaps://ldap.google.com:636',
|
||||||
tlsOptions
|
tlsOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.fetchDNs();
|
this.fetchDNs();
|
||||||
@ -57,7 +57,7 @@ export class GoogleLDAPAuth implements IAuthentication {
|
|||||||
const dns: { [key: string]: string } = {};
|
const dns: { [key: string]: string } = {};
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
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);
|
console.error('Error in ldap', error);
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
@ -65,7 +65,7 @@ export class GoogleLDAPAuth implements IAuthentication {
|
|||||||
ldapDNClient.search(
|
ldapDNClient.search(
|
||||||
this.base,
|
this.base,
|
||||||
{
|
{
|
||||||
scope: 'sub'
|
scope: 'sub',
|
||||||
},
|
},
|
||||||
(err, res) => {
|
(err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -73,24 +73,24 @@ export class GoogleLDAPAuth implements IAuthentication {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.on('searchEntry', function(entry) {
|
res.on('searchEntry', function (entry) {
|
||||||
// log('entry: ' + JSON.stringify(entry.object));
|
// log('entry: ' + JSON.stringify(entry.object));
|
||||||
usernameFields.forEach(field => {
|
usernameFields.forEach((field) => {
|
||||||
const index = entry.object[field] as string;
|
const index = entry.object[field] as string;
|
||||||
dns[index] = entry.object.dn;
|
dns[index] = entry.object.dn;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
res.on('searchReference', function(referral) {
|
res.on('searchReference', function (referral) {
|
||||||
log(`referral: ${referral.uris.join()}`);
|
log(`referral: ${referral.uris.join()}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
res.on('error', function(ldapErr) {
|
res.on('error', function (ldapErr) {
|
||||||
console.error(`error: ${ldapErr.message}`);
|
console.error(`error: ${ldapErr.message}`);
|
||||||
reject();
|
reject();
|
||||||
});
|
});
|
||||||
|
|
||||||
res.on('end', result => {
|
res.on('end', (result) => {
|
||||||
log(`ldap status: ${result?.status}`);
|
log(`ldap status: ${result?.status}`);
|
||||||
|
|
||||||
// replace with new dns
|
// replace with new dns
|
||||||
|
@ -48,9 +48,9 @@ export class IMAPAuth implements IAuthentication {
|
|||||||
user: username,
|
user: username,
|
||||||
password,
|
password,
|
||||||
tlsOptions: {
|
tlsOptions: {
|
||||||
servername: this.host // SNI (needs to be set for gmail)
|
servername: this.host, // SNI (needs to be set for gmail)
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
|
@ -33,7 +33,7 @@ export class LDAPAuth implements IAuthentication {
|
|||||||
const tlsOptions = {
|
const tlsOptions = {
|
||||||
key: fs.readFileSync(config.tls.keyFile),
|
key: fs.readFileSync(config.tls.keyFile),
|
||||||
cert: fs.readFileSync(config.tls.certFile),
|
cert: fs.readFileSync(config.tls.certFile),
|
||||||
...config.tlsOptions
|
...config.tlsOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ldap = new LdapAuth({
|
this.ldap = new LdapAuth({
|
||||||
@ -41,16 +41,16 @@ export class LDAPAuth implements IAuthentication {
|
|||||||
searchBase: config.base,
|
searchBase: config.base,
|
||||||
tlsOptions,
|
tlsOptions,
|
||||||
searchFilter: config.searchFilter || '(uid={{username}})',
|
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);
|
console.error('LdapAuth: ', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticate(username: string, password: string) {
|
async authenticate(username: string, password: string) {
|
||||||
const authResult: boolean = await new Promise((resolve, reject) => {
|
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) {
|
if (err) {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
console.error('ldap error', err);
|
console.error('ldap error', err);
|
||||||
|
@ -47,8 +47,8 @@ export class SMTPAuth implements IAuthentication {
|
|||||||
port: this.port,
|
port: this.port,
|
||||||
secure: this.useSecureTransport,
|
secure: this.useSecureTransport,
|
||||||
tlsOptions: {
|
tlsOptions: {
|
||||||
servername: this.host // SNI (needs to be set for gmail)
|
servername: this.host, // SNI (needs to be set for gmail)
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
|
@ -16,7 +16,7 @@ export class StaticAuth implements IAuthentication {
|
|||||||
|
|
||||||
async authenticate(username: string, password: string) {
|
async authenticate(username: string, password: string) {
|
||||||
return !!this.validCredentials.find(
|
return !!this.validCredentials.find(
|
||||||
credential => credential.username === username && credential.password === password
|
(credential) => credential.username === username && credential.password === password
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export const newDeferredPromise = (): IDeferredPromise => {
|
|||||||
return {
|
return {
|
||||||
promise: P,
|
promise: P,
|
||||||
resolve: fResolve,
|
resolve: fResolve,
|
||||||
reject: fReject
|
reject: fReject,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,4 +38,4 @@ export const newDeferredPromise = (): IDeferredPromise => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const delay = (timeout: number) =>
|
export const delay = (timeout: number) =>
|
||||||
new Promise(resolve => setTimeout(() => resolve(), timeout));
|
new Promise((resolve) => setTimeout(() => resolve(), timeout));
|
||||||
|
@ -14,7 +14,7 @@ export class PacketHandler implements IPacketHandler {
|
|||||||
new EAPPacketHandler([
|
new EAPPacketHandler([
|
||||||
new EAPTTLS(authentication, this),
|
new EAPTTLS(authentication, this),
|
||||||
new EAPGTC(authentication),
|
new EAPGTC(authentication),
|
||||||
new EAPMD5(authentication)
|
new EAPMD5(authentication),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
this.packetHandlers.push(new UserPasswordPacketHandler(authentication));
|
this.packetHandlers.push(new UserPasswordPacketHandler(authentication));
|
||||||
|
@ -34,11 +34,11 @@ export class RadiusService {
|
|||||||
packet,
|
packet,
|
||||||
code: response.code,
|
code: response.code,
|
||||||
secret: this.secret,
|
secret: this.secret,
|
||||||
attributes: response.attributes
|
attributes: response.attributes,
|
||||||
}),
|
}),
|
||||||
// if message is accept or reject, we conside this as final message
|
// 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)
|
// 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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export class EAPPacketHandler implements IPacketHandler {
|
|||||||
|
|
||||||
if (!this.eapConnectionStates.get(stateID)) {
|
if (!this.eapConnectionStates.get(stateID)) {
|
||||||
this.eapConnectionStates.set(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);
|
supportedEAPMethods.push(supportedMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentState.validMethods = currentState.validMethods.filter(method => {
|
currentState.validMethods = currentState.validMethods.filter((method) => {
|
||||||
return supportedEAPMethods.includes(method.getEAPType()); // kick it out?
|
return supportedEAPMethods.includes(method.getEAPType()); // kick it out?
|
||||||
});
|
});
|
||||||
// save
|
// save
|
||||||
@ -93,7 +93,7 @@ export class EAPPacketHandler implements IPacketHandler {
|
|||||||
// continue with responding a NAK and add rest of supported methods
|
// continue with responding a NAK and add rest of supported methods
|
||||||
// eslint-disable-next-line no-fallthrough
|
// eslint-disable-next-line no-fallthrough
|
||||||
default: {
|
default: {
|
||||||
const eapMethod = this.eapMethods.find(method => {
|
const eapMethod = this.eapMethods.find((method) => {
|
||||||
return type === method.getEAPType();
|
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
|
// 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()
|
method.getEAPType()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
IPacket,
|
IPacket,
|
||||||
IPacketHandler,
|
IPacketHandler,
|
||||||
IPacketHandlerResult,
|
IPacketHandlerResult,
|
||||||
PacketResponseCode
|
PacketResponseCode,
|
||||||
} from '../../types/PacketHandler';
|
} from '../../types/PacketHandler';
|
||||||
|
|
||||||
const log = debug('radius:user-pwd');
|
const log = debug('radius:user-pwd');
|
||||||
@ -32,13 +32,13 @@ export class UserPasswordPacketHandler implements IPacketHandler {
|
|||||||
// success
|
// success
|
||||||
return {
|
return {
|
||||||
code: PacketResponseCode.AccessAccept,
|
code: PacketResponseCode.AccessAccept,
|
||||||
attributes: [['User-Name', username]]
|
attributes: [['User-Name', username]],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed
|
// Failed
|
||||||
return {
|
return {
|
||||||
code: PacketResponseCode.AccessReject
|
code: PacketResponseCode.AccessReject,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ export function buildEAP(identifier: number, msgType: number, data?: Buffer) {
|
|||||||
identifier,
|
identifier,
|
||||||
0, // length (1/2)
|
0, // length (1/2)
|
||||||
0, // length (2/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;
|
const resBuffer = data ? Buffer.concat([buffer, data]) : buffer;
|
||||||
@ -38,7 +38,7 @@ export function buildEAPResponse(
|
|||||||
): IPacketHandlerResult {
|
): IPacketHandlerResult {
|
||||||
return {
|
return {
|
||||||
code: PacketResponseCode.AccessChallenge,
|
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,
|
identifier,
|
||||||
length,
|
length,
|
||||||
type,
|
type,
|
||||||
data
|
data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ export class EAPGTC implements IEAPMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extractValue(msg: Buffer) {
|
extractValue(msg: Buffer) {
|
||||||
let tillBinary0 = msg.findIndex(v => v === 0) || msg.length;
|
let tillBinary0 = msg.findIndex((v) => v === 0) || msg.length;
|
||||||
if (tillBinary0 < 0) {
|
if (tillBinary0 < 0) {
|
||||||
tillBinary0 = msg.length - 1;
|
tillBinary0 = msg.length - 1;
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ export class EAPGTC implements IEAPMethod {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
|
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
|
||||||
attributes: (success && [['User-Name', username]]) || undefined
|
attributes: (success && [['User-Name', username]]) || undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
IPacketAttributes,
|
IPacketAttributes,
|
||||||
IPacketHandler,
|
IPacketHandler,
|
||||||
IPacketHandlerResult,
|
IPacketHandlerResult,
|
||||||
PacketResponseCode
|
PacketResponseCode,
|
||||||
} from '../../../../types/PacketHandler';
|
} from '../../../../types/PacketHandler';
|
||||||
import { MAX_RADIUS_ATTRIBUTE_SIZE, newDeferredPromise } from '../../../../helpers';
|
import { MAX_RADIUS_ATTRIBUTE_SIZE, newDeferredPromise } from '../../../../helpers';
|
||||||
import { IEAPMethod } from '../../../../types/EAPMethod';
|
import { IEAPMethod } from '../../../../types/EAPMethod';
|
||||||
@ -108,7 +108,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
0, // length (1/2)
|
0, // length (1/2)
|
||||||
0, // length (2/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
|
||||||
flags // flags: 000000 (L include lenghts, M .. more to come)
|
flags, // flags: 000000 (L include lenghts, M .. more to come)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// append length
|
// append length
|
||||||
@ -132,7 +132,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
dataLength: (data && data.byteLength) || 0,
|
dataLength: (data && data.byteLength) || 0,
|
||||||
msgType: msgType.toString(10),
|
msgType: msgType.toString(10),
|
||||||
flags: `00000000${flags.toString(2)}`.substr(-8),
|
flags: `00000000${flags.toString(2)}`.substr(-8),
|
||||||
data
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (dataToQueue) {
|
if (dataToQueue) {
|
||||||
@ -161,7 +161,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
if (resBuffer.length > 0) {
|
if (resBuffer.length > 0) {
|
||||||
attributes.push([
|
attributes.push([
|
||||||
'EAP-Message',
|
'EAP-Message',
|
||||||
resBuffer.slice(sentDataSize, sentDataSize + MAX_RADIUS_ATTRIBUTE_SIZE)
|
resBuffer.slice(sentDataSize, sentDataSize + MAX_RADIUS_ATTRIBUTE_SIZE),
|
||||||
]);
|
]);
|
||||||
sentDataSize += MAX_RADIUS_ATTRIBUTE_SIZE;
|
sentDataSize += MAX_RADIUS_ATTRIBUTE_SIZE;
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
code: PacketResponseCode.AccessChallenge,
|
code: PacketResponseCode.AccessChallenge,
|
||||||
attributes
|
attributes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
// R
|
// R
|
||||||
// reserved: flags & 0b00011000,
|
// reserved: flags & 0b00011000,
|
||||||
// V
|
// V
|
||||||
version: flags & 0b00000111
|
version: flags & 0b00000111,
|
||||||
};
|
};
|
||||||
|
|
||||||
let msglength;
|
let msglength;
|
||||||
@ -226,14 +226,14 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
decodedFlags,
|
decodedFlags,
|
||||||
identifier,
|
identifier,
|
||||||
msglength,
|
msglength,
|
||||||
data
|
data,
|
||||||
// dataStr: data.toString()
|
// dataStr: data.toString()
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
decodedFlags,
|
decodedFlags,
|
||||||
msglength,
|
msglength,
|
||||||
data
|
data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
success ? 3 : 4, // 3.. success, 4... failure
|
success ? 3 : 4, // 3.. success, 4... failure
|
||||||
identifier + 1,
|
identifier + 1,
|
||||||
0, // length (1/2)
|
0, // length (1/2)
|
||||||
4 // length (2/2)
|
4, // length (2/2)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const attributes: any[] = [];
|
const attributes: any[] = [];
|
||||||
@ -268,13 +268,13 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
attributes.push([
|
attributes.push([
|
||||||
'Vendor-Specific',
|
'Vendor-Specific',
|
||||||
311,
|
311,
|
||||||
[[16, encodeTunnelPW(keyingMaterial.slice(64), packet.authenticator, secret)]]
|
[[16, encodeTunnelPW(keyingMaterial.slice(64), packet.authenticator, secret)]],
|
||||||
]); // MS-MPPE-Send-Key
|
]); // MS-MPPE-Send-Key
|
||||||
|
|
||||||
attributes.push([
|
attributes.push([
|
||||||
'Vendor-Specific',
|
'Vendor-Specific',
|
||||||
311,
|
311,
|
||||||
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), packet.authenticator, secret)]]
|
[[17, encodeTunnelPW(keyingMaterial.slice(0, 64), packet.authenticator, secret)]],
|
||||||
]); // MS-MPPE-Recv-Key
|
]); // MS-MPPE-Recv-Key
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
@ -284,7 +284,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
|
code: success ? PacketResponseCode.AccessAccept : PacketResponseCode.AccessReject,
|
||||||
attributes
|
attributes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
|
|
||||||
// build attributes for packet handler
|
// build attributes for packet handler
|
||||||
const attributes: IPacketAttributes = {};
|
const attributes: IPacketAttributes = {};
|
||||||
AVPs.forEach(avp => {
|
AVPs.forEach((avp) => {
|
||||||
attributes[attr_id_to_name(avp.type)] = avp.data;
|
attributes[attr_id_to_name(avp.type)] = avp.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -347,7 +347,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
// handle incoming package via inner tunnel
|
// handle incoming package via inner tunnel
|
||||||
const result = await this.innerTunnel.handlePacket(
|
const result = await this.innerTunnel.handlePacket(
|
||||||
{
|
{
|
||||||
attributes
|
attributes,
|
||||||
},
|
},
|
||||||
this.getEAPType()
|
this.getEAPType()
|
||||||
);
|
);
|
||||||
@ -367,15 +367,15 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
...packet,
|
...packet,
|
||||||
attributes: {
|
attributes: {
|
||||||
...packet.attributes,
|
...packet.attributes,
|
||||||
...this.transformAttributesArrayToMap(result.attributes)
|
...this.transformAttributesArrayToMap(result.attributes),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const eapMessage = result.attributes?.find(attr => attr[0] === 'EAP-Message');
|
const eapMessage = result.attributes?.find((attr) => attr[0] === 'EAP-Message');
|
||||||
if (!eapMessage) {
|
if (!eapMessage) {
|
||||||
throw new Error('no eap message found');
|
throw new Error('no eap message found');
|
||||||
}
|
}
|
||||||
@ -456,7 +456,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
// L
|
// L
|
||||||
V: !!(flags & 0b10000000),
|
V: !!(flags & 0b10000000),
|
||||||
// M
|
// M
|
||||||
M: !!(flags & 0b01000000)
|
M: !!(flags & 0b01000000),
|
||||||
};
|
};
|
||||||
|
|
||||||
// const length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
|
// const length = buffer.slice(5, 8).readUInt16BE(0); // actually a Int24BE
|
||||||
@ -478,7 +478,7 @@ export class EAPTTLS implements IEAPMethod {
|
|||||||
decodedFlags,
|
decodedFlags,
|
||||||
length,
|
length,
|
||||||
vendorId,
|
vendorId,
|
||||||
data
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ensure length is a multiple of 4 octect
|
// ensure length is a multiple of 4 octect
|
||||||
|
@ -11,7 +11,7 @@ const log = debug('radius:tls');
|
|||||||
|
|
||||||
// https://nodejs.org/api/tls.html
|
// https://nodejs.org/api/tls.html
|
||||||
const tlsOptions: tls.SecureContextOptions = {
|
const tlsOptions: tls.SecureContextOptions = {
|
||||||
...config.certificate
|
...config.certificate,
|
||||||
};
|
};
|
||||||
log('tlsOptions', tlsOptions);
|
log('tlsOptions', tlsOptions);
|
||||||
const secureContext = createSecureContext(tlsOptions);
|
const secureContext = createSecureContext(tlsOptions);
|
||||||
@ -33,7 +33,7 @@ export function startTLSServer(): ITLSServer {
|
|||||||
// enableTrace: true,
|
// enableTrace: true,
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
// handshakeTimeout: 10,
|
// handshakeTimeout: 10,
|
||||||
requestCert: false
|
requestCert: false,
|
||||||
});
|
});
|
||||||
const encrypted = duplexpair.socket2;
|
const encrypted = duplexpair.socket2;
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export function startTLSServer(): ITLSServer {
|
|||||||
emitter.emit('end');
|
emitter.emit('end');
|
||||||
});
|
});
|
||||||
|
|
||||||
cleartext.on('keylog', line => {
|
cleartext.on('keylog', (line) => {
|
||||||
log('############ KEYLOG #############', line);
|
log('############ KEYLOG #############', line);
|
||||||
// cleartext.getTicketKeys()
|
// cleartext.getTicketKeys()
|
||||||
});
|
});
|
||||||
@ -109,7 +109,7 @@ export function startTLSServer(): ITLSServer {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
events: emitter,
|
events: emitter,
|
||||||
tls: cleartext
|
tls: cleartext,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export enum PacketResponseCode {
|
export enum PacketResponseCode {
|
||||||
AccessChallenge = 'Access-Challenge',
|
AccessChallenge = 'Access-Challenge',
|
||||||
AccessAccept = 'Access-Accept',
|
AccessAccept = 'Access-Accept',
|
||||||
AccessReject = 'Access-Reject'
|
AccessReject = 'Access-Reject',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPacketHandlerResult {
|
export interface IPacketHandlerResult {
|
||||||
|
Loading…
Reference in New Issue
Block a user