More RADIUS work

This commit is contained in:
Garrett Mills 2021-11-22 09:08:22 -06:00
parent 6e161dd383
commit ffbcf1b514
5 changed files with 96 additions and 38 deletions

1
.gitignore vendored
View File

@ -150,3 +150,4 @@ tmp.uploads/*
!tmp.uploads/.gitkeep !tmp.uploads/.gitkeep
uploads/* uploads/*
!uploads/.gitkeep !uploads/.gitkeep
ttls-pap.conf

View File

@ -9,6 +9,9 @@ class RadiusController extends Controller {
const User = this.models.get('auth:User') const User = this.models.get('auth:User')
const Client = this.models.get('radius:Client') const Client = this.models.get('radius:Client')
this.output.debug('RADIUS attempt:')
this.output.debug(req.body)
if ( !req.body.username || !req.body.password ) { if ( !req.body.username || !req.body.password ) {
this.output.error('RADIUS error: missing username or password') this.output.error('RADIUS error: missing username or password')
return this.fail(res) return this.fail(res)
@ -21,7 +24,9 @@ class RadiusController extends Controller {
parts.reverse() parts.reverse()
const username = parts.join('@') const username = parts.join('@')
const password = req.body.password const password = String(req.body.password).replace(/\0/g, '')
this.output.debug(`clientId: ${clientId}, username: ${username}, password: ${password}`)
const user = await User.findOne({ uid: username, active: true }) const user = await User.findOne({ uid: username, active: true })
if ( !user ) { if ( !user ) {

View File

@ -12,6 +12,38 @@ class RadiusUnit extends Unit {
return [...super.services, 'configs', 'output', 'models'] return [...super.services, 'configs', 'output', 'models']
} }
getPacketDecoder() {
const RadiusClient = this.models.get('radius:Client')
return async (msg) => {
const clients = await RadiusClient.find({ active: true })
// Try the secrets for all active clients.
// If we can successfully decode the packet with a client's secret, then we know
// that the message came from that client.
let authenticatedClient
let packet
for ( const client of clients ) {
try {
packet = radius.decode({ packet: msg, secret: client.secret })
authenticatedClient = client
break
} catch (e) {}
}
packet.credentialMiddleware = (username, password) => {
this.output.debug(`Called credential middleware: ${username}`)
return [`${username}@${authenticatedClient.id}`, password]
}
return {
packet,
secret: authenticatedClient.secret || '',
}
}
}
async go(app) { async go(app) {
if ( !(await this.port_free()) ) { if ( !(await this.port_free()) ) {
this.output.info('RADIUS server port is in use. Will not start!') this.output.info('RADIUS server port is in use. Will not start!')
@ -19,15 +51,27 @@ class RadiusUnit extends Unit {
} }
const config = this.getConfig() const config = this.getConfig()
const packageInterface = require('@coreid/radius-server/dist/interface').default.get()
packageInterface.setConfig(config)
packageInterface.packetDecoder = this.getPacketDecoder()
packageInterface.log = (...any) => any.forEach(x => this.output.info(x))
const { RadiusServer } = require('@coreid/radius-server/dist/radius/RadiusServer')
const server = RadiusServer.get()
await server.up()
this.output.success('Started RADIUS server!')
// await packageInterface.up()
// Overwrite radius-server's global config object with the user-provided values // Overwrite radius-server's global config object with the user-provided values
const radiusConfig = require('radius-server/config') /*const radiusConfig = require('radius-server/config')
for ( const key in config ) { for ( const key in config ) {
if ( !Object.hasOwnProperty.apply(config, [key]) ) continue if ( !Object.hasOwnProperty.apply(config, [key]) ) continue
radiusConfig[key] = config[key] radiusConfig[key] = config[key]
} }*/
const { Authentication } = require('radius-server/dist/auth') /*const { Authentication } = require('radius-server/dist/auth')
const { UDPServer } = require('radius-server/dist/server/UDPServer') const { UDPServer } = require('radius-server/dist/server/UDPServer')
const { RadiusService } = require('radius-server/dist/radius/RadiusService') const { RadiusService } = require('radius-server/dist/radius/RadiusService')
@ -65,15 +109,21 @@ class RadiusUnit extends Unit {
// Start the radius server // Start the radius server
await this.server.start() await this.server.start()
this.output.success('Started RADIUS server!') this.output.success('Started RADIUS server!')*/
} }
async cleanup(app) { async cleanup(app) {
if ( this.server ) { const { RadiusServer } = require('@coreid/radius-server/dist/radius/RadiusServer')
const server = RadiusServer.get()
await server.down()
// const packageInterface = require('@coreid/radius-server/dist/interface').get()
// await packageInterface.down()
/*if ( this.server ) {
// radius-server doesn't expose a "close" method explicitly, which is annoying // radius-server doesn't expose a "close" method explicitly, which is annoying
// instead, reach in and close the internal UDP socket // instead, reach in and close the internal UDP socket
this.server.server.close() this.server.server.close()
} }*/
} }
/** /**
@ -92,7 +142,7 @@ class RadiusUnit extends Unit {
let packet let packet
for ( const client of clients ) { for ( const client of clients ) {
try { try {
packet = radius.decode({ packet: msg, secret: client.secret }) packet = radius.decode({ packet: msg, secret: this.getConfig().secret /*client.secret*/ })
authenticatedClient = client authenticatedClient = client
break break
} catch (e) {} } catch (e) {}
@ -107,12 +157,14 @@ class RadiusUnit extends Unit {
// This allows us to check IAM access in the controller // This allows us to check IAM access in the controller
packet.attributes['User-Name'] = `${packet.attributes['User-Name']}@${authenticatedClient.id}` packet.attributes['User-Name'] = `${packet.attributes['User-Name']}@${authenticatedClient.id}`
this.output.info(`RADIUS auth attempt: ${packet.attributes['User-Name']}`) this.output.info(`RADIUS auth attempt: ${packet.attributes['User-Name']}`)
this.output.debug(packet)
const response = await this.radiusService.packetHandler.handlePacket(packet) const response = await this.radiusService.packetHandler.handlePacket(packet)
// still no response, we are done here // still no response, we are done here
if (!response || !response.code) { if (!response || !response.code) {
this.output.debug(`RADIUS error: no response / response code`) this.output.debug(`RADIUS error: no response / response code`)
this.output.debug(response)
return return
} }
@ -121,7 +173,7 @@ class RadiusUnit extends Unit {
data: radius.encode_response({ data: radius.encode_response({
packet, packet,
code: response.code, code: response.code,
secret: authenticatedClient.secret, // use the client's secret to encode the response secret: this.getConfig().secret, // authenticatedClient.secret, // use the client's secret to encode the response
attributes: response.attributes, attributes: response.attributes,
}), }),
@ -150,7 +202,7 @@ class RadiusUnit extends Unit {
const config = { const config = {
port: this.configs.get('radius.port', 1812), port: this.configs.get('radius.port', 1812),
secret: uuid(), // this is never used - client-specific secrets are injected instead secret: 'testing123', // uuid(), // this is never used - client-specific secrets are injected instead
certificate: { certificate: {
cert: fs.readFileSync(this.configs.get('radius.cert_file.public')), cert: fs.readFileSync(this.configs.get('radius.cert_file.public')),
key: [ key: [

View File

@ -16,6 +16,7 @@
"author": "Garrett Mills <garrett@glmdev.tech> (https://garrettmills.dev/)", "author": "Garrett Mills <garrett@glmdev.tech> (https://garrettmills.dev/)",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@coreid/radius-server": "^1.2.6",
"bullmq": "^1.8.8", "bullmq": "^1.8.8",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"flitter-auth": "^0.19.6", "flitter-auth": "^0.19.6",
@ -40,7 +41,6 @@
"oidc-provider": "^6.29.0", "oidc-provider": "^6.29.0",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"radius": "^1.1.4", "radius": "^1.1.4",
"radius-server": "^1.2.0",
"samlp": "^3.4.1", "samlp": "^3.4.1",
"speakeasy": "^2.0.0", "speakeasy": "^2.0.0",
"uuid": "^8.3.0", "uuid": "^8.3.0",

View File

@ -182,7 +182,24 @@
lodash "^4.17.13" lodash "^4.17.13"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@hokify/node-ts-cache@^5.4.1": "@coreid/radius-server@^1.2.6":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@coreid/radius-server/-/radius-server-1.2.6.tgz#51914c20740a5ba7a3eed36deb67f3def4e69ced"
integrity sha512-oYmEytDUf1uiTd+pnqHlODXoz/ybjkPZpEjUmB9gjF/DQ/PwwiUDtRXfRLD6fjkY58Z4y4LF4YXDilAgSnPWlA==
dependencies:
"@hokify/node-ts-cache" "^5.5.1"
axios "^0.21.1"
debug "^4.3.1"
imap-simple "^5.0.0"
ldapauth-fork "^5.0.1"
ldapjs "^2.3.0"
native-duplexpair "^1.0.0"
node-cache "^5.1.2"
radius "~1.1.4"
smtp-client "^0.4.0"
yargs "~17.0.1"
"@hokify/node-ts-cache@^5.5.1":
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/@hokify/node-ts-cache/-/node-ts-cache-5.6.0.tgz#47a7b9f2be426c03f1c1d92adcecfda06e3fa60c" resolved "https://registry.yarnpkg.com/@hokify/node-ts-cache/-/node-ts-cache-5.6.0.tgz#47a7b9f2be426c03f1c1d92adcecfda06e3fa60c"
integrity sha512-VdjeFjLAT9gGrRlzjZsMeY9ZWJyfz8y8ODeZsUdSnDdwxqb0keZNAtS3PMswBzSECBfNV1RT+NGiC8j6P1Cv6w== integrity sha512-VdjeFjLAT9gGrRlzjZsMeY9ZWJyfz8y8ODeZsUdSnDdwxqb0keZNAtS3PMswBzSECBfNV1RT+NGiC8j6P1Cv6w==
@ -3310,7 +3327,7 @@ ldapjs@^1.0.2:
optionalDependencies: optionalDependencies:
dtrace-provider "~0.8" dtrace-provider "~0.8"
ldapjs@^2.2.1, ldapjs@^2.2.3: ldapjs@^2.2.1, ldapjs@^2.3.0:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-2.3.1.tgz#04136815fb1f21d692ac87fab5961a04d86e8b04" resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-2.3.1.tgz#04136815fb1f21d692ac87fab5961a04d86e8b04"
integrity sha512-kf0tHHLrpwKaBAQOhYHXgdeh2PkFuCCxWgLb1MRn67ZQVo787D2pij3mmHVZx193GIdM8xcfi8HF6AIYYnj0fQ== integrity sha512-kf0tHHLrpwKaBAQOhYHXgdeh2PkFuCCxWgLb1MRn67ZQVo787D2pij3mmHVZx193GIdM8xcfi8HF6AIYYnj0fQ==
@ -4576,23 +4593,6 @@ quoted-printable@^1.0.0:
dependencies: dependencies:
utf8 "^2.1.0" utf8 "^2.1.0"
radius-server@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/radius-server/-/radius-server-1.2.0.tgz#74d5932b66906c0b5ea7763bb11bb1c6a6a219e6"
integrity sha512-JRscm5uafissZMgJYFOemiUjnwpmIWEjVAL0O/tn9Fiy2mqPAX+xVKqWEopu2BZ7NZzHScqlQnVomLyzyHk08Q==
dependencies:
"@hokify/node-ts-cache" "^5.4.1"
axios "^0.21.1"
debug "^4.3.1"
imap-simple "^5.0.0"
ldapauth-fork "^5.0.1"
ldapjs "^2.2.3"
native-duplexpair "^1.0.0"
node-cache "^5.1.2"
radius "~1.1.4"
smtp-client "^0.3.3"
yargs "~16.2.0"
radius@^1.1.4, radius@~1.1.4: radius@^1.1.4, radius@~1.1.4:
version "1.1.4" version "1.1.4"
resolved "https://registry.yarnpkg.com/radius/-/radius-1.1.4.tgz#3ce58d18a497d615618bc7d9286464ebecb50cb5" resolved "https://registry.yarnpkg.com/radius/-/radius-1.1.4.tgz#3ce58d18a497d615618bc7d9286464ebecb50cb5"
@ -5136,10 +5136,10 @@ smtp-channel@0.2.3:
line-buffer "^0.1.4" line-buffer "^0.1.4"
promised-timeout "^0.2.0" promised-timeout "^0.2.0"
smtp-client@^0.3.3: smtp-client@^0.4.0:
version "0.3.3" version "0.4.0"
resolved "https://registry.yarnpkg.com/smtp-client/-/smtp-client-0.3.3.tgz#54f5211b5613f86cb801892e298c53f60cdde515" resolved "https://registry.yarnpkg.com/smtp-client/-/smtp-client-0.4.0.tgz#2015da1f4d9821e67bf22ced01568b027d305245"
integrity sha512-bneg34/4sug5MAVROUaOgQFEEDQDcmv5qXa/E9mDdwjV9jOvexidMzGH9jR1cgQCsFh1yWrVToY0MCWvoVwWSA== integrity sha512-TvxdX02b96hN6732TGkXcXHsaTeXgVMXjdAhYzz/pLGE6V1p/5jh1XYJa/PfE+O21jHLmwHYWVP3c7JNFWwmOg==
dependencies: dependencies:
promised-timeout "0.5.1" promised-timeout "0.5.1"
smtp-channel "0.2.3" smtp-channel "0.2.3"
@ -5977,10 +5977,10 @@ yargs@^15.0.2:
y18n "^4.0.0" y18n "^4.0.0"
yargs-parser "^18.1.1" yargs-parser "^18.1.1"
yargs@~16.2.0: yargs@~17.0.1:
version "16.2.0" version "17.0.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==
dependencies: dependencies:
cliui "^7.0.2" cliui "^7.0.2"
escalade "^3.1.1" escalade "^3.1.1"