Perl ssl client auth using certificate - perl

I'm having trouble getting the following code to work and at a point where I am stuck. I am trying to perform client side authentication using a certificate during a POST request. I'm only interested in sending the client cert to the server and don't really need to check the server certificate.
Here is the cUrl command that trying to replicate:
curl --cacert caCertificate.pem --cert clientCerticate.pem -d "string" https://xx.xx.xx.xx:8443/postRf
I keep getting the following error in my Perl script:
ssl handshake failure
I guess I have two questions: what should I be pointing to for CRT7 AND KEY8 variables? and is this the best way to send a POST request using client cert authentication?
!/usr/bin/perl
use warnings;
use strict;
use Net::SSLeay qw(post_https);
my $$hostIp = "xx.xx.xx.xx"
my $hostPort = "8443"
my $postCommand = "/postRf/string";
my $http_method = 'plain/text';
my $path_to_crt7 = 'pathToCert.pem';
my $path_to_key8 = 'pathToKey.pem';
my ($page, $response, %reply_headers) =
post_https($hostIp, $hostPort, $postCommand, '',
$http_method, $path_to_crt7, $path_to_key8
);
print $page . "\n";
print $response . "\n";

See LWP::UserAgent and IO::Socket::SSL.
use strictures;
use LWP::UserAgent qw();
require LWP::Protocol::https;
my $ua = LWP::UserAgent->new;
$ua->ssl_opts(
SSL_ca_file => 'caCertificate.pem',
SSL_cert_file => 'clientCerticate.pem',
);
$ua->post(
'https://xx.xx.xx.xx:8443/postRf',
Content => 'string',
);
I haven't tested this code.

Related

Implementing custom Curl authentication in Perl script

