Initial push 0.2.0
This commit is contained in:
1 parent
93472ae250
commit
1d8bd0c989
55 files changed
+3515
No files matched your search
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+16
@@ -0,0 +1,16 @@
|
||||
VENDOR Airespace 14179
|
||||
|
||||
BEGIN-VENDOR Airespace
|
||||
ATTRIBUTE Airespace-Wlan-Id 1 integer
|
||||
ATTRIBUTE Airespace-QOS-Level 2 integer
|
||||
ATTRIBUTE Airespace-DSCP 3 integer
|
||||
ATTRIBUTE Airespace-8021p-Tag 4 integer
|
||||
ATTRIBUTE Airespace-Interface-Name 5 string
|
||||
ATTRIBUTE Airespace-ACL-Name 6 string
|
||||
|
||||
VALUE Airespace-QOS-Level Bronze 3
|
||||
VALUE Airespace-QOS-Level Silver 0
|
||||
VALUE Airespace-QOS-Level Gold 1
|
||||
VALUE Airespace-QOS-Level Platinum 2
|
||||
|
||||
END-VENDOR Airespace
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# Aruba attributes
|
||||
VENDORATTR 14823 Aruba-User-Role 1 string
|
||||
VENDORATTR 14823 Aruba-User-Vlan 2 integer
|
||||
VENDORATTR 14823 Aruba-Priv-Admin-User 3 integer
|
||||
VENDORATTR 14823 Aruba-Admin-Role 4 string
|
||||
VENDORATTR 14823 Aruba-Essid-Name 5 String
|
||||
VENDORATTR 14823 Aruba-Location-Id 6 string
|
||||
VENDORATTR 14823 Aruba-Port-Id 7 string
|
||||
VENDORATTR 14823 Aruba-Template-User 8 string
|
||||
VENDORATTR 14823 Aruba-Named-User-Vlan 9 string
|
||||
VENDORATTR 14823 Aruba-AP-Group 10 string
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
VENDOR 123Foo 995486
|
||||
|
||||
BEGIN-VENDOR 123Foo
|
||||
ATTRIBUTE 1Integer 1 integer
|
||||
END-VENDOR 123Foo
|
||||
|
||||
VENDORATTR 995486 1String 2 string
|
||||
VENDORATTR 995486 12345 3 string
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
ATTRIBUTE Attribute-Test1 244 string
|
||||
|
||||
$INCLUDE dictionary.test2
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
ATTRIBUTE Attribute-Test2 245 string
|
||||
|
||||
# don't do anything crazy like loop forever
|
||||
$INCLUDE dictionary.test1
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# Fake tunnel type to be loaded before ATTRIBUTE Tunnel-Type is defined
|
||||
|
||||
VALUE Tunnel-Type TESTTUNNEL 31
|
||||
+970
@@ -0,0 +1,970 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user