971 lines
28 KiB
JavaScript
Executable File
971 lines
28 KiB
JavaScript
Executable File
var testCase = require('nodeunit').testCase;
|
|
var radius = require('../lib/radius');
|
|
var fs = require('fs');
|
|
var crypto = require('crypto');
|
|
|
|
var secret;
|
|
|
|
var test_args = {};
|
|
|
|
module.exports = testCase({
|
|
setUp: function(callback) {
|
|
secret = "nearbuy";
|
|
callback();
|
|
},
|
|
tearDown: function(callback) {
|
|
radius.unload_dictionaries();
|
|
callback();
|
|
},
|
|
|
|
test_decode_mac_auth: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/aruba_mac_auth.packet');
|
|
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.aruba');
|
|
|
|
var decoded = radius.decode({ packet: raw_packet, secret: secret });
|
|
|
|
test.equal( decoded.code, 'Access-Request' );
|
|
test.equal( decoded.identifier, 58 );
|
|
test.equal( decoded.length, 208 );
|
|
|
|
var expected_attrs = {
|
|
'NAS-IP-Address': '10.0.0.90',
|
|
'NAS-Port': 0,
|
|
'NAS-Port-Type': 'Wireless-802.11',
|
|
'User-Name': '7c:c5:37:ff:f8:af',
|
|
'User-Password': '7c:c5:37:ff:f8:af',
|
|
'Calling-Station-Id': '7CC537FFF8AF',
|
|
'Called-Station-Id': '000B86F02068',
|
|
'Service-Type': 'Login-User',
|
|
'Vendor-Specific': {
|
|
'Aruba-Essid-Name': 'muir-aruba-guest',
|
|
'Aruba-Location-Id': '00:1a:1e:c6:b0:ca',
|
|
'Aruba-AP-Group': 'cloud-cp'
|
|
},
|
|
'Message-Authenticator': new Buffer('f8a12329c7ed5a6e2568515243efb918', 'hex')
|
|
};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_decode_mac_auth_without_secret: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/aruba_mac_auth.packet');
|
|
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.aruba');
|
|
|
|
var decoded = radius.decode_without_secret({ packet: raw_packet });
|
|
|
|
test.equal( decoded.code, 'Access-Request' );
|
|
test.equal( decoded.identifier, 58 );
|
|
test.equal( decoded.length, 208 );
|
|
|
|
var expected_attrs = {
|
|
'NAS-IP-Address': '10.0.0.90',
|
|
'NAS-Port': 0,
|
|
'NAS-Port-Type': 'Wireless-802.11',
|
|
'User-Name': '7c:c5:37:ff:f8:af',
|
|
'User-Password': null, // this is an encrypted field, and so cannot be read without the password
|
|
'Calling-Station-Id': '7CC537FFF8AF',
|
|
'Called-Station-Id': '000B86F02068',
|
|
'Service-Type': 'Login-User',
|
|
'Vendor-Specific': {
|
|
'Aruba-Essid-Name': 'muir-aruba-guest',
|
|
'Aruba-Location-Id': '00:1a:1e:c6:b0:ca',
|
|
'Aruba-AP-Group': 'cloud-cp'
|
|
},
|
|
'Message-Authenticator': new Buffer('f8a12329c7ed5a6e2568515243efb918', 'hex')
|
|
};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
secret: secret,
|
|
code: "Access-Request",
|
|
attributes: {
|
|
'User-Name': 'Caenogaean-asphyxia',
|
|
'User-Password': 'barratry-Wertherism'
|
|
}
|
|
})
|
|
});
|
|
|
|
test.equal( decoded.attributes['User-Password'], 'barratry-Wertherism' );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// make sure everthing is fine with no dictionaries
|
|
test_decode_no_dicts: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/aruba_mac_auth.packet');
|
|
|
|
radius.unload_dictionaries();
|
|
var orig_load = radius.load_dictionary;
|
|
radius.load_dictionary = function() { };
|
|
|
|
var decoded = radius.decode({ packet: raw_packet, secret: secret });
|
|
|
|
test.equal( decoded.code, 'Access-Request' );
|
|
test.equal( decoded.identifier, 58 );
|
|
test.equal( decoded.length, 208 );
|
|
|
|
// no pretty attributes
|
|
test.deepEqual( decoded.attributes, {} );
|
|
|
|
var expected_raw_attrs = [
|
|
[4, new Buffer([10, 0, 0, 90])],
|
|
[5, new Buffer([0, 0, 0, 0])],
|
|
[61, new Buffer([0, 0, 0, 19])],
|
|
[1, new Buffer('7c:c5:37:ff:f8:af')],
|
|
[2, new Buffer('eb2ef7e83ec1a05e04fb5c6d91e088569a990fa2b1b2dc6a0f048596081164cd', 'hex')],
|
|
[31, new Buffer('7CC537FFF8AF')],
|
|
[30, new Buffer('000B86F02068')],
|
|
[6, new Buffer([0, 0, 0, 1])],
|
|
[26, new Buffer('000039e705126d7569722d61727562612d6775657374', 'hex')],
|
|
[26, new Buffer('000039e7061330303a31613a31653a63363a62303a6361', 'hex')],
|
|
[26, new Buffer('000039e70a0a636c6f75642d6370', 'hex')],
|
|
[80, new Buffer('f8a12329c7ed5a6e2568515243efb918', 'hex')]
|
|
];
|
|
|
|
test.deepEqual( decoded.raw_attributes, expected_raw_attrs );
|
|
|
|
radius.load_dictionary = orig_load;
|
|
|
|
test.done();
|
|
},
|
|
|
|
// can make a "naked" packet
|
|
test_encode_access_request: function(test) {
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.aruba');
|
|
|
|
var attributes = [
|
|
['User-Name', 'ornithopter-aliptic'],
|
|
['User-Password', 'nucleohistone-overwilily'],
|
|
['Service-Type', 'Login-User'],
|
|
['NAS-IP-Address', '169.134.68.136'],
|
|
|
|
['Vendor-Specific', 14823, [
|
|
['Aruba-User-Role', 'cracked-tylote'],
|
|
[2, 825]
|
|
]],
|
|
['Vendor-Specific', 14823, [['Aruba-Essid-Name', 'phene-dentinalgia']]]
|
|
];
|
|
var packet = radius.encode({
|
|
code: 'Access-Request',
|
|
identifier: 123,
|
|
attributes: attributes,
|
|
secret: secret
|
|
});
|
|
|
|
var decoded = radius.decode({ packet: packet, secret: secret });
|
|
test.equal( decoded.code, 'Access-Request' );
|
|
test.equal( decoded.identifier, 123 );
|
|
|
|
var expected_attrs = {
|
|
'User-Name': 'ornithopter-aliptic',
|
|
'User-Password': 'nucleohistone-overwilily',
|
|
'Service-Type': 'Login-User',
|
|
'NAS-IP-Address': '169.134.68.136',
|
|
'Vendor-Specific': {
|
|
'Aruba-User-Role': 'cracked-tylote',
|
|
'Aruba-User-Vlan': 825,
|
|
'Aruba-Essid-Name': 'phene-dentinalgia'
|
|
}
|
|
};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_decode_hash_attributes: function(test) {
|
|
var attrs = {
|
|
'User-Name': 'ornithopter-aliptic',
|
|
'User-Password': 'nucleohistone-overwilily',
|
|
'Service-Type': 'Login-User',
|
|
'NAS-IP-Address': '169.134.68.136'
|
|
};
|
|
var packet = radius.encode({
|
|
code: 'Access-Request',
|
|
identifier: 123,
|
|
attributes: attrs,
|
|
secret: secret
|
|
});
|
|
|
|
var decoded = radius.decode({ packet: packet, secret: secret });
|
|
test.equal( decoded.code, 'Access-Request' );
|
|
test.equal( decoded.identifier, 123 );
|
|
test.deepEqual( decoded.attributes, attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_throws_on_nested_hash_attributes: function(test) {
|
|
var attrs = {
|
|
'User-Name': 'ornithopter-aliptic',
|
|
'User-Password': 'nucleohistone-overwilily',
|
|
'Service-Type': 'Login-User',
|
|
'NAS-IP-Address': '169.134.68.136',
|
|
'Vendor-Specific': {
|
|
'Aruba-User-Role': 'cracked-tylote',
|
|
'Aruba-User-Vlan': 825,
|
|
'Aruba-Essid-Name': 'phene-dentinalgia'
|
|
}
|
|
};
|
|
|
|
test.throws(function() {
|
|
var packet = radius.encode({
|
|
code: 'Access-Request',
|
|
identifier: 123,
|
|
attributes: attrs,
|
|
secret: secret
|
|
});
|
|
});
|
|
test.done();
|
|
},
|
|
|
|
// test that our encoded packet matches bit-for-bit with a "real"
|
|
// RADIUS packet
|
|
test_encode_bit_for_bit: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/aruba_mac_auth.packet');
|
|
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.aruba');
|
|
|
|
var encoded = radius.encode({
|
|
code: 'Access-Request',
|
|
identifier: 58,
|
|
authenticator: new Buffer('4a45fae086d9e114286b37b5f371ec6c', 'hex'),
|
|
attributes: [
|
|
['NAS-IP-Address', '10.0.0.90'],
|
|
['NAS-Port', 0],
|
|
['NAS-Port-Type', 'Wireless-802.11'],
|
|
['User-Name', '7c:c5:37:ff:f8:af'],
|
|
['User-Password', '7c:c5:37:ff:f8:af'],
|
|
['Calling-Station-Id', '7CC537FFF8AF'],
|
|
['Called-Station-Id', '000B86F02068'],
|
|
['Service-Type', 'Login-User'],
|
|
['Vendor-Specific', 14823, [['Aruba-Essid-Name', 'muir-aruba-guest']]],
|
|
['Vendor-Specific', 14823, [['Aruba-Location-Id', '00:1a:1e:c6:b0:ca']]],
|
|
['Vendor-Specific', 14823, [['Aruba-AP-Group', 'cloud-cp']]]
|
|
],
|
|
secret: secret,
|
|
add_message_authenticator: true
|
|
});
|
|
|
|
test.equal( encoded.toString('hex'), raw_packet.toString('hex') );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// encode will choose a random identifier for you if you don't provide one
|
|
test_encode_random_identifer: function(test) {
|
|
var decoded = radius.decode({
|
|
packet: radius.encode({
|
|
code: 'Access-Request',
|
|
secret: secret
|
|
}),
|
|
secret: secret
|
|
});
|
|
test.ok( decoded.identifier >= 0 && decoded.identifier < 256 );
|
|
|
|
var starting_id = decoded.identifier;
|
|
|
|
// if you are unlucky this is an infinite loop
|
|
while (true) {
|
|
decoded = radius.decode({
|
|
packet: radius.encode({
|
|
code: 'Access-Request',
|
|
secret: secret
|
|
}),
|
|
secret: secret
|
|
});
|
|
if (decoded.identifier != starting_id)
|
|
break;
|
|
}
|
|
|
|
test.ok( true );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// given a previously decoded packet, prepare a response packet
|
|
test_packet_response: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/cisco_mac_auth.packet');
|
|
|
|
var decoded = radius.decode({ packet: raw_packet, secret: secret });
|
|
|
|
var response = radius.encode_response({
|
|
packet: decoded,
|
|
code: 'Access-Reject',
|
|
secret: secret
|
|
});
|
|
|
|
var raw_response = fs.readFileSync(__dirname + '/captures/cisco_mac_auth_reject.packet');
|
|
test.equal( response.toString('hex'), raw_response.toString('hex') );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// response needs to include proxy state
|
|
test_response_include_proxy_state: function(test) {
|
|
var request_with_proxy = radius.decode({
|
|
packet: radius.encode({
|
|
code: 'Access-Request',
|
|
secret: secret,
|
|
attributes: [
|
|
['User-Name', 'ascribe-despairer'],
|
|
['Proxy-State', new Buffer('womanhouse-Pseudotsuga')],
|
|
['User-Password', 'ridiculous'],
|
|
['Proxy-State', new Buffer('regretfully-unstability')]
|
|
]
|
|
}),
|
|
secret: secret
|
|
});
|
|
|
|
var decoded_response = radius.decode({
|
|
packet: radius.encode_response({
|
|
packet: request_with_proxy,
|
|
code: 'Access-Reject',
|
|
secret: secret
|
|
}),
|
|
secret: secret
|
|
});
|
|
|
|
var expected_raw_attributes = [
|
|
[radius.attr_name_to_id('Proxy-State'), new Buffer('womanhouse-Pseudotsuga')],
|
|
[radius.attr_name_to_id('Proxy-State'), new Buffer('regretfully-unstability')]
|
|
];
|
|
|
|
test.deepEqual( decoded_response.raw_attributes, expected_raw_attributes );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// dont accidentally strip null bytes when encoding
|
|
test_password_encode: function(test) {
|
|
var decoded = radius.decode({
|
|
packet: radius.encode({
|
|
code: 'Access-Request',
|
|
authenticator: new Buffer('426edca213c1bf6e005e90a64105ca3a', 'hex'),
|
|
attributes: [['User-Password', 'ridiculous']],
|
|
secret: secret
|
|
}),
|
|
secret: secret
|
|
});
|
|
|
|
test.equal( decoded.attributes['User-Password'], 'ridiculous' );
|
|
|
|
test.done();
|
|
},
|
|
|
|
accounting_group: {
|
|
setUp: function(cb) {
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.airespace');
|
|
|
|
test_args = {};
|
|
test_args.raw_acct_request = fs.readFileSync(__dirname + '/captures/cisco_accounting.packet');
|
|
test_args.expected_acct_attrs = {
|
|
'User-Name': 'user_7C:C5:37:FF:F8:AF_134',
|
|
'NAS-Port': 1,
|
|
'NAS-IP-Address': '10.0.3.4',
|
|
'Framed-IP-Address': '10.2.0.252',
|
|
'NAS-Identifier': 'Cisco 4400 (Anchor)',
|
|
'Vendor-Specific': {
|
|
'Airespace-Wlan-Id': 2
|
|
},
|
|
'Acct-Session-Id': '4fecc41e/7c:c5:37:ff:f8:af/9',
|
|
'Acct-Authentic': 'RADIUS',
|
|
'Tunnel-Type': [0x00, 'VLAN'],
|
|
'Tunnel-Medium-Type': [0x00, 'IEEE-802'],
|
|
'Tunnel-Private-Group-Id': 5,
|
|
'Acct-Status-Type': 'Start',
|
|
'Calling-Station-Id': '7c:c5:37:ff:f8:af',
|
|
'Called-Station-Id': '00:22:55:90:39:60'
|
|
};
|
|
cb();
|
|
},
|
|
|
|
test_accounting: function(test) {
|
|
var raw_acct_request = test_args.raw_acct_request;
|
|
var decoded = radius.decode({ packet: raw_acct_request, secret: secret });
|
|
|
|
var expected_attrs = test_args.expected_acct_attrs;
|
|
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
// test we can encode the same packet
|
|
var encoded = radius.encode({
|
|
code: 'Accounting-Request',
|
|
identifier: decoded.identifier,
|
|
secret: secret,
|
|
attributes: [
|
|
['User-Name', 'user_7C:C5:37:FF:F8:AF_134'],
|
|
['NAS-Port', 1],
|
|
['NAS-IP-Address', '10.0.3.4'],
|
|
['Framed-IP-Address', '10.2.0.252'],
|
|
['NAS-Identifier', 'Cisco 4400 (Anchor)'],
|
|
['Vendor-Specific', 'Airespace', [['Airespace-Wlan-Id', 2]]],
|
|
['Acct-Session-Id', '4fecc41e/7c:c5:37:ff:f8:af/9'],
|
|
['Acct-Authentic', 'RADIUS'],
|
|
['Tunnel-Type', 0x00, 'VLAN'],
|
|
['Tunnel-Medium-Type', 0x00, 'IEEE-802'],
|
|
['Tunnel-Private-Group-Id', '5'],
|
|
['Acct-Status-Type', 'Start'],
|
|
['Calling-Station-Id', '7c:c5:37:ff:f8:af'],
|
|
['Called-Station-Id', '00:22:55:90:39:60']
|
|
]
|
|
});
|
|
test.equal( encoded.toString('hex'), raw_acct_request.toString('hex') );
|
|
|
|
var raw_acct_response = fs.readFileSync(__dirname +
|
|
'/captures/cisco_accounting_response.packet');
|
|
encoded = radius.encode_response({
|
|
packet: decoded,
|
|
secret: secret,
|
|
code: 'Accounting-Response'
|
|
});
|
|
test.equal( encoded.toString('hex'), raw_acct_response.toString('hex') );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_invalid_accounting_packet_authenticator: function(test) {
|
|
var raw_acct_request = test_args.raw_acct_request;
|
|
var expected_attrs = test_args.expected_acct_attrs;
|
|
|
|
// detect invalid accounting packets
|
|
test.throws( function() {
|
|
radius.decode({ packet: raw_acct_request, secret: 'not-secret' });
|
|
} );
|
|
|
|
try {
|
|
radius.decode({ packet: raw_acct_request, secret: 'not-secret' });
|
|
} catch (err) {
|
|
test.deepEqual( err.decoded.attributes, expected_attrs );
|
|
}
|
|
test.done();
|
|
}
|
|
},
|
|
|
|
test_no_empty_strings: function(test) {
|
|
var decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
code: 'Access-Request',
|
|
attributes: [['User-Name', '']],
|
|
secret: secret
|
|
})
|
|
});
|
|
|
|
// don't send empty strings (see RFC2865)
|
|
test.deepEqual( decoded.attributes, {} );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_repeated_attribute: function(test) {
|
|
var decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
secret: secret,
|
|
code: 'Access-Reject',
|
|
attributes: [
|
|
['Reply-Message', 'message one'],
|
|
['Reply-Message', 'message two']
|
|
]
|
|
})
|
|
});
|
|
|
|
var expected_attrs = {
|
|
'Reply-Message': ['message one', 'message two']
|
|
};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_dictionary_include: function(test) {
|
|
radius.unload_dictionaries();
|
|
radius.add_dictionary(__dirname + '/dictionaries/dictionary.test1');
|
|
|
|
var decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
secret: secret,
|
|
code: 'Access-Request',
|
|
attributes: [['Attribute-Test1', 'foo'], ['Attribute-Test2', 'bar']]
|
|
})
|
|
});
|
|
|
|
var expected_attrs = {
|
|
'Attribute-Test1': 'foo',
|
|
'Attribute-Test2': 'bar'
|
|
};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// make sure we can load the dicts in any order
|
|
test_dictionary_out_of_order: function(test) {
|
|
var dicts = fs.readdirSync(__dirname + '/../dictionaries');
|
|
|
|
// make sure we can load any dictionary first
|
|
for (var i = 0; i < dicts.length; i++) {
|
|
radius.unload_dictionaries();
|
|
radius.load_dictionary(__dirname + '/../dictionaries/' + dicts[i]);
|
|
}
|
|
|
|
// and spot check things actually work loaded out of order
|
|
radius.unload_dictionaries();
|
|
radius.load_dictionary(__dirname + '/../dictionaries/dictionary.rfc2867');
|
|
radius.load_dictionary(__dirname + '/../dictionaries/dictionary.rfc2866');
|
|
|
|
var decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
code: 'Accounting-Request',
|
|
secret: secret,
|
|
attributes: [
|
|
['Acct-Status-Type', 'Tunnel-Reject']
|
|
]
|
|
})
|
|
});
|
|
|
|
test.equal( decoded.attributes['Acct-Status-Type'], 'Tunnel-Reject' );
|
|
|
|
radius.unload_dictionaries();
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.test_tunnel_type');
|
|
radius.load_dictionaries();
|
|
|
|
decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
code: 'Accounting-Request',
|
|
secret: secret,
|
|
attributes: [
|
|
['Tunnel-Type', 0x00, 'TESTTUNNEL']
|
|
]
|
|
})
|
|
});
|
|
|
|
var expected_attrs = {'Tunnel-Type': [0x00, 'TESTTUNNEL']};
|
|
test.deepEqual( decoded.attributes, expected_attrs );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_zero_identifer: function(test) {
|
|
var decoded = radius.decode({
|
|
packet: radius.encode({
|
|
secret: secret,
|
|
code: 'Access-Request',
|
|
identifier: 0
|
|
}),
|
|
secret: secret
|
|
});
|
|
|
|
test.equal( decoded.identifier, 0 );
|
|
test.done();
|
|
},
|
|
|
|
test_date_type: function(test) {
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/motorola_accounting.packet');
|
|
|
|
var decoded = radius.decode({
|
|
packet: raw_packet,
|
|
secret: secret
|
|
});
|
|
|
|
var epoch = 1349879753;
|
|
|
|
test.equal( decoded.attributes['Event-Timestamp'].getTime(), epoch * 1000 );
|
|
|
|
var encoded = radius.encode({
|
|
code: 'Accounting-Request',
|
|
identifier: decoded.identifier,
|
|
attributes: [
|
|
['User-Name', '00-1F-3B-8C-3A-15'],
|
|
['Acct-Status-Type', 'Start'],
|
|
['Acct-Session-Id', '1970D5A4-001F3B8C3A15-0000000001'],
|
|
['Calling-Station-Id', '00-1F-3B-8C-3A-15'],
|
|
['Called-Station-Id', 'B4-C7-99-77-59-D0:muir-moto-guest-site1'],
|
|
['NAS-Port', 1],
|
|
['NAS-Port-Type', 'Wireless-802.11'],
|
|
['NAS-IP-Address', '10.2.0.3'],
|
|
['NAS-Identifier', 'ap6532-70D5A4'],
|
|
['NAS-Port-Id', 'radio2'],
|
|
['Event-Timestamp', new Date(epoch * 1000)],
|
|
['Tunnel-Type', 0x00, 'VLAN' ],
|
|
['Tunnel-Medium-Type', 0x00, 'IEEE-802'],
|
|
['Tunnel-Private-Group-Id', '30'],
|
|
['Acct-Authentic', 'RADIUS']
|
|
],
|
|
secret: secret
|
|
});
|
|
|
|
test.equal( encoded.toString('hex'), raw_packet.toString('hex') );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_date_type_non_mult_1000_ms: function(test) {
|
|
var encoded;
|
|
test.doesNotThrow(function() {
|
|
encoded = radius.encode({
|
|
code: 'Accounting-Request',
|
|
identifier: 123,
|
|
attributes: [
|
|
['Event-Timestamp', new Date(1403025894009)]
|
|
],
|
|
secret: secret
|
|
});
|
|
});
|
|
|
|
// truncates ms
|
|
var decoded = radius.decode({ packet: encoded, secret: secret });
|
|
test.equal( decoded.attributes['Event-Timestamp'].getTime(), 1403025894000 );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_disconnect_request: function(test) {
|
|
var encoded = radius.encode({
|
|
code: 'Disconnect-Request',
|
|
identifier: 54,
|
|
secret: secret,
|
|
attributes: [
|
|
['User-Name', 'mariticide-inquietation'],
|
|
['NAS-Identifier', 'Aglauros-charioted']
|
|
]
|
|
});
|
|
|
|
// check we did the non-user-password authenticator
|
|
var got_authenticator = new Buffer(16);
|
|
encoded.copy(got_authenticator, 0, 4);
|
|
encoded.fill(0, 4, 20);
|
|
|
|
var expected_authenticator = new Buffer(16);
|
|
var hasher = crypto.createHash("md5");
|
|
hasher.update(encoded);
|
|
hasher.update(secret);
|
|
expected_authenticator.write(hasher.digest("binary"), 0, 16, "binary");
|
|
|
|
test.equal( got_authenticator.toString('hex'), expected_authenticator.toString('hex') );
|
|
|
|
// and make sure we check the authenticator when decoding
|
|
test.throws(function() {
|
|
radius.decode({
|
|
packet: encoded,
|
|
secret: secret
|
|
});
|
|
});
|
|
|
|
expected_authenticator.copy(encoded, 4, 0);
|
|
test.doesNotThrow(function() {
|
|
radius.decode({
|
|
packet: encoded,
|
|
secret: secret
|
|
});
|
|
});
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_verify_response: function(test) {
|
|
var request = radius.encode({
|
|
secret: secret,
|
|
code: 'Accounting-Request',
|
|
attributes: {
|
|
'User-Name': '00-1F-3B-8C-3A-15',
|
|
'Acct-Status-Type': 'Start'
|
|
}
|
|
});
|
|
|
|
var response = radius.encode_response({
|
|
secret: secret,
|
|
code: 'Accounting-Response',
|
|
packet: radius.decode({ packet: request, secret: secret })
|
|
});
|
|
|
|
test.ok( radius.verify_response({
|
|
request: request,
|
|
response: response,
|
|
secret: secret
|
|
}) );
|
|
|
|
test.ok( !radius.verify_response({
|
|
request: request,
|
|
response: response,
|
|
secret: "Calliopsis-misbeholden"
|
|
}) );
|
|
|
|
// response encoded with wrong secret
|
|
response = radius.encode_response({
|
|
secret: "moyenne-paraboliform",
|
|
code: 'Accounting-Response',
|
|
packet: radius.decode({ packet: request, secret: secret })
|
|
});
|
|
test.ok( !radius.verify_response({
|
|
request: request,
|
|
response: response,
|
|
secret: secret
|
|
}) );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_server_request: function(test) {
|
|
var encoded1 = radius.encode({
|
|
code: 'Status-Server',
|
|
identifier: 54,
|
|
secret: secret,
|
|
attributes: [
|
|
['NAS-Identifier', 'symphilism-dicentrine']
|
|
]
|
|
});
|
|
|
|
var encoded2 = radius.encode({
|
|
code: 'Status-Server',
|
|
identifier: 54,
|
|
secret: secret,
|
|
attributes: [
|
|
['NAS-Identifier', 'symphilism-dicentrine']
|
|
]
|
|
});
|
|
|
|
// check we are doing a random authenticator
|
|
var got_authenticator1 = new Buffer(16);
|
|
encoded1.copy(got_authenticator1, 0, 4);
|
|
|
|
var got_authenticator2 = new Buffer(16);
|
|
encoded2.copy(got_authenticator2, 0, 4);
|
|
|
|
test.notEqual( got_authenticator1.toString(), got_authenticator2.toString() );
|
|
|
|
var response = radius.encode_response({
|
|
code: 'Access-Accept',
|
|
secret: secret,
|
|
packet: radius.decode({packet: encoded1, secret: secret})
|
|
});
|
|
|
|
test.ok( radius.verify_response({
|
|
request: encoded1,
|
|
response: response,
|
|
secret: secret
|
|
}) );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_vendor_names_with_numbers: function(test) {
|
|
radius.load_dictionary(__dirname + '/dictionaries/dictionary.number_vendor_name');
|
|
|
|
var encoded = radius.encode({
|
|
code: "Access-Request",
|
|
secret: secret,
|
|
|
|
attributes: [
|
|
['Vendor-Specific', '123Foo', [
|
|
['1Integer', 478],
|
|
['1String', 'Zollernia-fibrovasal'],
|
|
['12345', 'myrmecophagoid-harn']
|
|
]]
|
|
]
|
|
});
|
|
|
|
var decoded = radius.decode({
|
|
packet: encoded,
|
|
secret: secret
|
|
});
|
|
|
|
test.equal( radius.vendor_name_to_id('123Foo'), 995486 );
|
|
|
|
test.deepEqual( decoded.attributes, {
|
|
'Vendor-Specific': {
|
|
'1Integer': 478,
|
|
'1String': 'Zollernia-fibrovasal',
|
|
'12345': 'myrmecophagoid-harn'
|
|
}
|
|
} );
|
|
|
|
test.done();
|
|
},
|
|
|
|
message_authenticator_group: {
|
|
setUp: function(cb) {
|
|
secret = "testing123";
|
|
|
|
test_args = {
|
|
raw_request: fs.readFileSync(__dirname + '/captures/eap_request.packet')
|
|
};
|
|
test_args.parsed_request = radius.decode({
|
|
packet: test_args.raw_request,
|
|
secret: secret
|
|
});
|
|
cb();
|
|
},
|
|
|
|
// make sure we calculate the same Message-Authenticator
|
|
test_calculate: function(test) {
|
|
var attrs_without_ma = test_args.parsed_request.raw_attributes.filter(function(a) {
|
|
return a[0] != radius.attr_name_to_id('Message-Authenticator');
|
|
});
|
|
|
|
var encoded = radius.encode({
|
|
code: test_args.parsed_request.code,
|
|
identifier: test_args.parsed_request.identifier,
|
|
authenticator: test_args.parsed_request.authenticator,
|
|
attributes: attrs_without_ma,
|
|
secret: secret
|
|
});
|
|
|
|
test.equal( encoded.toString('hex'), test_args.raw_request.toString('hex') );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// encode_response should calculate the appropriate Message-Authenticator
|
|
test_encode_response: function(test) {
|
|
var response = radius.encode_response({
|
|
code: "Access-Accept",
|
|
secret: secret,
|
|
packet: test_args.parsed_request
|
|
});
|
|
|
|
var parsed_response = radius.decode({
|
|
packet: response,
|
|
secret: secret
|
|
});
|
|
|
|
// calculate expected Message-Authenticator
|
|
|
|
var empty = new Buffer(16);
|
|
empty.fill(0);
|
|
|
|
var expected_response = radius.encode({
|
|
code: "Access-Accept",
|
|
identifier: test_args.parsed_request.identifier,
|
|
authenticator: test_args.parsed_request.authenticator,
|
|
attributes: [["Message-Authenticator", empty]],
|
|
secret: secret
|
|
});
|
|
|
|
// expected_response's authenticator is correct, but Message-Authenticator is wrong
|
|
// (it's all 0s). make sure verify_response checks both
|
|
test.ok( !radius.verify_response({
|
|
request: test_args.raw_request,
|
|
response: expected_response,
|
|
secret: secret
|
|
}) );
|
|
|
|
// put back the request's authenticator
|
|
test_args.parsed_request.authenticator.copy(expected_response, 4);
|
|
|
|
var expected_ma = radius.calculate_message_authenticator(expected_response, secret);
|
|
test.equal(
|
|
parsed_response.attributes["Message-Authenticator"].toString("hex"),
|
|
expected_ma.toString("hex")
|
|
);
|
|
|
|
test.ok( radius.verify_response({
|
|
request: test_args.raw_request,
|
|
response: response,
|
|
secret: secret
|
|
}) );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// response is missing Message-Authenticator, not okay
|
|
test_response_missing_ma: function(test) {
|
|
var bad_response = radius.encode({
|
|
code: "Access-Accept",
|
|
identifier: test_args.parsed_request.identifier,
|
|
authenticator: test_args.parsed_request.authenticator,
|
|
attributes: [],
|
|
secret: secret
|
|
});
|
|
|
|
test.ok( !radius.verify_response({
|
|
request: test_args.raw_request,
|
|
response: bad_response,
|
|
secret: secret
|
|
}) );
|
|
|
|
test.done();
|
|
},
|
|
|
|
// make sure we verify Message-Authenticator when decoding requests
|
|
test_decode_verify: function(test) {
|
|
test.throws(function() {
|
|
radius.decode({
|
|
packet: test_args.raw_request,
|
|
secret: 'wrong secret'
|
|
});
|
|
});
|
|
|
|
test.done();
|
|
}
|
|
},
|
|
|
|
test_utf8_strings: function(test) {
|
|
var encoded = radius.encode({
|
|
secret: "密码",
|
|
code: "Access-Request",
|
|
attributes: {
|
|
"User-Name": "金庸先生",
|
|
"User-Password": "降龙十八掌"
|
|
}
|
|
});
|
|
|
|
var decoded = radius.decode({
|
|
packet: encoded,
|
|
secret: "密码"
|
|
});
|
|
|
|
test.deepEqual( {
|
|
"User-Name": "金庸先生",
|
|
"User-Password": "降龙十八掌"
|
|
}, decoded.attributes );
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_invalid_packet_attribute_length: function(test) {
|
|
var invalid_packet = fs.readFileSync(__dirname + '/captures/invalid_register.packet');
|
|
var raw_packet = fs.readFileSync(__dirname + '/captures/aruba_mac_auth.packet');
|
|
|
|
// should fail decode packet attributes
|
|
test.throws(function() {
|
|
radius.decode_without_secret({ packet: invalid_packet });
|
|
} );
|
|
|
|
// should decode packet attributes
|
|
test.doesNotThrow(function() {
|
|
radius.decode_without_secret({ packet: raw_packet });
|
|
});
|
|
|
|
test.done();
|
|
},
|
|
|
|
test_tag_fields: function(test) {
|
|
var decoded = radius.decode({
|
|
secret: secret,
|
|
packet: radius.encode({
|
|
code: 'Accounting-Request',
|
|
secret: secret,
|
|
attributes: [
|
|
['Tunnel-Type', 0x01, 'VLAN'],
|
|
['User-Name', 'honeymooner-hitched'],
|
|
]
|
|
})
|
|
});
|
|
|
|
test.deepEqual( {
|
|
'Tunnel-Type': [ 1, 'VLAN'],
|
|
'User-Name': 'honeymooner-hitched'
|
|
}, decoded.attributes );
|
|
test.done();
|
|
}
|
|
});
|