I am building bot application trying to use perl script to implement the curl request, the issue I have is with Authorization.
The simple curl command is something like.
curl \
-H 'Authorization: Bearer VM2CKBMXI3AVX2GMYPLBMYFRW3RCHYXS' \
'https://api.wit.ai/message?v=20160722&q='
I preferred not to use system() calls from the Perl script as there will be plenty of back and forth between the user and the bot.
I found this library
http://search.cpan.org/~szbalint/WWW-Curl-4.17/lib/WWW/Curl.pm
I was searching for setopt function in order to find out which params does it accept as my issue is where to put the Authorization param inside the command.
I found this link
http://web.mit.edu/darwin/src/modules/curl/curl/perl/Curl_easy/easy.pm
My Script code for now it is like the following:
use strict;
use warnings;
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new;
my $Authorization="Authorization: Bearer VM2CKBMXI3AVX2GMYPLBMYFRW3RCHYXS";
$curl->setopt(CURLOPT_HEADER,1);
$curl->setopt(CURLOPT_URL, 'https://api.wit.ai/message?v=20160721&q=hello');
# A filehandle, reference to a scalar or reference to a typeglob can be used here.
my $response_body;
$curl->setopt(CURLOPT_WRITEDATA,\$response_body);
# Starts the actual request
my $retcode = $curl->perform;
# Looking at the results...
if ($retcode == 0) {
print("Transfer went ok\n");
my $response_code = $curl->getinfo(CURLINFO_HTTP_CODE);
# judge result and next action based on $response_code
print("Received response: $response_body\n");
} else {
# Error code, type of error, error message
print("An error happened: $retcode ".$curl->strerror($retcode)." ".$curl->errbuf."\n");
}
I just need to know which CURLOPT should I need to use in order to implement authorization.
If you have any idea that will be great.
Thanks
Eran Gross
If you just want to set the header "Authorization" the option is CURLOPT_HTTPHEADER:
#!/usr/bin/perl
use strict;
use warnings;
use WWW::Curl::Easy;
my $curl = WWW::Curl::Easy->new;
$curl->setopt(CURLOPT_URL, 'http://127.0.0.1/dumprequest.php');
my #headers = ("Authorization: keygoeshere", "X-Foo: Bah");
$curl->setopt(CURLOPT_HTTPHEADER, \#headers);
$curl->setopt(CURLOPT_HEADER, 1);
my $retcode = $curl->perform;
Gives:
GET dumprequest.php HTTP/1.1
Host: 127.0.0.1
Accept: */*
Authorization: keygoeshere
X-Foo: Bah
But if you actually want to do HTTP authentication then you would use CURLOPT_USERPWD and CURLOPT_HTTPAUTH. See https://curl.haxx.se/libcurl/c/curl_easy_setopt.html for more info on options.

Scrape from .onion site using Web::Scraper

Problem: Scrape from tor .onion site using Web::Scraper
I would like to modify my code to connect to .onion site. I believe I need to connect to the SOCKS5 proxy, but unsure of how to do it with Web::Scraper
Existing code:
use Web::Scraper;
my $piratelink=$PIRATEBAYSERVER.'/search/' . $srstring . '%20'. 's'.$sval[1].'e'.$epinum.'/0/7/0';
my $purlToScrape = $piratelink;
my $ns = scraper {
process "td>a", 'mag[]' => '#href';
process "td>div>a", 'tor[]' => '#href';
process "td font.detDesc", 'sizerow[]' => 'TEXT';
};
my $mres = $ns->scrape(URI->new($purlToScrape));
Web::Scraper uses LWP if you pass a URI to scrape.
You can either fetch the HTML using some other HTTP library that uses SOCKS, or using the shared UserAgent variable from Web::Scraper, you can set up LWP to use SOCKS and pass that as the agent.
use strict;
use LWP::UserAgent;
use Web::Scraper;
# set up a LWP object with Tor socks address
my $ua = LWP::UserAgent->new(
agent => q{Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.2.0; .NET CLR 1.1.4322)},
);
$ua->proxy([qw/ http https /] => 'socks://localhost:9050'); # Tor proxy
$ua->cookie_jar({});
my $PIRATEBAYSERVER = 'http://uj3wazyk5u4hnvtk.onion';
my $srstring = 'photoshop';
my $piratelink=$PIRATEBAYSERVER.'/search/' . $srstring; # . '%20'. 's'.$sval[1].'e'.$epinum.'/0/7/0';
my $purlToScrape = $piratelink;
my $ns = scraper {
process "td>a", 'mag[]' => '#href';
process "td>div>a", 'tor[]' => '#href';
process "td font.detDesc", 'sizerow[]' => 'TEXT';
};
# override Scraper's UserAgent with our SOCKS LWP object
$Web::Scraper::UserAgent = $ua;
my $mres = $ns->scrape(URI->new($purlToScrape));
print $mres;
Note, you will also need to install the CPAN module LWP::Protocol::socks

HTTP Basic Authentication in Asana with perl

I'm trying to use Asana API with HTTP Basic Auth. The following program prints
{"errors":[{"message":"Not Authorized"}]}
It seems that LWP doesn't send the auth credentials to the server.
#!/usr/bin/perl
use v5.14.0;
use LWP;
my $ua = new LWP::UserAgent;
$ua->credentials('app.asana.com:443', 'realm', 'api_key_goes_here' => '');
my $res = $ua->get("https://app.asana.com/api/1.0/users/me");
say $res->decoded_content;
I've run into something similar (on a completely different service), and couldn't get it working. I think it's to do with a realm/hostname mismatch.
As you note - if you hit that URL directly, from a web browser, you get the same answer (without an auth prompt).
But what I ended up doing instead:
my $request = HTTP::Request -> new ( 'GET' => 'https://path/to/surl' );
$request -> authorization_basic ( 'username', 'password' );
my $results = $user_agent -> request ( $request );

How to get http and https return code in perl

I am new to perl and any help will be appreciated!!
I have to invoke some URLs through perl (On unix machine).URLs are both http and https
if URL gets invoked successfully,then its fine else create a log file stating that unable to invoke a URL.
For invoking the URL,I am thinking to use for e.g.
exec 'firefox http://www.yahoo.com';
But how to get http and https request status code? Something like if status is 200,then ok else error..
Kindly help!!
Rather than using a browser such a Firefox you should use an HTTP client library such as HTTP::Tiny or LWP::UserAgent.
For exmaple:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use HTTP::Tiny;
my $Client = HTTP::Tiny->new();
my #urls = (
'http://www.yahoo.com',
'https://www.google.com',
'http://nosuchsiteexists.com',
);
for my $url (#urls) {
my $response = $Client->get($url);
say $url, ": ", $response->{status};
}
Which outputs:
alex#yuzu:~$ ./return_status.pl
http://www.yahoo.com: 200
https://www.google.com: 200
http://nosuchsiteexists.com: 599
If you want to correctly recognise redirect status codes (3XX) you would have to set the max_redirect parameter to 0.
alex#yuzu:~$ perl -MHTTP::Tiny -E 'say HTTP::Tiny->new(max_redirect => 0)->get("http://www.nestoria.co.uk/soho")->{status};'
301
If all you care about is success then the response hashref contains a 'success' field which will be true on success and false on failure.
alex#yuzu:~$ perl -MHTTP::Tiny -E 'say HTTP::Tiny->new()->get("http://www.google.com")->{success};'
1

Error: 500 Can't connect to example.com:443 (certificate verify failed)

I get that error. Here is my code.
use LWP::UserAgent;
use HTTP::Request::Common qw(POST);
use HTTP::Cookies;
$URL="https://example.com/my.plicy";
$UA = LWP::UserAgent->new();
$UA->ssl_opts( verify_hostnames => 0 );
#UA->ssl_opts( SSL_ca_file => Mozilla::CA::SSL_ca_file() );
$req =HTTP::Request::Common::POST("$URL",
Content_type=>'form-data',
Content =>[
'username'=>'111',
'password'=>'2222',
'vhost'=>'standard'
]
);
$req->header('Cookie' =>q(TIN=287000; LastMRH_Session=439960f5; MRHSession=78c9c47291c1fcedae166121439960f5));
$resp=$UA->request($req);
if( ($resp->code() >= 200) && ($resp->code() <400) ) {
print $resp->decoded_content;
}else{
print "Error: ". $resp->status_line. "\n";
}
The problem is that I have no real certificate to provide, because the site is in development stages, and a certificate of the localhost is used... the browsers don't recognize it.
Is there a way to bypass the verification?? and avoid the error?
UPDATE:
I changed my code a bit. Added another library and added this function:
use CACertOrg::CA;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
$UA->ssl_opts(
verify_hostnames => 0,
SSL_ca_file => CACertOrg::CA::SSL_ca_file()
);
Now I get this:
Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER
together with SSL_ca_file|SSL_ca_path for verification.
If you really don't want to verify the certificate and keep the
connection open to Man-In-The-Middle attacks please set
SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
at C:/Perl/lib/LWP/Protocol/http.pm line 31.
So I changed the options to this:
$UA->ssl_opts(
SSL_verify_mode => 'SSL_VERIFY_NONE',
verify_hostnames => 0,
SSL_ca_file => CACertOrg::CA::SSL_ca_file()
);
I get nothing printed... I don't get an error, though. Is it a good sign?
You need to add this line after use .. part:
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
Try this
my $UA = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0, } );
Digging up corpses here but I was in the same position and here is what you need to include in order to fix it ;)
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
$ENV{PERL_LWP_SSL_CA_FILE} = "/path/to/your/cert.pem";
Only setting verify_hostnames to 0 is not enough when you play around with self signed certificates.
None of those solutions worked for me (two and a half years after the last update.. but still it is the top search result so I thought I would add the solution that worked for me) - I needed an additional package to the installation on my Server. It is the LWP::Protocol::https package that I installed via cpan. To install it I typed into the commandline on my server shell:
cpan install LWP::Protocol::https
After the package is installed the code works as it was before without any alterations to the code.