Device-Firewall-PaloAlto
view release on metacpan or search on metacpan
lib/Device/Firewall/PaloAlto/API.pm view on Meta::CPAN
package Device::Firewall::PaloAlto::API;
$Device::Firewall::PaloAlto::API::VERSION = '0.1.9';
use strict;
use warnings;
use 5.010;
use URI;
use URI::Encode;
use Carp;
use LWP::UserAgent;
use HTTP::Request::Common;
use XML::Twig;
use Class::Error;
use Device::Firewall::PaloAlto::Errors qw(fatal_error);
# VERSION
# PODNAME
# ABSTRACT: Palo Alto firewall API module
# Sends a request to the firewall. The query string parameters come from the key/value
# parameters passed to the function, ie _send_request(type = 'op', cmd => '<xml>')
#
# The method automatically adds in the autentication key if it exists.
sub _send_request {
my $self = shift;
my %query = @_;
# If we're authenticated, add the API key
$query{key} = $self->{api_key} if $self->{api_key};
# Create the request and pass it to the raw request function.
# This function exists to allow us to wrap it in debug functions
# and see the raw requests and responses
my $request = POST $self->{uri}->as_string, [ %query ];
my $response = $self->_send_raw_request($request);
# Check and return
return _parse_and_check_response( $response );
}
sub _send_raw_request {
my $self = shift;
return $self->{user_agent}->request($_[0]);
}
sub _parse_and_check_response {
my ($http_response) = @_;
my $r;
$r = _check_http_response($http_response) or return $r;
return _check_api_response($r);
}
# Checks whether the HTTP response is an error.
# Returns an error object if there's an HTTP error.
# Returns the decoded HTTP content on success.
sub _check_http_response {
my ($http_response) = @_;
if ($http_response->is_error) {
my $err = "HTTP Error: @{[$http_response->status_line]} - @{[$http_response->code]}";
return fatal_error($err, 0);
}
return $http_response->decoded_content;
}
# Parses the API response and checks if it's an API error.
# Returns a data structure representing the XML content on success.
# On failure returns 'false'.
sub _check_api_response {
my ($http_content) = @_;
return $http_content unless $http_content;
my $api_response = XML::Twig->new->safe_parse( $http_content );
return fatal_error('Invalid XML returned in PA response') unless $api_response;
$api_response = $api_response->simplify( forcearray => ['entry'] );
if ($api_response->{status} eq 'error') {
my $error_string = _clean_error_message($api_response);
my $err = "API Error: $error_string (Code: $api_response->{code})";
return fatal_error($err);
}
return $api_response;
}
# The error messages that come back from the firewall are in some very strange and different structures.
# This functiona attempts to clean them up
sub _clean_error_message {
my ($response) = @_;
my $ret_string;
if (!defined $response->{msg}{line}) {
return 'No error message defined';
}
my $error_structure = ref $response->{msg}{line};
if (!$error_structure) {
return $response->{msg}{line};
} elsif ($error_structure eq 'ARRAY') {
return join(', ', @{$response->{msg}{line}});
} else {
return '';
}
return $response->{msg}{line};
}
use Data::Dumper;
sub _debug_pre_wrap {
my $self = shift;
my ($http_request) = @_;
say "Request:";
say $http_request->as_string;
say "Decoded Request:";
say URI::Encode->new->decode( $http_request->as_string );
}
( run in 1.944 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )