From e45b214de498a94cf54f0c6f33b888972d364ce5 Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Thu, 4 Dec 2014 14:24:35 +0200 Subject: [PATCH] MT#9177 Add yealink, change architecture and fix credentials store issue Squashed commit of the following: commit 79484a6e87392a7a335c590fc593cd2de321ba4f Author: Irina Peshinskaya Date: Wed Dec 3 02:11:23 2014 +0200 MT#9177 We don't need update device_id in credentials. Rather usual thing. commit d2161a9b3fe02f5617bec8ec61d31fe4caa31261 Author: Irina Peshinskaya Date: Tue Nov 25 13:16:02 2014 +0200 MT#9177 Return unregister into utils area. commit ac8115bcc2641ef1a54be8319b65ff026f03e0a7 Author: Irina Peshinskaya Date: Sun Nov 16 13:58:35 2014 +0200 MT#9177 Yealink works commit 51336e2b18d318d5acaa3d0fd1ab266ab7a25f5f Author: Irina Peshinskaya Date: Sun Nov 16 12:23:19 2014 +0200 MT#9177 Yealink add_server commit 6dc0fde8ddeee12b2ccddd5f2a1fe3c61387d9bc Author: Irina Peshinskaya Date: Fri Nov 14 09:54:14 2014 +0200 MT#9177 Yealink url via serverName commit ec00e658780b9a29c50bbe48def95852d1c30938 Author: Irina Peshinskaya Date: Thu Nov 13 10:55:07 2014 +0200 MT#9177 Yealink requires server length < 20 commit 0c29750e74983b3a1dcc89238a862ef31ae72d07 Author: Irina Peshinskaya Date: Thu Nov 13 10:45:27 2014 +0200 MT#9177 Wonderfully authorization for Panasonic started to work Without = at the end commit 7d3c540a82524cb9ae31b64985f2ae08f3a7dd2a Author: Irina Peshinskaya Date: Thu Nov 13 10:36:51 2014 +0200 MT#9177 Fix yealink authorization too commit e39da24bc9ca3ba590695cafdacf7fe1ab925b7a Author: Irina Peshinskaya Date: Thu Nov 13 10:15:26 2014 +0200 MT#9177 Small fixes for yealink commit 9b9e2973eeca983672a6ca46fe5133a71fe928bb Author: Irina Peshinskaya Date: Thu Nov 13 08:12:33 2014 +0200 MT#9177 Add yealink credentials fields commit d63e9ab9672f6a38a8dbae146356e6b0ad2f8dd7 Author: Irina Peshinskaya Date: Thu Nov 13 06:24:46 2014 +0200 MT#9177 Some fixes for this layout commit bd2a026ed4bdaed33a018e6bd866a9f94fbc0f35 Author: Irina Peshinskaya Date: Wed Nov 12 22:43:37 2014 +0200 MT#9177 Use custom bootstrap uri in this layout commit bfd2f7a96c78486e714992f190281591f586f661 Author: Irina Peshinskaya Date: Wed Nov 12 17:07:50 2014 +0200 MT#9177 Further yealink changes commit 3779466cb6c85228a48c445e2d619d8bb75d965f Author: Irina Peshinskaya Date: Wed Nov 12 15:55:47 2014 +0200 MT#9177 Yealink added commit 3fa77dcdb020cfdb11e9020b8365e8554354ac77 Author: Irina Peshinskaya Date: Wed Nov 5 08:23:56 2014 +0200 MT#9177 Refactor code to separate vendor specific and common logic Change-Id: I41a912a5c8f90b3c58cf49b87a38a3b6a7b64bd6 --- Build.PL | 1 + .../Panel/Controller/API/PbxDeviceModels.pm | 1 + lib/NGCP/Panel/Controller/Device.pm | 4 +- lib/NGCP/Panel/Form/Device/Model.pm | 26 ++- lib/NGCP/Panel/Form/Device/ModelAPI.pm | 2 +- lib/NGCP/Panel/Form/Device/ModelAdmin.pm | 2 +- lib/NGCP/Panel/Role/API/PbxDeviceModels.pm | 1 + lib/NGCP/Panel/Utils/DeviceBootstrap.pm | 131 +++++++++--- .../Panel/Utils/DeviceBootstrap/Panasonic.pm | 192 ++++++++---------- .../Panel/Utils/DeviceBootstrap/VendorRPC.pm | 157 ++++++++++++++ .../Panel/Utils/DeviceBootstrap/Yealink.pm | 145 +++++++++++++ share/templates/device/list.tt | 4 - 12 files changed, 514 insertions(+), 152 deletions(-) create mode 100644 lib/NGCP/Panel/Utils/DeviceBootstrap/VendorRPC.pm create mode 100644 lib/NGCP/Panel/Utils/DeviceBootstrap/Yealink.pm diff --git a/Build.PL b/Build.PL index 39a3f9c9c9..f2b96ae23a 100644 --- a/Build.PL +++ b/Build.PL @@ -47,6 +47,7 @@ my $builder = Local::Module::Build->new( 'DateTime::Format::ISO8601' => 0, 'DateTime::Format::RFC3339' => 0, 'DBIx::Class::ResultSet::RecursiveUpdate' => '0.30', + 'Digest::MD5' => 0, 'Email::Sender::Simple' => 0, 'Email::Sender::Transport::SMTP' => 0, 'Email::Valid' => 0, diff --git a/lib/NGCP/Panel/Controller/API/PbxDeviceModels.pm b/lib/NGCP/Panel/Controller/API/PbxDeviceModels.pm index 8677f2aa1e..d19f0594fb 100644 --- a/lib/NGCP/Panel/Controller/API/PbxDeviceModels.pm +++ b/lib/NGCP/Panel/Controller/API/PbxDeviceModels.pm @@ -275,6 +275,7 @@ sub POST :Allow { $item = $c->model('DB')->resultset('autoprov_devices')->create($resource); NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_credentials_store($c, $item, $credentials); NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_parameters_store($c, $item, $sync_parameters); + NGCP::Panel::Utils::DeviceBootstrap::dispatch_devmod($c, 'add_server', $item); foreach my $range(@{ $linerange }) { unless(ref $range eq "HASH") { diff --git a/lib/NGCP/Panel/Controller/Device.pm b/lib/NGCP/Panel/Controller/Device.pm index d6565e7073..d43c25d2af 100644 --- a/lib/NGCP/Panel/Controller/Device.pm +++ b/lib/NGCP/Panel/Controller/Device.pm @@ -185,7 +185,8 @@ sub devmod_create :Chained('base') :PathPart('model/create') :Args(0) :Does(ACL) my $devmod = $schema->resultset('autoprov_devices')->create($form->params); NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_credentials_store($c, $devmod, $credentials); NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_parameters_store($c, $devmod, $sync_parameters); - + NGCP::Panel::Utils::DeviceBootstrap::dispatch_devmod($c, 'add_server', $devmod); + foreach my $range(@{ $linerange }) { delete $range->{id}; $range->{num_lines} = @{ $range->{keys} }; # backward compatibility @@ -368,6 +369,7 @@ sub devmod_edit :Chained('devmod_base') :PathPart('edit') :Args(0) :Does(ACL) :A device_id => $c->stash->{devmod}->id, })->delete; NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_parameters_store($c, $c->stash->{devmod}, $sync_parameters); + NGCP::Panel::Utils::DeviceBootstrap::dispatch_devmod($c, 'add_server', $c->stash->{devmod} ); my @existing_range = (); my $range_rs = $c->stash->{devmod}->autoprov_device_line_ranges; diff --git a/lib/NGCP/Panel/Form/Device/Model.pm b/lib/NGCP/Panel/Form/Device/Model.pm index 64df1cecaf..230e78f3b7 100644 --- a/lib/NGCP/Panel/Form/Device/Model.pm +++ b/lib/NGCP/Panel/Form/Device/Model.pm @@ -204,6 +204,7 @@ has_field 'bootstrap_method' => ( options => [ { label => 'Cisco', value => 'http' }, { label => 'Panasonic', value => 'redirect_panasonic' }, + { label => 'Yealink', value => 'redirect_yealink' }, ], default => 'http', element_attr => { @@ -286,7 +287,28 @@ has_field 'bootstrap_config_redirect_panasonic_password' => ( title => ['Password used to configure bootstrap url on Panasonic redirect server. Obtained from Panasonic.'], }, ); - +has_field 'bootstrap_config_redirect_yealink_user' => ( + type => 'Text', + required => 0, + label => 'Yealink username', + default => '', + wrapper_class => [qw/ngcp-bootstrap-config ngcp-bootstrap-config-redirect_yealink/], + element_attr => { + rel => ['tooltip'], + title => ['Username used to configure bootstrap url on Yealink redirect server. Obtained from Yealink.'], + }, +); +has_field 'bootstrap_config_redirect_yealink_password' => ( + type => 'Text', + required => 0, + label => 'Yealink password', + default => '', + wrapper_class => [qw/ngcp-bootstrap-config ngcp-bootstrap-config-redirect_yealink/], + element_attr => { + rel => ['tooltip'], + title => ['Password used to configure bootstrap url on Yealink redirect server. Obtained from Yealink.'], + }, +); has_field 'save' => ( type => 'Submit', @@ -298,7 +320,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/vendor model linerange linerange_add bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password front_image mac_image/], + render_list => [qw/vendor model linerange linerange_add bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password bootstrap_config_redirect_yealink_user bootstrap_config_redirect_yealink_password front_image mac_image/], ); has_block 'actions' => ( diff --git a/lib/NGCP/Panel/Form/Device/ModelAPI.pm b/lib/NGCP/Panel/Form/Device/ModelAPI.pm index 8db1a99430..941ceeab16 100644 --- a/lib/NGCP/Panel/Form/Device/ModelAPI.pm +++ b/lib/NGCP/Panel/Form/Device/ModelAPI.pm @@ -7,7 +7,7 @@ use Moose::Util::TypeConstraints; has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/reseller vendor model linerange bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password/], + render_list => [qw/reseller vendor model linerange bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password bootstrap_config_redirect_yealink_user bootstrap_config_redirect_yealink_password/], ); override 'field_list' => sub { diff --git a/lib/NGCP/Panel/Form/Device/ModelAdmin.pm b/lib/NGCP/Panel/Form/Device/ModelAdmin.pm index e59cccf43d..5dfff979ba 100644 --- a/lib/NGCP/Panel/Form/Device/ModelAdmin.pm +++ b/lib/NGCP/Panel/Form/Device/ModelAdmin.pm @@ -26,7 +26,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/reseller vendor model linerange linerange_add bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password front_image mac_image/], + render_list => [qw/reseller vendor model linerange linerange_add bootstrap_uri bootstrap_method bootstrap_config_http_sync_uri bootstrap_config_http_sync_method bootstrap_config_http_sync_params bootstrap_config_redirect_panasonic_user bootstrap_config_redirect_panasonic_password bootstrap_config_redirect_yealink_user bootstrap_config_redirect_yealink_password front_image mac_image/], ); has_block 'actions' => ( diff --git a/lib/NGCP/Panel/Role/API/PbxDeviceModels.pm b/lib/NGCP/Panel/Role/API/PbxDeviceModels.pm index 8340400c51..c163e0575b 100644 --- a/lib/NGCP/Panel/Role/API/PbxDeviceModels.pm +++ b/lib/NGCP/Panel/Role/API/PbxDeviceModels.pm @@ -166,6 +166,7 @@ sub update_item { })->delete; NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_credentials_store($c, $item, $credentials); NGCP::Panel::Utils::DeviceBootstrap::devmod_sync_parameters_store($c, $item, $sync_parameters); + NGCP::Panel::Utils::DeviceBootstrap::dispatch_devmod($c, 'add_server', $item); my @existing_range = (); my $range_rs = $item->autoprov_device_line_ranges; diff --git a/lib/NGCP/Panel/Utils/DeviceBootstrap.pm b/lib/NGCP/Panel/Utils/DeviceBootstrap.pm index 519fe1aa59..973bb901d2 100644 --- a/lib/NGCP/Panel/Utils/DeviceBootstrap.pm +++ b/lib/NGCP/Panel/Utils/DeviceBootstrap.pm @@ -1,40 +1,81 @@ package NGCP::Panel::Utils::DeviceBootstrap; -use Sipwise::Base; -use NGCP::Panel::Utils::DeviceBootstrap::Panasonic; - -sub get_baseuri { - my ($c) = @_; - my $uri = - ($c->config->{deviceprovisioning}->{secure} ? 'https' : 'http'). - '://'. - ($c->config->{deviceprovisioning}->{host} // $c->req->uri->host). - ':'. - ($c->config->{deviceprovisioning}->{port} // 1444). - '/device/autoprov/config/'; +use strict; +use Data::Dumper; +use NGCP::Panel::Utils::DeviceBootstrap::VendorRPC; +use NGCP::Panel::Utils::DeviceBootstrap::Panasonic; +use NGCP::Panel::Utils::DeviceBootstrap::Yealink; - return $uri; +sub dispatch{ + my($c, $action, $fdev, $old_identifier) = @_; + + my $params = { + %{get_devmod_params($c, $fdev->profile->config->device)}, + mac => $fdev->identifier, + mac_old => $old_identifier, + }; + my $redirect_processor = get_redirect_processor($params); + my $ret; + if($redirect_processor){ + if( ('register' eq $action) && $old_identifier && ( $old_identifier ne $fdev->identifier ) ){ + $redirect_processor->redirect_server_call('unregister'); + } + $ret = $redirect_processor->redirect_server_call($action); + } + return $ret; } - -sub dispatch { - my ($c, $action, $dev, $old_mac) = @_; - - my $btype = $dev->profile->config->device->bootstrap_method; - my $mod = 'NGCP::Panel::Utils::DeviceBootstrap'; - - if($btype eq 'redirect_panasonic') { - $mod .= '::Panasonic'; - } elsif($btype eq 'http') { - return; - } else { - return; +sub dispatch_devmod{ + my($c, $action, $devmod) = @_; + + my $params = get_devmod_params($c,$devmod); + my $redirect_processor = get_redirect_processor($params); + my $ret; + if($redirect_processor){ + $ret = $redirect_processor->redirect_server_call($action); + } + return $ret; +} +sub get_devmod_params{ + my($c, $devmod) = @_; + + my $credentials = $devmod->autoprov_redirect_credentials; + my $vcredentials; + if($credentials){ + $vcredentials = { map { $_ => $credentials->$_ } qw/user password/}; } - $mod .= '::'.$action; - $c->log->debug("dispatching bootstrap call to '$mod'"); - no strict "refs"; - return $mod->($c, $dev, $dev->identifier, $old_mac); + my $sync_params_rs = $devmod->autoprov_sync->search_rs({ + 'autoprov_sync_parameters.parameter_name' => 'sync_params', + },{ + join => 'autoprov_sync_parameters', + select => ['me.parameter_value'], + }); + my $sync_params = $sync_params_rs->first ? $sync_params_rs->first->parameter_value : ''; + + my $params = { + c => $c, + bootstrap_method => $devmod->bootstrap_method, + redirect_uri => $devmod->bootstrap_uri, + redirect_uri_params => $sync_params, + credentials => $vcredentials, + }; + return $params; +} +sub get_redirect_processor{ + my ($params) = @_; + my $c = $params->{c}; + my $bootstrap_method = $params->{bootstrap_method}; + $c->log->debug( "bootstrap_method=$bootstrap_method;" ); + my $redirect_processor; + if('redirect_panasonic' eq $bootstrap_method){ + $redirect_processor = NGCP::Panel::Utils::DeviceBootstrap::Panasonic->new( params => $params ); + }elsif('redirect_yealink' eq $bootstrap_method){ + $redirect_processor = NGCP::Panel::Utils::DeviceBootstrap::Yealink->new( params => $params ); + }elsif('http' eq $bootstrap_method){ + #$ret = panasonic_bootstrap_register($params); + } + return $redirect_processor; } sub devmod_sync_parameters_prefetch{ @@ -77,7 +118,8 @@ sub devmod_sync_credentials_store{ $credentials->{device_id} = $devmod->id; $schema->resultset('autoprov_redirect_credentials')->create($credentials); }else{ - $credentials_rs->update($credentials); + delete $credentials->{device_id}; + $credentials_rs->update($credentials); } } @@ -97,3 +139,30 @@ sub devmod_sync_parameters_store { $schema->resultset('autoprov_sync')->create($sync_parameter); } } +1; + +=head1 NAME + +NGCP::Panel::Utils::DeviceBootstrap + +=head1 DESCRIPTION + +Make API requests to configure remote redirect servers for requested MAC with autorpov uri. + +=head1 METHODS + +=head2 bootstrap + +Dispatch to proper vendor API call. + +=head1 AUTHOR + +Irina Peshinskaya C<< >> + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Utils/DeviceBootstrap/Panasonic.pm b/lib/NGCP/Panel/Utils/DeviceBootstrap/Panasonic.pm index 3538ba0c0a..3b983d30cd 100644 --- a/lib/NGCP/Panel/Utils/DeviceBootstrap/Panasonic.pm +++ b/lib/NGCP/Panel/Utils/DeviceBootstrap/Panasonic.pm @@ -1,134 +1,102 @@ package NGCP::Panel::Utils::DeviceBootstrap::Panasonic; -use Sipwise::Base; -use URI::Escape; -use MIME::Base64 qw/encode_base64/; -use Net::HTTPS::Any qw/https_post/; -use RPC::XML::ParserFactory 'XML::LibXML'; -use RPC::XML; +use strict; +use Moose; use Data::Dumper; +extends 'NGCP::Panel::Utils::DeviceBootstrap::VendorRPC'; + +has 'rpc_server_params' => ( + is => 'rw', + isa => 'HashRef', + accessor => '_rpc_server_params', +); +has 'register_content' => ( + is => 'rw', + isa => 'Str', + accessor => '_register_content', +); +has 'unregister_content' => ( + is => 'rw', + isa => 'Str', + accessor => '_unregister_content', +); +sub rpc_server_params{ + my $self = shift; + my $cfg = { + proto => 'https', + host => 'provisioning.e-connecting.net', + port => '443', + path => '/redirect/xmlrpc', + }; + $cfg->{headers} = { %{$self->get_basic_authorization($self->params->{credentials})} }; + $self->{rpc_server_params} = $cfg; + return $self->{rpc_server_params}; +} -my $cfg = { - proto => 'https', - host => 'provisioning.e-connecting.net', - port => '443', - path => '/redirect/xmlrpc', -}; - -sub prepare { - my ($c, $fdev) = @_; - my $p = {}; - - my $devmod = $fdev->profile->config->device; - my $creds = $devmod->autoprov_redirect_credentials; - if($creds) { - $p->{auth} = encode_base64($creds->user.':'.$creds->password); - } +sub register_content { + my $self = shift; +#".URI::Escape::uri_escape($self->content_params->{uri})." + $self->{register_content} = " + +ipredirect.registerPhone + +".$self->content_params->{mac}." +content_params->{uri}."]]> + +"; + return $self->{register_content}; +} - $p->{uri} = ($devmod->bootstrap_uri) - ? $devmod->bootstrap_uri - : NGCP::Panel::Utils::DeviceBootstrap::get_baseuri($c); - - if ($p->{uri} !~/\{MAC\}$/){ - if ($p->{uri} !~/\/$/){ - $p->{uri} .= '/' ; - } - $p->{uri} .= '{MAC}' ; - } - $p->{uri} = URI::Escape::uri_escape($p->{uri}); - - return $p; +sub unregister_content { + my $self = shift; + $self->{unregister_content} = " + +ipredirect.unregisterPhone + +".$self->content_params->{mac_old}." + +"; + return $self->{unregister_content}; } -# return faultString or undef if ok -sub check_result { - my ($c, $data) = @_; - my $val = ''; - if($data){ - my $parser = RPC::XML::ParserFactory->new(); - my $rpc = $parser->parse($data); - $val = $rpc->value->value; - } +sub parse_rpc_response{ + my($self,$rpc_response) = @_; + return $rpc_response->value->value; +} - $c->log->debug("panasonic redirect call returned: " . Dumper $val); +sub extract_response_description{ + my($self,$response_value) = @_; - if(ref $val eq 'HASH' && $val->{faultString}) { - return $val->{faultString}; + if(('HASH' eq ref $response_value) && $response_value->{faultString}){ + return $response_value->{faultString}; } else { return; } } +1; -sub normalize_mac { - my ($mac) = @_; - return unless($mac); - $mac =~s/[^A-F0-9]//gi; - $mac = uc($mac); - return $mac; -} +=head1 NAME -sub unregister { - my ($c, $fdev, $mac, $old_mac) = @_; +NGCP::Panel::Utils::DeviceBootstrap - my $p = prepare($c, $fdev); - $old_mac = normalize_mac($old_mac); +=head1 DESCRIPTION - my $data = " - -ipredirect.unregisterPhone - -".$old_mac." - -"; - $c->log->debug("panasonic redirect call $data"); - - my($res, $code) = https_post({ - 'host' => $cfg->{host}, - 'port' => $cfg->{port}, - 'path' => $cfg->{path}, - 'headers' => { 'Authorization' => 'Basic '.$p->{auth} }, - 'Content-Type' => 'text/xml', - 'content' => $data, - }); - return check_result($c, $res); -} +Make API requests to configure remote redirect servers for requested MAC with autorpov uri. -sub register { - my ($c, $fdev, $mac, $old_mac) = @_; +=head1 METHODS - my $p = prepare($c, $fdev); - $mac = normalize_mac($mac); - $old_mac = normalize_mac($old_mac); +=head2 bootstrap - # we don't check for the result here, in the worst case - # we leave an orphaned entry behind - unregister($c, $fdev, $mac, $old_mac) if($old_mac && $old_mac ne $mac); - - my $data = " - -ipredirect.registerPhone - -".$mac." -".$p->{uri}." - -"; - $c->log->debug("panasonic redirect call $data"); - - my($res, $code) = https_post({ - 'host' => $cfg->{host}, - 'port' => $cfg->{port}, - 'path' => $cfg->{path}, - 'headers' => { 'Authorization' => 'Basic '.$p->{auth} }, - 'Content-Type' => 'text/xml', - 'content' => $data, - }); - if($res){ - $c->log->debug("register returned with code $code and data $res"); - return check_result($c, $res); - }else{ - return 'Empty response'; - } -} +Dispatch to proper vendor API call. -1; +=head1 AUTHOR + +Irina Peshinskaya C<< >> + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Utils/DeviceBootstrap/VendorRPC.pm b/lib/NGCP/Panel/Utils/DeviceBootstrap/VendorRPC.pm new file mode 100644 index 0000000000..6458039023 --- /dev/null +++ b/lib/NGCP/Panel/Utils/DeviceBootstrap/VendorRPC.pm @@ -0,0 +1,157 @@ +package NGCP::Panel::Utils::DeviceBootstrap::VendorRPC; + +use strict; +use URI::Escape; +use MIME::Base64 qw/encode_base64/; +use Net::HTTPS::Any qw/https_post/; +use RPC::XML::ParserFactory 'XML::LibXML'; +use RPC::XML; +use Data::Dumper; +use Moose; + +has 'params' => ( + is => 'rw', + isa => 'HashRef', +); +has 'content_params' => ( + is => 'rw', + isa => 'HashRef', +); +has 'rpc_server_params' => ( + is => 'rw', + isa => 'HashRef', +); + +sub redirect_server_call{ + my ($self, $action) = @_; + my $c = $self->params->{c}; + $self->init_content_params(); + $c->log->debug(Dumper ($self->content_params)); + my($content,$response_value,$ret); + my $method = $action.'_content'; + if($self->can($method)){ + $content = $self->$method(); + }else{ + $ret = "Unknown method: $action"; + } + if($content){ + $response_value = $self->rpc_https_call($content); + $ret = $self->extract_response_description($response_value); + } + return $ret; +} + +sub rpc_https_call{ + my($self, $content, $cfg) = @_; + $cfg //= $self->rpc_server_params; + my $c = $self->params->{c}; + $c->log->debug( "host=$cfg->{host}; port=$cfg->{port}; path=$cfg->{path}; content=$content;" ); + $c->log->debug( Dumper($cfg->{headers}) ); + my( $page, $response_code, %reply_headers ) = https_post({ + 'host' => $cfg->{host}, + 'port' => $cfg->{port}, + 'path' => $cfg->{path}, + 'headers' => $cfg->{headers}, + 'Content-Type' => 'text/xml', + 'content' => $content, + },); + $c->log->info( "response=$response_code; page=$page;" ); + my $response_value = ''; + if($page){ + my $parser = RPC::XML::ParserFactory->new(); + my $rpc_response = $parser->parse($page); + $response_value = $self->parse_rpc_response($rpc_response); + $c->log->info("response_value=".Dumper($response_value)); + } + return $response_value; +} + +sub init_content_params{ + my($self) = @_; + $self->{content_params} ||= {}; + $self->content_params->{uri} = $self->get_bootstrap_uri(); + + $self->content_params->{mac} = normalize_mac($self->params->{mac}); + if(defined $self->params->{mac_old}) { + $self->content_params->{mac_old} = normalize_mac($self->params->{mac_old}); + } +} +sub normalize_mac { + my ($mac) = @_; + return unless($mac); + $mac =~s/[^A-F0-9]//gi; + $mac = uc($mac); + return $mac; +} + + +sub get_basic_authorization{ + my($self) = @_; + my $authorization = encode_base64(join(':',@{$self->params->{credentials}}{qw/user password/})); + $authorization =~s/[ \s]//gis; + #$authorization .= '='; + return { 'Authorization' => 'Basic '.$authorization }; +} +sub get_bootstrap_uri{ + my ($self) = @_; + my $uri = $self->params->{redirect_uri}; + my $uri_params = $self->params->{redirect_uri_params} || ''; + if(!$uri){ + my $cfg = $self->get_bootstrap_uri_conf(); + $uri = "$cfg->{schema}://$cfg->{host}:$cfg->{port}/device/autoprov/config/"; + } + $uri .= $uri_params; + return $self->process_uri($uri); +} + +sub process_uri{ + my($self,$uri) = @_; + if($uri !~/^(?:https?|t?ftp):\/\//i ){ + $uri = 'http://'.$uri; + } + if ($uri !~/\{MAC\}$/){ + if ($uri !~/\/$/){ + $uri .= '/' ; + } + $uri .= '{MAC}' ; + } + return $uri; +} +#separated as this logic also used in other places, so can be moved to other utils module +sub get_bootstrap_uri_conf{ + my ($self) = @_; + my $c = $self->params->{c}; + my $cfg = { + schema => $c->config->{deviceprovisioning}->{secure} ? 'https' : 'http', + host => $c->config->{deviceprovisioning}->{host} // $c->req->uri->host, + port => $c->config->{deviceprovisioning}->{port} // 1444, + }; + return $cfg; +} +1; + +=head1 NAME + +NGCP::Panel::Utils::DeviceBootstrap + +=head1 DESCRIPTION + +Make API requests to configure remote redirect servers for requested MAC with autorpov uri. + +=head1 METHODS + +=head2 bootstrap + +Dispatch to proper vendor API call. + +=head1 AUTHOR + +Irina Peshinskaya C<< >> + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Utils/DeviceBootstrap/Yealink.pm b/lib/NGCP/Panel/Utils/DeviceBootstrap/Yealink.pm new file mode 100644 index 0000000000..e2d072db6f --- /dev/null +++ b/lib/NGCP/Panel/Utils/DeviceBootstrap/Yealink.pm @@ -0,0 +1,145 @@ +package NGCP::Panel::Utils::DeviceBootstrap::Yealink; + +use strict; +use Moose; +use Digest::MD5 qw/md5_hex/; +extends 'NGCP::Panel::Utils::DeviceBootstrap::VendorRPC'; + +has 'rpc_server_params' => ( + is => 'rw', + isa => 'HashRef', + accessor => '_rpc_server_params', +); +has 'register_content' => ( + is => 'rw', + isa => 'Str', + accessor => '_register_content', +); +has 'unregister_content' => ( + is => 'rw', + isa => 'Str', + accessor => '_unregister_content', +); +has 'add_server_content' => ( + is => 'rw', + isa => 'Str', + accessor => '_add_server_content', +); +sub rpc_server_params{ + my $self = shift; + my $cfg = { + proto => 'https', + host => 'rps.yealink.com', + port => '443', + path => '/xmlrpc', + }; + $cfg->{headers} = { %{$self->get_basic_authorization($self->params->{credentials})} }; + $self->{rpc_server_params} = $cfg; + return $self->{rpc_server_params}; +} + +sub register_content { + my $self = shift; + $self->{register_content} ||= " + +redirect.registerDevice + + +".$self->content_params->{mac}." + + +content_params->{server_name}."]]> + + +"; + return $self->{register_content}; +} + +sub unregister_content { + my $self = shift; + $self->{unregister_content} ||= " + +redirect.deRegisterDevice + + +".$self->content_params->{mac_old}." + + +"; + return $self->{unregister_content}; +} +sub add_server_content { + my $self = shift; + $self->{add_server_content} ||= " + +redirect.addServer + + + +content_params->{server_name}."]]> + + + + +content_params->{uri}."]]> + + + +"; + return $self->{add_server_content}; +} + +sub parse_rpc_response{ + my($self,$rpc_response) = @_; + return $rpc_response->value->value; +} + +sub extract_response_description{ + my($self,$response_value) = @_; + + if(('HASH' eq ref $response_value) && $response_value->{faultString}){ + return $response_value->{faultString}; + } else { + return; + } +} +override 'process_uri' => sub { + my($self,$uri) = @_; + $self->content_params->{uri} = super(); + $self->uri2server_name(); + return $self->content_params->{uri}; +}; + +sub uri2server_name{ + my($self) = @_; + #http://stackoverflow.com/questions/4826403/hash-algorithm-with-alphanumeric-output-of-20-characters-max + $self->content_params->{server_name} ||= substr(md5_hex($self->content_params->{uri}),0,20); + return $self->content_params->{server_name}; +} +1; + +=head1 NAME + +NGCP::Panel::Utils::DeviceBootstrap + +=head1 DESCRIPTION + +Make API requests to configure remote redirect servers for requested MAC with autorpov uri. + +=head1 METHODS + +=head2 bootstrap + +Dispatch to proper vendor API call. + +=head1 AUTHOR + +Irina Peshinskaya C<< >> + +=head1 LICENSE + +This library is free software. You can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut +# vim: set tabstop=4 expandtab: diff --git a/share/templates/device/list.tt b/share/templates/device/list.tt index d1c54692c5..b82a74c916 100644 --- a/share/templates/device/list.tt +++ b/share/templates/device/list.tt @@ -34,10 +34,6 @@ function vendor2bootstrapMethod(vendorField){ bootstrapMethod = 'redirect_panasonic'; break; ; - case "linksys": - bootstrapMethod = 'redirect_linksys'; - break; - ; case "yealink": bootstrapMethod = 'redirect_yealink'; break;