You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Utils/DeviceBootstrap/VendorRPC.pm

231 lines
6.0 KiB

package NGCP::Panel::Utils::DeviceBootstrap::VendorRPC;
use strict;
use URI::Escape;
use MIME::Base64 qw/encode_base64/;
use LWP::UserAgent;
use HTTP::Request::Common;
use RPC::XML::ParserFactory 'XML::LibXML';
use RPC::XML;
use Data::Dumper;
use Moo;
use Types::Standard qw(HashRef Str);
has 'params' => (
is => 'rw',
isa => HashRef,
);
has 'content_params' => (
is => 'rw',
isa => HashRef,
);
has 'response' => (
is => 'rw',
);
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 redirect_server_call{
my ($self, $action) = @_;
my $c = $self->params->{c};
$self->init_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};
$cfg->{query_string} //= '';
$c->log->debug( "rpc_https_call: host=$cfg->{host}; port=$cfg->{port}; path=$cfg->{path}; query_string=$cfg->{query_string}; content=$content;" );
#$c->log->debug( Dumper($cfg->{headers}) );
my( $page, $response_code, $response_value, $reply_headers ) = ('','','',{});
eval {
local $SIG{ALRM} = sub { die "Connection timeout\n" };
alarm(25);
my $ua = LWP::UserAgent->new;
$ua->credentials($cfg->{host}.':'.$cfg->{port}, $cfg->{realm} // '', @$cfg{qw/user password/});
$ua->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => 0,
);
$cfg->{port} //= '';
my $uri = $cfg->{proto}.'://'.$cfg->{host}.($cfg->{port} ? ':' : '').$cfg->{port}.$cfg->{path};
my $request = POST $uri,
Content_Type => $cfg->{content_type} // 'text/xml',
%{$cfg->{headers}},
Content => $content;
my $response = $ua->request($request);
$self->response($response);
( $page, $response_code, $reply_headers ) = ($response->content,$response->code,$response->headers);
alarm(0);
};
alarm(0);
if ($@ && !$page) {
$c->log->debug( "eval error: $@;" );
if ($@ =~ /Connection timeout/) {
$response_value = 'Connection timeout';
}
}
$c->log->info( "response=$response_code; page=$page;" );
if($page){
my $rpc_response = $self->parse_rpc_response_page($page);
$response_value = $self->parse_rpc_response($rpc_response);
}
return $response_value;
}
sub parse_rpc_response_page{
my($self, $page) = @_;
my $parser = RPC::XML::ParserFactory->new();
return $parser->parse($page);
}
sub parse_rpc_response{
my($self,$rpc_response) = @_;
return $rpc_response->value->value;
}
sub extract_response_description{
my($self,$response_value) = @_;
#polyycom version
if(('HASH' eq ref $response_value) && $response_value->{faultString}){
return $response_value->{faultString};
} else {
return '';
}
}
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;
return { 'Authorization' => 'Basic '.$authorization };
}
sub get_bootstrap_uri{
my ($self) = @_;
my $uri = $self->params->{redirect_uri};
my $uri_params = $self->params->{redirect_params}->{sync_params} || '';
if(!$uri){
my $cfg = $self->bootstrap_uri_conf();
$uri = "$cfg->{schema}://$cfg->{host}:$cfg->{port}/device/autoprov/bootstrap/";
}
$uri .= $uri_params;
return $self->process_bootstrap_uri($uri);
}
sub process_bootstrap_uri{
my($self,$uri) = @_;
$uri = $self->bootstrap_uri_protocol($uri);
return $uri;
}
sub bootstrap_uri_protocol{
my($self,$uri) = @_;
if($uri !~/^(?:https?|t?ftp):\/\//i ){
$uri = 'http://'.$uri;
}
return $uri;
}
sub bootstrap_uri_mac{
my($self, $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 bootstrap_uri_conf{
my ($self) = @_;
my $c = $self->params->{c};
my $cfg = {
#schema => $c->config->{deviceprovisioning}->{secure} ? 'https' : 'http',
schema => 'http', # for bootstrapping, we always use http
host => $c->config->{deviceprovisioning}->{host} // $c->req->uri->host,
port => $c->config->{deviceprovisioning}->{bootstrap_port} // 1445,
};
return $cfg;
}
sub unknown_error{
my ($self) = @_;
my $c = $self->params->{c};
return $c->loc('Unknown error');
}
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<< <ipeshinskaya@sipwise.com> >>
=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: