Perl JSON::RPC::Client Not a HASH reference Error - perl

When i call remote echo procedure my call reachs to rpc server which is written in python with txjsonrpc module. but this script says:
malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "read failed: at /us...") at /usr/local/lib/perl/5.14.2/Moose/Meta/Method/Delegation.pm line 110
Any idea? Code is here:
use LWP::UserAgent;
use JSON::RPC::LWP;
use Net::SSL ();
use JSON::RPC::Client;
$ENV{HTTPS_DEBUG} = 1;
# CA cert peer verification
$ENV{HTTPS_CA_FILE} = 'ca_file';
$ENV{HTTPS_CA_DIR} = 'ca_dir';
# Client PKCS12 cert support
$ENV{HTTPS_PKCS12_FILE} = 'pkcs12 cert';
$ENV{HTTPS_PKCS12_PASSWORD} = 'password';
my $ua = eval { LWP::UserAgent->new() }
or die "Could not make user-agent! $#";
$ua->ssl_opts( verify_hostname => 0);
print "JSON RPC CONNECTION\n";
my $rpc = JSON::RPC::Client->new(
ua => $ua,
version => '2.0'
);
my $result = $rpc->call( 'https://...', {method=>'echo', params=>['param']});
print $result->result, "\n";

What version of JSON::RPC::Client are you using? If it is the most current one, that error is happening because the server is returning something other than a JSON object.

Related

use of uninitialized value. How can I fix this error?

#!/usr/bin/perl
use Net::SSH::Expect;
use warnings;
use strict;
#my($stdout, $stderr, $exit) = $ssh->cmd("ls -l /home/$usr")
# Making an ssh connection with user-password authentication
# 1) construct the object
my $ssh = Net::SSH::Expect->new (
host => "host",
password=> 'pwd',
user => 'user',
raw_pty => 1
#Expect=>log_file("finally.txt")
);
# 2) logon to the SSH server using those credentials.
# test the login output to make sure we had success
my $login_output = $ssh->login();
if ($login_output !~ /Welcome/) {
die "Login has failed. Login output was $login_output";
}
# disable terminal translations and echo on the SSH server
# executing on the server the stty command:
$ssh->exec("stty raw -echo");
my $stdout = $ssh->send(chr(13));
my $stdout2 = $ssh->send("SDT-FI");
my $stdout3 = $ssh->send("ENG");
my $stdout4 = $ssh->send('SORT FI-WIP "84144"');
my $stdout5 = $ssh->send(chr(13));
my $stdout6 = $ssh->send("OFF");
my $stdout7 = $ssh->send(chr(13));
print($stdout3);
#$expect->log_file("adp-n.txt");
#y $line;
# returns the next line, removing it from the input stream:
# while ( defined ($line = $ssh->read_all()) ) {
# print $line . "\n";
#}
So i am trying to print $stdout3 so i can get information about the output
but i keep getting " use of uninitialized value $stdout3 in print at connnn3.pl line 50"
is there something in my code wrong?
how can i fix this?
UPDATE, SOLVED!
The reason why it was returning "use of uninitialized value" was because the function
send()
Is void, so instead i used
exec()
And that solved it
From the documentation of Net::SSH::Expect:
void send($string) - sends $string to the SSH server, returns nothing
Thus, send obviously returns nothing (void) and that's why you get this warning when trying to print the (non-existing) return value of send. If you want to get data back from the server use peek, eat, read_all or similar as documented.

Using LWP with SSL and client certificates

I'm porting an application from PHP/cURL to Perl and LWP::UserAgent. I need to do a POST request to a web server and provide a client certificate and key file. The PHP code I'm trying to replicate is this:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSLCERT, "/path/to/certificate.pem");
curl_setopt($ch, CURLOPT_SSLKEY, "/path/to/private.key");
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, "secretpassword");
And here's my Perl code:
my $ua = LWP::UserAgent->new();
$ua->ssl_opts(
SSL_verify_mode => 0,
SSL_cert_file => '/path/to/certificate.pem',
SSL_key_file => "/path/to/private.key",
SSL_passwd_cb => sub { return "secretpassword"; }
);
The PHP code successfully connects to the server but the Perl code fails with:
SSL read error error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
I can't figure out what I'm missing.
sub send_command(){
my $command = shift;
my $parser = XML::LibXML->new('1.0','utf-8');
print color ("on_yellow"), "SEND: ", $command, color ("reset"), "\n";
# Create a request
my $req = HTTP::Request->new( GET => $Gateway.$command );
# Pass request to the user agent and get a response back
my $res;
eval {
my $ua;
local $SIG{'__DIE__'};
$ua = LWP::UserAgent->new(); # или
$ua->ssl_opts( #$key => $value
SSL_version => 'SSLv3',
SSL_ca_file => '/ca.pem',
#SSL_passwd_cb => sub { return "xxxxx\n"; },
SSL_cert_file => '/test_test_cert.pem',
SSL_key_file => '/test_privkey_nopassword.pem',
); # ssl_opts => { verify_hostname => 0 }
$ua->agent("xxxxxx xxxx_tester.pl/0.1 ");
$res = $ua->request($req);
};
warn $# if $#;
# Check the outcome of the response
if ( $res->is_success ) {
open xxxLOG, ">> $dir/XXXX_tester.log";
my $without_lf = $res->content;
$without_lf =~ s/(\r|\n)//gm;
print PAYLOG $without_lf,"\n";
close PAYLOG;
}
else {
return $res->status_line;
}
print color ("on_blue"), "RESPONSE: ", color ("reset"), respcode_color($res->content), color ("reset"),"\n\n";
return $res->content;
}
The answer from emazep above solved my problem. I'm using the sample Perl code from UPS to connect to their Rate service via XML. From my tests, this will work any time LWP::UserAgent is being called without arguments that you can control directly, which makes it handy if you're using some other module which makes calls to LWP for you. Just use Net::SSL (in addition to whatever packages have already used LWP) and set a few environment variables:
...
use Net::SSL;
$ENV{HTTPS_VERSION} = 3;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
my $browser = LWP::UserAgent->new();
...
That's it! You shouldn't even need to specify the path to your server's root certificate with $ENV{PERL_LWP_SSL_CA_FILE}.
Indeed this is a messy bit. Depending on your setup LWP::UserAgent may use one of (at least) two SSL modules to handle the SSL connection.
IO::Socket::SSL
Net::SSL
The first one should be the default for newer versions of LWP::UserAgent. You can test which of these are installed by running the standard command in a terminal for each module:
perl -e 'use <module>;'
IO::socket::SSL requires the SSL configuration with the ssl_opts as in your example.
Net::SSL requires the SSL configuration in environment variables as in goddogsrunnings answer.
Personally I fall in the second category and had good inspiration from the Crypt::SSLeay page. Particularly the section named "CLIENT CERTIFICATE SUPPORT ".

Can't use an undefined value as a symbol reference

