#!/usr/bin/perl # Version 1.0.1 # Need the following: # Modules - Authen::HTTP::Signature, DateTime, DateTime::Format::HTTP, Mozilla::CA, File::Slurp, LWP::UserAgent, LWP::Protocol::https # LWP::UserAgent and LWP::Protoco::https >= 6.06 # OpenSSL >= 1.0.1 use strict; use warnings; { package OCISigner; use Authen::HTTP::Signature; use Digest::SHA qw(sha256_base64); use DateTime; use DateTime::Format::HTTP; my @generic_headers = ( 'date', '(request-target)', 'host' ); my @body_headers = ( 'content-length', 'content-type', 'x-content-sha256' ); my @all_headers = (@generic_headers, @body_headers); my %required_headers = ( get => \@generic_headers, delete => \@generic_headers, head => \@generic_headers, post => \@all_headers, put => \@all_headers ); sub new { my ( $class, $api_key, $private_key) = @_; my $self = { _api_key => $api_key, _private_key => $private_key }; bless $self, $class; return $self; } sub sign_request { my ( $self, $request ) = @_; my $verb = lc($request->method); my $sign_body = grep(/^$verb$/, ('post', 'put')); $self->inject_missing_headers($request, $sign_body); my $headers = $required_headers{$verb}; my $all_auth = Authen::HTTP::Signature->new( key => $self->{_private_key}, request => $request, key_id => $self->{_api_key}, headers => $headers, ); $all_auth->sign(); } sub inject_missing_headers { my ( $self, $request, $sign_body ) = @_; $request->header('content-type', 'application/json') unless $request->header('content-type'); $request->header('accept', '*/*') unless $request->header('accept'); my $class = 'DateTime::Format::HTTP'; $request->header('date', $class->format_datetime(DateTime->now)) unless $request->header('date'); $request->header('host', $request->uri->host) unless $request->header('host'); if ($sign_body) { $request->content('') unless $request->content; $request->header('content-length', length($request->content)) unless $request->header('content-length'); $request->header('x-content-sha256', $self->compute_sha256($request->content)) unless $request->header('x-content-sha256'); } } sub compute_sha256 { my ( $self, $content ) = @_; my $digest = sha256_base64($content); while (length($digest) % 4) { $digest .= '='; } return $digest; } } # OCISigner { package OCIClient; use LWP::UserAgent; use Mozilla::CA; sub new { my ( $class, $api_key, $private_key ) = @_; my $ua = LWP::UserAgent->new; $ua->ssl_opts( verify_hostname => 1, SSL_ca_file => Mozilla::CA::SSL_ca_file() ); my $self = { _signer => OCISigner->new($api_key, $private_key), _ua => $ua }; bless $self, $class; return $self; } sub make_request { my ( $self, $request ) = @_; print "Sending request\n"; $self->{_signer}->sign_request($request); my $response = $self->{_ua}->request($request); if ($response->is_success) { my $message = $response->decoded_content; print "Received reply: $message\n"; } else { print "HTTP GET error code: ", $response->code, "\n"; print "HTTP GET error message: ", $response->message, "\n"; } } } # OCIClient use File::Slurp qw(read_file); my $api_key = "ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/" . "ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/" . "20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34"; my $private_key = read_file('../sample-private-key') or die $!; my $client = OCIClient->new($api_key, $private_key); # Uncomment to use a fixed date #my $fixed_date = 'Thu, 05 Jan 2014 21:31:40 GMT'; my $fixed_date; # GET with query parameters # Note: Older ocid formats included ":" which must be escaped my %query_args = ( availability_domain => "Pjwf%3A%20PHX-AD-1", compartment_id => "ocid1.compartment.oc1..aaaaaaaam3we6vgnherjq5q2idnccdflvjsnog7mlr6rtdb25gilchfeyjxa", display_name => "TeamXInstances", volume_id => "ocid1.volume.oc1.phx.abyhqljrgvttnlx73nmrwfaux7kcvzfs3s66izvxf2h4lgvyndsdsnoiwr5q" ); my $uri = "https://iaas.us-ashburn-1.oraclecloud.com/20160918/instances?availabilityDomain=" . $query_args{availability_domain} . "&compartmentId=" . $query_args{compartment_id} . "&displayName=" . $query_args{display_name} . "&volumeId=" . $query_args{volume_id}; my $request = HTTP::Request->new(GET => $uri); $request->header('date', $fixed_date) if $fixed_date; $client->make_request($request); # POST with body $uri = "https://iaas.us-ashburn-1.oraclecloud.com/20160918/volumeAttachments"; my $body = q|{ "compartmentId": "ocid1.compartment.oc1..aaaaaaaam3we6vgnherjq5q2idnccdflvjsnog7mlr6rtdb25gilchfeyjxa", "instanceId": "ocid1.instance.oc1.phx.abuw4ljrlsfiqw6vzzxb43vyypt4pkodawglp3wqxjqofakrwvou52gb6s5a", "volumeId": "ocid1.volume.oc1.phx.abyhqljrgvttnlx73nmrwfaux7kcvzfs3s66izvxf2h4lgvyndsdsnoiwr5q" }|; $request = HTTP::Request->new(POST => $uri); $request->header('date', $fixed_date) if $fixed_date; $request->content($body); $client->make_request($request);