Skip to content

Commit fd75571

Browse files
Merge pull request #8500 from inverse-inc/feature/ruckus_unleashed
Support for Ruckus unleashed AP
2 parents 0353d73 + 79cf530 commit fd75571

11 files changed

+247
-0
lines changed
49.6 KB
Loading
71.8 KB
Loading
82.6 KB
Loading
50.6 KB
Loading
46.9 KB
Loading
62.4 KB
Loading
63.3 KB
Loading
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// to display images directly on GitHub
2+
ifdef::env-github[]
3+
:encoding: UTF-8
4+
:lang: en
5+
:doctype: book
6+
:toc: left
7+
:imagesdir: ../../images
8+
endif::[]
9+
10+
////
11+
12+
This file is part of the PacketFence project.
13+
14+
See PacketFence_Network_Devices_Configuration_Guide.asciidoc
15+
for authors, copyright and license information.
16+
17+
////
18+
19+
20+
//=== Ruckus Unleashed
21+
22+
[float]
23+
==== Web Authentication
24+
25+
In order to use PacketFence as an external captive portal for web authentication, you will need to first configure your RADIUS authentication and accounting server (see steps above).
26+
27+
[float]
28+
===== Hotspot configuration
29+
30+
Create a new Wi-Fi network, define the SSID name, select Usage Type as "Hotspot Service", the Authentication Method to "Open" and the Encryption Method to "None".
31+
32+
image::ruckus_unleashed_hotspot-1.png[scaledwidth="100%",alt="Hotspot Service"]
33+
34+
Configure the Hotspot service profile to redirect devices to your PacketFence portal. Click on the + next tro Hotspot Services.
35+
36+
image::ruckus_unleashed_hotspot-2.png[scaledwidth="100%",alt="Hotspot Service"]
37+
38+
1 - Name of your Hotspot service
39+
2 - Login Page: URL of PacketFence portal interface (http://192.168.1.5/Ruckus::Unleashed)
40+
3 - Start Page: redirect to the URL that the user intends to visit.
41+
42+
In the Authentication Tab, click + next to Authentication server and define the RADIUS server.
43+
44+
image::ruckus_unleashed_hotspot-3.png[scaledwidth="100%",alt="Hotspot Service"]
45+
46+
In the Authentication Tab, click + next to Accounting server and define the RADIUS server.
47+
48+
image::ruckus_unleashed_hotspot-4.png[scaledwidth="100%",alt="Hotspot Service"]
49+
50+
Save your configuration.
51+
52+
==== MAC Authentication
53+
54+
.Open SSID
55+
* Enter a Name/SSID
56+
* Select *Standard* as the Type
57+
* Select *MAC Address* as the authentication method
58+
* Select *Open* as the encryption method
59+
* Select the proper RADIUS server as the authentication server
60+
* Select the proper RADIUS server as the accounting server
61+
62+
image::ruckus_unleashed_mac_auth.png[scaledwidth="100%",alt="Mac Auth"]
63+
64+
==== 802.1X Configuration
65+
66+
.Secure SSID
67+
* Enter a Name/SSID
68+
* Select *Standard* as the Type
69+
* Select *802.1X EAP* as the authentication method
70+
* Select *WAP2* as the encryption method
71+
* Select the proper RADIUS server as the authentication server
72+
* Select the proper RADIUS server as the accounting server
73+
* In Advanced Options -> WLAN Priority check "Enable Dynamic VLAN"
74+
75+
image::ruckus_unleashed_secure-1.png[scaledwidth="100%",alt="802.1x"]

docs/network/wireless_controllers_and_access_point_configuration.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ include::networkdevice/ruckus.asciidoc[]
185185
186186
include::networkdevice/ruckus_smartzone.asciidoc[]
187187
188+
=== Ruckus Unleashed
189+
190+
include::networkdevice/ruckus_unleashed.asciidoc[]
191+
188192
=== Trapeze
189193
190194
include::networkdevice/trapeze.asciidoc[]

lib/pf/Switch/Ruckus/Unleashed.pm

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package pf::Switch::Ruckus::Unleashed;
2+
3+
=head1 NAME
4+
5+
pf::Switch::Ruckus::Unleashed
6+
7+
=head1 SYNOPSIS
8+
9+
Implements methods to manage Ruckus Unleashed AP
10+
11+
=head1 BUGS AND LIMITATIONS
12+
13+
=cut
14+
15+
use strict;
16+
use warnings;
17+
18+
use base ('pf::Switch::Ruckus::SmartZone');
19+
20+
use pf::constants;
21+
use pf::util;
22+
use pf::util::wpa;
23+
use pf::node;
24+
use pf::config qw (
25+
$WEBAUTH_WIRELESS
26+
);
27+
use pf::log;
28+
29+
sub description { 'Ruckus Unleashed' }
30+
use pf::SwitchSupports qw(
31+
WirelessMacAuth
32+
);
33+
34+
=over
35+
36+
=item supportsWebFormRegistration
37+
38+
Will be activated only if HTTP is selected as a deauth method
39+
40+
=cut
41+
42+
sub supportsWebFormRegistration {
43+
my ($self) = @_;
44+
return $TRUE;
45+
}
46+
47+
=item parseExternalPortalRequest
48+
49+
Parse external portal request using URI and it's parameters then return an hash reference with the appropriate parameters
50+
51+
See L<pf::web::externalportal::handle>
52+
53+
=cut
54+
55+
sub parseExternalPortalRequest {
56+
my ( $self, $r, $req ) = @_;
57+
my $logger = $self->logger;
58+
59+
# Using a hash to contain external portal parameters
60+
my %params = ();
61+
62+
%params = (
63+
client_mac => clean_mac($req->param('client_mac')),
64+
client_ip => defined($req->param('uip')) ? $req->param('uip') : undef,
65+
ssid => $req->param('ssid'),
66+
redirect_url => $req->param('url'),
67+
switch_id => $req->param('sip'),
68+
switch_mac => clean_mac($req->param('mac')),
69+
synchronize_locationlog => $TRUE,
70+
connection_type => $WEBAUTH_WIRELESS,
71+
);
72+
73+
return \%params;
74+
}
75+
76+
sub getAcceptForm {
77+
my ( $self, $mac, $destination_url, $portalSession ) = @_;
78+
my $logger = $self->logger;
79+
$logger->debug("Creating web release form");
80+
81+
my $node = node_view($mac);
82+
my $last_ssid = $node->{last_ssid};
83+
$mac =~ s/:/-/g;
84+
my $html_form = qq[
85+
<form name="weblogin_form" data-autosubmit="1000" method="POST" action="https://unleashed.ruckuswireless.com:9998/login">
86+
<input type="hidden" name="username" value="$mac">
87+
<input type="hidden" name="password" value="$mac">
88+
</form>
89+
<script src="/content/autosubmit.js" type="text/javascript"></script>
90+
];
91+
92+
$logger->debug("Generated the following html form : ".$html_form);
93+
return $html_form;
94+
}
95+
sub find_user_by_psk {
96+
my ($self, $radius_request, $args) = @_;
97+
my $pid;
98+
if($radius_request->{"Ruckus-DPSK-Cipher"} != 4) {
99+
get_logger->error("Ruckus-DPSK-Cipher isn't for WPA2 that uses AES and HMAC-SHA1. This isn't supported by this module.");
100+
return $pid;
101+
}
102+
103+
my $ssid = $radius_request->{'Ruckus-SSID'};
104+
my $bssid = pack("H*", sprintf("%v02x", $radius_request->{"Ruckus-BSSID"}) =~ s/\.//rg);
105+
my $username = pack("H*", $radius_request->{'User-Name'});
106+
my $anonce = pack('H*', sprintf("%v02x",$radius_request->{'Ruckus-DPSK-Anonce'}) =~ s/\.//rg);
107+
my $snonce = pf::util::wpa::snonce_from_eapol_key_frame(pack("H*",sprintf("%v02x",$radius_request->{"Ruckus-DPSK-EAPOL-Key-Frame"}) =~ s/\.//rg));
108+
my $eapol_key_frame = pack("H*", sprintf("%v02x",$radius_request->{"Ruckus-DPSK-EAPOL-Key-Frame"}) =~ s/\.//rg);
109+
my $cache = $self->cache;
110+
# Try first the pid of the mac address
111+
if (exists $args->{'owner'} && $args->{'owner'}->{'pid'} ne "" && exists $args->{'owner'}->{'psk'} && defined $args->{'owner'}->{'psk'} && $args->{'owner'}->{'psk'} ne "") {
112+
if (check_if_radius_request_psk_matches($cache, $radius_request, $args->{'owner'}->{'psk'}, $ssid, $bssid, $username, $anonce, $snonce, $eapol_key_frame)) {
113+
get_logger->info("PSK matches the pid associated with the mac ".$args->{'owner'}->{'pid'});
114+
return $args->{'owner'}->{'pid'};
115+
}
116+
}
117+
118+
my ($status, $iter) = pf::dal::person->search(
119+
-where => {
120+
psk => {'!=' => [-and => '', undef]},
121+
},
122+
-columns => [qw(pid psk)],
123+
-no_default_join => 1,
124+
);
125+
126+
while (my $person = $iter->next) {
127+
get_logger->debug("User ".$person->{pid}." has a PSK. Checking if it matches the one in the packet");
128+
if (check_if_radius_request_psk_matches($cache, $radius_request, $person->{psk}, $ssid, $bssid, $username, $anonce, $snonce, $eapol_key_frame)) {
129+
get_logger->info("PSK matches the one of ".$person->{pid});
130+
$pid = $person->{pid};
131+
last;
132+
}
133+
}
134+
return $pid;
135+
}
136+
137+
138+
=back
139+
140+
=head1 AUTHOR
141+
142+
Inverse inc. <[email protected]>
143+
144+
=head1 COPYRIGHT
145+
146+
Copyright (C) 2005-2022 Inverse inc.
147+
148+
=head1 LICENSE
149+
150+
This program is free software; you can redistribute it and/or
151+
modify it under the terms of the GNU General Public License
152+
as published by the Free Software Foundation; either version 2
153+
of the License, or (at your option) any later version.
154+
155+
This program is distributed in the hope that it will be useful,
156+
but WITHOUT ANY WARRANTY; without even the implied warranty of
157+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
158+
GNU General Public License for more details.
159+
160+
You should have received a copy of the GNU General Public License
161+
along with this program; if not, write to the Free Software
162+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
163+
USA.
164+
165+
=cut
166+
167+
1;

0 commit comments

Comments
 (0)