I'm trying to use an API for a Palo Alto Networks software. The code is supposed to submit username and ipaddress of user network logins to a web interface.
When I try using PANs' API with their sample code for a windows machine the following exception is thrown:
Can't use an undefined value as a symbol reference at
C:/Perl/lib/PAN/API.pm line 179 (#1)
PAN::API::UID::login('PAN::API::UID=HASH(0x7fd113828598)', 'SCU-DSM22/pmmertens', 172.16.6.117) called at API_events.pl line 12
This is the code-example that comes with the API documentation:
#!/usr/bin/perl -w
use strict;
use PAN::API;
my $useridagent = '10.0.0.99'; #I changed this to our PAN server address
my $useridapi = PAN::API::UID->new($useridagent);
my $user = $ENV{USERDOMAIN}.'/'.$ENV{USERNAME};
my $ipaddress = unpack('W4',gethostbyname($ENV{COMPUTERNAME}));
$useridapi->login($user,$ipaddress);
I've ensure that all variables are retrieved correctly. Substituting literal values did not help either. Googling this error turned up references about hard and soft references but I don't see any infractions of these rules in the code below.
This is the codeblock from PAN/Api.pm. Line 179 is where the print starts.
sub submit () {
my $self = shift;
use IO::Socket::INET;
use IO::Socket::SSL;
my $socket = IO::Socket::INET->new(PeerAddr => $self->{server},
PeerPort => $self->{port},
Proto => 'tcp');
my $socketssl = IO::Socket::SSL->start_SSL( $socket,
SSL_version =>'TLSv1');
print $socketssl $self->xml;
$socketssl->close;
$socketssl->stop_SSL;
}
Both the IO::Socket::INET and IO::Socket::SSL lines should have error checking. Something like:
my $socket = IO::Socket::INET->new(....)
or die "Failed to create socket: $!"
And:
my $socketssl = IO::Socket::SSL->start_SSL(...)
or die "Failed to start SSL: ".IO::Socket::SSL::errstr();
Although instead of die I might go with Carp::confess.

How can I get the ultimate URL without fetching the pages using Perl and LWP?

I'm doing some web scraping using Perl's LWP. I need to process a set of URLs, some of which may redirect (1 or more times).
How can I get ultimate URL with all redirects resolved, using HEAD method?
If you use the fully featured version of LWP::UserAgent, then the response that is returned is an instance of HTTP::Response which in turn has as an attribute an HTTP::Request. Note that this is NOT necessarily the same HTTP::Request that you created with the original URL in your set of URLs, as described in the HTTP::Response documentation for the method to retrieve the request instance within the response instance:
$r->request( $request )
This is used to get/set the request attribute. The request attribute is a reference to the the request that caused this response. It does not have to be the same request passed to the $ua->request() method, because there might have been redirects and authorization retries in between.
Once you have the request object, you can use the uri method to get the URI. If redirects were used, the URI is the result of following the chain of redirects.
Here's a Perl script, tested and verified, that gives you the skeleton of what you need:
#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
my $ua; # Instance of LWP::UserAgent
my $req; # Instance of (original) request
my $res; # Instance of HTTP::Response returned via request method
$ua = LWP::UserAgent->new;
$ua->agent("$0/0.1 " . $ua->agent);
$req = HTTP::Request->new(HEAD => 'http://www.ecu.edu/wllc');
$req->header('Accept' => 'text/html');
$res = $ua->request($req);
if ($res->is_success) {
# Using double method invocation, prob. want to do testing of
# whether res is defined.
# This is inline version of
# my $finalrequest = $res->request();
# print "Final URL = " . $finalrequest->url() . "\n";
print "Final URI = " . $res->request()->uri() . "\n";
} else {
print "Error: " . $res->status_line . "\n";
}
As stated in perldoc LWP::UserAgent, the default is to follow redirects for GET and HEAD requests:
$ua = LWP::UserAgent->new( %options )
...
KEY DEFAULT
----------- --------------------
max_redirect 7
...
requests_redirectable ['GET', 'HEAD']
Here is an example:
#!/usr/bin/perl
use strict; use warnings;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
$ua->show_progress(1);
my $response = $ua->head('http://unur.com/');
if ( $response->is_success ) {
print $response->request->uri->as_string, "\n";
}
Output:
** HEAD http://unur.com/ ==> 301 Moved Permanently (1s)
** HEAD http://www.unur.com/ ==> 200 OK
http://www.unur.com/

How do I authenticate into Gmail using Perl?

I've installed this module to gain access and controls within a Gmail inbox. However, when I try to connect through a small Perl script and test the functionality, I get this error message.
Error: Could not login with those credentials - could not find final URL
Additionally, HTTP error: 200 OK
This is an error built within the Gmail.pm module.
I can ping the URL in question ( https://www.google.com/accounts/ServiceLoginBoxAuth ) so I feel that the trouble isn't finding the URL. Furthermore, I know the credentials are correct and work at that URL because I have tried them manually.
I'm using this script for testing. I have supplied my credentials in the appropriate places.
I've also installed this module with the same type of error.
Any idea why I'm getting blocked?
Use Mail::IMAPClient as shown below. To get pass SSL authentication through Mail::IMAPClient, you should have IO::Socket::SSL from Net::SSLeay installed. If so this works like a charm.
#!/usr/bin/env perl
use strict; use warnings;
use Mail::IMAPClient;
# Connect to IMAP server
my $client = Mail::IMAPClient->new(
Server => 'imap.gmail.com',
User => 'yourusername',
Password => 'yourp4a55w0r&',
Port => 993,
Ssl => 1,
)
or die "Cannot connect through IMAPClient: $!";
# List folders on remote server (see if all is ok)
if ( $client->IsAuthenticated() ) {
print "Folders:\n";
print "- ", $_, "\n" for #{ $client->folders() };
};
# Say so long
$client->logout();
I am successfully accessing a gmail account (google apps account to be precise) using Mail::POP3Client
If you cannot access gmail through normal POP3 or IMAP either, then you have a configuration problem rather than a programming problem.
I fetch my mail from gmail (actually Google Apps, which uses the same interface), using configuration details described here: http://download.gna.org/hpr/fetchmail/FAQ/gmail-pop-howto.html
(This answer is far more appropriate for Super User though!)
You can tried with the following module
Mail::Webmail::Gmail
You can use the following code also
use warnings;
use strict;
use Mail::POP3Client;
use IO::Socket::SSL;
use CGI qw(:standard);
my $cgi = new CGI;
my $LOG ;
open $LOG , ">>filename" ;
my $username = 'name#gmail.com';
my $password = '*******' ;
chomp($password);
my $mailhost = 'pop.gmail.com';
my $port = '995';
$cgi->header();
my $pop = new Mail::POP3Client(
USER => $username,
PASSWORD => $password,
HOST => $mailhost,
PORT => $port,
USESSL => 'true',
DEBUG => 0,
);
if (($pop->Count()) < 1) {
exit;
}
print $pop->Count() . " messages found!:$!\n";
for(my $i = 1; $i <= $pop->Count(); $i++) {
foreach($pop->Head($i)) {
/^(From|Subject|Email):\s+/i && print $_, "\n";
}
$pop->BodyToFile($LOG,$i);
}
$pop->Close();
exit;