-
Notifications
You must be signed in to change notification settings - Fork 287
/
DeviceRegistration.pm
308 lines (248 loc) · 10.7 KB
/
DeviceRegistration.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package captiveportal::PacketFence::Controller::DeviceRegistration;;
use Moose;
use namespace::autoclean;
use pf::Authentication::constants;
use pf::config qw(%ConfigSelfService);
use pf::constants;
use pf::log;
use pf::node;
use pf::util;
use pf::error qw(is_success);
use pf::web;
use pf::enforcement qw(reevaluate_access);
use pf::fingerbank;
use fingerbank::DB_Factory;
use pf::constants::realm;
use POSIX;
BEGIN { extends 'captiveportal::Base::Controller'; }
__PACKAGE__->config( namespace => 'device-registration' );
=head1 NAME
captiveportal::PacketFence::Controller::DeviceRegistration - Catalyst Controller
=head1 DESCRIPTION
Catalyst Controller.
=head1 METHODS
=cut
sub auto : Private {
my ( $self, $c ) = @_;
$c->stash->{isDeviceRegEnable} = $self->isDeviceRegEnabled($c);
unless($c->stash->{isDeviceRegEnable}) {
$self->showError($c,"Device registration module is not enabled" );
$c->detach;
}
return $TRUE;
}
=head2 isDeviceRegEnabled
Checks whether or not a device registration policy is enabled on the current connection profile
=cut
sub isDeviceRegEnabled {
my ($self, $c) = @_;
if ($c->profile->{'_self_service'}) {
return $TRUE
} else {
return $FALSE;
}
}
=head2 index
=cut
sub index : Path : Args(0) {
my ( $self, $c ) = @_;
my $logger = $c->log;
my $pid = $c->user_session->{"username"} // $c->{_session}->{username};
my $request = $c->request;
# See if user is trying to login and if is not already authenticated
if ( ( !$pid ) ) {
# Verify if user is authenticated
$c->forward('userNotLoggedIn');
} elsif ( $request->param('cancel') ) {
$c->user_session({});
$c->response->redirect('/status');
}
if ( $request->method eq 'POST' && $request->param('device_mac') ) {
# User is authenticated and requesting to register a device
my $device_mac = clean_mac($request->param('device_mac'));
my $device_type;
$device_type = $request->param('console_type') if ( defined($request->param('console_type')) );
my $registration_role = $request->param('registration_role') if ( defined($request->param('registration_role')) );
if(valid_mac($device_mac)) {
# Register device
$c->forward('registerNode', [ $pid, $device_mac, $device_type, $registration_role ]);
}
$c->stash(txt_auth_error => "Please verify the provided MAC address.");
}
my $device_reg_profile = $c->profile->{'_self_service'};
my @registration_roles = map { { value => $_, label => $_ } } split(',', $ConfigSelfService{$device_reg_profile}{'device_registration_roles'});
$c->stash->{device_registration_list_roles} = \@registration_roles;
# User is authenticated so display registration page
$c->stash(title => "Registration", template => 'device-registration/registration.html');
}
=head2 gaming_registration
Backwards compatability
/gaming-registration
=cut
sub gaming_registration: Path('/gaming-registration') {
my ( $self, $c ) = @_;
$c->forward('index');
}
=head2 userNotLoggedIn
=cut
sub userNotLoggedIn : Private {
my ($self, $c) = @_;
$c->response->redirect('/status/login');
}
sub landing : Local : Args(0) {
my ( $self, $c ) = @_;
$c->stash( title => "Device registration landing", template => 'device-registration/registration.html' );
}
sub registerNode : Private {
my ( $self, $c, $pid, $mac, $type, $role ) = @_;
my $logger = $c->log;
my $device_reg_profile = $c->profile->{'_self_service'};
if ( is_allowed($mac, $device_reg_profile) && valid_mac($mac) ) {
my ($node) = node_view($mac);
if( $node && $node->{status} ne $pf::node::STATUS_UNREGISTERED ) {
$c->stash( status_msg_error => ["%s is already registered or pending to be registered. Please verify MAC address if correct contact your network administrator", $mac]);
$c->detach('Controller::Status', 'index');
} else {
my $session = $c->user_session;
my $source_id = $session->{source_id};
my %info;
my $params = { username => $pid, 'context' => $pf::constants::realm::PORTAL_CONTEXT};
$c->stash->{device_mac} = $mac;
# Get role for device registration
if (!(defined($role))) {
$role = $ConfigSelfService{$device_reg_profile}{'device_registration_roles'};
if ($role) {
$logger->debug("Device registration role is $role (from self_service.conf)");
} else {
# Use role of user
$role = pf::authentication::match( $source_id, $params , $Actions::SET_ROLE, undef, $c->user_session->{extra});
$logger->debug("Gaming devices role is $role (from username $pid)");
}
}
my $duration = $ConfigSelfService{$device_reg_profile}{'device_registration_access_duration'};
if($duration > 0) {
$info{unregdate} = POSIX::strftime("%Y-%m-%d %H:%M:%S", localtime(time + $duration));
$logger->debug("Got unregdate $info{unregdate} for username $pid through the self-service configuration");
}
else {
my $unregdate = pf::authentication::match( $source_id, $params, $Actions::SET_UNREG_DATE, undef, $c->user_session->{extra});
if ( defined $unregdate ) {
$logger->debug("Got unregdate $unregdate for username $pid");
$info{unregdate} = $unregdate;
}
}
my $time_balance = &pf::authentication::match( $source_id, $params, $Actions::SET_TIME_BALANCE);
if ( defined $time_balance ) {
$logger->debug("Got time balance $time_balance for username $pid");
$info{time_balance} = pf::util::normalize_time($time_balance);
}
my $bandwidth_balance = &pf::authentication::match( $source_id, $params, $Actions::SET_BANDWIDTH_BALANCE);
if ( defined $bandwidth_balance ) {
$logger->debug("Got bandwidth balance $bandwidth_balance for username $pid");
$info{bandwidth_balance} = pf::util::unpretty_bandwidth($bandwidth_balance);
}
$info{'category'} = $role if ( defined $role );
$info{'auto_registered'} = 1;
$info{'mac'} = $mac;
$info{'pid'} = $pid;
$info{'regdate'} = mysql_date();
$info{'notes'} = $type if ( defined($type) );
$c->portalSession->guestNodeMac($mac);
node_modify($mac, status => "reg", %info);
reevaluate_access($mac, 'manage_register');
$c->stash( status_msg => [ "The MAC address %s has been successfully registered.", $mac ]);
$c->detach('Controller::Status', 'index');
}
} else {
$c->stash( status_msg_error => [ "The provided MAC address %s is not allowed to be registered using this self-service page.", $mac ]);
$c->detach('landing');
}
}
=item device_from_mac_vendor
Get the matching device infos by mac vendor from Fingerbank
=cut
sub device_from_mac_vendor {
my ($mac_vendor) = @_;
my $logger = get_logger();
my ($status, $device_id) = fingerbank::API->new_from_config->device_id_from_oui($mac_vendor);
if(is_success($status)) {
return $device_id;
}
else {
return undef;
}
}
=item is_allowed
Verify
=cut
sub is_allowed {
my ($mac, $device_reg_profile) = @_;
$mac =~ s/O/0/i;
my $logger = get_logger();
my $oses = $ConfigSelfService{$device_reg_profile}{'device_registration_allowed_devices'};
# If no oses are defined then it will allow every devices to be registered
return $TRUE if @$oses == 0;
# Verify if the device is existing in the table node and if it's device_type is allowed
node_add_simple($mac);
pf::fingerbank::process($mac, 1);
my $node = node_view($mac);
my $device_type = $node->{device_type};
my $device_manufacturer = $node->{device_manufacturer};
for my $id (@$oses) {
my $endpoint = fingerbank::Model::Endpoint->new(name => $device_type, version => undef, score => undef);
if ( defined($device_type) && $endpoint->is_a_by_id($id)) {
$logger->debug("The devices type ".$device_type." is authorized to be registered via the device-registration module");
return $TRUE;
}
my $endpoint_manufacturer = fingerbank::Model::Endpoint->new(name => $device_manufacturer, version => undef, score => undef);
if ( defined($device_manufacturer) && $endpoint_manufacturer->is_a_by_id($id)) {
$logger->debug("The devices manufacturer ".$device_manufacturer." is authorized to be registered via the device-registration module");
return $TRUE;
}
}
$mac =~ s/://g;
my $mac_vendor = substr($mac, 0,6);
my $device_id = device_from_mac_vendor($mac_vendor);
my ($status, $result) = fingerbank::Model::Device->find([{ id => $device_id}, {columns => ['name']}]);
# We are loading the fingerbank endpoint model to verify if the device id is matching as a parent or child
if (is_success($status)){
my $device_name = $result->name;
my $endpoint = fingerbank::Model::Endpoint->new(name => $device_name, version => undef, score => undef);
for my $id (@$oses) {
if ($endpoint->is_a_by_id($id)) {
$logger->debug("The devices type ".$device_name." is authorized to be registered via the device-registration module");
return $TRUE;
}
}
}
$logger->debug("Cannot find a matching device name for this device id ".$device_id." .");
return $FALSE;
}
=head2 logout
allow user to logout
=cut
sub logout : Local {
my ( $self, $c ) = @_;
$c->user_session({});
$c->forward('index');
}
=head1 AUTHOR
Inverse inc. <info@inverse.ca>
=head1 COPYRIGHT
Copyright (C) 2005-2024 Inverse inc.
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
=cut
__PACKAGE__->meta->make_immutable unless $ENV{"PF_SKIP_MAKE_IMMUTABLE"};
1;